Gameboy in C #

Als ich gerade mit dem Programmieren angefangen habe, wollte ich, wie viele andere auch, Spiele machen. Aber vor mir gab es viele architektonische Probleme, die ich nicht lösen konnte, ich hörte nicht einmal von doppelter Pufferung und ich wollte das Ergebnis so schnell wie möglich erhalten. Deshalb habe ich mich kürzlich entschlossen, ein Projekt zu schreiben, in dem es möglich sein wird, einfache Spiele ohne Probleme zu schreiben. Spiele in diesem Projekt können wie GameBoy erstellt werden, dh: Tetris, Schlange usw. Sie können aber auch mit der Maus darauf klicken.

Link zum Projekt auf GitHub .

In diesem Artikel möchte ich die Entstehung einer Schlange erkennen.

Das erste, mit dem Sie beginnen müssen, ist, eine eigene Spielklasse zu erstellen und von der Spielbasisklasse zu erben.

class Snake : Game 

Es implementiert bereits das Spielfeld und die Ereignisse, die auftreten, wenn das Spiel von einem Zustand in einen anderen übergeht. Im Wesentlichen müssen wir nur die Ereignisbehandlung deklarieren.

 public Snake() : base() { OnPreview += BasePreview; OnNewGame += Snake_OnNewGame; OnUpdateGame += Snake_OnUpdateGame; OnGameOver += DrawScore; } 

Für OnPreview- und OnGameOver-Ereignisse gibt es bereits vorgefertigte Stubs in der Game-Klasse. Sie können sie nicht implementieren. Es bleibt nur ein neues Spiel zu initialisieren und Update-Ereignisse zu verarbeiten.

 private GameBlock head; private List<GameBlock> body; private GameBlock eat; private void Snake_OnNewGame() { head = new GameBlock() { X = 10, Y = 10, Vector = Vector.Up, Color = GameColor.Green }; body = new List<GameBlock>(); body.Add( head ); body.Add( new GameBlock() { X = 10, Y = 11, Vector = Vector.Up, Color = GameColor.Black } ); body.Add( new GameBlock() { X = 10, Y = 12, Vector = Vector.Up, Color = GameColor.Black } ); CreateEat(); DrawField(); } 

Um ein Feld zu zeichnen, können Sie direkt damit arbeiten oder die vorgefertigte GameBlock-Klasse verwenden, die beispielsweise Position, Bewegungsrichtung und Farbe implementiert.

In dieser Funktion haben wir den Körper der Schlange deklariert, das erste Stück Futter erstellt und angezeigt, was auf dem Feld passiert.

 private void CreateEat() { var emptyBlocks = new List<GameBlock>(); for( int i = 0; i < MainForm.FIELD_SIZE; i++ ) for( int j = 0; j < MainForm.FIELD_SIZE; j++ ) if( CheckEmptyBlock( i, j ) ) emptyBlocks.Add(new GameBlock() { X = i, Y = j, Color = GameColor.Red } ); if (emptyBlocks.Count > 0) eat = emptyBlocks[random.Next( emptyBlocks.Count )]; } 

Um eine Mahlzeit zu erstellen, erhalten wir eine Liste mit leeren Blöcken und wählen mit Hilfe eines Zufallsgenerators (der bereits im Spiel deklariert ist) zufällig aus. Falls die Schlange das gesamte Feld besetzt hat, wird die Größe der Liste überprüft.

Eigentlich ist die Funktion der Überprüfung der leeren Zelle:

 private bool CheckEmptyBlock(int x, int y) => !( x < 0 || y < 0 || x == MainForm.FIELD_SIZE || y == MainForm.FIELD_SIZE ) && !body.Exists( a => a.Equals( new GameBlock() { X = x, Y = y } ) ); 

Das Rendering des Feldes ist wie folgt:

 private void DrawField() { Field.Clear( GameColor.White ); Field.DrawGameBlock( eat ); Field.DrawGameBlocks( body ); WriteScore(); } 

