今天怕p8架构师用154行写个冒险岛,小白都看得懂的语言描述

Posted 编程界的小胖子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了今天怕p8架构师用154行写个冒险岛,小白都看得懂的语言描述相关的知识,希望对你有一定的参考价值。

今天这篇文章可能会有点长,一定要耐心看完,超级有意思的用python只需158行代码就能写成

相比大家小时候玩过一个fc游戏叫冒险岛,不知道大家有没有玩过,还是挺有趣的,有好几个代,本文试着用154行写个简版的冒险岛。

 

1. 初始化

引入pygame

import pygame
复制代码

初始化

pygame.init()
复制代码

设置宽高

screen = pygame.display.set_mode((800,400))
复制代码

设置标题

pygame.display.set_caption('Runner')
复制代码

设置时钟

clock = pygame.time.Clock()
复制代码

填充颜色

screen.fill((94,129,162))
复制代码

渲染

while True:
    # 更新
    pygame.display.update()
    # 时间开始走,60帧
    clock.tick(60)
复制代码

python3 island.py打开测试下

出现了个问题,鼠标点击会卡死,我们添加事件捕捉

for event in pygame.event.get():
    # 这边先pass代码
    pass
复制代码

现在执行python3 island.py,点击鼠标就不会卡死

代码整理如下:

import pygame

# 初始化
pygame.init()
# 设置宽高
screen = pygame.display.set_mode((800,400))
# 设置标题
pygame.display.set_caption('Runner')
clock = pygame.time.Clock()
# 填充颜色
screen.fill((94,129,162))

while True:
    for event in pygame.event.get():
        # 这边先pass代码
        pass
    # 显示更新
    pygame.display.update()
    # 时间开始走,60帧
    clock.tick(60)
复制代码

2. 主界面

刚才的代码执行了下,发现无法关闭,只能关闭脚本,检测下关闭事件

while True:
    for event in pygame.event.get():
        # 检测退出
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
    # 显示更新
    pygame.display.update()
    # 时间开始走,60帧
    clock.tick(60)
复制代码

现在可以正常关闭了

我们来添加初始页面,添加游戏状态,默认未启动

game_active = False
复制代码

引入玩家图片

player_stand = pygame.image.load('graphics/player/player_stand.png').convert_alpha()
复制代码

设置放置位置

player_stand_rect = player_stand.get_rect(center = (400,200))
复制代码

渲染出来看下效果

 

好像缺点啥,加个提示,自定义字体,这边选择的是像素字体

test_font = pygame.font.Font('font/Pixeltype.ttf', 50)

game_message = test_font.render('Press space to run',False,(111,196,169))
game_message_rect = game_message.get_rect(center = (400,330))
复制代码

显示出来

 

在加个标题

game_name = test_font.render('Huamiao Runner',False,(111,196,169))
game_name_rect = game_name.get_rect(center = (400,80))
复制代码

显示出来

 

代码整理如下:

import pygame

# 初始化
pygame.init()
# 设置宽高
screen = pygame.display.set_mode((800,400))
# 设置标题
pygame.display.set_caption('Runner')
clock = pygame.time.Clock()
# 舞台填充颜色
screen.fill((94,129,162))
# 游戏状态
game_active = False
# 玩家图标
player_stand = pygame.image.load('graphics/player/player_stand.png').convert_alpha()
player_stand_rect = player_stand.get_rect(center = (400,200))
# 引入像素字体
test_font = pygame.font.Font('font/Pixeltype.ttf', 50)
# 游戏提示
game_message = test_font.render('Press space to run',False,(111,196,169))
game_message_rect = game_message.get_rect(center = (400,330))
# 游戏标题
game_name = test_font.render('Huamiao Runner',False,(111,196,169))
game_name_rect = game_name.get_rect(center = (400,80))

while True:
    # 监听事件
    for event in pygame.event.get():
        # 检测退出
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
    if game_active:
        pass
    else:
        # 显示玩家
        screen.blit(player_stand,player_stand_rect)
        # 显示游戏提示信息
        screen.blit(game_message,game_message_rect)
        # 显示游戏名称
        screen.blit(game_name,game_name_rect)
    # 显示更新
    pygame.display.update()
    # 时间开始走,60帧
    clock.tick(60)
复制代码

3. 开始游戏

实现按空格开始游戏,添加监听

    if ~game_active:
        # 按下空格开始
        if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            game_active = True
复制代码

添加开始信息文字

# 游戏开始提示
game_start_message = test_font.render('Game start',False,(111,196,169))
game_start_message_rect = game_start_message.get_rect(center = (400,330))
复制代码

显示开始游戏信息

    if game_active:
        screen.fill((94,129,162))
        screen.blit(game_start_message,game_start_message_rect)
    else:
        # 显示玩家
        screen.blit(player_stand,player_stand_rect)
        # 显示游戏提示信息
        screen.blit(game_message,game_message_rect)
        # 显示游戏名称
        screen.blit(game_name,game_name_rect)
    # 显示更新
    pygame.display.update()
    # 时间开始走,60帧
    clock.tick(60)
复制代码

执行脚本,python3 island.py按下空格

这个界面只是测试,我们改为正常的游戏画面,需要有天空和地面,我们来添加下:

# 加载天空图片
sky_surface = pygame.image.load('graphics/Sky.png').convert()
# 加载地面图片
ground_surface = pygame.image.load('graphics/ground.png').convert()
复制代码

把刚才的测试信息改下:

    if game_active:
        # 绘制天空
        screen.blit(sky_surface,(0,0))
        # 绘制地面
        screen.blit(ground_surface,(0,300))
复制代码

执行脚本,按下空格

gif截图软件小问题,颜色稍微失真,看个效果:

