This article is participating in Python Theme Month. See the link to the event for more details

XDJMM, I am an unwomanly cat.

When I was a child, I played a FC game called Adventure Island. I don’t know if you have played it, but it is very interesting. There are several generations.

1. Initialization

The introduction of pygame

import pygame
Copy the code

Initialize the

pygame.init()
Copy the code

Set the width of high

Screen = pygame. Display. Set_mode ((800400))Copy the code

Set the title

pygame.display.set_caption('Runner')
Copy the code

Set the clock

clock = pygame.time.Clock()
Copy the code

Fill color

Screen. The fill ((94129162))Copy the code

Apply colours to a drawing

While True: # update pygame.display.update() # Time starts to go, 60 frames clock.tick(60)Copy the code

Python3 island.py open the test

There is a problem that mouse click will get stuck, we add event capture

For event in PyGame.event.get ()Copy the code

Now execute python3 island.py and click the mouse without getting stuck

The code is arranged as follows:

Screen = pygame.display.set_mode((800,400) Pygame.display.set_caption ('Runner') clock = Pygame.time.clock () # fill color.screen ((94,129,162)) while True: For event in Pygame.event.get (): # For event in Pygame.event.get (): # for event in Pygame.event.get (): # for event in Pygame.event.get (): # for event in PyGame.event.get (): #Copy the code

2. The main interface

Just the code execution, found unable to close, can only close the script, detect the close event

While True: for event in PyGame.event.get (): Pygame.quit () exit() # Display update pygame.display.update() # Time starts to go, 60 frames clock.tick(60)Copy the code

It can now be closed properly

Let’s add the initial page and add the game state, which is not started by default

game_active = False
Copy the code

Introducing player images

player_stand = pygame.image.load('graphics/player/player_stand.png').convert_alpha()
Copy the code

Set placement

Player_stand_rect = player_stand.get_rect(center = (400,200))Copy the code

Render it and see what it looks like

If game_active: pass else: # Game over, display score etc screen.blit(player_stand,player_stand_rectCopy the code

There’s something wrong with that, so I’m going to add a hint, custom font, and I’m going to say pixel font

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 = (400330))Copy the code

display

screen.blit(game_message,game_message_rect)
Copy the code

Add a title

Game_name = test_font. Render ('Huamiao Runner',False,(111,196,169)) game_name_rect = game_name.get_rect(center = (400))Copy the code

display

screen.blit(game_name,game_name_rect)
Copy the code

The code is arranged as follows:

Screen = pygame.display.set_mode((800,400) Pygame.display.set_caption ('Runner') clock = Pygame.time.clock () # Stage fill color 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)) # Adopt pixel font test_font = pygame.font. Game_message = test_font. Render ('Press space to run',False,(111,196,169)) game_message_rect = Game_name = test_font. Render ('Huamiao Runner',False,(111,196,169)) Game_name_rect = game_name.get_rect(center = (400,80)) while True: If event.type == pygame.quit: pygame.quit() exit() if game_active: pass else: # Display player screen.blit(game_message,game_message_rect) # Display game name Screen.blit (game_name,game_name_rect) # Pygame.display.update () # Time to start to go, 60 frames clock.tick(60)Copy the code

3. Start the game

To achieve the space to start the game, add listening

If event.type == Pygame. KEYDOWN and event.key == Pygame. K_SPACE: game_active = TrueCopy the code

Add start message text

Game_start_message = test_font. Render ('Game start',False,(111,196,169)) game_start_message_rect = Game_start_message. Get_rect (center = (400330))Copy the code

Display start game information

If game_active: screen.fill((94,129,162)) screen.blit(game_start_message,game_start_message_rect) else: # Display player screen.blit(game_message,game_message_rect) # Display game name Screen.blit (game_name,game_name_rect) # Pygame.display.update () # Time to start to go, 60 frames clock.tick(60)Copy the code

Execute the script, python3 island.py and press the space

This interface is just a test, let’s change it to a normal game screen with sky and ground, let’s add the following:

# Load sky_surface = pygame.image.load('graphics/ sky.png ').convert() # Load ground_surface = pygame.image.load('graphics/ground.png').convert()Copy the code

Change the test information below:

If game_active: # draw sky screen.blit(sky_surface,(0,0)) # draw ground screen.blit(ground_surface,(0,300))Copy the code

To execute the script, press space

GIF screenshot software small problem, the color is slightly distorted, see the effect:

4. Add players

Player = # players pygame. Sprite. GroupSingle () player. The add (player ())Copy the code

Create the Player class to enrich the class

class Player(pygame.sprite.Sprite): def __init__(self): Super ().__init__() # Load two walking pictures, 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() Player_walk = [player_Walk_1, Player_Walk_2] # Initialize index self.player_index = 0 # Player walk initial frame self.image = Self. rect = self.image.get_rect(midbottom = (80,300))Copy the code

Draw the player

If game_active: # code... # Player.draw (screen)Copy the code

Look at the effect

The character is out, we’re going to do a walking animation, we’re going to need a listener:

# Player.update () # Player.update ()Copy the code

Add an animation in the Player class

def animation_state(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()Copy the code

Look at the effect

5. Player event listening

Listen for the player to press a space, jump up, and add sound to the action

# Player class # Jump sound Self.jump_sound = pygame.mixer.sound ('audio/jump.mp3') self.jump_sound.set_volume(0.5) # Player event listener def player_input(self): If keys[pygame.k_space] and self.rect.bottom >= 300: Self.jump_sound.play ()Copy the code

Add gravity calculation method, and listen

Def gravity(self): self.rect.y += self.rect.y += self.gravity if self.rect.bottom >= 300: self.rect.bottom = 300Copy the code

Animation state needs to be changed

Def animation_state(self): if self.rect.bottom < 300: self.image = self.player_jump else: 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)]Copy the code

