在 PyGTK 编程教程的这一部分中,我们将创建一个贪食蛇游戏克隆。
贪食蛇游戏
贪食蛇是较旧的经典视频游戏。 它最初是在 70 年代后期创建的。 后来它被带到 PC 上。 在这个游戏中,玩家控制蛇。 目的是尽可能多地吃苹果。 蛇每次吃一个苹果,它的身体就会长大。 蛇必须避开墙壁和自己的身体。 该游戏有时称为 Nibbles 。
开发
蛇的每个关节的大小为 10px。 蛇由光标键控制。 最初,蛇具有三个关节。 游戏立即开始。 如果游戏结束,我们将在棋盘中间显示"Game Over"消息。
snake.py
#!/usr/bin/python# ZetCode PyGTK tutorial## This is a simple snake game# clone## author: jan bodnar# website: zetcode.com# last edited: February 2009import sysimport gtkimport cairoimport randomimport glibWIDTH = 300HEIGHT = 270DOT_SIZE = 10ALL_DOTS = WIDTH * HEIGHT / (DOT_SIZE * DOT_SIZE)RAND_POS = 26x = [0] * ALL_DOTSy = [0] * ALL_DOTSclass Board(gtk.DrawingArea):def __init__(self):super(Board, self).__init__()self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0, 0, 0))self.set_size_request(WIDTH, HEIGHT)self.connect("expose-event", self.expose)self.init_game()def on_timer(self):if self.inGame:self.check_apple()self.check_collision()self.move()self.queue_draw()return Trueelse:return Falsedef init_game(self):self.left = Falseself.right = Trueself.up = Falseself.down = Falseself.inGame = Trueself.dots = 3for i in range(self.dots):x[i] = 50 - i * 10y[i] = 50try:self.dot = cairo.ImageSurface.create_from_png("dot.png")self.head = cairo.ImageSurface.create_from_png("head.png")self.apple = cairo.ImageSurface.create_from_png("apple.png")except Exception, e:print e.messagesys.exit(1)self.locate_apple()glib.timeout_add(100, self.on_timer)def expose(self, widget, event):cr = widget.window.cairo_create()if self.inGame:cr.set_source_rgb(0, 0, 0)cr.paint()cr.set_source_surface(self.apple, self.apple_x, self.apple_y)cr.paint()for z in range(self.dots):if (z == 0):cr.set_source_surface(self.head, x[z], y[z])cr.paint()else:cr.set_source_surface(self.dot, x[z], y[z])cr.paint()else:self.game_over(cr)def game_over(self, cr):w = self.allocation.width / 2h = self.allocation.height / 2(x, y, width, height, dx, dy) = cr.text_extents("Game Over")cr.set_source_rgb(65535, 65535, 65535)cr.move_to(w - width/2, h)cr.show_text("Game Over")self.inGame = Falsedef check_apple(self):if x[0] == self.apple_x and y[0] == self.apple_y:self.dots = self.dots + 1self.locate_apple()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 check_collision(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.inGame = Falseif y[0] < 0:self.inGame = Falseif x[0] > WIDTH - DOT_SIZE:self.inGame = Falseif x[0] < 0:self.inGame = Falsedef locate_apple(self):r = random.randint(0, RAND_POS)self.apple_x = r * DOT_SIZEr = random.randint(0, RAND_POS)self.apple_y = r * DOT_SIZEdef on_key_down(self, event):key = event.keyvalif key == gtk.keysyms.Left and not self.right:self.left = Trueself.up = Falseself.down = Falseif key == gtk.keysyms.Right and not self.left:self.right = Trueself.up = Falseself.down = Falseif key == gtk.keysyms.Up and not self.down:self.up = Trueself.right = Falseself.left = Falseif key == gtk.keysyms.Down and not self.up:self.down = Trueself.right = Falseself.left = Falseclass Snake(gtk.Window):def __init__(self):super(Snake, self).__init__()self.set_title('Snake')self.set_size_request(WIDTH, HEIGHT)self.set_resizable(False)self.set_position(gtk.WIN_POS_CENTER)self.board = Board()self.connect("key-press-event", self.on_key_down)self.add(self.board)self.connect("destroy", gtk.main_quit)self.show_all()def on_key_down(self, widget, event):key = event.keyvalself.board.on_key_down(event)Snake()gtk.main()
首先,我们将定义一些在游戏中使用的全局变量。
WIDTH和HEIGHT常数确定电路板的大小。 DOT_SIZE是苹果的大小和蛇的点。 ALL_DOTS常数定义了板上可能的最大点数。 RAND_POS常数用于计算苹果的随机位置。 DELAY常数确定游戏的速度。
x = [0] * ALL_DOTSy = [0] * ALL_DOTS
这两个列表存储蛇的所有可能关节的 x,y 坐标。
init_game()方法初始化变量,加载图像并启动超时功能。
self.left = Falseself.right = Trueself.up = Falseself.down = Falseself.inGame = Trueself.dots = 3
游戏开始时,蛇有三个关节。 而且它正在向右行驶。
在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.inGame = False
如果蛇击中了棋盘的底部,我们就结束了游戏。
locate_apple()方法在表格上随机定位一个苹果。
r = random.randint(0, RAND_POS)
我们得到一个从 0 到RAND_POS-1的随机数。
self.apple_x = r * DOT_SIZE...self.apple_y = r * DOT_SIZE
这些行设置了apple对象的 x,y 坐标。
self.connect("key-press-event", self.on_key_down)...def on_key_down(self, widget, event):key = event.keyvalself.board.on_key_down(event)
我们在Snake类中捕获按键事件,并将处理委托给board对象。
在Board类的on_key_dow()方法中,我们确定玩家按下了哪些键。
if key == gtk.keysyms.Left and not self.right:self.left = Trueself.up = Falseself.down = False
如果我们按左光标键,则将self.left变量设置为True。 在move()方法中使用此变量来更改蛇对象的坐标。 还要注意,当蛇向右行驶时,我们不能立即向左转。

图:贪食蛇
这是使用 PyGTK 编程库编程的贪食蛇电脑游戏。