4. 添加玩家

# 玩家
player = pygame.sprite.GroupSingle()
player.add(Player())
复制代码

创建Player类,丰富这个类

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        # 加载两张走路的图片,让走路动起来
        player_walk_1 = pygame.image.load('graphics/player/player_walk_1.png').convert_alpha()
        player_walk_2 = pygame.image.load('graphics/player/player_walk_2.png').convert_alpha()
        
        # 放在list里面,使用索引切换
        self.player_walk = [player_walk_1,player_walk_2]
        
        # 初始化索引
        self.player_index = 0

        # 玩家走路初始帧
        self.image = self.player_walk[self.player_index]
        
        # 设置玩家初始位置,左下角地面上
        self.rect = self.image.get_rect(midbottom = (80,300))
复制代码

绘制玩家

    # 游戏开始
    if game_active:
        # code ……
        # 绘制玩家
        player.draw(screen)
复制代码

看下效果

 

人物出来了,我们要弄个走路的动画效果,我们需要个监听器:

        # 绘制玩家
        player.draw(screen)
        # 玩家监听器
        player.update()
复制代码

Player类添加动画

    def animation_state(self):
            self.player_index += 0.1
            if self.player_index >= len(self.player_walk):self.player_index = 0
            self.image = self.player_walk[int(self.player_index)]
    # 监听器
    def update(self):
        self.animation_state()
复制代码

看下效果

5. 玩家事件监听

监听玩家按了空格,跳起来,并为动作添加音效

    # Player类

    # 跳跃音效,音量
    self.jump_sound = pygame.mixer.Sound('audio/jump.mp3')
    self.jump_sound.set_volume(0.5)
    
    # 玩家事件监听
    def player_input(self):
        keys = pygame.key.get_pressed()
        # 玩家按下空格且不是跳跃状态
        if keys[pygame.K_SPACE] and self.rect.bottom >= 300:
            # 播放跳跃音效
            self.jump_sound.play()
复制代码

添加重力计算方法,并监听

    # 重力计算
    def apply_gravity(self):
        self.gravity += 1
        self.rect.y += self.gravity
        if self.rect.bottom >= 300:
            self.rect.bottom = 300
复制代码

动画状态需要改下

    # 动画状态
    def animation_state(self):
        if self.rect.bottom < 300: 
            self.image = self.player_jump
        else:
            self.player_index += 0.1
            if self.player_index >= len(self.player_walk):self.player_index = 0
            self.image = self.player_walk[int(self.player_index)]
复制代码

监听器

    # 监听器
    def update(self):
        self.animation_state()
        self.player_input()
        self.apply_gravity()
复制代码

看下效果

代码整理如下:

import pygame

# 初始化
pygame.init()
# 设置宽高
screen = pygame.display.set_mode((800,400))
# 设置标题
pygame.display.set_caption('Runner')
clock = pygame.time.Clock()
# 舞台填充颜色
screen.fill((94,129,162))
# 游戏状态
game_active = False
# 玩家图标
player_stand = pygame.image.load('graphics/player/player_stand.png').convert_alpha()
player_stand_rect = player_stand.get_rect(center = (400,200))
# 引入像素字体
test_font = pygame.font.Font('font/Pixeltype.ttf', 50)
# 游戏提示
game_message = test_font.render('Press space to run',False,(111,196,169))
game_message_rect = game_message.get_rect(center = (400,330))
# 游戏标题
game_name = test_font.render('Huamiao Runner',False,(111,196,169))
game_name_rect = game_name.get_rect(center = (400,80))
# 游戏结束提示
game_over_message = test_font.render('Game over',False,(111,196,169))
game_over_message_rect = game_over_message.get_rect(center = (400,330))
# 游戏开始提示
game_start_message = test_font.render('Game start',False,(111,196,169))
game_start_message_rect = game_start_message.get_rect(center = (400,330))

# 加载天空图片
sky_surface = pygame.image.load('graphics/Sky.png').convert()
# 加载地面图片
ground_surface = pygame.image.load('graphics/ground.png').convert()

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        # 加载两张走路的图片,让走路动起来
        player_walk_1 = pygame.image.load('graphics/player/player_walk_1.png').convert_alpha()
        player_walk_2 = pygame.image.load('graphics/player/player_walk_2.png').convert_alpha()
        
        # 放在list里面
        self.player_walk = [player_walk_1,player_walk_2]
        self.player_index = 0

        # 加载跳起来的图片
        self.player_jump = pygame.image.load('graphics/player/jump.png').convert_alpha()

        # 玩家走路初始位帧
        self.image = self.player_walk[self.player_index]

        # 设置初始位置
        self.rect = self.image.get_rect(midbottom = (80,300))
    
        # 跳跃音效,音量
        self.jump_sound = pygame.mixer.Sound('audio/jump.mp3')
        self.jump_sound.set_volume(0.5)
    # 玩家事件监听
    def player_input(self):
        keys = pygame.key.get_pressed()
        # 玩家按下空格且不是跳跃状态
        if keys[pygame.K_SPACE] and self.rect.bottom >= 300:
            # 设置重力
            self.gravity = -20
            # 播放跳跃音效
            self.jump_sound.play()

    # 重力计算
    def apply_gravity(self):
        self.gravity += 1
        self.rect.y += self.gravity
        if self.rect.bottom >= 300:
            self.rect.bottom = 300

    # 动画状态
    def animation_state(self):
        if self.rect.bottom < 300: 
            self.image = self.player_jump
        else:
            self.player_index += 0.1
            if self.player_index >= len(self.player_walk):self.player_index = 0
            self.image = self.player_walk[int(self.player_index)]
    # 监听器
    def update(self):
        self.animation_state()
        self.player_input()
        self.apply_gravity()