The listener

# def update(self): self.animation_state() self.player_input() self.apply_gravity() self.apply_gravity()Copy the code

Look at the effect

The code is arranged as follows:

Screen = pygame.display.set_mode((800,400) Pygame.display.set_caption ('Runner') clock = Pygame.time.clock () # Stage fill color 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)) # Adopt pixel font test_font = pygame.font. Game_message = test_font. Render ('Press space to run',False,(111,196,169)) game_message_rect = Game_name = test_font. Render ('Huamiao Runner',False,(111,196,169)) 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_rect = test_font. Render ('Game start',False,(111,196,169) 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__() # Load two walking pictures, 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() # in list self.player_walk = [player_walk_1,player_walk_2] self.player_index = 0 Pygame.image.load ('graphics/player/jump.png').convert_alpha() # Player walk initial bit frame self.image = 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) # Player event listener def player_input(self): 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: Def animation_state(self): if self.rect.bottom < 300: self.image = self.player_jump else: 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 () the self. The apply_gravity () # player to player = pygame. Sprite. GroupSingle () Player.add (player ()) while True: # Listen for event in Pygame.event.get (): # Check for exit if event.type == Pygame.quit: If event.type == Pygame.keydown and event.key == Pygame.k_space: Game_active = True # screen-blit (sky_surface,(0,0)) # screen-blit (ground_surface,(0,300)) # player.draw(screen) # player listener player.update() else: # Display player screen.blit(game_message,game_message_rect) # Display game name Screen.blit (game_name,game_name_rect) # Pygame.display.update () # Time to start to go, 60 frames clock.tick(60)Copy the code

6. Add time and score

Add the global display time method, here we calculate the score based on how long the player can finish, as follows:

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_timeCopy the code

Displays the score after starting the game

# score = display_score()Copy the code

The score can now be calculated normally

Fixed a previous bug, not using ~

If event.type == Pygame.quit: pygame.quit() exit() if game_active: pass else: If event.type == Pygame. KEYDOWN and event.key == Pygame. K_SPACE: TrueCopy the code

7. Add obstacles

Adding an Obstacle Group

obstacle_group = pygame.sprite.Group()
Copy the code

Adding an Obstacle Event

obstacle_timer = pygame.USEREVENT + 1
pygame.time.set_timer(obstacle_timer,1500)
Copy the code

Add a snail

# Come on a snail, Two images move snail_frame_1 = pygame. Image. The load (' graphics/q/snail1. PNG). The convert_alpha snail_frame_2 = () pygame.image.load('graphics/snail/snail2.png').convert_alpha() snail_frames = [snail_frame_1, Snail_surf = snail_frames[snail_frame_index]Copy the code

Adding a Snail event

snail_animation_timer = pygame.USEREVENT + 2
pygame.time.set_timer(snail_animation_timer,500)
Copy the code

To add an obstacle class, we will reserve one type and add different types of obstacles later

# def init__(self,type): Super () __init__ () # snail animation snail_1 = pygame. Image. The load (' graphics/q/snail1. PNG). The convert_alpha snail_2 = () Pygame. Image. The load (' graphics/q/snail2. PNG). The convert_alpha (self). The frames height = [snail_1 snail_2] # y_pos = 300 Self.animation_index = 0 self.image = self.frames[self.animation_index] # Create obstacle self.rect = Self. Image. Get_rect (midbottom = (randint (900110), y_pos))Copy the code

Add obstacle animation

Def def frames (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)]Copy the code

