C# spil (del 3) - Space Invaders, sådan!

Relaterede dokumenter
C# spil (del 2) - Tilstandmaskiner i spil

C# spil (del 1) - Kom i gang med et simpelt spil

Som sagt kræves der helst lidt viden om OOP hvis man virkelig vil lærer noget, og ikke bare lave copypaste

Hvad er Objekter - Programmering

Java Klasse nedarvninger

I denne artikel vil du ved hjælp af arrays kunne afrunde et decimaltal til et helt tal.

Bekrig Klonerne. Introduktion. Scratch. I dette projekt skal du lære, hvordan du laver et spil, hvor du skal redde Jorden fra monstre i rummet.

Tilfældige tal. Denne artikel introducerer generering af tilfældige tal og viser lidt om hvad man kan og ikke mindst hvad man ikke bør bruge.

Singleton pattern i C#

At klippe en streng over på det mest hensigtsmæssige sted

Singleton pattern i Java

Bits, bit operationer, integers og floating point

Parameters. Denne artikel beskriver hvorfor parameters er gode. Den forudsætter lidt kendskab til C# og ADO.NET.

Den forudsætter kendskab til XML og C# men ikke til brug af XML i C#.

Undtagelseshåndtering i C#

PROGRAM. using System; using System.Collections.Generic; using System.Text; using System.Collections;

Send fra Java. Denne artikel fortæller hvad man skal bruge og hvordan man skal kode for at sende fra Java.

DM01 DM Obl. Afl. Jacob Christiansen, , D12, Elias 18/ Side 1 af 11

Threads i Java. Denne artikel giver en introduktion til threads i Java. Den beskriver hvad tråde er og forklarer hvordan de bruges i Java

Anvendelse af metoder - Programmering

//Udskriver System.out.println("Hej " + ditfornavn + " " + ditefternavn + "."); System.out.println("Du er " + dinalder + " aar gammel!

University of Southern Denmark Syddansk Universitet. DM503 Forelæsning 11

Introduktion til ActionScript, fortsat

Mircobit Kursus Lektion 4 (Du skal her vælge Lets Code Og herefter Block Editor.)

Plugin-arkitektur med.net

Tagwall med Php & MySQL

Abstrakte datatyper C#-version

I denne manual kan du finde en hurtig introduktion til hvordan du:

AAU, Programmering i Java Intern skriftlig prøve 18. maj 2007

Brugerdefineret menuer i Access

Listen over reserverede ord er meget lang, men de væsentligste vil jeg beskrive her i denne artikel:

SESSION med PHP. En let begynderguide som kan føre dig ind i en verden af muligheder. Denne guide er oprindeligt udgivet på Eksperten.

Tree klassen fra sidste forelæsning

Delphi - CrackMe og Keygen

Den forudsætter kendskab til C++ og lidt kendskab til SQL og MySQL C API.

Hukommelsesspil. Introduktion. Scratch

Programmering for begyndere Lektion 2. Opsamling mm

Eksempel: et ordresystem note 5 Lagdeling s. 1

Mircobit Kursus Lektion 3 (Du skal her vælge Lets Code Og nederst Microsoft Block Editor.)

Med register_globals = On får du automatisk adgang til en række variabelnavne i dit script.

DM507 Algoritmer og datastrukturer

SWC eksamens-spørgsmål. Oversigt

Derfor vil jeg bygge dette eksempel på een table hvor der kan tilkyttes personer til ALLE noder og der kan tilføjes et vilkårligt antal niveauer

Vejledende løsninger

Indledning. Hvorfor det forholder sig sådan har jeg en masse idéer om, men det bliver for meget at komme ind på her. God fornøjelse med læsningen.

RMI introduktion. Denne artikel beskriver Java RMI (Remtote Method Invocation).

University of Southern Denmark Syddansk Universitet. DM502 Forelæsning 2

Offset til terminalskærm i Java

Oprettelse af Titelblok i Capture og Capture CIS

Arrays i PHP. Denne guide er oprindeligt udgivet på Eksperten.dk. Skrevet den 04. Feb 2009 af taskmgr I kategorien Programmering / PHP

