谁没有玩过谷歌著名的 “恐龙游戏”?也许每个人都玩过这个游戏。今天,在这篇文章中,我们将帮助你用 Python 开发一个恐龙游戏。本教程将深入讲解每一行代码,并提供参考资料。我们将尽力让读者详细、透彻地理解这个项目。Python 版恐龙游戏的任务记录包括图片文档和 Python 资料。图形用户界面使用了 pygame 库。
我们将使用最著名的 Python 库之一 PyGame。除此之外,我们还将使用随机、os 和 sys 库来开发 Python 版恐龙游戏。在开始实际编码之前,让我们先简要了解一下恐龙游戏是怎么回事?它是如何运行的?然后,我们将看看需要添加到游戏中的功能列表。因此,让我们不再赘述,直接开始本文。
Python 中恐龙游戏的基本构思
这款简化游戏的主要目标是在不被任何障碍物干扰的情况下获得越来越多的分数。所有游戏都使用相同的游戏技巧。如前所述,这款小游戏的核心是在不接触任何障碍物的情况下积累分数。用户必须使用两个键盘键来玩这款简单的游戏。用空格键跳跃,用向下箭头掩护。与原版相比,本副本的游戏环境有所改动。
有了对这款游戏的基本概念。让我们来谈谈 Python 中的恐龙游戏项目必须具备的功能。
本游戏的特点
Dino Game 的一系列功能包括以下内容:
- 显示之前的高分和当前分数
- 键盘支持
- 恐龙跳跃和死亡时的声音
- 检查点声音
- 重玩游戏的选项
现在,让我们开始这个项目的实际编码工作。
用 Python 编写恐龙游戏
基本库导入
import os
import sys
import pygame
import random
from pygame import *
pygame.init()
解释:
在这里,我们导入了本项目开发过程中要用到的所有库。最后一行 pygame. init() 用于初始化所有导入的 pygame 模块。
设置显示窗口和标题
screenDisplay = (width_screen, height_screen) = (600, 400)
FPS = 60
gravity = 0.6
black_color = (0,0,0)
white_color = (255,255,255)
backgroundColor = (235, 235, 235)
highest_scores = 0
screenDisplay = pygame.display.set_mode(screenDisplay)
timerClock = pygame.time.Clock()
pygame.display.set_caption("Dino Run - CopyAssignment ")
解释:
在 Python 中的 Dino Game 这部分代码中,我们使用了 PyGame 的各种函数来设置窗口大小、标题等。我们使用 display.set_mode 将窗口或屏幕初始化为显示模式。为了设置窗口的标题,我们使用了 set_caption
添加基本资源
soundOnJump = pygame.mixer.Sound('resources/jump.wav')
soundOnDie = pygame.mixer.Sound('resources/die.wav')
soundOnCheckpoint = pygame.mixer.Sound('resources/checkPoint.wav')
解释:
我们在这里声明了三个变量,主要用于在游戏中添加各种声音。我们创建了一个名为 resources 的文件夹,里面有三个 .wav 文件。为了向游戏发送声音,我们使用了 mixer.Sound()。我们将在代码的其他部分使用这三种声音。
加载图像的函数
def load_image(
name,
sx=-1,
sy=-1,
colorkey=None,
):
fullname = os.path.join('resources', name)
img = pygame.image.load(fullname)
img = img.convert()
if colorkey is not None:
if colorkey == -1:
colorkey = img.get_at((0, 0))
img.set_colorkey(colorkey, RLEACCEL)
if sx != -1 or sy != -1:
img = pygame.transform.scale(img, (sx, sy))
return (img, img.get_rect())
def load_sprite_sheet(
s_name,
namex,
namey,
scx = -1,
scy = -1,
c_key = None,
):
fullname = os.path.join('resources', s_name)
sh = pygame.image.load(fullname)
sh = sh.convert()
sh_rect = sh.get_rect()
sprites = []
sx = sh_rect.width/ namex
sy = sh_rect.height/ namey
for i in range(0, namey):
for j in range(0, namex):
rect = pygame.Rect((j*sx,i*sy,sx,sy))
img = pygame.Surface(rect.size)
img = img.convert()
img.blit(sh,(0,0),rect)
if c_key is not None:
if c_key == -1:
c_key = img.get_at((0, 0))
img.set_colorkey(c_key, RLEACCEL)
if scx != -1 or scy != -1:
img = pygame.transform.scale(img, (scx, scy))
sprites.append(img)
sprite_rect = sprites[0].get_rect()
return sprites,sprite_rect
解释:
接下来是 Python 中 Dino Game 的其他代码块,这部分主要负责在 Dino Game 的游戏窗口中加载图片。在这里,我们使用了 Python 的 os.path.join() 函数,它可以智能地连接一个或多个路径组件。除了最后一个路径组件外,这种方法通过在每个非空部分后放置一个目录分隔符(‘/’)来连接不同的路径组件。如果要连接的最后一个路径组件为空,则会在其末尾添加一个目录分隔符(‘/’)。
pygame.image.load() 可以帮助我们加载图像,然后在 for 循环中使用 set_colorkey(),基本上可以设置透明色键。同样,我们在另一个名为 load_sprite_sheet 的用户自定义函数中使用了上述函数
要在信息上方显示游戏
def gameover_display_message(rbtn_image, gmo_image):
rbtn_rect = rbtn_image.get_rect()
rbtn_rect.centerx = width_screen / 2
rbtn_rect.top = height_screen * 0.52
gmo_rect = gmo_image.get_rect()
gmo_rect.centerx = width_screen / 2
gmo_rect.centery = height_screen * 0.35
screenDisplay.blit(rbtn_image, rbtn_rect)
screenDisplay.blit(gmo_image, gmo_rect)
def extractDigits(num):
if num > -1:
d = []
i = 0
while(num / 10 != 0):
d.append(num % 10)
num = int(num / 10)
d.append(num % 10)
for i in range(len(d),5):
d.append(0)
d.reverse()
return d
解释:
在此函数中,我们使用了两个矩形来显示两幅图像:一个是 "游戏结束 "图像,另一个是 “重放图像”。我们使用了 blit(),它的意思是块传输,指的是将材料从一个表面复制到另一个表面的过程。您制作的屏幕和新的 Surface 就是相关的两个表面。因此,这个 Surface 将被 blit() 函数提取并放置在屏幕之上。这种方法需要两个参数。我们定义的另一个函数是 extractDigits() - 这个函数负责跟踪用户的分数。
定义恐龙类
class Dino():
def __init__(self, sx=-1, sy=-1):
self.imgs, self.rect = load_sprite_sheet('dino.png', 5, 1, sx, sy, -1)
self.imgs1, self.rect1 = load_sprite_sheet('dino_ducking.png', 2, 1, 59, sy, -1)
self.rect.bottom = int(0.98 * height_screen)
self.rect.left = width_screen / 15
self.image = self.imgs[0]
self.index = 0
self.counter = 0
self.score = 0
self.jumping = False
self.dead = False
self.ducking = False
self.blinking = False
self.movement = [0,0]
self.jumpSpeed = 11.5
self.stand_position_width = self.rect.width
self.duck_position_width = self.rect1.width
def draw(self):
screenDisplay.blit(self.image, self.rect)
def checkbounds(self):
if self.rect.bottom > int(0.98 * height_screen):
self.rect.bottom = int(0.98 * height_screen)
self.jumping = False
def update(self):
if self.jumping:
self.movement[1] = self.movement[1] + gravity
if self.jumping:
self.index = 0
elif self.blinking:
if self.index == 0:
if self.counter % 400 == 399:
self.index = (self.index + 1)%2
else:
if self.counter % 20 == 19:
self.index = (self.index + 1)%2
elif self.ducking:
if self.counter % 5 == 0:
self.index = (self.index + 1)%2
else:
if self.counter % 5 == 0:
self.index = (self.index + 1)%2 + 2
if self.dead:
self.index = 4
if not self.ducking:
self.image = self.imgs[self.index]
self.rect.width = self.stand_position_width
else:
self.image = self.imgs1[(self.index) % 2]
self.rect.width = self.duck_position_width
self.rect = self.rect.move(self.movement)
self.checkbounds()
if not self.dead and self.counter % 7 == 6 and self.blinking == False:
self.score += 1
if self.score % 100 == 0 and self.score != 0:
if pygame.mixer.get_init() != None:
soundOnCheckpoint.play()
self.counter = (self.counter + 1)
解释:
该类可视为 Python 中恐龙游戏的核心。它主要负责处理恐龙的所有功能。最初,我们硬编码了恐龙的所有不同变量,如速度、跳跃动作等。除此之外,为了显示恐龙的动作,我们还使用了函数 update(),它将记录恐龙的所有动作,如躲避、跳跃、死亡等。
定义仙人掌类
class Ground():
def __init__(self,speed=-5):
self.image,self.rect = load_image('ground.png',-1,-1,-1)
self.image1,self.rect1 = load_image('ground.png',-1,-1,-1)
self.rect.bottom = height_screen
self.rect1.bottom = height_screen
self.rect1.left = self.rect.right
self.speed = speed
def draw(self):
screenDisplay.blit(self.image, self.rect)
screenDisplay.blit(self.image1, self.rect1)
def update(self):
self.rect.left += self.speed
self.rect1.left += self.speed
if self.rect.right < 0:
self.rect.left = self.rect1.right
if self.rect1.right < 0:
self.rect1.left = self.rect.right
解释:
该类负责在 Python 中的恐龙游戏中处理仙人掌的摆放位置。首先,我们从资源文件夹中加载仙人掌图像,并设置其位置、移动等。为了移除屏幕上的仙人掌,我们使用了 update()。在其中,我们设置了一个 if 块,条件是 self.rect.right < 0,然后我们将调用 self.kill()
定义小鸟类
class birds(pygame.sprite.Sprite):
def __init__(self, speed=5, sx=-1, sy=-1):
pygame.sprite.Sprite.__init__(self,self.containers)
self.imgs, self.rect = load_sprite_sheet('birds.png', 2, 1, sx, sy, -1)
self.birds_height = [height_screen * 0.82, height_screen * 0.75, height_screen * 0.60]
self.rect.centery = self.birds_height[random.randrange(0, 3)]
self.rect.left = width_screen + self.rect.width
self.image = self.imgs[0]
self.movement = [-1*speed,0]
self.index = 0
self.counter = 0
def draw(self):
screenDisplay.blit(self.image, self.rect)
def update(self):
if self.counter % 10 == 0:
self.index = (self.index+1)%2
self.image = self.imgs[self.index]
self.rect = self.rect.move(self.movement)
self.counter = (self.counter + 1)
if self.rect.right < 0:
self.kill()
解释:
该类负责在 Python 中的恐龙游戏中处理仙人掌的摆放位置。首先,我们从资源文件夹中加载仙人掌图像,并设置其位置、移动等。为了移除屏幕上的仙人掌,我们使用了 update()。在其中,我们设置了一个 if 块,条件是 self.rect.right < 0,然后我们将调用 self.kill()。它用于将 widget 从屏幕中移除,因此我们使用 kill()。
定义地面类
class Ground():
def __init__(self,speed=-5):
self.image,self.rect = load_image('ground.png',-1,-1,-1)
self.image1,self.rect1 = load_image('ground.png',-1,-1,-1)
self.rect.bottom = height_screen
self.rect1.bottom = height_screen
self.rect1.left = self.rect.right
self.speed = speed
def draw(self):
screenDisplay.blit(self.image, self.rect)
screenDisplay.blit(self.image1, self.rect1)
def update(self):
self.rect.left += self.speed
self.rect1.left += self.speed
if self.rect.right < 0:
self.rect.left = self.rect1.right
if self.rect1.right < 0:
self.rect1.left = self.rect.right
说明
与定义鸟类的方法相同,我们定义了地面类,并使用了与鸟类相同的函数来实现地面的移动。
定义云类
class Cloud(pygame.sprite.Sprite):
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self,self.containers)
self.image,self.rect = load_image('cloud.png',int(90*30/42),30,-1)
self.speed = 1
self.rect.left = x
self.rect.top = y
self.movement = [-1*self.speed,0]
def draw(self):
screenDisplay.blit(self.image, self.rect)
def update(self):
self.rect = self.rect.move(self.movement)
if self.rect.right < 0:
self.kill()
解释:
接着来看 Python 中恐龙游戏的另一个类。云也是这个游戏的组成部分之一。它的功能和动作与地面完全相同。该类中的函数与我们在地面类中使用的函数相同。
处理分数
class Scoreboard():
def __init__(self,x=-1,y=-1):
self.score = 0
self.scre_img, self.screrect = load_sprite_sheet('numbers.png', 12, 1, 11, int(11 * 6 / 5), -1)
self.image = pygame.Surface((55,int(11*6/5)))
self.rect = self.image.get_rect()
if x == -1:
self.rect.left = width_screen * 0.89
else:
self.rect.left = x
if y == -1:
self.rect.top = height_screen * 0.1
else:
self.rect.top = y
def draw(self):
screenDisplay.blit(self.image, self.rect)
def update(self,score):
score_digits = extractDigits(score)
self.image.fill(backgroundColor)
for s in score_digits:
self.image.blit(self.scre_img[s], self.screrect)
self.screrect.left += self.screrect.width
self.screrect.left = 0
解释:
现在我们要处理恐龙游戏中的记分板。我们通过跟踪屏幕的移动来完成这项工作。我们使用 "numbers.png "图片来更新分数。此外,我们还调用了之前声明的 extractDigits() 函数,从图像中提取个位数,然后根据窗口上组件的移动情况显示出来。
介绍屏幕
def introduction_screen():
ado_dino = Dino(44,47)
ado_dino.blinking = True
starting_game = False
t_ground,t_ground_rect = load_sprite_sheet('ground.png',15,1,-1,-1,-1)
t_ground_rect.left = width_screen / 20
t_ground_rect.bottom = height_screen
logo,l_rect = load_image('logo.png',300,140,-1)
l_rect.centerx = width_screen * 0.6
l_rect.centery = height_screen * 0.6
while not starting_game:
if pygame.display.get_surface() == None:
print("Couldn't load display surface")
return True
else:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE or event.key == pygame.K_UP:
ado_dino.jumping = True
ado_dino.blinking = False
ado_dino.movement[1] = -1*ado_dino.jumpSpeed
ado_dino.update()
if pygame.display.get_surface() != None:
screenDisplay.fill(backgroundColor)
screenDisplay.blit(t_ground[0], t_ground_rect)
if ado_dino.blinking:
screenDisplay.blit(logo, l_rect)
ado_dino.draw()
pygame.display.update()
timerClock.tick(FPS)
if ado_dino.jumping == False and ado_dino.blinking == False:
starting_game = True
解释:
每当用户运行 Python 中的 Dino Game 程序时,首先会显示此屏幕。该屏幕最初将只加载游戏的一些组件,如地面和徽标图像。我们使用 if-else 来显示 "无法加载显示面 "的信息,以防图片无法加载。除此之外,我们还使用了上下方向键和空格键来启动游戏。只有当用户按下其中任何一个键时,游戏才会启动。按键的处理是通过事件来完成的。
处理整个游戏过程
def gameplay():
global highest_scores
gp = 4
s_Menu = False
g_Over = False
g_exit = False
gamer_Dino = Dino(44,47)
new_grnd = Ground(-1*gp)
score_boards = Scoreboard()
highScore = Scoreboard(width_screen * 0.78)
counter = 0
cactusan = pygame.sprite.Group()
smallBird = pygame.sprite.Group()
skyClouds = pygame.sprite.Group()
last_end_obs = pygame.sprite.Group()
Cactus.containers = cactusan
birds.containers = smallBird
Cloud.containers = skyClouds
rbtn_image,rbtn_rect = load_image('replay_button.png',35,31,-1)
gmo_image,gmo_rect = load_image('game_over.png',190,11,-1)
t_images,t_rect = load_sprite_sheet('numbers.png',12,1,11,int(11*6/5),-1)
ado_image = pygame.Surface((22,int(11*6/5)))
ado_rect = ado_image.get_rect()
ado_image.fill(backgroundColor)
ado_image.blit(t_images[10],t_rect)
t_rect.left += t_rect.width
ado_image.blit(t_images[11],t_rect)
ado_rect.top = height_screen * 0.1
ado_rect.left = width_screen * 0.73
while not g_exit:
while s_Menu:
pass
while not g_Over:
if pygame.display.get_surface() == None:
print("Couldn't load display surface")
g_exit = True
g_Over = True
else:
for event in pygame.event.get():
if event.type == pygame.QUIT:
g_exit = True
g_Over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if gamer_Dino.rect.bottom == int(0.98 * height_screen):
gamer_Dino.jumping = True
if pygame.mixer.get_init() != None:
soundOnJump.play()
gamer_Dino.movement[1] = -1*gamer_Dino.jumpSpeed
if event.key == pygame.K_DOWN:
if not (gamer_Dino.jumping and gamer_Dino.dead):
gamer_Dino.ducking = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
gamer_Dino.ducking = False
for c in cactusan:
c.movement[0] = -1*gp
if pygame.sprite.collide_mask(gamer_Dino,c):
gamer_Dino.dead = True
if pygame.mixer.get_init() != None:
soundOnDie.play()
for p in smallBird:
p.movement[0] = -1*gp
if pygame.sprite.collide_mask(gamer_Dino,p):
gamer_Dino.dead = True
if pygame.mixer.get_init() != None:
soundOnDie.play()
if len(cactusan) < 2:
if len(cactusan) == 0:
last_end_obs.empty()
last_end_obs.add(Cactus(gp,40,40))
else:
for l in last_end_obs:
if l.rect.right < width_screen*0.7 and random.randrange(0, 50) == 10:
last_end_obs.empty()
last_end_obs.add(Cactus(gp, 40, 40))
if len(smallBird) == 0 and random.randrange(0,200) == 10 and counter > 500:
for l in last_end_obs:
if l.rect.right < width_screen*0.8:
last_end_obs.empty()
last_end_obs.add(birds(gp, 46, 40))
if len(skyClouds) < 5 and random.randrange(0,300) == 10:
Cloud(width_screen, random.randrange(height_screen / 5, height_screen / 2))
gamer_Dino.update()
cactusan.update()
smallBird.update()
skyClouds.update()
new_grnd.update()
score_boards.update(gamer_Dino.score)
highScore.update(highest_scores)
if pygame.display.get_surface() != None:
screenDisplay.fill(backgroundColor)
new_grnd.draw()
skyClouds.draw(screenDisplay)
score_boards.draw()
if highest_scores != 0:
highScore.draw()
screenDisplay.blit(ado_image, ado_rect)
cactusan.draw(screenDisplay)
smallBird.draw(screenDisplay)
gamer_Dino.draw()
pygame.display.update()
timerClock.tick(FPS)
if gamer_Dino.dead:
g_Over = True
if gamer_Dino.score > highest_scores:
highest_scores = gamer_Dino.score
if counter%700 == 699:
new_grnd.speed -= 1
gp += 1
counter = (counter + 1)
if g_exit:
break
while g_Over:
if pygame.display.get_surface() == None:
print("Couldn't load display surface")
g_exit = True
g_Over = False
else:
for event in pygame.event.get():
if event.type == pygame.QUIT:
g_exit = True
g_Over = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
g_exit = True
g_Over = False
if event.key == pygame.K_RETURN or event.key == pygame.K_SPACE:
g_Over = False
gameplay()
highScore.update(highest_scores)
if pygame.display.get_surface() != None:
gameover_display_message(rbtn_image, gmo_image)
if highest_scores != 0:
highScore.draw()
screenDisplay.blit(ado_image, ado_rect)
pygame.display.update()
timerClock.tick(FPS)
pygame.quit()
quit()
解释:
每当用户按下上述三个键启动游戏时,游戏玩法函数就会开始工作。游戏启动后,gameplay() 函数的职责就是控制游戏中每个组件的移动。除此以外,恐龙的各种移动按键也由该函数控制。不断显示的小鸟、仙人掌、云朵等。最后,如果玩家输了,游戏就会自动进入 quit() 状态。这将帮助我们将游戏带入退出状态,并显示重玩和游戏结束两个图像。
主函数
def main():
isGameQuit = introduction_screen()
if not isGameQuit:
gameplay()
main()
解释:
如果用户退出游戏,该函数将调用 introduction_screen()。如果没有退出,则会调用 gameplay() 函数。这仅仅意味着游戏将再次处于用户可以进行游戏的状态。