# 玩家
player = pygame.sprite.GroupSingle()
player.add(Player())

while True:
    # 监听事件
    for event in pygame.event.get():
        # 检测退出
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        if ~game_active:
            # 按下空格开始
            if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                game_active = True

    # 游戏开始
    if game_active:
        # 绘制天空
        screen.blit(sky_surface,(0,0))
        # 绘制地面
        screen.blit(ground_surface,(0,300))
        # 绘制玩家
        player.draw(screen)
        # 玩家监听器
        player.update()
    else:
        # 显示玩家
        screen.blit(player_stand,player_stand_rect)
        # 显示游戏提示信息
        screen.blit(game_message,game_message_rect)
        # 显示游戏名称
        screen.blit(game_name,game_name_rect)
    # 显示更新
    pygame.display.update()
    # 时间开始走,60帧
    clock.tick(60)
复制代码

6. 添加时间及分数

添加全局显示时间方法,这边我们根据玩家能完多久来计算分数,如下:

# 开始时间
start_time = 0

# 显示分数
def display_score():
    current_time = int(pygame.time.get_ticks() / 1000) - start_time
    score_surf = test_font.render(f'Score: {current_time}',False,(64,64,64))
    score_rect = score_surf.get_rect(center = (400,50))
    screen.blit(score_surf,score_rect)
    return current_time
复制代码

在开始游戏后显示分数

        # 分数
        score = display_score()
复制代码

分数已经可以正常计算来

改下之前的一个bug,不使用~

while True:
    # 监听事件
    for event in pygame.event.get():
        # 检测退出
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        if game_active:
            pass
        else:
            # 按下空格开始
            if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                game_active = True
复制代码

7. 添加障碍物

添加障碍物组

obstacle_group = pygame.sprite.Group()
复制代码

添加障碍物事件

obstacle_timer = pygame.USEREVENT + 1
pygame.time.set_timer(obstacle_timer,1500)
复制代码

添加个蜗牛

# 来只蜗牛,两张图片动起来
snail_frame_1 = pygame.image.load('graphics/snail/snail1.png').convert_alpha()
snail_frame_2 = pygame.image.load('graphics/snail/snail2.png').convert_alpha()
snail_frames = [snail_frame_1, snail_frame_2]
snail_frame_index = 0
# 定义当前帧的图片
snail_surf = snail_frames[snail_frame_index]
复制代码

添加蜗牛事件

snail_animation_timer = pygame.USEREVENT + 2
pygame.time.set_timer(snail_animation_timer,500)
复制代码

添加障碍物类,我们预留个类型,后面会添加不同类型的障碍物

# 障碍物类
class Obstacle(pygame.sprite.Sprite):
    def __init__(self,type):
        super().__init__()
        # 蜗牛的动画
        snail_1 = pygame.image.load('graphics/snail/snail1.png').convert_alpha()
        snail_2 = pygame.image.load('graphics/snail/snail2.png').convert_alpha()
        self.frames = [snail_1,snail_2]
        # 高度
        y_pos  = 300

        self.animation_index = 0
        self.image = self.frames[self.animation_index]
        # 在右侧屏幕生成障碍物
        self.rect = self.image.get_rect(midbottom = (randint(900,1100),y_pos))
复制代码

添加障碍物动画

    # 动画状态
    def animation_state(self):
        self.animation_index += 0.1 
        if self.animation_index >= len(self.frames): self.animation_index = 0
        self.image = self.frames[int(self.animation_index)]
复制代码

监听障碍物

    # 监听
    def update(self):
        self.animation_state()
        self.rect.x -= 6
        self.destroy()
复制代码

销毁障碍物

    # 销毁
    def destroy(self):
        if self.rect.x <= -100: 
            self.kill()
复制代码

障碍物事件添加到循环中

while True:
    # 监听事件
    for event in pygame.event.get():
        # 检测退出
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        if game_active:
            # 障碍物事件
            if event.type == obstacle_timer:
                # 设置障碍物概率,蜗牛和苍蝇3:1
                obstacle_group.add(Obstacle(choice(['snail'])))

            # 蜗牛事件
            if event.type == snail_animation_timer:
                if snail_frame_index == 0: snail_frame_index = 1
                else: snail_frame_index = 0
                snail_surf = snail_frames[snail_frame_index] 
复制代码

游戏开始的地方添加障碍物渲染

    # 游戏开始
    if game_active:
        # 绘制天空
        screen.blit(sky_surface,(0,0))
        # 绘制地面
        screen.blit(ground_surface,(0,300))
        # 分数
        score = display_score()
        # 绘制玩家
        player.draw(screen)
        # 玩家监听器
        player.update()
        # 绘制障碍物
        obstacle_group.draw(screen)
        obstacle_group.update()
复制代码

看下效果

8. 添加额外的障碍物

# 来只苍蝇,同上
fly_frame1 = pygame.image.load('graphics/fly/fly1.png').convert_alpha()
fly_frame2 = pygame.image.load('graphics/fly/fly2.png').convert_alpha()
fly_frames = [fly_frame1, fly_frame2]
fly_frame_index = 0
fly_surf = fly_frames[fly_frame_index]
复制代码

添加苍蝇事件

# 苍蝇事件
fly_animation_timer = pygame.USEREVENT + 3
pygame.time.set_timer(fly_animation_timer,200)
复制代码

障碍物类改下