Forelæsning Uge 4 Torsdag

Kapitel 4 Løkker i C#

Hvilket sprog er hurtigst

Fang Prikkerne. Introduktion. Scratch

Om binære søgetræer i Java

Forelæsning Uge 2 Torsdag

Kontrol-strukturer i PHP

Denne artikel er til dem der ønsker at vide mere om hvad CSS er og hvad CSS kan bruges til hvad angår WWW.

Kapitel 1 I gang med C#

Specifikation Abstrakt OO OS-API Rev Specifikation. Abstrakt, objektorienteret operativsystem-api

JSP, Tomcat. Tutorial lavet af Jákup W. Hansen TSU semester 10.october 2007

class Time { int hours, min; } } Time t1; // Erklær variabel af type Time class Time1 { public static void main(string[] args) { Time t1; t1.

Greenfoot En kort introduktion til Programmering og Objekt-Orientering

Koden i denne guide vil kun virke i Flash MX 2003 og MX ikke ældre versioner!

Lynkursus i Stencyl. Lynkursus: Lad os lave et spil! (del 1 af 5) Introduktion download programmet. Download kittet til lynkurset

Test af It-komponent

Introduction til.net remoting i C#

I denne artikel vil vi bruge en User klasse som vi så vil gruppere på forskellige måder.

Forelæsning Uge 2 Torsdag

MS Visual Studio Basic En kort vejledning

Register-databasen med.net

Kursusarbejde 3 Grundlæggende Programmering

Ghostbusters. Introduktion. Scratch. Du skal lave et fangelegsspil med spøgelser! Arbejdsliste. Test dit Projekt. Gem dit Projekt

I denne artikel, vil der blive gennemgået de grundlæggende PHP-funktioner, såsom udskrift til skærmen, tid og dato og if-sætningen.

Skriftlig eksamen i Datalogi

Kilder: Troldspejlets Spilskolen, yoyogames.com

Navn: Søren Guldbrand Pedersen Klasse: 2i Fag: up/ansi Opgave: Brev til Sigurd Lære: John Austin Side 1 af 8 Dato:

Den forudsætter kendskab til XML og VB.NET men ikke til brug af XML i VB.NET.

Forelæsning Uge 2 Torsdag

Tyngdekraft i Scratch

Tracking af YouTube i Google Tag Manager og Universal Analytics (Seneste version)

DMX styring med USB-interface

1B fil database. //globale variabler DateTime tid; // erklærer en variabel af typen datetime DateTime dag; // erklærer en variabel af typen datetime

Forelæsning Uge 4 Torsdag

Bærbar varme og støj - Vcore ændringer

Skriftlig eksamen i Datalogi

Introduktion til funktioner, moduler og scopes i Python

Forelæsning Uge 2 Torsdag

Manual til AVG Antivirus

Videregående programmering i Java

METODER ARV KLASSER. Grundlæggende programmering Lektion 5

MUS Opsætning af spørgeramme

I denne artikel vil jeg gennemgå hvordan en side for RSS "Live Bogmærke" kan se ud.

Kursusarbejde 1 Grundlæggende Programmering. Arne Jørgensen, klasse dm032-1a

VEJLEDNING LAV ET NAVNESKILT I INKSCAPE

Kursusarbejde 2 Grundlæggende Programmering

Kursus navn: Indledende programmering Kursus nr

Ratingsystem i PHP og MySQL

Databaseadgang fra Java

Transkript:

Denne guide er oprindeligt udgivet på Eksperten.dk C# spil (del 3) - Space Invaders, sådan! Artiklen indeholder implementeringen af spillet Space Invaders, og forklarer overordnet ideen bag. Sprite- og Kollisionsklasser fra C# spil (del 2), skal bruges i denne artikel. Kendskab til del 1 & 2 er en klar fordel! Skrevet den 05. Feb 2009 af sovsekoder I kategorien Programmering / C# Indledning Denne artikel vil præsentere og kommentere koden til et space invaders spil. Kendskab til C# spil (del1 & del2) er en stor fordel. Sidst i artiklen findes den komplette source-code, og en forklaring til projektets opsætning. Source coden til BlockSprite- og SpriteCollision kan findes i C# spil del 2. Pga. at det er besværligt at copy/paste koden ind og se spillet i aktion, har jeg gjort det muligt at downloade VS2003 C# projektet her : http://www.svendborggade.dk/download/invaders.zip Så starter vi :o Tilstands maskiner Spillet indeholder 3 tilstandsmaskiner: 1) spil-tilstandsmaskine, styrer spillets tilstande: vent på nyt spil, nyt spil, game over... 2) invader-flytnings tilstandsmaskine. 3) Spiller tilstande: spiller skyder, spiller skyder ikke. Disse tilstands maskiner sørger for spillets "flow" - at spillet kører korrekt, og overholder de givne regler for "Space Invaders". Bevægelses mønster for Space Invaders Jeg vil starte med tilstandsmaskine (2) - den der styrer invaders. Invaders skal styres rigtigt rundt på skærmen, de skal gå fra højre mod venstre indtil den invader længst mod højre rammer kanten. Herefter bevæger de sig et hak ned. Hvorefter de bevæger sig tilbage fra højre mod venstre, indtil den invader længst mod venstre rammer højre kant. Herefter vandrer invaders et hak ned igen. Bevægelsen gentages, men! - når invaders når bunden har spilleren tabt. For at kunne implementere dette bevægelses mønster, har vi brug for en tilstands maskine, og en go' plan :). Den go'e plan består i at være i stand til at finde ud af, hvornår invaders er nået højre kant, venstre kant og bunden. Dette foretages i metoden FindBorderSprites(), for go' pedagoisk ro og orden er disse invaders farvet rød, blå og gul - så man kan se at algoritmen virker. Vi har nu: Blå invader => længst til venstre Gul invader => længst til højre Rød invader => længst nede. Igen.. farven er der kun for at understrege algoritmens virkemåde. Algoritmen virker således at, når blå sprite rammer venstre kant skal invaders bevæge sig ned. Når gul sprite rammer højre kant bevæger invaders sig ned. Når rød sprite har nået bunden, har spilleren tabt!

Tilstands maskinen er nu i stand til at flytte invader rundt. Vi har 4 tilstande: MoveRight, MoveLeft, MoveDownLeft, MoveDownRight MoveRight og MoveLeft giver mere eller mindre sig selv: disse tilstande flytter invaders til højre og ventre. Det er dog mere underligt at der er to tilstande til at flytte invaders ned, hvorfor er der det?!!? Grunden til at vi skal bruge to tilstande til at flyte invaders ned er, at vi har brug for en forskellig overgang når invaders er flyttet et hak ned. Hvis vi kom fra højre, og har nået kanten - så går vi ned, og herefter skal vil til VENSTRE!. Hvis vi kom fra venstre og rammer kanten, går vi ned - men skal herefter gå til HØJRE!. Bevægelsen kan skrives på følgende måde: MoveRight => ModeDownRight ModeDownRight => MoveLeft MoveLEft => MoveDownLEft MoveDownLeft => MoveRight, og bevægelsen går i ring. Vi kunne godt ha' implementeret bevægelsen med blot 3 tilstande (kun een tilstand til at bevæge sig ned) - dette ville dog kræve en varibel som skulle sættes ved overgangen fra MoveLeft og MoveRight. Det er en smags-sag hvorvidt man vil benytte den ene eller den anden metode - den ene er ikke mere rigtig (eller forkert) end den anden. Spiller-tilstandsmaskine Denne tilstandsmaskine styrer spilleren. Denne tilstandsmaksine har 2 tilstande: Fire, Idle. Disse tilstande tages i brug når der trykkes på musen. Reglerne er således at der kun må være eet skud på skærmen af gangen. Så når der trykkes på musen tjekkes det om spilleren er i Fire-tilstanden, hvis dette er tilfældet ignoreres trykket, ellers skydes der. Spiler tilstanden ryger tilbage i idle, når skuddet når udover spilrammen. Spil-tilstandsmaskinen Denne tilstandsmaksine styrer spillet. Denne tilstandsmaskine benyttes primært i gameloop, der kaldes løbende vha. timeren (artikkel 1). Men tilstandsmaskinen benyttes også i f.eks. MouseDown-metoden, der kaldes når der trykkes på musen. Grunden til dette er at musse-tryk har flere funktioner. Et musse tryk kan betyde at spilleren skyder, men når man ikke er inde i spillet (dvs. vi venter på at et nyt spil skal starte) så betyder et mussetryk at spillet skal starte. Spil-tilstands maskinen benyttes til at fortolke musse-trykket på den rigtige måde (se koden i MouseDown). Spil-tilstandsmaskinen har en tilstand, GameOver, der angiver at du har tabt. Når tilstanden sættes = GameOver, så er spillet slut og der vises en besked ("ARGGG - du er død"). Dette udnyttes f.eks. ved at have en CollisionListener der lytter på om invader-skud har ramt spillen. Den eneste kode der er i denne lytter er: gamestate = GameStates.GameOver; - Hvilket straks sætter tilstanden til GameOver når spilleren rammes af et skud - enkelt! Spil-tilstandsmaskinen benyttes også i OnPaint -der tegner formen. I dette spil bruges tilstandsmaskinen til at vise de korrekte tekst beskeder som: "Tryk musen for start.." (start af nyt spil)

