在 Qyoto C# 编程教程的这一部分中,我们将创建贪食蛇游戏克隆。
Nibbles是较旧的经典视频游戏。 它最初是在 70 年代后期创建的。 后来它被带到 PC 上。 在这个游戏中,玩家控制蛇。 目的是尽可能多地吃苹果。 蛇每次吃一个苹果,它的身体就会长大。 蛇必须避开墙壁和自己的身体。
开发
蛇的每个关节的大小为 10px。 蛇由光标键控制。 最初,蛇具有三个关节。 游戏立即开始。 游戏结束后,我们在窗口中心显示"Game Over"消息。
board.cs
using System;using QtCore;using QtGui;public class Board : QFrame{const int WIDTH = 300;const int HEIGHT = 300;const int DOT_SIZE = 10;const int ALL_DOTS = 900;const int RAND_POS = 30;const int DELAY = 140;int[] x = new int[ALL_DOTS];int[] y = new int[ALL_DOTS];int dots;int apple_x;int apple_y;bool left = false;bool right = true;bool up = false;bool down = false;bool inGame = true;QBasicTimer timer;QImage ball;QImage apple;QImage head;public Board(){StyleSheet = "QWidget { background-color: black }";FocusPolicy = Qt.FocusPolicy.StrongFocus;ball = new QImage("dot.png");apple = new QImage("apple.png");head = new QImage("head.png");InitGame();}void InitGame(){dots = 3;for (int z = 0; z < dots; z++) {x[z] = 50 - z*10;y[z] = 50;}LocateApple();timer = new QBasicTimer();timer.Start(DELAY, this);}protected override void OnPaintEvent(QPaintEvent e){QPainter painter = new QPainter();painter.Begin(this);if (inGame){DrawObjects(painter);} else {GameOver(painter);}painter.End();}void DrawObjects(QPainter painter){painter.DrawImage(apple_x, apple_y, apple);for (int z = 0; z < dots; z++){if (z == 0)painter.DrawImage(x[z], y[z], head);else painter.DrawImage(x[z], y[z], ball);}}void GameOver(QPainter painter){String msg = "Game Over";QFont small = new QFont("Helvetica", 12,(int) QFont.Weight.Bold);QFontMetrics metr = new QFontMetrics(small);int textWidth = metr.Width(msg);int h = Height;int w = Width;painter.SetPen(GlobalColor.white);painter.Font = small;painter.Translate(new QPoint(w/2, h/2));painter.DrawText(-textWidth/2, 0, msg);}void CheckApple(){if ((x[0] == apple_x) && (y[0] == apple_y)){dots++;LocateApple();}}void Move(){for (int z = dots; z > 0; z--){x[z] = x[(z - 1)];y[z] = y[(z - 1)];}if (left){x[0] -= DOT_SIZE;}if (right){x[0] += DOT_SIZE;}if (up){y[0] -= DOT_SIZE;}if (down){y[0] += DOT_SIZE;}}void CheckCollision(){for (int z = dots; z > 0; z--){if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])){inGame = false;}}if (y[0] > HEIGHT){inGame = false;}if (y[0] < 0){inGame = false;}if (x[0] > WIDTH){inGame = false;}if (x[0] < 0){inGame = false;}}void LocateApple(){Random rand = new Random();int r = (int) (rand.Next(RAND_POS));apple_x = ((r * DOT_SIZE));r = (int) (rand.Next(RAND_POS));apple_y = ((r * DOT_SIZE));}protected override void OnTimerEvent(QTimerEvent arg1){if (inGame){CheckApple();CheckCollision();Move();} else{timer.Stop();}Repaint();}protected override void OnKeyPressEvent(QKeyEvent e){int key = e.Key();if (key == (int) Qt.Key.Key_Left && !right){left = true;up = false;down = false;}if ((key == (int) Qt.Key.Key_Right) && !left){right = true;up = false;down = false;}if ((key == (int) Qt.Key.Key_Up) && !down){up = true;right = false;left = false;}if ((key == (int) Qt.Key.Key_Down) && !up){down = true;right = false;left = false;}}}
首先,我们将定义一些在游戏中使用的全局变量。
WIDTH和HEIGHT常数确定电路板的大小。 DOT_SIZE是苹果的大小和蛇的点。 ALL_DOTS常数定义了板上可能的最大点数。 RAND_POS常数用于计算苹果的随机位置。 DELAY常数确定游戏的速度。
int[] x = new int[ALL_DOTS];int[] y = new int[ALL_DOTS];
这两个数组存储蛇的所有可能关节的 x,y 坐标。
InitGame()方法初始化变量,加载图像并启动超时功能。
if (inGame){DrawObjects(painter);} else {GameOver(painter);}
在PaintEvent()方法内部,我们检查inGame变量。 如果为真,则绘制对象。 苹果和蛇的关节。 否则,我们显示"Game Over"文本。
void DrawObjects(QPainter painter){painter.DrawImage(apple_x, apple_y, apple);for (int z = 0; z < dots; z++){if (z == 0)painter.DrawImage(x[z], y[z], head);else painter.DrawImage(x[z], y[z], ball);}}
DrawObjects()方法绘制苹果和蛇的关节。 蛇的第一个关节是其头部,用红色圆圈表示。
void CheckApple(){if ((x[0] == apple_x) && (y[0] == apple_y)){dots++;LocateApple();}}
CheckApple()方法检查蛇是否击中了苹果对象。 如果是这样,我们添加另一个蛇形关节并调用LocateApple()方法,该方法将随机放置一个新的Apple对象。
在Move()方法中,我们有游戏的关键算法。 要了解它,请看一下蛇是如何运动的。 您控制蛇的头。 您可以使用光标键更改其方向。 其余关节在链上向上移动一个位置。 第二关节移动到第一个关节的位置,第三关节移动到第二个关节的位置,依此类推。
for (int z = dots; z > 0; z--){x[z] = x[(z - 1)];y[z] = y[(z - 1)];}
该代码将关节向上移动。
if (left){x[0] -= DOT_SIZE;}
将头向左移动。
在CheckCollision()方法中,我们确定蛇是否击中了自己或撞墙之一。
for (int z = dots; z > 0; z--){if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])){inGame = false;}}
如果蛇用头撞到关节之一,我们就结束游戏。
if (y[0] > HEIGHT){inGame = false;}
如果蛇击中了棋盘的底部,我们就结束了游戏。
LocateApple()方法在板上随机放置一个苹果。
Random rand = new Random();int r = (int) (rand.Next(RAND_POS));
我们得到一个从 0 到RAND_POS-1的随机数。
apple_x = ((r * DOT_SIZE));...apple_y = ((r * DOT_SIZE));
这些行设置了 apple 对象的 x,y 坐标。
if (inGame){CheckApple();CheckCollision();Move();} else{timer.Stop();}
每 140 毫秒,将调用TimerEvent()方法。 如果我们参与了游戏,我们将调用三种构建游戏逻辑的方法。 否则,我们将停止计时器。
在 Board 类的KeyPressEvent()方法中,我们确定按下的键。
if (key == (int) Qt.Key.Key_Left && !right){left = true;up = false;down = false;}
如果单击左光标键,则将left变量设置为true。 在Move()方法中使用此变量来更改蛇对象的坐标。 还要注意,当蛇向右行驶时,我们不能立即向左转。
nibbles.cs
using System;using QtCore;using QtGui;/*** ZetCode Qyoto C# tutorial** In this program, we create* a Nibbles game clone.** @author Jan Bodnar* website zetcode.com* last modified October 2012*/public class QyotoApp : QMainWindow{public QyotoApp(){WindowTitle = "Nibbles";CentralWidget= new Board();Resize(310, 310);Move(300, 300);Show();}[STAThread]public static int Main(String[] args){new QApplication(args);new QyotoApp();return QApplication.Exec();}}
在这个类中,我们设置了贪食蛇游戏。

图:贪食蛇
这是用 Qyoto 库和 C# 编程语言编程的贪食蛇电脑游戏。