# 障碍物类
class Obstacle(pygame.sprite.Sprite):
    def __init__(self,type):
        super().__init__()
        if type == 'fly':
            # 苍蝇的动画
            fly_1 = pygame.image.load('graphics/fly/fly1.png').convert_alpha()
            fly_2 = pygame.image.load('graphics/fly/fly2.png').convert_alpha()
            self.frames = [fly_1,fly_2]
            # 高度
            y_pos = 210
        else:
            # 蜗牛的动画
            snail_1 = pygame.image.load('graphics/snail/snail1.png').convert_alpha()
            snail_2 = pygame.image.load('graphics/snail/snail2.png').convert_alpha()
            self.frames = [snail_1,snail_2]
            # 高度
            y_pos  = 300
复制代码

在障碍物生成的事件中添加苍蝇,由于我们之前预留了一个chioce

while True:
    # 监听事件
    for event in pygame.event.get():
        # 检测退出
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        if game_active:
            # 障碍物事件
            if event.type == obstacle_timer:
                # 设置障碍物概率,蜗牛和苍蝇3:1
                obstacle_group.add(Obstacle(choice(['snail', 'fly'])))
复制代码

看下效果

代码整理如下:

import pygame
from random import randint,choice

# 初始化
pygame.init()
# 设置宽高
screen = pygame.display.set_mode((800,400))
# 设置标题
pygame.display.set_caption('Runner')
clock = pygame.time.Clock()
# 舞台填充颜色
screen.fill((94,129,162))
# 游戏状态
game_active = False
# 玩家图标
player_stand = pygame.image.load('graphics/player/player_stand.png').convert_alpha()
player_stand_rect = player_stand.get_rect(center = (400,200))
# 引入像素字体
test_font = pygame.font.Font('font/Pixeltype.ttf', 50)
# 游戏提示
game_message = test_font.render('Press space to run',False,(111,196,169))
game_message_rect = game_message.get_rect(center = (400,330))
# 游戏标题
game_name = test_font.render('Huamiao Runner',False,(111,196,169))
game_name_rect = game_name.get_rect(center = (400,80))
# 游戏结束提示
game_over_message = test_font.render('Game over',False,(111,196,169))
game_over_message_rect = game_over_message.get_rect(center = (400,330))
# 游戏开始提示
game_start_message = test_font.render('Game start',False,(111,196,169))
game_start_message_rect = game_start_message.get_rect(center = (400,330))

# 加载天空图片
sky_surface = pygame.image.load('graphics/Sky.png').convert()
# 加载地面图片
ground_surface = pygame.image.load('graphics/ground.png').convert()

# 开始时间
start_time = 0

# 显示分数
def display_score():
    current_time = int(pygame.time.get_ticks() / 1000) - start_time
    score_surf = test_font.render(f'Score: {current_time}',False,(64,64,64))
    score_rect = score_surf.get_rect(center = (400,50))
    screen.blit(score_surf,score_rect)
    return current_time

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        # 加载两张走路的图片,让走路动起来
        player_walk_1 = pygame.image.load('graphics/player/player_walk_1.png').convert_alpha()
        player_walk_2 = pygame.image.load('graphics/player/player_walk_2.png').convert_alpha()
        
        # 放在list里面
        self.player_walk = [player_walk_1,player_walk_2]
        self.player_index = 0

        # 加载跳起来的图片
        self.player_jump = pygame.image.load('graphics/player/jump.png').convert_alpha()

        # 玩家走路初始位帧
        self.image = self.player_walk[self.player_index]

        # 设置初始位置
        self.rect = self.image.get_rect(midbottom = (80,300))
    
        # 跳跃音效,音量
        self.jump_sound = pygame.mixer.Sound('audio/jump.mp3')
        self.jump_sound.set_volume(0.5)
    # 玩家事件监听
    def player_input(self):
        keys = pygame.key.get_pressed()
        # 玩家按下空格且不是跳跃状态
        if keys[pygame.K_SPACE] and self.rect.bottom >= 300:
            # 设置重力
            self.gravity = -20
            # 播放跳跃音效
            self.jump_sound.play()

    # 重力计算
    def apply_gravity(self):
        self.gravity += 1
        self.rect.y += self.gravity
        if self.rect.bottom >= 300:
            self.rect.bottom = 300

    # 动画状态
    def animation_state(self):
        if self.rect.bottom < 300: 
            self.image = self.player_jump
        else:
            self.player_index += 0.1
            if self.player_index >= len(self.player_walk):self.player_index = 0
            self.image = self.player_walk[int(self.player_index)]
    # 监听器
    def update(self):
        self.animation_state()
        self.player_input()
        self.apply_gravity()
# 玩家
player = pygame.sprite.GroupSingle()
player.add(Player())

# 障碍物组
obstacle_group = pygame.sprite.Group()

# 障碍物事件
obstacle_timer = pygame.USEREVENT + 1
pygame.time.set_timer(obstacle_timer,1500)

# 蜗牛事件
snail_animation_timer = pygame.USEREVENT + 2
pygame.time.set_timer(snail_animation_timer,500)

# 来只蜗牛,两张图片动起来
snail_frame_1 = pygame.image.load('graphics/snail/snail1.png').convert_alpha()
snail_frame_2 = pygame.image.load('graphics/snail/snail2.png').convert_alpha()
snail_frames = [snail_frame_1, snail_frame_2]
snail_frame_index = 0
# 定义当前帧的图片
snail_surf = snail_frames[snail_frame_index]

# 苍蝇事件
# fly_animation_timer = pygame.USEREVENT + 3
# pygame.time.set_timer(fly_animation_timer,200)

