【Python游戏开发】使用pygame实现谷歌小恐龙

在上一期中我使用了PixiJS开发了网页版的谷歌小恐龙,这一期我使用python也实现一下

介绍

Pygame是一个开放源代码的跨平台Python库,它使得多媒体应用程序(尤其是视频游戏)的开发变得简单易行。Pygame基于Simple DirectMedia Layer(SDL)库和多个流行的库来抽象最常见的功能,使编写程序变得更直观。

Pygame的主要特点和功能包括:

  1. 跨平台:Pygame支持在大部分操作系统上运行,包括Windows、Mac OS和Linux等,并且可以在经过编译后在Android手机和网页上运行。
  2. 适合新手:与一些类似框架相比,Pygame更加适合新手入门游戏开发。
  3. 功能全面:Pygame支持的功能包括图片、文字、绘图、OpenGL 3D、音频、摄像头、游戏手柄等。
  4. 易于使用:Pygame提供了直观的API,使得开发者可以简单地创建游戏窗口、绘制图像、形状和文字,以及添加音效和背景音乐到游戏中。
  5. 游戏开发框架:Pygame游戏开发框架共包含四个部分:引入pygame和sys、初始化pygame游戏引擎并完成游戏窗体设置、在一个无限循环中获取pygame事件并逐类响应、在该无限循环中不断刷新游戏屏幕。

Pygame的原作者是Pete Shinners,其协议为GNU Lesser General Public License。它原本是为了代替突然停止的pySDL和其他一些游戏制作竞赛中的工具而开发的。

要使用Pygame,你需要先将它安装到你的机器上。最简单的安装方法是使用pip:pip install pygamepip 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()

游戏素材

仿谷歌浏览器小恐龙游戏pygame是一款基于pygame开发的仿谷歌浏览器小恐龙游戏pygame是一个专门用于制作2D游戏Python库,其提供了丰富的功能和工具,使开发者能够轻松创建各种游戏。 这款仿谷歌浏览器小恐龙游戏通过pygame实现了类似于谷歌浏览器中小恐龙的跳跃、躲避障碍物和计分等基本功能。游戏中的主角是一个小恐龙,玩家需要控制小恐龙跳过障碍物,尽可能地获得更高的分数。 在游戏实现过程中,首先需要使用pygame创建游戏窗口,设置游戏的背景、音效等。然后,定义小恐龙和障碍物的类,同时设置它们的初始位置、速度和碰撞等属性。接着,利用游戏循环不断更新画面,监听玩家的操作并根据操作来移动小恐龙和生成障碍物。当小恐龙与障碍物发生碰撞或者跳跃不当导致掉落时,游戏结束,最终显示玩家的得分。 在游戏的设计过程中,需要考虑到玩家体验、难度和趣味性等因素。通过调整障碍物的生成频率、速度和高度等参数,可以增加游戏的难度。同时,可以设置特殊道具或者陷阱,增加游戏的趣味性和挑战。 总的来说,仿谷歌浏览器小恐龙游戏pygame是一个基于pygame开发的2D游戏,通过使用pygame库的功能和工具,开发者可以轻松实现跳跃、躲避障碍物和计分等游戏功能,同时可以通过调整难度和添加特殊道具等方式增加游戏的趣味性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值