"Op med hastigheden!" (næste level) "ARGG - du er død!" (gameover) Spil-tilstanden: PlayLevel - spillet er i fuld gang I Spil-tilstanden, PlayLevel - spilles spillet. I denne tilstand skal invaders opdateres - spilleren skal flyttes, kort sagt her skal vi sørge for at opdatere alt så spillet foregår korrekt. I følgende kode ses implementeringen af denne tilstand: case GameStates.PlayLevel: // Her kæmpes der mod invaders // - bevægelse af spiller, samt styring af skud // - bevægelse af invaders // - bevægelse af missiler // - Tjek for kollisioner // - Tjek for game over ell. sejr PlayerAction(); MoveInvaders(); InvaderAttack(); MoveMissiles(); collisions.check(); CheckForGameOver(); CheckForPlayerWin(); PlayerAction(): Denne funktion fyrer et missil af, afhængigt af spiller-tilstanden. Herefter flyttes spilleren i retning af musen. Forstået således at spilleren flyttes til højre hvis musen er tilhøjre for spilleren, og omvendt. MoveInvaders(): Her tages invader-tilstandsmaskinen i brug, og invaders flyttes efter algoritmen beskrevet tidligere. InvaderAttack(): Her vælges tilfældige invarders til at skyde. Der er et øvre loft på antallet af skud fra invaders (i konstanten: invadermissilecount), så hvis dette loft er nået skydes der slet ikke før et af missilerne af ude over spil-rammen. MoveMissiles(): Denne funktion sørger for at flytte missilerne. Der er i denne forbindelse oprettet en klasse, Missile. Dette er gjort for at vise hvordan man kan nedarve fra BlockSprite-klassen. I denne nedarvet klasse findes en metode, AutoMove, der opdaterer missilet. Missilet flyttes op eller ned afhængigt af hvordan det er oprettet (spilleren missiler flyttes op, invader-missiler flyttes ned). I denne nedarvet klasse kan man implementere Draw. På denne måde kan man tegne bitmaps, altså rigtige figurer istedet for bare sorte kasser. collisions.check(): her tjekkes for kollisioner, og listeners kaldes hvis der er sprites der har kollideret. CheckForGameOver(): har spilleren tabt? hvis dette er tilfældet justeres spi-tilstanden med det sammen. CheckForPlayerWin(): Der tjekkes om spilleren har vundet, hvis dette er tilfældet sættes næste level op (hvor det går en tand hurtigere). Space invaders Ideerne omkring implementeringen af space invaders er nu ridset op. Du kan kopiere source koden ind i et windows-form projekt, og se spillet i fuld aktion. Når spillet kører kan man få en fornemmelse af de ting jeg