# 障碍物类
class Obstacle(pygame.sprite.Sprite):
    def __init__(self,type):
        super().__init__()
        if type == 'fly':
            # 苍蝇的动画
            fly_1 = pygame.image.load('graphics/fly/fly1.png').convert_alpha()
            fly_2 = pygame.image.load('graphics/fly/fly2.png').convert_alpha()
            self.frames = [fly_1,fly_2]
            # 高度
            y_pos = 210
        else:
            # 蜗牛的动画
            snail_1 = pygame.image.load('graphics/snail/snail1.png').convert_alpha()
            snail_2 = pygame.image.load('graphics/snail/snail2.png').convert_alpha()
            self.frames = [snail_1,snail_2]
            # 高度
            y_pos  = 300

        self.animation_index = 0
        self.image = self.frames[self.animation_index]
        # 在右侧屏幕生成障碍物
        self.rect = self.image.get_rect(midbottom = (randint(900,1100),y_pos))

    # 动画状态
    def animation_state(self):
        self.animation_index += 0.1 
        if self.animation_index >= len(self.frames): self.animation_index = 0
        self.image = self.frames[int(self.animation_index)]

    # 监听
    def update(self):
        self.animation_state()
        self.rect.x -= 6
        self.destroy()

    # 销毁
    def destroy(self):
        if self.rect.x <= -100: 
            self.kill()

# 来只苍蝇,同上
fly_frame1 = pygame.image.load('graphics/fly/fly1.png').convert_alpha()
fly_frame2 = pygame.image.load('graphics/fly/fly2.png').convert_alpha()
fly_frames = [fly_frame1, fly_frame2]
fly_frame_index = 0
fly_surf = fly_frames[fly_frame_index]

# 苍蝇事件
fly_animation_timer = pygame.USEREVENT + 3
pygame.time.set_timer(fly_animation_timer,200)

while True:
    # 监听事件
    for event in pygame.event.get():
        # 检测退出
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        if game_active:
            # 障碍物事件
            if event.type == obstacle_timer:
                # 设置障碍物概率,蜗牛和苍蝇3:1
                obstacle_group.add(Obstacle(choice(['snail', 'fly'])))

            # 蜗牛事件
            if event.type == snail_animation_timer:
                if snail_frame_index == 0: snail_frame_index = 1
                else: snail_frame_index = 0
                snail_surf = snail_frames[snail_frame_index] 

            # 苍蝇事件
            if event.type == fly_animation_timer:
                if fly_frame_index == 0: fly_frame_index = 1
                else: fly_frame_index = 0
                fly_surf = fly_frames[fly_frame_index]
        else:
            # 按下空格开始
            if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                game_active = True

    # 游戏开始
    if game_active:
        # 绘制天空
        screen.blit(sky_surface,(0,0))
        # 绘制地面
        screen.blit(ground_surface,(0,300))
        # 分数
        score = display_score()
        # 绘制玩家
        player.draw(screen)
        # 玩家监听器
        player.update()
        # 绘制障碍物
        obstacle_group.draw(screen)
        obstacle_group.update()
    else:
        # 显示玩家
        screen.blit(player_stand,player_stand_rect)
        # 显示游戏提示信息
        screen.blit(game_message,game_message_rect)
        # 显示游戏名称
        screen.blit(game_name,game_name_rect)
    # 显示更新
    pygame.display.update()
    # 时间开始走,60帧
    clock.tick(60)
复制代码

9. 碰撞检测

添加全局碰撞检测方法

def collision_sprite():
    if pygame.sprite.spritecollide(player.sprite,obstacle_group,False):
        obstacle_group.empty()
        return False
    else: return True
复制代码

到开始游戏中注册

    # 游戏开始
    if game_active:
        # 绘制天空
        screen.blit(sky_surface,(0,0))
        # 绘制地面
        screen.blit(ground_surface,(0,300))
        # 分数
        score = display_score()
        # 绘制玩家
        player.draw(screen)
        # 玩家监听器
        player.update()
        # 绘制障碍物
        obstacle_group.draw(screen)
        obstacle_group.update()
        # 碰撞检测 
        game_active = collision_sprite()
复制代码

试试

发现死掉了展示的不符合我们的要求

9. 优化细节

之前我们在这里设置背景

# 初始化
pygame.init()
# 设置宽高
screen = pygame.display.set_mode((800,400))
# 设置标题
pygame.display.set_caption('Runner')
clock = pygame.time.Clock()
# 舞台填充颜色
screen.fill((94,129,162))
复制代码

我们改下,这边去掉,改到:

    # 游戏开始
    if game_active:
        # 绘制天空
        screen.blit(sky_surface,(0,0))
        # 绘制地面
        screen.blit(ground_surface,(0,300))
        # 分数
        score = display_score()
        # 绘制玩家
        player.draw(screen)
        # 玩家监听器
        player.update()
        # 绘制障碍物
        obstacle_group.draw(screen)
        obstacle_group.update()
        # 碰撞检测 
        game_active = collision_sprite()
    else:
        # 在这里粉刷背景
        screen.fill((94,129,162))
        # 显示玩家
        screen.blit(player_stand,player_stand_rect)
复制代码

再试试

 

死掉是这个界面,跟初始界面一样,我们要提示分数

全局设置分数

score = 0
复制代码

初始化显示初始界面,死了显示分数

    # 游戏开始
    if game_active:
        # 绘制天空
        screen.blit(sky_surface,(0,0))
        # 绘制地面
        screen.blit(ground_surface,(0,300))
        # 分数
        score = display_score()
        # 绘制玩家
        player.draw(screen)
        # 玩家监听器
        player.update()
        # 绘制障碍物
        obstacle_group.draw(screen)
        obstacle_group.update()
        # 碰撞检测 
        game_active = collision_sprite()
    else:
        # 在这里粉刷背景
        screen.fill((94,129,162))
        # 显示玩家
        screen.blit(player_stand,player_stand_rect)
        # 显示游戏提示信息
        # screen.blit(game_message,game_message_rect)
        # 显示游戏名称
        screen.blit(game_name,game_name_rect)

        # 显示分数
        score_message = test_font.render(f'Your score: {score}',False,(111,196,169))
        score_message_rect = score_message.get_rect(center = (400,330))
        screen.blit(game_name,game_name_rect)
        # 根据分值显示不同提示语
        if score == 0: screen.blit(game_message,game_message_rect)
        else: screen.blit(score_message,score_message_rect)
