赞
踩
在上一期中我使用了PixiJS开发了网页版的谷歌小恐龙,这一期我使用python也实现一下
Pygame是一个开放源代码的跨平台Python库,它使得多媒体应用程序(尤其是视频游戏)的开发变得简单易行。Pygame基于Simple DirectMedia Layer(SDL)库和多个流行的库来抽象最常见的功能,使编写程序变得更直观。
Pygame的主要特点和功能包括:
Pygame的原作者是Pete Shinners,其协议为GNU Lesser General Public License。它原本是为了代替突然停止的pySDL和其他一些游戏制作竞赛中的工具而开发的。
要使用Pygame,你需要先将它安装到你的机器上。最简单的安装方法是使用pip:pip install pygame
或pip install pygame-ce
(推荐使用pygame官方的社区编辑版)。
- #创建动画精灵父类,继承pygame的Sprite
- class AnimatedSprite(pygame.sprite.Sprite):
- def __init__(self, animation_frames):
- super().__init__()
- #传入动画每一帧的列表
- self.frames = animation_frames
- #当前帧索引
- self.frame_index = 0
- self.image, self.rect = self.frames[self.frame_index]
- self.animation_speed = 0.1 # 动画速度,单位是秒
- self.last_update = pygame.time.get_ticks()
-
- def update(self, current_time):
- # 检查是否需要更新帧
- if current_time - self.last_update > int(self.animation_speed * 1000):
- self.frame_index = (self.frame_index + 1) % len(self.frames)
- self.image, self.rect = self.frames[self.frame_index]
- self.last_update = current_time
该部分编写了动画精灵类,用于实现精灵的动画效果
- #编写恐龙类,继承我们刚刚编写的动画精灵类
- class PinoSprite(AnimatedSprite):
- def __init__(self):
- self.load_animation_frames()
- #调用父类构造方法,将帧列表传入
- super().__init__(self.run_animation_frames)
- self.is_jump = False
- self.speed = 7
- #获取动画帧列表
- def load_animation_frames(self):
- #加载总素材图片
- base_frame = pygame.image.load("./googlepino.png").convert_alpha()
- self.run_animation_frames = []
- for i in range(2):
- #切割出每一帧的奔跑动作
- frame = base_frame.subsurface(pygame.Rect(935 + (i * 45), 0, 45, 50))
- frame_rect = frame.get_rect()
- #设置位置
- frame_rect.bottom = SCREEN_HEIGHT
- frame_rect.x = 50
- self.run_animation_frames.append((frame, frame_rect))
- self.squat_animation_frames = []
- for i in range(2):
- #切割出每一帧的蹲下动作
- frame = base_frame.subsurface(pygame.Rect(1110 + (i * 60), 20, 60, 30))
- frame_rect = frame.get_rect()
- #设置位置
- frame_rect.bottom = SCREEN_HEIGHT
- frame_rect.x = 50
- self.squat_animation_frames.append((frame, frame_rect))
- #切换蹲下动作
- def squat(self):
- self.frames = self.squat_animation_frames
- #切换奔跑动作
- def run(self):
- self.frames = self.run_animation_frames
- #切换跳跃动作
- def jump(self):
- self.is_jump = True
- self.is_up = True
-
- def update(self, current_time):
- super().update(current_time)
- if self.is_jump:
- #如果跳跃的话,设置每一个动作的位置
- for frame in self.frames:
- rect = frame[1]
- if self.is_up:
- #向上的话y坐标减小
- rect.bottom -= self.speed
- #如果y坐标已经达到跳跃最高处,则向下
- if rect.bottom <= SCREEN_HEIGHT - rect.height * 2:
- self.is_up = False
- else:
- #向下的话y坐标增加
- rect.bottom += self.speed
- #如果y坐标已经到地面了,则跳跃结束
- if rect.bottom >= SCREEN_HEIGHT:
- self.is_jump = False
- #如果已经完成跳跃动作了,则设置每一个动作的位置都到地面
- if not self.is_jump:
- for frame in self.frames:
- rect = frame[1]
- rect.bottom = SCREEN_HEIGHT
该部分我们实现了恐龙精灵的编写,完成了恐龙的跳跃,奔跑,蹲下动作
- #编写飞鸟类,继承动画精灵类
- class FlyBirdSprite(AnimatedSprite):
- def __init__(self):
- self.load_animation_frames()
- super().__init__(self.animation_frames)
- #获取飞鸟动画帧列表
- def load_animation_frames(self):
- self.animation_frames = []
- base_frame = pygame.image.load("./googlepino.png").convert_alpha()
- #设置x坐标随机位置
- x = random.randint(1400, 1500)
- #切割出每一个动画动作帧
- for i in range(2):
- frame = base_frame.subsurface(pygame.Rect(135 + (i * 45), 0, 45, 30))
- frame_rect = frame.get_rect()
- #设置位置
- frame_rect.bottom = SCREEN_HEIGHT - 35
- frame_rect.x = x
- self.animation_frames.append((frame, frame_rect))
-
- def update(self, current_time):
- super().update(current_time)
- for frame in self.frames:
- rect = frame[1]
- #设置每次向左移动10
- rect.x -= 10
- #如果已经超出了屏幕,则重新设置飞鸟的位置
- if rect.x <= 0:
- x = random.randint(1400, 1500)
- for frame in self.frames:
- frame[1].x = x
该部分我们完成了飞鸟类的编写,实现了飞鸟的移动,刷新
- #封装自己的精灵类
- class GameSprite(pygame.sprite.Sprite):
- def __init__(self, rect):
- super().__init__()
- base_frame = pygame.image.load("./googlepino.png").convert_alpha()
- #设置图片切割的位置
- self.image = base_frame.subsurface(rect)
- self.rect = self.image.get_rect()
-
- def update(self):
- #每次向左移动10
- self.rect.x -= 10
该部分我们封装了自己的精灵类,用于继承
- #编写仙人掌精灵类,继承我们编写的精灵父类
- class GroundSprite(GameSprite):
- def __init__(self, is_alt=False):
- #调用父类构造方法,切割出仙人掌的图片
- super().__init__(pygame.Rect(10, 52, 1200, 15))
- #设置位置
- self.rect.bottom = SCREEN_HEIGHT
- #如果是第二张图片,则放到后面
- if is_alt:
- self.rect.x = SCREEN_WIDTH
-
- def update(self):
- super().update()
- #判断是否滚动完一张,滚动完设置到后面,循环滚动
- if self.rect.right <= 0:
- self.rect.x = SCREEN_WIDTH
该部分完成了地面精灵类的编写,实现地面循环滚动
- #编写仙人掌精灵类,继承父类精灵
- class CactusSprite(GameSprite):
- def __init__(self):
- #切割仙人掌图片
- super().__init__(pygame.Rect(356, 0, 25, 55))
- #位置设置到中间
- self.rect.x = SCREEN_WIDTH / 2
- self.rect.bottom = SCREEN_HEIGHT
-
- def update(self):
- super().update()
- #超出屏幕左侧时设置到右侧
- if self.rect.x <= 0:
- self.rect.x = SCREEN_WIDTH
该部分完成了仙人掌精灵类的编写,实现仙人掌的移动,刷新
- class Game:
- #初始化
- def __init__(self):
- pygame.init()
- #设置游戏窗口
- self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
- self.clock = pygame.time.Clock()
- #设置分数
- self.score = 0
- #设置游戏状态
- self.game_play = False
- #设置字体
- self.game_font = pygame.font.Font("./中文像素字体.ttf", 25)
该部分我们完成了游戏类的构造方法
- #设置字体
- def set_text(self, text):
- if text != "开始游戏":
- #清除掉原来的文字区域内容
- pygame.draw.rect(self.screen, (255, 255, 255), self.text_rect)
- self.text_info = text
- self.text = self.game_font.render(text, True, (0, 0, 0))
- self.text_rect = self.text.get_rect()
- #设置位置
- self.text_rect.center = self.screen.get_rect().center
- #显示到屏幕
- self.screen.blit(self.text, self.text_rect)
编写了游戏字体的设置
- #创建精灵
- def create_sprites(self):
- self.pino = PinoSprite()
- self.pino_group = pygame.sprite.Group(self.pino)
- ground1 = GroundSprite()
- ground2 = GroundSprite(True)
- self.ground_group = pygame.sprite.Group(ground1, ground2)
- self.cactus = CactusSprite()
- self.cactus_group = pygame.sprite.Group(self.cactus)
- self.fly_brid_group = pygame.sprite.Group()
该部分我们编写了精灵的创建方法,创建了恐龙精灵,地面精灵,仙人掌精灵和组,添加到组中
- #精灵状态的更新
- def update_sprites(self):
- #填充为白色
- self.screen.fill((255, 255, 255))
- current_time = pygame.time.get_ticks()
- self.pino_group.update(current_time)
- self.pino_group.draw(self.screen)
- self.fly_brid_group.update(current_time)
- self.fly_brid_group.draw(self.screen)
- self.ground_group.update()
- self.ground_group.draw(self.screen)
- self.cactus_group.update()
- self.cactus_group.draw(self.screen)
该部分编写了所有精灵的更新方法
- #检测碰撞
- def check_bump(self):
- #如果恐龙和仙人掌碰撞,则游戏结束
- group = pygame.sprite.spritecollide(self.pino, self.cactus_group, False)
- if len(group) > 0:
- self.game_over()
- #如果恐龙和飞鸟碰撞,则游戏结束
- group = pygame.sprite.spritecollide(self.pino, self.fly_brid_group, False)
- if len(group) > 0:
- self.game_over()
-
- def game_over(self):
- self.game_play = False
- self.set_text("游戏结束,分数为: {},点击重新开始游戏".format(self.score))
该部分我们编写了恐龙的碰撞检测方法,检测恐龙是否与障碍物碰撞了,如果发生碰撞,游戏结束,spritecollide方法是pygame提供的一个检测碰撞的方法,如果发生碰撞了会返回碰撞到的精灵组
- #计算分数
- def calculate_scroe(self):
- #如果仙人掌已经到屏幕左侧,则分数加1
- if self.cactus.rect.x <= 10:
- self.score += 1
- #分数到5时出现飞鸟
- if self.score == 5:
- self.fly_brid = FlyBirdSprite()
- self.fly_brid_group.add(self.fly_brid)
- if len(self.fly_brid_group) > 0:
- #如果飞鸟已经到屏幕左侧,则分数加1
- for frame in self.fly_brid.frames:
- rect = frame[1]
- if rect.x <= 10:
- self.score += 1
- break
- #设置当前分数信息
- self.set_text("当前分数为: {}".format(self.score))
该部分完成了分数的计算
- #编写事件判断
- def event_handle(self):
- #遍历所有事件
- for event in pygame.event.get():
- #如果是关闭窗口,则直接停止程序
- if event.type == pygame.QUIT:
- pygame.quit()
- exit()
- #鼠标点击文字开始游戏
- elif event.type == pygame.MOUSEBUTTONDOWN:
- if self.text_rect.collidepoint(event.pos):
- if self.text_info == "开始游戏":
- self.game_play = True
- self.set_text("当前分数为: {}".format(self.score))
- else:
- #游戏重新开始,初始化游戏状态
- self.score = 0
- self.cactus.rect.x = SCREEN_WIDTH / 2
- self.fly_brid_group.empty()
- self.game_play = True
- self.set_text("当前分数为: {}".format(self.score))
- #如果按下了空格,则恐龙跳跃
- key_pressed = pygame.key.get_pressed()
- if key_pressed[pygame.K_SPACE]:
- self.pino.jump()
- #如果按下下箭头,则恐龙蹲下
- elif key_pressed[pygame.K_DOWN]:
- #判断当前状态是否跳跃,跳跃时不能蹲下
- if not self.pino.is_jump:
- self.pino.squat()
- else:
- #其他状态恐龙恢复奔跑状态
- self.pino.run()
该部分完成了游戏的操作,键盘控制恐龙的状态以及开始游戏和重新开始
- if __name__ == "__main__":
- #游戏运行
- game = Game()
- game.start_game()
最后我们可以运行游戏了!
项目文件
game_sprite.py文件
- import random
- import pygame
-
- SCREEN_WIDTH = 1200
- SCREEN_HEIGHT = 300
-
-
- class AnimatedSprite(pygame.sprite.Sprite):
- def __init__(self, animation_frames):
- super().__init__()
- self.frames = animation_frames
- self.frame_index = 0
- self.image, self.rect = self.frames[self.frame_index]
- self.animation_speed = 0.1 # 动画速度,单位是秒
- self.last_update = pygame.time.get_ticks()
-
- def update(self, current_time):
- # 检查是否需要更新帧
- if current_time - self.last_update > int(self.animation_speed * 1000):
- self.frame_index = (self.frame_index + 1) % len(self.frames)
- self.image, self.rect = self.frames[self.frame_index]
- self.last_update = current_time
-
-
- class PinoSprite(AnimatedSprite):
- def __init__(self):
- self.load_animation_frames()
- super().__init__(self.run_animation_frames)
- self.is_jump = False
- self.speed = 7
-
- def load_animation_frames(self):
- base_frame = pygame.image.load("./googlepino.png").convert_alpha()
- self.run_animation_frames = []
- for i in range(2):
- frame = base_frame.subsurface(pygame.Rect(935 + (i * 45), 0, 45, 50))
- frame_rect = frame.get_rect()
- frame_rect.bottom = SCREEN_HEIGHT
- frame_rect.x = 50
- self.run_animation_frames.append((frame, frame_rect))
- self.squat_animation_frames = []
- for i in range(2):
- frame = base_frame.subsurface(pygame.Rect(1110 + (i * 60), 20, 60, 30))
- frame_rect = frame.get_rect()
- frame_rect.bottom = SCREEN_HEIGHT
- frame_rect.x = 50
- self.squat_animation_frames.append((frame, frame_rect))
-
- def squat(self):
- self.frames = self.squat_animation_frames
-
- def run(self):
- self.frames = self.run_animation_frames
-
- def jump(self):
- self.is_jump = True
- self.is_up = True
-
- def update(self, current_time):
- super().update(current_time)
- if self.is_jump:
- for frame in self.frames:
- rect = frame[1]
- if self.is_up:
- rect.bottom -= self.speed
- if rect.bottom <= SCREEN_HEIGHT - rect.height * 2:
- self.is_up = False
- else:
- rect.bottom += self.speed
- if rect.bottom >= SCREEN_HEIGHT:
- self.is_jump = False
- if not self.is_jump:
- for frame in self.frames:
- rect = frame[1]
- rect.bottom = SCREEN_HEIGHT
-
-
- class FlyBirdSprite(AnimatedSprite):
- def __init__(self):
- self.load_animation_frames()
- super().__init__(self.animation_frames)
-
- def load_animation_frames(self):
- self.animation_frames = []
- base_frame = pygame.image.load("./googlepino.png").convert_alpha()
- x = random.randint(1400, 1500)
- for i in range(2):
- frame = base_frame.subsurface(pygame.Rect(135 + (i * 45), 0, 45, 30))
- frame_rect = frame.get_rect()
- frame_rect.bottom = SCREEN_HEIGHT - 35
- frame_rect.x = x
- self.animation_frames.append((frame, frame_rect))
-
- def update(self, current_time):
- super().update(current_time)
- for frame in self.frames:
- rect = frame[1]
- rect.x -= 10
- if rect.x <= 0:
- x = random.randint(1400, 1500)
- for frame in self.frames:
- frame[1].x = x
-
-
- class GameSprite(pygame.sprite.Sprite):
- def __init__(self, rect):
- super().__init__()
- base_frame = pygame.image.load("./googlepino.png").convert_alpha()
- self.image = base_frame.subsurface(rect)
- self.rect = self.image.get_rect()
-
- def update(self):
- self.rect.x -= 10
-
-
- class GroundSprite(GameSprite):
- def __init__(self, is_alt=False):
- super().__init__(pygame.Rect(10, 52, 1200, 15))
- self.rect.bottom = SCREEN_HEIGHT
- if is_alt:
- self.rect.x = SCREEN_WIDTH
-
- def update(self):
- super().update()
- if self.rect.right <= 0:
- self.rect.x = SCREEN_WIDTH
-
-
- class CactusSprite(GameSprite):
- def __init__(self):
- super().__init__(pygame.Rect(356, 0, 25, 55))
- self.rect.x = SCREEN_WIDTH / 2
- self.rect.bottom = SCREEN_HEIGHT
-
- def update(self):
- super().update()
- if self.rect.x <= 0:
- self.rect.x = SCREEN_WIDTH
game.py文件
- import pygame
- from game_sprite import *
-
-
- class Game:
- def __init__(self):
- pygame.init()
- self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
- self.clock = pygame.time.Clock()
- self.score = 0
- self.game_play = False
- self.game_font = pygame.font.Font("./中文像素字体.ttf", 25)
-
- def start_game(self):
- self.create_sprites()
- self.update_sprites()
- self.set_text("开始游戏")
- while True:
- self.event_handle()
- if self.game_play:
- self.clock.tick(60)
- self.update_sprites()
- self.calculate_scroe()
- self.check_bump()
- pygame.display.update()
-
- def set_text(self, text):
- if text != "开始游戏":
- pygame.draw.rect(self.screen, (255, 255, 255), self.text_rect)
- self.text_info = text
- self.text = self.game_font.render(text, True, (0, 0, 0))
- self.text_rect = self.text.get_rect()
- self.text_rect.center = self.screen.get_rect().center
- self.screen.blit(self.text, self.text_rect)
-
- def create_sprites(self):
- self.pino = PinoSprite()
- self.pino_group = pygame.sprite.Group(self.pino)
- ground1 = GroundSprite()
- ground2 = GroundSprite(True)
- self.ground_group = pygame.sprite.Group(ground1, ground2)
- self.cactus = CactusSprite()
- self.cactus_group = pygame.sprite.Group(self.cactus)
- self.fly_brid_group = pygame.sprite.Group()
-
- def update_sprites(self):
- self.screen.fill((255, 255, 255))
- current_time = pygame.time.get_ticks()
- self.pino_group.update(current_time)
- self.pino_group.draw(self.screen)
- self.fly_brid_group.update(current_time)
- self.fly_brid_group.draw(self.screen)
- self.ground_group.update()
- self.ground_group.draw(self.screen)
- self.cactus_group.update()
- self.cactus_group.draw(self.screen)
-
- def check_bump(self):
- group = pygame.sprite.spritecollide(self.pino, self.cactus_group, False)
- if len(group) > 0:
- self.game_over()
- group = pygame.sprite.spritecollide(self.pino, self.fly_brid_group, False)
- if len(group) > 0:
- self.game_over()
-
- def calculate_scroe(self):
- if self.cactus.rect.x <= 10:
- self.score += 1
- if self.score == 5:
- self.fly_brid = FlyBirdSprite()
- self.fly_brid_group.add(self.fly_brid)
- if len(self.fly_brid_group) > 0:
- for frame in self.fly_brid.frames:
- rect = frame[1]
- if rect.x <= 10:
- self.score += 1
- break
- self.set_text("当前分数为: {}".format(self.score))
-
- def game_over(self):
- self.game_play = False
- self.set_text("游戏结束,分数为: {},点击重新开始游戏".format(self.score))
-
- def event_handle(self):
- for event in pygame.event.get():
- if event.type == pygame.QUIT:
- pygame.quit()
- exit()
- elif event.type == pygame.MOUSEBUTTONDOWN:
- if self.text_rect.collidepoint(event.pos):
- if self.text_info == "开始游戏":
- self.game_play = True
- self.set_text("当前分数为: {}".format(self.score))
- else:
- self.score = 0
- self.cactus.rect.x = SCREEN_WIDTH / 2
- self.fly_brid_group.empty()
- self.game_play = True
- self.set_text("当前分数为: {}".format(self.score))
- key_pressed = pygame.key.get_pressed()
- if key_pressed[pygame.K_SPACE]:
- self.pino.jump()
- elif key_pressed[pygame.K_DOWN]:
- if not self.pino.is_jump:
- self.pino.squat()
- else:
- self.pino.run()
-
-
- if __name__ == "__main__":
- game = Game()
- game.start_game()
游戏素材
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。