Da es nicht schwer zu erraten ist, wird das Feld in Weiß geräumt und Futter mit einer Schlange angezeigt. WriteScore ist eine weitere Standardfunktion zum Anzeigen einer Punktzahl in einer speziellen Statusleiste.

Wir wenden uns also dem Spielaktualisierungsereignis zu, das mit einer Frequenz von 300 ms auftritt.

 private void Snake_OnUpdateGame( Controller controller ) { ControlMove( controller.GameKey ); if( CheckGameOver() ) GameOver(); else SnakeMove(); } 

Darin passieren vier Dinge: Ändern der Bewegungsrichtung, Überprüfen des Spielendes, Aufrufen des Ereignisses am Ende des Spiels und Bewegen der Schlange, falls alles in Ordnung ist.

 private void ControlMove( GameKey key ) { switch( key ) { case GameKey.Left: head.Vector = head.Vector == Vector.Right ? Vector.Right : Vector.Left; break; case GameKey.Right: head.Vector = head.Vector == Vector.Left ? Vector.Left : Vector.Right; break; case GameKey.Up: head.Vector = head.Vector == Vector.Down ? Vector.Down : Vector.Up; break; case GameKey.Down: head.Vector = head.Vector == Vector.Up ? Vector.Up : Vector.Down; break; default: break; } } 

Um die Bewegungsrichtung in der Schlange zu ändern, müssen wir den Vektor in ihrem Kopf ändern. Daher wird bei der Steuerung der Bewegung der Fall der Inversion des Vektors überprüft, damit die Schlange nicht auf sich selbst zu klettern beginnt.

 private bool CheckGameOver() { switch( head.Vector ) { case Vector.Up: return !CheckEmptyBlock( head.X, head.Y - 1 ); case Vector.Down: return !CheckEmptyBlock( head.X, head.Y + 1 ); case Vector.Left: return !CheckEmptyBlock( head.X - 1, head.Y ); case Vector.Right: return !CheckEmptyBlock( head.X + 1, head.Y ); default: throw new NotImplementedException(); } } 

Um das Ende des Spiels zu überprüfen, überprüfen Sie einfach, ob der Block in der Richtung frei ist oder nicht. Wie Sie vielleicht erraten haben, wird das Essen im Scheck ignoriert.

Es bleibt die Bewegungsfunktion der Schlange zu analysieren:

 private void SnakeMove() { var temp = body.Last().Copy(); foreach( var block in body ) block.Move(); for( int i = body.Count - 1; i > 0; i-- ) body[i].Vector = body[i - 1].Vector; if( head.Equals( eat ) ) { score++; body.Add( temp ); CreateEat(); } DrawField(); } 

Das Ende des Schwanzes wird kopiert, sodass Sie, wenn das Futter erreicht ist, es als Schlangenverlängerung hinzufügen. Das Verschieben von Blöcken ist nicht schwierig, da diese Funktion bereits in der Blockklasse implementiert ist. Dann werden die Vektoren über die Bewegung der Schlange verteilt und auf Schnittpunkt mit Nahrung überprüft. Wenn Nahrung gefunden wird, erhöht sich die Rechnung, die Schlange wächst und neue Nahrung wird erzeugt. Damit unser Spiel in der Liste der Spiele angezeigt wird, müssen Sie es der Formularinitialisierung hinzufügen:

 List<Game> games = new List<Game>(); games.Add( new Snake() ); games.Add( new Tetris() ); games.Add( new Life() ); Application.Run( new MainForm( games ) ); 

Das ist alles Der gesamte Spielcode bestand nur aus 102 Zeilen. Wie Sie dem Beispiel entnehmen können, wurden dem Projekt bereits Tetris und Spieleleben hinzugefügt. Unten finden Sie das Ergebnis.

Bild
Spielauswahlmenü

Bild
Spielprozess

Bild
Ende des Spiels

Source: https://habr.com/ru/post/de448604/


All Articles