复制代码

试试,死了是预期的界面

又活捉个bug,死了再开始分数没有重新计算

判断按下空格开始的时候,重置下计时,我们的分数会自动设置为0,因为我们的分数是基于时间计算的:

            # 按下空格开始
            if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                game_active = True
                start_time = int(pygame.time.get_ticks() / 1000)
复制代码

顺便加个游戏背景音乐

# 加载背景音乐
bg_music = pygame.mixer.Sound('audio/music.wav')
# 背景音乐播放,无限循环播放
bg_music.play(loops = -1)
复制代码

最后试试

有背景音乐还是挺带劲的

完美,收工。

所有代码如下:

import pygame
from random import randint,choice

# 初始化
pygame.init()
# 设置宽高
screen = pygame.display.set_mode((800,400))
# 设置标题
pygame.display.set_caption('Runner')
clock = pygame.time.Clock()
# 舞台填充颜色
# screen.fill((94,129,162))
# 游戏状态
game_active = False
# 玩家图标
player_stand = pygame.image.load('graphics/player/player_stand.png').convert_alpha()
player_stand_rect = player_stand.get_rect(center = (400,200))
# 引入像素字体
test_font = pygame.font.Font('font/Pixeltype.ttf', 50)
# 游戏提示
game_message = test_font.render('Press space to run',False,(111,196,169))
game_message_rect = game_message.get_rect(center = (400,330))
# 游戏标题
game_name = test_font.render('Huamiao Runner',False,(111,196,169))
game_name_rect = game_name.get_rect(center = (400,80))
# 游戏结束提示
game_over_message = test_font.render('Game over',False,(111,196,169))
game_over_message_rect = game_over_message.get_rect(center = (400,330))
# 游戏开始提示
game_start_message = test_font.render('Game start',False,(111,196,169))
game_start_message_rect = game_start_message.get_rect(center = (400,330))

# 加载天空图片
sky_surface = pygame.image.load('graphics/Sky.png').convert()
# 加载地面图片
ground_surface = pygame.image.load('graphics/ground.png').convert()

# 开始时间
start_time = 0

# 显示分数
def display_score():
    current_time = int(pygame.time.get_ticks() / 1000) - start_time
    score_surf = test_font.render(f'Score: {current_time}',False,(64,64,64))
    score_rect = score_surf.get_rect(center = (400,50))
    screen.blit(score_surf,score_rect)
    return current_time

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        # 加载两张走路的图片,让走路动起来
        player_walk_1 = pygame.image.load('graphics/player/player_walk_1.png').convert_alpha()
        player_walk_2 = pygame.image.load('graphics/player/player_walk_2.png').convert_alpha()
        
        # 放在list里面
        self.player_walk = [player_walk_1,player_walk_2]
        self.player_index = 0

        # 加载跳起来的图片
        self.player_jump = pygame.image.load('graphics/player/jump.png').convert_alpha()

        # 玩家走路初始位帧
        self.image = self.player_walk[self.player_index]

        # 设置初始位置
        self.rect = self.image.get_rect(midbottom = (80,300))
    
        # 跳跃音效,音量
        self.jump_sound = pygame.mixer.Sound('audio/jump.mp3')
        self.jump_sound.set_volume(0.5)
    # 玩家事件监听
    def player_input(self):
        keys = pygame.key.get_pressed()
        # 玩家按下空格且不是跳跃状态
        if keys[pygame.K_SPACE] and self.rect.bottom >= 300:
            # 设置重力
            self.gravity = -20
            # 播放跳跃音效
            self.jump_sound.play()

    # 重力计算
    def apply_gravity(self):
        self.gravity += 1
        self.rect.y += self.gravity
        if self.rect.bottom >= 300:
            self.rect.bottom = 300

    # 动画状态
    def animation_state(self):
        if self.rect.bottom < 300: 
            self.image = self.player_jump
        else:
            self.player_index += 0.1
            if self.player_index >= len(self.player_walk):self.player_index = 0
            self.image = self.player_walk[int(self.player_index)]
    # 监听器
    def update(self):
        self.animation_state()
        self.player_input()
        self.apply_gravity()
# 玩家
player = pygame.sprite.GroupSingle()
player.add(Player())

# 障碍物组
obstacle_group = pygame.sprite.Group()

# 障碍物事件
obstacle_timer = pygame.USEREVENT + 1
pygame.time.set_timer(obstacle_timer,1500)

# 蜗牛事件
snail_animation_timer = pygame.USEREVENT + 2
pygame.time.set_timer(snail_animation_timer,500)

# 来只蜗牛,两张图片动起来
snail_frame_1 = pygame.image.load('graphics/snail/snail1.png').convert_alpha()
snail_frame_2 = pygame.image.load('graphics/snail/snail2.png').convert_alpha()
snail_frames = [snail_frame_1, snail_frame_2]
snail_frame_index = 0
# 定义当前帧的图片
snail_surf = snail_frames[snail_frame_index]

