在 Mono IronPython Winforms 编程教程的这一部分中,我们将创建一个贪食蛇游戏克隆。
贪食蛇游戏
贪食蛇是较旧的经典视频游戏。 它最初是在 70 年代后期创建的。 后来它被带到 PC 上。 在这个游戏中,玩家控制蛇。 目的是尽可能多地吃苹果。 蛇每次吃一个苹果,它的身体就会长大。 蛇必须避开墙壁和自己的身体。 该游戏有时称为 Nibbles 。
开发
蛇的每个关节的大小为 10px。 蛇由光标键控制。 最初,蛇具有三个关节。 游戏立即开始。 如果游戏结束,我们将在棋盘中间显示Game Over消息。
board.py
import clrclr.AddReference("System.Drawing")clr.AddReference("System")from System.Windows.Forms import UserControl, Keys, Timerfrom System.Drawing import Size, Color, Bitmap, Brushes, RectangleFfrom System.Drawing import Font, StringAlignment, StringFormat, PointFfrom System import Randomfrom System.ComponentModel import ContainerWIDTH = 300HEIGHT = 300DOT_SIZE = 10ALL_DOTS = 900RAND_POS = 27x = [0] * ALL_DOTSy = [0] * ALL_DOTSclass Board(UserControl):def __init__(self):self.Text = 'Snake'self.components = Container()self.BackColor = Color.Blackself.DoubleBuffered = Trueself.ClientSize = Size(WIDTH, HEIGHT)self.left = Falseself.right = Trueself.up = Falseself.down = Falseself.inGame = Truetry:self.dot = Bitmap("dot.png")self.apple = Bitmap("apple.png")self.head = Bitmap("head.png")except Exception, e:print e.Messageself.initGame()def OnTick(self, sender, event):if self.inGame:self.checkApple()self.checkCollision()self.move()self.Refresh()def initGame(self):self.dots = 3for i in range(self.dots):x[i] = 50 - i * 10y[i] = 50self.locateApple()self.KeyUp += self.OnKeyUpself.timer = Timer(self.components)self.timer.Enabled = Trueself.timer.Interval = 100self.timer.Tick += self.OnTickself.Paint += self.OnPaintdef OnPaint(self, event):g = event.Graphicsif (self.inGame):g.DrawImage(self.apple, self.apple_x, self.apple_y)for i in range(self.dots):if i == 0:g.DrawImage(self.head, x[i], y[i])else:g.DrawImage(self.dot, x[i], y[i])else:self.gameOver(g)def gameOver(self, g):msg = "Game Over"format = StringFormat()format.Alignment = StringAlignment.Centerformat.LineAlignment = StringAlignment.Centerwidth = float(self.ClientSize.Width)height = float(self.ClientSize.Height)rectf = RectangleF(0.0, 0.0, width, height)g.DrawString(msg, self.Font, Brushes.White, rectf, format)self.timer.Stop()def checkApple(self):if x[0] == self.apple_x and y[0] == self.apple_y:self.dots = self.dots + 1self.locateApple()def move(self):z = self.dotswhile z > 0:x[z] = x[(z - 1)]y[z] = y[(z - 1)]z = z - 1if self.left:x[0] -= DOT_SIZEif self.right:x[0] += DOT_SIZEif self.up:y[0] -= DOT_SIZEif self.down:y[0] += DOT_SIZEdef checkCollision(self):z = self.dotswhile z > 0:if z > 4 and x[0] == x[z] and y[0] == y[z]:self.inGame = Falsez = z - 1if y[0] >= HEIGHT - DOT_SIZE - self.TITLEBAR_HEIGHT:self.inGame = Falseif y[0] < 0:self.inGame = Falseif x[0] >= WIDTH - DOT_SIZE - self.BORDER_WIDTH:self.inGame = Falseif x[0] < 0:self.inGame = Falsedef locateApple(self):rand = Random()r = rand.Next(RAND_POS)self.apple_x = r * DOT_SIZEr = rand.Next(RAND_POS)self.apple_y = r * DOT_SIZEdef OnKeyUp(self, event):key = event.KeyCodeif key == Keys.Left and not self.right:self.left = Trueself.up = Falseself.down = Falseif key == Keys.Right and not self.left:self.right = Trueself.up = Falseself.down = Falseif key == Keys.Up and not self.down:self.up = Trueself.right = Falseself.left = Falseif key == Keys.Down and not self.up:self.down = Trueself.right = Falseself.left = False
首先,我们将定义游戏中使用的常量。
WIDTH和HEIGHT常数确定电路板的大小。 DOT_SIZE是苹果的大小和蛇的点。 ALL_DOTS常数定义了板上可能的最大点数。 (900 = 300 * 300 / 10 * 10)RAND_POS常数用于计算苹果的随机位置。 DELAY常数确定游戏的速度。
x = [0] * ALL_DOTSy = [0] * ALL_DOTS
这两个列表存储蛇的所有可能关节的 x,y 坐标。
在move()方法中,我们有游戏的关键算法。 要了解它,请看一下蛇是如何运动的。 您控制蛇的头。 您可以使用光标键更改其方向。 其余关节在链上向上移动一个位置。 第二关节移动到第一个关节的位置,第三关节移动到第二个关节的位置,依此类推。
while z > 0:x[z] = x[(z - 1)]y[z] = y[(z - 1)]z = z - 1
该代码将关节向上移动。
if self.left:x[0] -= DOT_SIZE
将头向左移动。
在checkCollision()方法中,我们确定蛇是否击中了自己或撞墙之一。
while z > 0:if z > 4 and x[0] == x[z] and y[0] == y[z]:self.inGame = Falsez = z - 1
如果蛇用头撞到其关节之一,则游戏结束。
if y[0] >= HEIGHT - DOT_SIZE - self.TITLEBAR_HEIGHT:self.inGame = False
如果蛇击中了棋盘的底部,则游戏结束。
下图有助于了解蛇形物体与棋盘底部的碰撞。