har gennemgået i artiklen. Det kan varmt anbefales at kigge koden igennem, start i metoden GameLoop(). Følg metoderne rundt, tegn evt. et diagram over tilstandende i tilstandsmaskinerne - for at få fornemmelsen af logikken. Prøv at skyde den blå/gule/røde invader, og se hvordan en ny invader findes for at opretholde algoritmen til invader-bevægelses mønstret. Go' fornøjelse :D Source code Sådan får du koden op at køre: Opret et windows form projekt. Filen med formen hedder Form1.cs. Følgende liste viser hvilke filer projektet skal bestå af: * Form1.cs (DEL3)- selve spillet * Missile.cs (DEL3)- missilsprite nedarvet fra BlockSprite * SpriteCollision.cs (DEL2)- håndtering af sprite kollision * BlockSprite.cs (DEL2)- visning af sprites (DEL3) betyder at source-coden findes i denne artikel. (DEL2) betyder at source-coden er i artiklen C# spil (del 2). Form1.cs using System; using System.Drawing; using System.Collections; using System.Windows.Forms; namespace SpaceInvaders public class Form1 : System.Windows.Forms.Form // konstanter der bruges af andre klasser public const int TopBorder = 10; public const int LeftBorder = 10; public const int RightBorder = 250; public const int LowerBorder = 250; // Konstanter relateret til invaders const int invadersize = 10; const int invaderrows = 5; const int invadercolumns = 10; const int invadermissilecount = 3; // Størrelsen af spiller spriten const int playersize = 20; // Tekstrenge der vises i spillet const string newgame = "Tryk musen for start.."; const string nextlevel = "Op med hastigheden!"; const string gameover = "ARGG - du er død!"; // Spillets Sprite variable

SpriteCollision collisions; BlockSprite[,] invaders; BlockSprite playersprite; Missile playermissile; Missile[] invadermissiles = new Missile[invaderMissileCount]; BlockSprite leftmostsprite; BlockSprite rightmostsprite; BlockSprite lowestsprite; // Spil variable int score; int level; string gametext = ""; // Overordnede Spil-tilstande enum GameStates InitializeNewGame, WaitForNewGame, PrepareNextLevel, PlayLevel, GameOver ; GameStates gamestate; // invader flytte-tilstande enum MoveStates Left, Right, DownLeft, DownRight, ; MoveStates movestate; // spiller tilstande enum PlayerStates Idle, Fire PlayerStates playerstate; // Variabler relateret til bevægelse af invaders int invadermovedowncounter; int invadermovedelay; int invadermoveclock; // Bruges til tilfældige tal Random rnd; private System.Windows.Forms.Timer timer1; private System.ComponentModel.IContainer components;

public Form1() // // Required for Windows Form Designer support // InitializeComponent(); // Tegn med double-buffering SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); SetStyle(ControlStyles.DoubleBuffer, true); // Initialiser spillet InitializeGame(); rnd = new Random(this.Handle.ToInt32()); // Set formens størrelse så der er plads til hele spillet const int slagx = 100; const int slagy = 40; this.size = new Size(RightBorder+LeftBorder+slagX, TopBorder+LowerBorder+slagY); #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() this.components = new System.ComponentModel.Container(); this.timer1 = new System.Windows.Forms.Timer(this.components); // // timer1 // this.timer1.enabled = true; this.timer1.interval = 10; this.timer1.tick += new System.EventHandler(this.Gameloop); // // Form1 // this.autoscalebasesize = new System.Drawing.Size(5, 13); this.clientsize = new System.Drawing.Size(456, 350); this.name = "Form1"; this.text = "Form1"; this.mousedown += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseDown); this.paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint); #endregion // Initialiser alt i spillet void InitializeGame()

