Pygame Notebook 3 贪吃蛇

2017/10/23

《Making Games with Python and Pygame》


Notebook <3>

第六章的游戏 Wormy 贪吃蛇游戏, 开局显示旋转变化的字体和方块,按下任意按键后会显示游戏界面,划分的网格,游走的蛇(绿色方块),苹果(红色的方块),碰撞到苹果身体变长,碰撞到自己和墙壁游戏结束,暂停并显示 Game Over,按下任意按键后又再次重新开始。同时实时显示分数。

亮点 / 思路

  • 程序很好的结合了吃苹果和游动的处理,使用蛇头坐标,一个字典列表表示蛇,每次都删除末尾,吃到则不删除。
  • Game Over时,进入显示Game Over while 死循环等待退出,其间其他的显示部分暂停在原处,死循环阻塞住了其他显示程序,显示程序仍旧在 Surface 上面显示界面,造成一种另外有暂停程序的假象。
  • 字体背景会随着字体的变化而变化,不需要额外控制。
  • 2D 图像的旋转,不完美,不应该直接覆盖变量,复用变量名的话则会造成字体的 Surface 越来越大,报错。
  • 智能的退出函数。

蛇的表示和长度的增加

  • 在当前的前进方向上增加头,删去尾巴,每次重新绘图时感觉就是在前进;吃到苹果则不删去,感觉就是增加了长度。
wormCoords = [ {'x':startx , 'y': starty} ,  {'x':startx-1 , 'y': starty}  ,  {'x':startx-2 , 'y': starty} ,{'x':startx-3 , 'y': starty} ]
if wormCoords[HEAD]['x'] == apple['x'] and wormCoords[HEAD]['y'] == apple['y']:
	apple = getRandomLocation() # set a new apple somewhere
else:
	del wormCoords[-1] 

if direction == UP:
	newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] - 1}
elif direction == DOWN:
	newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] + 1}
elif direction == LEFT:
	newHead = {'x': wormCoords[HEAD]['x'] - 1, 'y': wormCoords[HEAD]['y']}
elif direction == RIGHT:
	newHead = {'x': wormCoords[HEAD]['x'] + 1, 'y': wormCoords[HEAD]['y']}

wormCoords.insert(0, newHead)

显示 pygame.event 中的 type 值

#/usr/bin/env python
#coding=utf8

import random, pygame, sys
from pygame.locals import *

WINDOWWIDTH = 640
WINDOWHEIGHT = 480

def main():
	pygame.init()
	DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
	pygame.display.set_caption('event test')


	while True:
		for event in pygame.event.get():
			print 'event.type' , event.type

			if event.type == QUIT:
				pygame.quit()
				sys.exit()
			elif event.type == KEYDOWN:
				print event.key 

if __name__ == '__main__':
	main()

显示 文字旋转,背景转化,网格划分,按键退出

  • 运行文件
  • 背景转化更好的说明了每次用背景色覆盖后重新绘图的原理和好处
  • 文字旋转

    pygame.transform.rotate( surface , rotate_angle) 并不会改变传递给它的 Surface 对象,而是返回一个新的Surface 对象,旋转后的图形绘制于新的 Surface 对象上。

所以每次都重新绘图。

  • 旋转不要复用变量名。

    pygame.error: Width or height is too large

  • 退出函数 checkForKeyPress() 的使用
  • 网格划分,循环划线。
#/usr/bin/env python
#coding=utf8

import random, pygame, sys
from pygame.locals import *

FPS = 5
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
CELLSIZE = 20
assert WINDOWWIDTH % CELLSIZE == 0, "Window width must be a multiple of cell size."
assert WINDOWHEIGHT % CELLSIZE == 0, "Window height must be a multiple of cell size."
CELLWIDTH = int(WINDOWWIDTH / CELLSIZE)
CELLHEIGHT = int(WINDOWHEIGHT / CELLSIZE)
#	  R	G	B
WHITE	 = (255, 255, 255)
BLACK	 = (  0,   0,   0)
RED	   = (255,   0,   0)
GREEN	 = (  0, 255,   0)
DARKGREEN = (  0, 155,   0)
DARKGRAY  = ( 40,  40,  40)
BGCOLOR = BLACK
def terminate():
	pygame.quit()
	sys.exit()