# 障碍物类
class Obstacle(pygame.sprite.Sprite):
    def __init__(self,type):
        super().__init__()
        if type == 'fly':
            # 苍蝇的动画
            fly_1 = pygame.image.load('graphics/fly/fly1.png').convert_alpha()
            fly_2 = pygame.image.load('graphics/fly/fly2.png').convert_alpha()
            self.frames = [fly_1,fly_2]
            # 高度
            y_pos = 210
        else:
            # 蜗牛的动画
            snail_1 = pygame.image.load('graphics/snail/snail1.png').convert_alpha()
            snail_2 = pygame.image.load('graphics/snail/snail2.png').convert_alpha()
            self.frames = [snail_1,snail_2]
            # 高度
            y_pos  = 300

        self.animation_index = 0
        self.image = self.frames[self.animation_index]
        # 在右侧屏幕生成障碍物
        self.rect = self.image.get_rect(midbottom = (randint(900,1100),y_pos))

    # 动画状态
    def animation_state(self):
        self.animation_index += 0.1 
        if self.animation_index >= len(self.frames): self.animation_index = 0
        self.image = self.frames[int(self.animation_index)]

    # 监听
    def update(self):
        self.animation_state()
        self.rect.x -= 6
        self.destroy()

    # 销毁
    def destroy(self):
        if self.rect.x <= -100: 
            self.kill()

# 来只苍蝇,同上
fly_frame1 = pygame.image.load('graphics/fly/fly1.png').convert_alpha()
fly_frame2 = pygame.image.load('graphics/fly/fly2.png').convert_alpha()
fly_frames = [fly_frame1, fly_frame2]
fly_frame_index = 0
fly_surf = fly_frames[fly_frame_index]

# 苍蝇事件
fly_animation_timer = pygame.USEREVENT + 3
pygame.time.set_timer(fly_animation_timer,200)

def collision_sprite():
    if pygame.sprite.spritecollide(player.sprite,obstacle_group,False):
        obstacle_group.empty()
        return False
    else: return True

score = 0

# 加载背景音乐
bg_music = pygame.mixer.Sound('audio/music.wav')
# 背景音乐播放,无限循环播放
bg_music.play(loops = -1)

while True:
    # 监听事件
    for event in pygame.event.get():
        # 检测退出
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        if game_active:
            # 障碍物事件
            if event.type == obstacle_timer:
                # 设置障碍物概率,蜗牛和苍蝇3:1
                obstacle_group.add(Obstacle(choice(['snail', 'fly'])))

            # 蜗牛事件
            if event.type == snail_animation_timer:
                if snail_frame_index == 0: snail_frame_index = 1
                else: snail_frame_index = 0
                snail_surf = snail_frames[snail_frame_index] 

            # 苍蝇事件
            if event.type == fly_animation_timer:
                if fly_frame_index == 0: fly_frame_index = 1
                else: fly_frame_index = 0
                fly_surf = fly_frames[fly_frame_index]
        else:
            # 按下空格开始
            if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                game_active = True
                start_time = int(pygame.time.get_ticks() / 1000)

    # 游戏开始
    if game_active:
        # 绘制天空
        screen.blit(sky_surface,(0,0))
        # 绘制地面
        screen.blit(ground_surface,(0,300))
        # 分数
        score = display_score()
        # 绘制玩家
        player.draw(screen)
        # 玩家监听器
        player.update()
        # 绘制障碍物
        obstacle_group.draw(screen)
        obstacle_group.update()
        # 碰撞检测 
        game_active = collision_sprite()
    else:
        # 在这里粉刷背景
        screen.fill((94,129,162))
        # 显示玩家
        screen.blit(player_stand,player_stand_rect)
        # 显示游戏提示信息
        # screen.blit(game_message,game_message_rect)
        # 显示游戏名称
        screen.blit(game_name,game_name_rect)

        # 显示分数
        score_message = test_font.render(f'Your score: {score}',False,(111,196,169))
        score_message_rect = score_message.get_rect(center = (400,330))
        screen.blit(game_name,game_name_rect)
        # 根据分值显示不同提示语
        if score == 0: screen.blit(game_message,game_message_rect)
        else: screen.blit(score_message,score_message_rect)
    # 显示更新
    pygame.display.update()
    # 时间开始走,60帧
    clock.tick(60)
复制代码

删除注释以及空行,完整代码如下,总共154行:

import pygame
from random import randint,choice
pygame.init()
screen = pygame.display.set_mode((800,400))
pygame.display.set_caption('Runner')
clock = pygame.time.Clock()
game_active = False
player_stand = pygame.image.load('graphics/player/player_stand.png').convert_alpha()
player_stand_rect = player_stand.get_rect(center = (400,200))
test_font = pygame.font.Font('font/Pixeltype.ttf', 50)
game_message = test_font.render('Press space to run',False,(111,196,169))
game_message_rect = game_message.get_rect(center = (400,330))
game_name = test_font.render('Huamiao Runner',False,(111,196,169))
game_name_rect = game_name.get_rect(center = (400,80))
game_over_message = test_font.render('Game over',False,(111,196,169))
game_over_message_rect = game_over_message.get_rect(center = (400,330))
game_start_message = test_font.render('Game start',False,(111,196,169))
game_start_message_rect = game_start_message.get_rect(center = (400,330))
sky_surface = pygame.image.load('graphics/Sky.png').convert()
ground_surface = pygame.image.load('graphics/ground.png').convert()
start_time = 0
def display_score():
    current_time = int(pygame.time.get_ticks() / 1000) - start_time
    score_surf = test_font.render(f'Score: {current_time}',False,(64,64,64))
    score_rect = score_surf.get_rect(center = (400,50))
    screen.blit(score_surf,score_rect)
    return current_time