InitializeGameVariables(); InitializeSprites(); // Initialiser spillets variable void InitializeGameVariables() // Initialiser spil-tilstands maskinen gamestate = GameStates.InitializeNewGame; // nul-stil score og level score = 0; level = 0; // Initialiser variable der styrer invaders invadermovedowncounter = 0; invadermovedelay = 5; invadermoveclock = 0; // Initialiser alle sprites i spillet void InitializeSprites() movestate = MoveStates.Right; playerstate = PlayerStates.Idle; leftmostsprite = null; rightmostsprite = null; lowestsprite = null; collisions = new SpriteCollision(); // Opret spiller playersprite = new BlockSprite(LeftBorder, LowerBorder-playerSize, playersize, playersize); // Opret missiler for spiller og invader playermissile = new Missile(0, 0, true); playermissile.visible = false; playermissile.color = Color.Blue; // Opret invader-missiler for(int i=0; i<invadermissiles.length; i++) invadermissiles[i] = new Missile(0, 0, false); invadermissiles[i].speed = 1; invadermissiles[i].visible = false; invadermissiles[i].color = Color.Red; // Opret SpaceInvaders invaders = new BlockSprite[invaderRows,invaderColumns];

for(int i=0; i<invaderrows; i++) for(int j=0; j<invadercolumns; j++) invaders[i,j] = new BlockSprite(LeftBorder+j*(invaderSize*2), TopBorder+i*(2*invaderSize), invadersize, invadersize); // Sæt kollision lyttere op mellem invaders og missil for(int i=0; i<invaderrows; i++) for(int j=0; j<invadercolumns; j++) if(spriteexist(invaders[i,j])) collisions.addlistener(playermissile, invaders[i,j], new CollisionDelegate(PlayerMissileHandler)); // Sæt kollision lytter om mellem invader missiler og player for(int i=0; i<invadermissiles.length; i++) collisions.addlistener(invadermissiles[i], playersprite, new CollisionDelegate(InvaderMissileHandler)); // Initialiser grænse sprites (invaders) FindBorderSprites(); // Find de yderste invaders - så invaders ved hvornår de er nået til kanten void FindBorderSprites() BlockSprite leftmostspritetemp = leftmostsprite; BlockSprite rightmostspritetemp = rightmostsprite; BlockSprite lowestspritetemp = lowestsprite; for(int i=0; i<invaderrows; i++) for(int j=0; j<invadercolumns; j++) if(!spriteexist(invaders[i,j])) continue; if(!spriteexist(leftmostsprite)) if(!spriteexist(leftmostspritetemp)) leftmostspritetemp = invaders[i,j]; else if(invaders[i,j].x<leftmostspritetemp.x) leftmostspritetemp = invaders[i,j]; if(!spriteexist(rightmostsprite))

if(!spriteexist(rightmostspritetemp)) rightmostspritetemp = invaders[i,j]; else if(invaders[i,j].x>rightmostspritetemp.x) rightmostspritetemp = invaders[i,j]; if(!spriteexist(lowestsprite)) if(!spriteexist(lowestspritetemp)) lowestspritetemp = invaders[i,j]; else if(invaders[i,j].y>lowestspritetemp.y) lowestspritetemp = invaders[i,j]; // Updater grænse-sprites hvis det er nødvendigt if(!spriteexist(leftmostsprite)) leftmostsprite = leftmostspritetemp; if(!spriteexist(rightmostsprite)) rightmostsprite = rightmostspritetemp; if(!spriteexist(lowestsprite)) lowestsprite = lowestspritetemp; // Sæt farven på grænse sprites (invaders) leftmostsprite.color = Color.Blue; rightmostsprite.color = Color.Yellow; lowestsprite.color = Color.Red; // Bevæg invaders void MoveInvaders() FindBorderSprites(); if(invadermoveclock++ < invadermovedelay) return; invadermoveclock = 0; int dx=0, dy=0; switch(movestate) case MoveStates.DownLeft: dy = 1; invadermovedowncounter++; if(invadermovedowncounter==invadersize) invadermovedowncounter = 0; movestate = MoveStates.Right; case MoveStates.DownRight: dy = 1; invadermovedowncounter++; if(invadermovedowncounter==invadersize) invadermovedowncounter = 0; movestate = MoveStates.Left;