def main():
	global FPSCLOCK, DISPLAYSURF, BASICFONT
	pygame.init()
	FPSCLOCK = pygame.time.Clock()
	DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
	BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
	pygame.display.set_caption('Wormy')

	degrees1 = 0
	degrees2 = 0
	while True:	
		showStartScreen()
		showGameOverScreen()
def drawGrid():
	for x in range(0, WINDOWWIDTH, CELLSIZE): # draw vertical lines
		pygame.draw.line(DISPLAYSURF, DARKGRAY, (x, 0), (x, WINDOWHEIGHT))
	for y in range(0, WINDOWHEIGHT, CELLSIZE): # draw horizontal lines
		pygame.draw.line(DISPLAYSURF, DARKGRAY, (0, y), (WINDOWWIDTH, y))
def drawPressKeyMsg():
	pressKeySurf = BASICFONT.render('Press a key to play.', True, DARKGRAY)
	pressKeyRect = pressKeySurf.get_rect()
	pressKeyRect.topleft = (WINDOWWIDTH - 200, WINDOWHEIGHT - 30)
	DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
def checkForKeyPress():
	if len(pygame.event.get(QUIT)) > 0:
		terminate()
	keyUpEvents = pygame.event.get(KEYUP)
	if len(keyUpEvents) == 0:
		return None
	if keyUpEvents[0].key == K_ESCAPE:
		terminate()
	return keyUpEvents[0].key
def showStartScreen():
	titleFont = pygame.font.Font('freesansbold.ttf', 100)
	titleSurf1 = titleFont.render('Wormy!', True, WHITE, DARKGREEN)
	titleSurf2 = titleFont.render('Wormy!', True, GREEN)
	while True:
		DISPLAYSURF.fill(BGCOLOR)
		rotatedSurf1 = pygame.transform.rotate(titleSurf1, degrees1) #返回的是新的 Surface 对象
		rotatedRect1 = rotatedSurf1.get_rect()
		rotatedRect1.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
		DISPLAYSURF.blit(rotatedSurf1, rotatedRect1)
		rotatedSurf2 = pygame.transform.rotate(titleSurf2, degrees2) 
		rotatedRect2 = rotatedSurf2.get_rect()
		rotatedRect2.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
		DISPLAYSURF.blit(rotatedSurf2, rotatedRect2)
		# for event in pygame.event.get():
		# 	if event.type == QUIT:
		# 		terminate()
		if checkForKeyPress():
			pygame.event.get() # clear event queue
			return
		drawPressKeyMsg()
		drawGrid()
		pygame.display.update()
		FPSCLOCK.tick(FPS)
		degrees1 += 3 # rotate by 3 degrees each frame
		degrees2 += 7 # rotate by 7 degrees each frame
def showGameOverScreen():
	gameOverFont = pygame.font.Font('freesansbold.ttf', 150)
	gameSurf = gameOverFont.render('Game', True, WHITE)
	overSurf = gameOverFont.render('Over', True, WHITE)
	gameRect = gameSurf.get_rect()
	overRect = overSurf.get_rect()
	gameRect.midtop = (WINDOWWIDTH / 2, 10)
	overRect.midtop = (WINDOWWIDTH / 2, gameRect.height + 10 + 25)

	DISPLAYSURF.blit(gameSurf, gameRect)
	DISPLAYSURF.blit(overSurf, overRect)

	drawPressKeyMsg()

	pygame.display.update()
	pygame.time.wait(500)
	checkForKeyPress() # clear out any key presses in the event queue

	while True:
		if checkForKeyPress():
			pygame.event.get() # clear event queue
			return
if __name__ == '__main__':
	main()

Search

    Post Directory