Listen for obstacles

# def update(self): self.animation_state() self.rect.x -= 6 self.destroy()Copy the code

Destruction of obstacles

# def destroy(self): if self.rect.x <= -100: self.kill()Copy the code

The obstacle event is added to the loop

If event.type == Pygame.quit: Pygame.quit () exit() if game_active: # Event.type == obstacLE_timer: 3 obstacLE_group-add (Obstacle(choice(['snail']))) if snail_frame_index == 0: snail_frame_index = 1 else: snail_frame_index = 0 snail_surf = snail_frames[snail_frame_index]Copy the code

Add an obstacle render at the beginning of the game

If game_active: # scree.blit (sky_surface,(0,0)) # scree.blit (ground_surface,(0,300)) # score = display_score() # draw players Obstacle_group-update (screen) obstacLE_group-update ()Copy the code

Look at the effect

8. Add additional obstacles

# Come on a fly, 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]Copy the code

Add fly Events

Fly_animation_timer = Pygame.userEvent + 3 Pygame.time.set_timer (fly_animation_timer,200)Copy the code

Obstacle category changed

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] # height y_pos = 210 else: # snail animation snail_1 = pygame. Image. The load (' graphics/q/snail1. PNG). The convert_alpha snail_2 = () Pygame. Image. The load (' graphics/q/snail2. PNG). The convert_alpha (self). The frames height = [snail_1 snail_2] # y_pos = 300Copy the code

Add the fly to the event generated by the obstacle, since we reserved a chioce earlier

If event.type == Pygame.quit: Pygame.quit () exit() if game_active: # Event.type == obstacLE_timer: 3 obstacLE_group. Add (Obstacle(choice(['snail', 'fly'])))Copy the code

Look at the effect

The code is arranged as follows:

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)
Copy the code

9. Collision detection

Add a global collision detection method

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

Go to the start game to register

If game_active: # scree.blit (sky_surface,(0,0)) # scree.blit (ground_surface,(0,300)) # score = display_score() # draw players Obstacle_group-update (screen) obstACLE_group-update () # Collision detection game_active = collision_sprite()Copy the code

Have a try

Found dead display does not meet our requirements

9. Optimize details

This is where we set the background

# Set screen = pygame.display.set_mode((800,400)) # Set pygame.display.set_mode((800,400)) # Set Pygame.display.set_caption ('Runner') clock = Pygame.time.clock () # Screen fill((94,129,162))Copy the code

So let’s change it, let’s get rid of this, let’s change it to:

If game_active: # scree.blit (sky_surface,(0,0)) # scree.blit (ground_surface,(0,300)) # score = display_score() # draw players Obstacle_group-update (screen) obstACLE_group-update () # Collision detection game_active = collision_sprite() else: # Display player screen.blit(player_stand,player_stand_rect)Copy the code

Try again

Death is this interface, and just like the initial interface, we’re going to indicate the score

Global set score

score = 0
Copy the code

Initialize display initial interface, dead display score

If game_active: # scree.blit (sky_surface,(0,0)) # scree.blit (ground_surface,(0,300)) # score = display_score() # draw players Obstacle_group-update (screen) obstACLE_group-update () # Collision detection game_active = collision_sprite() else: # Paint the background here screen.fill((94,129,162)) # Display player screen.blit(player_stand,player_stand_rect) # Display game info # Screen.blit (game_name,game_name_rect) # Display score score_message = test_font.render(f'Your score: {score}',False,(111,196,169)) score_message_rect = score_message_rect (center = (400,330)) If score == 0: screen.blit(game_message,game_message_rect) else: screen.blit(game_message,game_message_rect) screen.blit(score_message,score_message_rect)Copy the code

Try it. Dead is the expected interface

Another bug caught alive, the score is not recalculated after death

Our score is automatically set to 0 when we press space to start, because our score is based on time:

If event.type == Pygame. KEYDOWN and event.key == Pygame. K_SPACE: game_active = True start_time = int(pygame.time.get_ticks() / 1000)Copy the code

Add a game background music by the way

Bg_music = Pygame.mixer.sound ('audio/music.wav') bg_music.play(loops = -1)Copy the code

The last try

It’s kind of fun with music in the background

Perfect. Call it a day.

All the code looks like this:

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)
Copy the code

Delete the comments and the blank lines. The complete code looks like this, with 154 lines:

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)
Copy the code

homework

Here is the homework:

  1. Organize and optimize your own code
  2. Change the elements of the game that need to be changed, such as the rules for calculating points
  3. According to the knowledge taught in today’s class, each student should do a cool run every day after class