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()#游戏启动