|
|
|
@ -0,0 +1,197 @@
|
|
|
|
|
import pygame, sys
|
|
|
|
|
import random
|
|
|
|
|
class Person(): # 金枪小帅的属性
|
|
|
|
|
def __init__(self, surf=None, y=None):
|
|
|
|
|
self.surface = surf#初始化surface对象
|
|
|
|
|
self.y = y # y坐标
|
|
|
|
|
self.w = surf.get_width()/ 12 # 宽度
|
|
|
|
|
self.h = surf.get_height() / 2 # 高度
|
|
|
|
|
self.cur_frame = -1 # 当前的运动状态帧
|
|
|
|
|
self.state = 0 # 0代表跑步状态,1代表跳跃状态,2代表连续跳跃
|
|
|
|
|
self.gravity = 1 # 重力加速度
|
|
|
|
|
self.velocity_y = 0 # y方向的速度
|
|
|
|
|
self.vy_start = -20 # 起跳开始速度
|
|
|
|
|
|
|
|
|
|
def getPos(self): # 获取当前的位置坐标,用于碰撞检测,是否与障碍物坐标一致
|
|
|
|
|
return (0, self.y + 12, self.w, self.h)#0表y向的速度,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Obstacle(object): # 障碍物的属性
|
|
|
|
|
def __init__(self, surf, x=0, y=0):
|
|
|
|
|
self.surface = surf#初始化surface对象
|
|
|
|
|
self.x = x#放置的x坐标
|
|
|
|
|
self.y = y#放置的y坐标
|
|
|
|
|
self.w = surf.get_width()#获取宽度
|
|
|
|
|
self.h = surf.get_height()#获取高度
|
|
|
|
|
self.cur_frame = random.randint(0, 7) # 随机获取一种障碍物的类型,共7种类型
|
|
|
|
|
self.w = 100#设置初始宽度
|
|
|
|
|
self.h = 100#设置初始高度
|
|
|
|
|
|
|
|
|
|
def getPos(self): # 获取人物角色金枪小帅或者障碍物(当前的)坐标信息,分别是x坐标,y坐标,宽度w,高度h
|
|
|
|
|
return (self.x, self.y, self.w, self.h)#返回坐标信息
|
|
|
|
|
|
|
|
|
|
def judgeCollision(self, rect1, rect2): # 碰撞检测,即是判断金枪小帅和障碍物的坐标是否一致,以及考虑障碍物的大小
|
|
|
|
|
if (rect2[0] >= rect1[2] - 20) or (rect1[0] + 40 >= rect2[2]) or (rect1[1] + rect1[3] < rect2[1] + 20) or (
|
|
|
|
|
rect2[1] + rect2[3] < rect1[1] + 20):
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BackGround(object): # 背景类属性设计,继承于object
|
|
|
|
|
def __init__(self, surf):
|
|
|
|
|
self.surface = surf # 初始化Surface对象
|
|
|
|
|
self.dx = -10
|
|
|
|
|
self.w = surf.get_width() # 返回 Surface 对象的宽度
|
|
|
|
|
self.rect = surf.get_rect() # 获取 Surface 对象的矩形区域
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PaoKu(object):#游戏运作过程
|
|
|
|
|
def __init__(self):
|
|
|
|
|
pygame.init()#初始化Pygame所有模块
|
|
|
|
|
pygame.mixer.init()#初始化Pygame的声音混合器模块
|
|
|
|
|
|
|
|
|
|
self.width = 1200 # 设置游戏窗口宽度
|
|
|
|
|
self.height = 500 # 设置游戏窗口高度
|
|
|
|
|
self.size = (self.width, self.height)#保存初始设置宽度,高度
|
|
|
|
|
self.screen = pygame.display.set_mode(self.size)#调用pygame.display打开size内容大小的窗口
|
|
|
|
|
pygame.display.set_caption('ygc0417版本跑酷小游戏!')#调用display.set_caption设置游戏的title内容
|
|
|
|
|
self.score = 0 # 游戏取得的分数
|
|
|
|
|
self.font1 = pygame.font.Font("resource/simkai.ttf", 32) # 字体文件问题处理
|
|
|
|
|
self.font2 = pygame.font.Font("resource/simkai.ttf", 64) # 字体文件问题处理
|
|
|
|
|
self.obstacle_pic = pygame.image.load("resource/obstacles.png").convert_alpha() # 从image下载障碍物图片,convert_alpha转变成字母
|
|
|
|
|
self.game_over = pygame.image.load("resource/gameover.bmp").convert_alpha() # 从image下载游戏结束图片,convert_alpha转变成字母
|
|
|
|
|
self.bg = BackGround(pygame.image.load("resource/bg.png").convert_alpha()) # 从image下载背景对象作BackGround类的对象(convert_alpha转变成字母)
|
|
|
|
|
self.person = Person(pygame.image.load("resource/person.png").convert_alpha(), 500 - 85) # 从image下载人物对象图片(convert_alpha转变成字母)
|
|
|
|
|
self.screen.blit(self.bg.surface, [0, 0]) # 初始化游戏背景,初始坐标(0,0)
|
|
|
|
|
|
|
|
|
|
self.obstacle_list = [] # 以空列表作障碍物对象数组
|
|
|
|
|
self.game_state = 0 # 设置游戏状态:0表示游戏中,1表示游戏结束
|
|
|
|
|
self.life = 3 # 初始的生命值,假如是3,即是可以碰撞的次数,为0则游戏自动结束,重新开始计分数
|
|
|
|
|
self.clock = pygame.time.Clock() # pygame.time.Clock从系统时间来用来时钟记时,用clock记录
|
|
|
|
|
self.bg_music = pygame.mixer.Sound(r"resource\bgm.wav").play(0, 0, 0) # 循环播放音乐
|
|
|
|
|
|
|
|
|
|
def startGame(self, screen): # 开始游戏界面设置的函数
|
|
|
|
|
gameStart = pygame.image.load("resource/start1new.png")#从image下载开始游戏界面的图片给gameStart
|
|
|
|
|
screen.blit(gameStart, (0, 0))#调用blit放置开始游戏界面的背景图,初始化(0,0)坐标
|
|
|
|
|
font = pygame.font.SysFont("resource/simkai.ttf", 70) # 设置字体格式
|
|
|
|
|
tip = font.render("Press Any Key To Start!, Press Esc To Quit", True, (65, 105, 225))#调用font.render()显示游戏开始的提示内容
|
|
|
|
|
screen.blit(tip, (self.width / 2 - 550, self.height / 2 + 150))#tip提示内容放置在窗口位置的设置
|
|
|
|
|
pygame.display.update()#调用pygame.display.update()更新整个屏幕显示
|
|
|
|
|
while True:#设置一个无限循环
|
|
|
|
|
for event in pygame.event.get(): # 关闭窗口的位置
|
|
|
|
|
if event.type == pygame.QUIT:#操作event.type=256后满足条件,退出游戏
|
|
|
|
|
self.terminate()#调用游戏结束函数terminate()
|
|
|
|
|
elif event.type == pygame.KEYDOWN:#操作event.type=768后满足条件,退出游戏
|
|
|
|
|
if (event.key == pygame.K_ESCAPE): # 按下ESC键退出游戏
|
|
|
|
|
self.terminate()#调用游戏结束函数terminate()
|
|
|
|
|
else:
|
|
|
|
|
return
|
|
|
|
|
def addObstacle(self): # 添加障碍物函数设置,相当于游戏的困难程度
|
|
|
|
|
rate = 3
|
|
|
|
|
#是否生成障碍物
|
|
|
|
|
if not random.randint(0, 300) < rate:#避免生成多余设置的障碍物,多余设置的数量就返回开始游戏阶段
|
|
|
|
|
return#返回上一步
|
|
|
|
|
y = random.choice([self.height - 100, self.height - 200, self.height - 300, self.height - 400])#调用choice()随机设置y坐标
|
|
|
|
|
obstacle = Obstacle(self.obstacle_pic, self.width + 40, y)#随机获取障碍物图片,并且设置它在窗口的坐标
|
|
|
|
|
self.obstacle_list.append(obstacle)#将获取的障碍物添加到obstacle_list空列表内
|
|
|
|
|
# 监听键盘事件,并做处理
|
|
|
|
|
def ListenKeyBoard(self): # 键盘事件处理函数设置
|
|
|
|
|
for event in pygame.event.get():
|
|
|
|
|
if event.type == pygame.QUIT:#256判断条件
|
|
|
|
|
sys.exit()#退出系统函数
|
|
|
|
|
elif event.type == pygame.KEYDOWN:#768判断条件
|
|
|
|
|
if self.game_state == 0:# 设置游戏状态0为开始
|
|
|
|
|
if event.key == pygame.K_SPACE:#设置空格键跳跃
|
|
|
|
|
pygame.mixer.Sound(r"resource\jump.wav").play()#开始游戏就循环播放音乐BGM
|
|
|
|
|
if self.person.state == 0:#初始角色状态
|
|
|
|
|
self.person.state = 1
|
|
|
|
|
self.person.velocity_y = self.person.vy_start
|
|
|
|
|
elif self.person.state == 1:
|
|
|
|
|
self.person.state = 2
|
|
|
|
|
self.person.velocity_y = self.person.vy_start#y坐标的速度设置,开始起跳速度为-20
|
|
|
|
|
elif self.game_state == 1:#游戏结束
|
|
|
|
|
if event.key == pygame.K_RETURN: # 重新开始游戏K_RETURN=13
|
|
|
|
|
self.bg_music.stop()#在结束界面,音乐结束
|
|
|
|
|
self.__init__()#游戏运作函数调用
|
|
|
|
|
|
|
|
|
|
if self.game_state == 0:#游戏开始中设置
|
|
|
|
|
# 以下BackGorund的运动
|
|
|
|
|
self.bg.dx += 10#这是游戏进程的设置??
|
|
|
|
|
if self.bg.dx == 1200:#游戏进程为1200吗??
|
|
|
|
|
self.bg.dx = 0
|
|
|
|
|
|
|
|
|
|
# Person的移动
|
|
|
|
|
if self.person.state == 0:#人物为跑步状态中
|
|
|
|
|
self.person.cur_frame += 1#角色运动帧选择+1
|
|
|
|
|
if self.person.cur_frame == 12:#判断运动帧是否到了最后一帧
|
|
|
|
|
self.person.cur_frame = 0#重新设置为0帧
|
|
|
|
|
else:#人物出去跳跃状态中
|
|
|
|
|
self.person.y += self.person.velocity_y#人物坐标加上在人物起跳y坐标的初始速度
|
|
|
|
|
self.person.velocity_y += self.person.gravity#人物起跳y坐标的初始速度+重力加速度1
|
|
|
|
|
if self.person.y >= 500 - 85:#当人物跳跃结束后,重新设置人物坐标
|
|
|
|
|
self.person.y = 500 - 85#结束跳跃状态后,设置好人物的y坐标
|
|
|
|
|
self.person.state = 0#结束跳跃状态后,人物状态设置为跑步0
|
|
|
|
|
# bstacle的操作
|
|
|
|
|
self.addObstacle()#调用障碍物函数生成障碍物
|
|
|
|
|
|
|
|
|
|
for obstacle in self.obstacle_list:#self.obstacle_list障碍物列表清单
|
|
|
|
|
obstacle.x -= 10 # obstacle向左移动十个像素
|
|
|
|
|
|
|
|
|
|
if obstacle.x + obstacle.w <= 0: # 当obstacle离开界面时
|
|
|
|
|
self.obstacle_list.remove(obstacle)#从obstacle_list列表移除掉这个障碍物
|
|
|
|
|
self.score += 100 # 每避开一个障碍物,加100分,分数获取
|
|
|
|
|
if obstacle.judgeCollision(self.person.getPos(), obstacle.getPos()): # 碰撞检测,当前的人物坐标与障碍物坐标作为形参
|
|
|
|
|
if obstacle.cur_frame == 6:#判断是否碰撞到的是金币
|
|
|
|
|
self.obstacle_list.remove(obstacle)#移除这个金币障碍物
|
|
|
|
|
self.score += 1000 # 吃金币加1000分
|
|
|
|
|
coin_sound = pygame.mixer.Sound(
|
|
|
|
|
r"resource/coin.wav")#coin_sound保存用pygame.mixer.Sound调用的音乐BGM,碰撞金币音效
|
|
|
|
|
coin_sound.play()#播放音效
|
|
|
|
|
else:
|
|
|
|
|
self.life -= 1#每碰撞到其他障碍物就减少1点生命值
|
|
|
|
|
self.obstacle_list.remove(obstacle)#从obstacle_list移除障碍物
|
|
|
|
|
if self.life <= 0:#生命值为0
|
|
|
|
|
self.game_state = 1 # 游戏失败,到结束游戏界面
|
|
|
|
|
die_sound = pygame.mixer.Sound(
|
|
|
|
|
r"resource\die.wav") # 添加碰撞之后产生的音效
|
|
|
|
|
die_sound.play()#播放音效
|
|
|
|
|
# 更新显示界面
|
|
|
|
|
def updateScreen(self, screen):
|
|
|
|
|
screen.blit(self.bg.surface, [-self.bg.dx, 0]) # 背景的贴图,并且设置坐标位置
|
|
|
|
|
screen.blit(self.bg.surface, [1200 - self.bg.dx, 0])#游戏进程完成后的界面显示,并且设置坐标位置
|
|
|
|
|
text = self.font1.render("score:%d" % self.score, True, (128, 128, 128)) # 调用render,分数的贴图,显示对象self.score,设置颜色
|
|
|
|
|
screen.blit(text, (500, 20))#绘制对象text分数的贴图,设置放置坐标
|
|
|
|
|
del text
|
|
|
|
|
rest_life = self.font1.render("life:%d" % self.life, True, (128, 128, 128)) # 剩余生命显示
|
|
|
|
|
screen.blit(rest_life, (400, 20))#生命显示的贴图,绘制对象rest_life
|
|
|
|
|
del rest_life
|
|
|
|
|
screen.blit(self.person.surface, [0, self.person.y], [int(self.person.cur_frame) * self.person.w, 0, self.person.w, self.person.h]) # 人物的贴图
|
|
|
|
|
for obstacle in self.obstacle_list: # 障碍物的贴图显示
|
|
|
|
|
screen.blit(obstacle.surface, [obstacle.x, obstacle.y],
|
|
|
|
|
[int(obstacle.cur_frame) * obstacle.w, 0, obstacle.w, obstacle.h])
|
|
|
|
|
# 判断游戏的状态
|
|
|
|
|
def judgeState(self, screen):
|
|
|
|
|
if self.game_state == 0:
|
|
|
|
|
self.updateScreen(screen)
|
|
|
|
|
return
|
|
|
|
|
elif self.game_state == 1:
|
|
|
|
|
screen.blit(self.game_over, [0, 0])
|
|
|
|
|
text = self.font1.render("GameOver Score:%d Press Enter to restart" % self.score, True, (255, 0, 0))#显示对象self.score,并且设置颜色(255, 0, 0)
|
|
|
|
|
screen.blit(text, (self.width / 2 - 350, self.height / 2 + 150))
|
|
|
|
|
# 游戏结束函数设置
|
|
|
|
|
def terminate(self):
|
|
|
|
|
pygame.quit()#退出窗口
|
|
|
|
|
sys.exit()#退出系统
|
|
|
|
|
|
|
|
|
|
# 游戏主入口函数
|
|
|
|
|
def main(self):
|
|
|
|
|
self.startGame(self.screen)#开始游戏
|
|
|
|
|
while True:
|
|
|
|
|
self.clock.tick(40) # 获取设置时钟频率
|
|
|
|
|
self.judgeState(self.screen)#识别游戏状态是否启动成功
|
|
|
|
|
self.ListenKeyBoard()#键盘处理函数调用
|
|
|
|
|
pygame.display.flip()#更新屏幕
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
paoku = PaoKu()#游戏运作
|
|
|
|
|
paoku.main()#游戏启动
|