case MoveStates.Left: dx = -1; if(leftmostsprite.x<=leftborder) dx = 0; invadermovedowncounter = 0; movestate = MoveStates.DownLeft; case MoveStates.Right: dx = 1; if(rightmostsprite.x+rightmostsprite.width>=rightborder) dx = 0; invadermovedowncounter = 0; movestate = MoveStates.DownRight; // Flyt invaders for(int i=0; i<invaderrows; i++) for(int j=0; j<invadercolumns; j++) if(spriteexist(invaders[i,j])) invaders[i,j].x += dx; invaders[i,j].y += dy; // Se om der findes flere invaders bool MoreInvadersAlive() return ( SpriteExist(leftMostSprite) SpriteExist(rightMostSprite) SpriteExist(lowestSprite)); // Check om spilleren har vundet (ikke flere space invaders) void CheckForPlayerWin() if(moreinvadersalive() == false) // Du har skudt alle invaders, du vinder dette level! gamestate = GameStates.PrepareNextLevel;

// Tjek om spilleren har tabt fordi invaders har nået bunden void CheckForGameOver() if(spriteexist(lowestsprite) && (lowestsprite.y>=playersprite.y)) gamestate = GameStates.GameOver; // Håndtering af musse tryk afhængig af gamestate private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) switch(gamestate) case GameStates.PlayLevel: playerstate = PlayerStates.Fire; case GameStates.WaitForNewGame: gamestate = GameStates.PlayLevel; case GameStates.PrepareNextLevel: gamestate = GameStates.PlayLevel; case GameStates.GameOver: gamestate = GameStates.InitializeNewGame; // Håndtering af tilfældig invader skud void InvaderAttack() for(int m=0; m<invadermissiles.length; m++) if(!spriteexist(invadermissiles[m])) int k = rnd.next(invaderrows*invadercolumns)+1; int i=0; int j=0; while(k>0) i++; if(i>=invaderrows) i=0; j++; if(j>=invadercolumns) j=0; if(spriteexist(invaders[i,j])) k--;

invadermissiles[m].x = invaders[i,j].x+invadersize/2; invadermissiles[m].y = invaders[i,j].y+invadersize/2; invadermissiles[m].visible = true; // Håndtering af spillerens aktioner void PlayerAction() switch(playerstate) case PlayerStates.Fire: if(playermissile.visible == false) FireTheMissile(); playerstate = PlayerStates.Idle; case PlayerStates.Idle: Point mouselocation = PointToClient(MousePosition); int centerspritex = playersprite.x+playersprite.width/2; if(mouselocation.x > centerspritex) if(playersprite.x < RightBorder-playerSize) playersprite.x++; else if(mouselocation.x < centerspritex) if(playersprite.x > LeftBorder) playersprite.x--; // Hoved Gameloop private void Gameloop(object sender, System.EventArgs e) switch(gamestate) case GameStates.InitializeNewGame: // Initialisering af spillet InitializeGame(); gamestate = GameStates.WaitForNewGame; case GameStates.WaitForNewGame: // Her ventes på musse tryk i Form1_MouseDown case GameStates.PrepareNextLevel: // Forbered det næste level_ // - Sæt hastigheden op, opdater level værdi // - Genindlæs sprites på deres positioner

if(invadermovedelay>0) invadermovedelay--; level++; InitializeSprites(); gamestate = GameStates.WaitForNewGame; case GameStates.PlayLevel: // Her kæmpes der mod invaders // - bevægelse af spiller, samt styring af skud // - bevægelse af invaders // - bevægelse af missiler // - Tjek for kollisioner // - Tjek for game over ell. sejr PlayerAction(); MoveInvaders(); InvaderAttack(); MoveMissiles(); collisions.check(); CheckForGameOver(); CheckForPlayerWin(); case GameStates.GameOver: // Her ventes på musse tryk i Form1_MouseDown // Paint screen Invalidate(true); // Fyr spillerens missil af void FireTheMissile() // Fyr missil af fra midten af spiller-spriten playermissile.x = playersprite.x+playersprite.width/2; playermissile.y = playersprite.y; playermissile.visible = true; // Flyt alle missiler i spillet void MoveMissiles() if(spriteexist(playermissile)) playermissile.automove(); for(int i=0; i<invadermissiles.length; i++) if(spriteexist(invadermissiles[i])) invadermissiles[i].automove(); // Tjek om en given sprite eksisterer