class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        player_walk_1 = pygame.image.load('graphics/player/player_walk_1.png').convert_alpha()
        player_walk_2 = pygame.image.load('graphics/player/player_walk_2.png').convert_alpha()
        self.player_walk = [player_walk_1,player_walk_2]
        self.player_index = 0
        self.player_jump = pygame.image.load('graphics/player/jump.png').convert_alpha()
        self.image = self.player_walk[self.player_index]
        self.rect = self.image.get_rect(midbottom = (80,300))
        self.jump_sound = pygame.mixer.Sound('audio/jump.mp3')
        self.jump_sound.set_volume(0.5)
    def player_input(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_SPACE] and self.rect.bottom >= 300:
            self.gravity = -20
            self.jump_sound.play()
    def apply_gravity(self):
        self.gravity += 1
        self.rect.y += self.gravity
        if self.rect.bottom >= 300:
            self.rect.bottom = 300
    def animation_state(self):
        if self.rect.bottom < 300: 
            self.image = self.player_jump
        else:
            self.player_index += 0.1
            if self.player_index >= len(self.player_walk):self.player_index = 0
            self.image = self.player_walk[int(self.player_index)]
    def update(self):
        self.animation_state()
        self.player_input()
        self.apply_gravity()
player = pygame.sprite.GroupSingle()
player.add(Player())
obstacle_group = pygame.sprite.Group()
obstacle_timer = pygame.USEREVENT + 1
pygame.time.set_timer(obstacle_timer,1500)
snail_animation_timer = pygame.USEREVENT + 2
pygame.time.set_timer(snail_animation_timer,500)
snail_frame_1 = pygame.image.load('graphics/snail/snail1.png').convert_alpha()
snail_frame_2 = pygame.image.load('graphics/snail/snail2.png').convert_alpha()
snail_frames = [snail_frame_1, snail_frame_2]
snail_frame_index = 0
snail_surf = snail_frames[snail_frame_index]
class Obstacle(pygame.sprite.Sprite):
    def __init__(self,type):
        super().__init__()
        if type == 'fly':
            fly_1 = pygame.image.load('graphics/fly/fly1.png').convert_alpha()
            fly_2 = pygame.image.load('graphics/fly/fly2.png').convert_alpha()
            self.frames = [fly_1,fly_2]
            y_pos = 210
        else:
            snail_1 = pygame.image.load('graphics/snail/snail1.png').convert_alpha()
            snail_2 = pygame.image.load('graphics/snail/snail2.png').convert_alpha()
            self.frames = [snail_1,snail_2]
            y_pos  = 300
        self.animation_index = 0
        self.image = self.frames[self.animation_index]
        self.rect = self.image.get_rect(midbottom = (randint(900,1100),y_pos))
    def animation_state(self):
        self.animation_index += 0.1 
        if self.animation_index >= len(self.frames): self.animation_index = 0
        self.image = self.frames[int(self.animation_index)]
    def update(self):
        self.animation_state()
        self.rect.x -= 6
        self.destroy()
    def destroy(self):
        if self.rect.x <= -100: 
            self.kill()
fly_frame1 = pygame.image.load('graphics/fly/fly1.png').convert_alpha()
fly_frame2 = pygame.image.load('graphics/fly/fly2.png').convert_alpha()
fly_frames = [fly_frame1, fly_frame2]
fly_frame_index = 0
fly_surf = fly_frames[fly_frame_index]
fly_animation_timer = pygame.USEREVENT + 3
pygame.time.set_timer(fly_animation_timer,200)
def collision_sprite():
    if pygame.sprite.spritecollide(player.sprite,obstacle_group,False):
        obstacle_group.empty()
        return False
    else: return True
score = 0
bg_music = pygame.mixer.Sound('audio/music.wav')
bg_music.play(loops = -1)
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        if game_active:
            if event.type == obstacle_timer:
                obstacle_group.add(Obstacle(choice(['snail', 'fly'])))
            if event.type == snail_animation_timer:
                if snail_frame_index == 0: snail_frame_index = 1
                else: snail_frame_index = 0
                snail_surf = snail_frames[snail_frame_index] 
            if event.type == fly_animation_timer:
                if fly_frame_index == 0: fly_frame_index = 1
                else: fly_frame_index = 0
                fly_surf = fly_frames[fly_frame_index]
        else:
            if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                game_active = True
                start_time = int(pygame.time.get_ticks() / 1000)
    if game_active:
        screen.blit(sky_surface,(0,0))
        screen.blit(ground_surface,(0,300))
        score = display_score()
        player.draw(screen)
        player.update()
        obstacle_group.draw(screen)
        obstacle_group.update()
        game_active = collision_sprite()
    else:
        screen.fill((94,129,162))
        screen.blit(player_stand,player_stand_rect)
        screen.blit(game_name,game_name_rect)
        score_message = test_font.render(f'Your score: {score}',False,(111,196,169))
        score_message_rect = score_message.get_rect(center = (400,330))
        screen.blit(game_name,game_name_rect)
        if score == 0: screen.blit(game_message,game_message_rect)
        else: screen.blit(score_message,score_message_rect)
    pygame.display.update()
    clock.tick(60)

喜欢小胖子的记得三连哦~

今天这篇文章可能有点长但是会让你们受益匪浅的哦~

 

以上是关于今天怕p8架构师用154行写个冒险岛,小白都看得懂的语言描述的主要内容,如果未能解决你的问题,请参考以下文章

小孩都看得懂的推荐系统

你不得不看,巨详细王大爷表示都看得懂

本科生学深度学习-史上最容易懂的RNN文章,小白也能看得懂

hdu 1024 Max Sum Plus Plus 小白都可以看得懂的解析

本科生学深度学习-史上最容易懂的RNN文章,小白也能看得懂,评论继续送书

本科生学深度学习-史上最容易懂的RNN文章,小白也能看得懂,评论继续送书