在这个游戏中,玩家通过控制屏幕中的精灵,躲开前方随机出现的敌人。玩家躲避敌人的时间越久,得到的分数就越高。
为了好玩,我们还会为游戏加入一些作弊模式。如果玩家按下了X键,每一个敌人的速度就会降低到超慢。如果玩家按下了Z键,敌人就会反转方向,沿着屏幕向上移动而不是往下落。
目录
(一)回顾pygame的基本数据类型
- pygame.Rect:Rect对象表示一个矩形空间的位置和大小。位置可以通过Rect对象的topleft(或者topright、bottomleft和bottomright)属性来确定。这些属性是表示X坐标和Y坐标的整数的一个元组。矩形的大小可以通过width属性和height属性来决定,这些属性表示矩形区域的长和高是多少像素。Rect对象有一个colliderect()方法,用来检查矩形是否和其他Rect对象有碰撞。
- pygame.Surface:Surface对象是带颜色的像素的区域。Surface对象表示一个矩形图像,而Rect对象只表示一个矩形的空间和位置。Surface对象有一个blit()方法,它将一个Surface对象上的图像绘制到另一个Surface对象之上。由pygame.display.set_mode()函数返回的Surface对象是特殊的,因为当调用pygame.display.update()函数时,在该Surface对象上绘制的任何物体都会显示在用户屏幕上。
- pygame.event.Event:当用户提供键盘、鼠标或其他类型的输入时,pygame.event模块会创建Event对象。pygame.event.get()函数返回这些Event对象的一个列表。可以通过查看Event对象的type属性,来查看事件的类型。QUIT、KEYDOWN和MOUSEBUTTONUP是一些事件类型的示例。
- pygame.font.Font:pygame.font模块拥有一个Font数据类型,用于表示pygame中的文本的字体。传递给pygame.font.SysFont()函数的参数是表示字体名称的一个字符串以及表示字体大小的一个整数。然而,通常传递None作为字体名称以获取默认系统字体。
- pygame.time.Clock:pygame.time模块中的Clock对象有助于避免程序运行得过快。Clock对象有一个tick()方法,它接收的参数表示想要游戏运行速度是每秒多少帧(FPS)。FPS越高,游戏运行越快。
(二)导入模块
import pygame, random, sys
from pygame.locals import *
pygame.locals模块提供了几个供pygame使用的常量,如事件类型(QUIT和KEYDOWN等)和键盘按键(K_ESCAPE和K_LEFT)等。通过使用from pygame.locals import *语句,我们可以在源代码中只输入QUIT,而不必输入pygame.locals.QUIT。*代表所有pygame.locals导出的对象名称。
(三)创建常量
WINDOWWIDTH = 600
WINDOWHEIGHT = 600
TEXTCOLOR = (0, 0, 0)
BACKGROUNDCOLOR = (255, 255, 255)
以上代码为窗口大小、文本颜色和背景颜色设置了常量。将常量赋值给变量,要比直接输入常量更具有描述性,而且也便于修改。
接下来我们为FPS设置了常量,这是想要让游戏按照每秒多少帧的速度运行:
FPS = 60
帧(frame是在游戏循环的单次迭代中所绘制的一个屏幕)。
后面跟代码中,我们将FPS传递给mainClock.tick方法,以便函数可以知道程序要暂停多久。
下面我们设置了更多的常量,用来描述落下的敌人。
BADDIEMINSIZE = 10
BADDIEMAXSIZE = 40
BADDIEMINSPEED = 1
BADDIEMAXSPEED = 8
ADDNEWBADDIERATE = 6
敌人的宽度和高度均在BADDIEMINSIZE和BADVIEMAXSIZE之间。在游戏循环的每次迭代中,敌人从屏幕上落下的速率在每秒BADDIEMINSPEED到BADDIEMINSPEED多个像素之间。游戏循环每经过ADDNEWBADDIERATE次迭代之后,将在窗口的顶部增加一个新的敌人。
如果玩家的角色是移动的,在游戏循环的每次迭代中,PLAYERMOVERATE将保存玩家的角色在窗口中移动的像素数。
PLAYERMOVERATE = 5
通过增大这个数字,就可以加快角色的移动速度。
(四)定义函数
我们将为这个游戏创建几个函数。terminate()和waitForPlayerToPressKey()函数将分别终止和暂停程序,playerHasHitBaddie()函数将会记录玩家和敌人的碰撞,drawText()函数将会把得分和其他的文本绘制到屏幕上。
1)终止和暂停游戏
def terminate():
pygame.quit()
sys.exit()
把pygame.quit()和sys.exit()放到一个函数里面。
有时,我们想要暂停游戏,直到玩家按下一个键再继续游戏。这里体现在Dodger标题文本刚出现的时候,需要玩家随意按下一个键来开始游戏,或者在出现Game Over且游戏结束的时候。我们创建了一个waitForPlayerToPressKey()函数:
def waitForPlayerToPressKey():
while True:
for event in pygame.event.get():
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE: # Pressing ESC quits.
terminate()
return
在这个函数中有一个无限循环,只有当接收到一个KEYDOWN或QUIT事件时,才会跳出该循环。否则代码将包初循环,看上去就像是冻结了,直到玩家按下一个键。
2)记录和敌人的碰撞
如果玩家的角色和一个敌人碰撞,playerHasHitBaddie()函数将返回True。
def playerHasHitBaddie(playerRect, baddies):
for b in baddies:
if playerRect.colliderect(b['rect']):
return True
return False
baddies参数是“baddie”字典数据结构的一个列表。其中每一个字典都有rect键,该键的值是表示敌人大小和位置的一个Rect对象。
playerRect也是一个Rect对象。playerRect对象和baddies列表中的Rect对象如果发生碰撞,则该方法返回True。
如果未发生碰撞,该函数返回False。
3)将文本绘制到窗口
在窗口绘制文本包含了几个步骤,我们把这些步骤放到drawText()函数中去。当我们呢需要在屏幕上显示文本的时候,只需要调用drawText()函数即可:
def drawText(text, font, surface, x, y):
textobj = font.render(text, 1, TEXTCOLOR)
textrect = textobj.get_rect()
textrect.topleft = (x, y)
surface.blit(tex