bool SpriteExist(BlockSprite sprite) if(sprite!= null && sprite.visible == true) return true; else return false; // Håndtering af kollision mellem spiller missil og invaders public void PlayerMissileHandler(object sender) Listener l = (Listener) sender; playermissile.visible = false; l.sprite2.visible = false; l.remove = true; score += 10; // Håndtering af kollision mellem invader missiler og spiller public void InvaderMissileHandler(object sender) gamestate = GameStates.GameOver; // Tegn grafikken inde i spillet void DrawGameGraphics(Graphics g) g.drawrectangle(new Pen(Color.Black), LeftBorder, TopBorder, RightBorder-LeftBorder, LowerBorder-TopBorder); g.drawstring( string.format("score: 0:000000\n\nLevel: 1:000",score,level), this.font, new SolidBrush(Color.Black), RightBorder+10, TopBorder); if(spriteexist(playermissile)) playermissile.draw(g); if(spriteexist(playersprite)) playersprite.draw(g); for(int i=0; i<invadermissiles.length; i++) if(spriteexist(invadermissiles[i])) invadermissiles[i].draw(g); if(invaders!= null) for(int i=0; i<invaderrows; i++) for(int j=0; j<invadercolumns; j++) if(spriteexist(invaders[i,j])) invaders[i,j].draw(g);

// Skriv tekst ud centreret i spil-rammen void CenterText(Graphics g, string text) SizeF textsize = g.measurestring(text, this.font); g.drawstring( text, this.font, new SolidBrush(Color.Black), (RightBorder-LeftBorder-textSize.Width)/2+LeftBorder, TopBorder+(LowerBorder-TopBorder)/2); // Tegning af spillet private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) Graphics g = e.graphics; DrawGameGraphics(g); // Gamestate afhængig grafik switch(gamestate) case GameStates.PrepareNextLevel: gametext = nextlevel; case GameStates.InitializeNewGame: gametext = newgame; case GameStates.GameOver: gametext = newgame; CenterText(g, gameover); case GameStates.WaitForNewGame: CenterText(g, gametext); /// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) if( disposing ) if (components!= null) components.dispose();

base.dispose( disposing ); [STAThread] static void Main() Application.Run(new Form1()); Missile.cs using System; namespace SpaceInvaders // Missile: Nedarvet klasse fra BlockSprite, tilføjer 2 properties og 1 metode // Properties: // - up : angiver om missilen flyver op eller ned // - speed : angiver hvor hurtigt missilet flyver. // Metode: // - AutoMove : Opdaterer missilets position public class Missile : BlockSprite const int missilewidth = 2; const int missileheight = 8; int speed = 7; bool up = true; // kun til sjov double t=0; public Missile(int x, int y, bool up) : base(x,y,missilewidth,missileheight) this.up = up; public void AutoMove() /* // Sjove skud :) if(up) t += Math.PI/20; double dx = 5*Math.Sin(t); base.x += (int)(dx); */

if(up) if(base.y < Form1.TopBorder) base.visible = false; else base.y -= speed; else if(base.y > Form1.LowerBorder) base.visible = false; else base.y += speed; public int Speed get return this.speed; set this.speed = value; public bool Up get return this.up; set this.up = value; Kommentar af mikze d. 16. Nov 2004 1 Cool :) Kommentar af mmbn d. 11. Nov 2005 2 Super artikel, kan næsten ikke vente på del 4 og 5. Kommentar af sorenbs d. 13. Jul 2005 3 Man kan virkeligt få brugt noget tid på det skidt :) Jeg glæder mig til de næste 2 artikler Kommentar af andr3as d. 30. Nov 2004 4 ok Kommentar af qbus d. 31. Oct 2005 5 Alletiders artikel :) Er igang med at lave dette spil: http://parachute.datamatikeronline.dk/ ud fra principperne i din artikel, dog med ændringer selvfølgelig :P Kommentar af tobiasahlmo d. 24. Jan 2008 6

Nice :) Kommentar af sovsekoder d. 23. Feb 2011 7 kig evt. på mit codeplex projekt ang. XNA og platform spil: http://mrdev.codeplex.com/