图:碰撞
locateApple()方法在表格上随机定位一个苹果。
rand = Random()r = rand.Next(RAND_POS)
我们得到一个从 0 到RAND_POS-1的随机数。
self.apple_x = r * DOT_SIZE...self.apple_y = r * DOT_SIZE
这些行设置了apple对象的 x,y 坐标。
在OnKeyUp()方法中,我们确定了键击玩家击键的时间。
if key == Keys.Left and not self.right:self.left = Trueself.up = Falseself.down = False
如果我们按左光标键,则将self.left变量设置为True。 在move()方法中使用此变量来更改蛇对象的坐标。 还要注意,当蛇向右行驶时,我们不能立即向左转。
snake.py
#!/usr/bin/ipyimport clrclr.AddReference("System.Windows.Forms")from System.Windows.Forms import Application, Form, FormBorderStylefrom board import Boardclass IForm(Form):def __init__(self):self.Text = 'Snake'self.FormBorderStyle = FormBorderStyle.FixedSingleborderWidth = (self.Width - self.ClientSize.Width) / 2titleBarHeight = self.Height - self.ClientSize.Height - borderWidthboard = Board()board.BORDER_WIDTH = borderWidthboard.TITLEBAR_HEIGHT = titleBarHeightself.Controls.Add(board)self.CenterToScreen()Application.Run(IForm())
这是主要的类。
borderWidth = (self.Width - self.ClientSize.Width) / 2titleBarHeight = self.Height - self.ClientSize.Height - borderWidth
在这里,我们获得窗体控件的边框宽度和标题栏高度。 这些值对于蛇与边界的碰撞检测是必需的。
board.BORDER_WIDTH = borderWidthboard.TITLEBAR_HEIGHT = titleBarHeight
我们将它们提供给董事会。

图:贪食蛇
这是使用 Iron Win 编程语言的 Mono Winforms 库编程的贪食蛇游戏。
