python/pygame飞机游戏边学边写-结束篇(七)

博主在摸鱼时对Pygame游戏进行修改。调整得分显示位置到窗口中间;限定玩家飞机生命、炸弹总数及防御值上限;优化生命血条代码,统一考虑防御值;修改boss机爆炸效果,加大显示规模。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

摸鱼时间试着玩了一会,发现一些问题,修改了几处小的细节:

1、得分显示,在分数增加,字段变长后会跑出游戏窗口,直接调整到游戏窗口中间显示。

2、限定玩家飞机生命总数不能超过5条,限定炸弹总数不能超过3个,防御值增加最多不超过3000。

3、调整生命血条代码,原来只考虑了hp值,血条瞬间消失,而且玩家飞机在增加防御buff后又会出现超长血条。现将双方飞机的防御值统一考虑进去,可以更真实的体现飞机被击中后的血量变化。

4、boss机没有爆炸效果,调整爆炸规模,如果是boss飞机,加大爆炸效果显示。

import random
import sys
import os
import pygame
import time

pygame.init()
pygame.mixer.init()

screen_info_height = pygame.display.Info().current_h

shoot_sound = pygame.mixer.Sound(os.path.join('sound', 'shoot_sound.mp3'))
bomb_sound = pygame.mixer.Sound(os.path.join('sound', 'bomb_sound.mp3'))

HEIGHT = int(screen_info_height * 0.9)
WIDTH = int(screen_info_height * 0.9 * 2 / 3)

RED = (255, 0, 0)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
FPS = 60

game_window = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()

running = True
state1 = True
state2 = False
new_buff = False
boss_time = False

level = 0
score = 0
life_number = 3
bomb_number = 3

enemy_time = 0
bullet_buff_time = 0


player_plane = pygame.image.load(os.path.join('image', 'my_plane.png'))
player_plane_mini = pygame.transform.scale(player_plane, (30, 20))
player_bullet = pygame.image.load(os.path.join('image', 'player_bullet1.png'))

enemy_grey_plane = pygame.image.load(os.path.join('image', 'enemy_grey_plane.png'))
enemy_orange_plane = pygame.image.load(os.path.join('image', 'enemy_orange_plane.png'))
enemy_red_plane = pygame.image.load(os.path.join('image', 'enemy_red_plane.png'))
enemy_blue_plane = pygame.image.load(os.path.join('image', 'enemy_blue_plane.png'))
enemy_green_plane = pygame.image.load(os.path.join('image', 'enemy_green_plane.png'))

enemy_bullet = pygame.image.load(os.path.join('image', 'enemy_bullet1.png'))

new_life = pygame.image.load(os.path.join('image', 'new_life.png'))
defence_buff = pygame.image.load((os.path.join('image', 'defence_buff.png')))
bullet_buff = pygame.image.load(os.path.join('image', 'bullet_buff.png'))
bomb_buff = pygame.image.load(os.path.join('image', 'bomb_buff.png'))
bomb_buff_mini = pygame.transform.scale(bomb_buff, (12, 20))

all_sprites = pygame.sprite.Group()
enemies = pygame.sprite.Group()
player_bullets = pygame.sprite.Group()
enemy_bullets = pygame.sprite.Group()
buff_group = pygame.sprite.Group()

pygame.time.set_timer(pygame.USEREVENT + 1, 30 * 1000)
pygame.time.set_timer(pygame.USEREVENT + 2, 150 * 1000)


class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.transform.scale(player_plane, (WIDTH * 0.09, WIDTH * 0.09 * 2 / 3))
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.centery = HEIGHT - 50
        self.speed = 10
        self.hp = 100
        self.defense = 300
        self.last_shoot = 0
        self.shoot_reload = 100
        self.damage = 500
        self.total_hp = self.hp + self.defense

    def update(self):

        key_pressed = pygame.key.get_pressed()
        if key_pressed[pygame.K_UP] and self.rect.top >= 50:
            self.rect.y -= self.speed
        if key_pressed[pygame.K_DOWN] and self.rect.bottom <= HEIGHT:
            self.rect.y += self.speed
        if key_pressed[pygame.K_LEFT] and self.rect.left >= -5:
            self.rect.x -= self.speed
        if key_pressed[pygame.K_RIGHT] and self.rect.right <= WIDTH + 5:
            self.rect.x += self.speed
        if key_pressed[pygame.K_SPACE]:
            now_shoot_time = pygame.time.get_ticks()
            if now_shoot_time - self.last_shoot >= self.shoot_reload:
                self.shoot()
                self.last_shoot = now_shoot_time
                shoot_sound.set_volume(0.3)
                shoot_sound.play()

    def shoot(self):
        bullet = Bullet('player_bullet', self.rect.centerx, self.rect.top)
        all_sprites.add(bullet)
        player_bullets.add(bullet)

        if int(time.time()) <= 20 + int(bullet_buff_time):
            bullet1 = Bullet('player_bullet', self.rect.centerx - 20, self.rect.top)
            bullet2 = Bullet('player_bullet', self.rect.centerx + 20, self.rect.top)
            all_sprites.add(bullet1, bullet2)
            player_bullets.add(bullet1, bullet2)


class Enemy(pygame.sprite.Sprite):
    enemy_plane_dic = {
        'grey': [enemy_grey_plane, 5, 100, 4000],
        'orange': [enemy_orange_plane, 4, 200, 3000],
        'red': [enemy_red_plane, 3, 400, 2000],
        'blue': [enemy_blue_plane, 2, 100, 1000],
        'green': [enemy_green_plane, 2, 200, 1000]
    }

    def __init__(self, color):
        pygame.sprite.Sprite.__init__(self)
        self.color = color
        if self.color == 'blue' or self.color == 'green':
            self.image = pygame.transform.scale(self.enemy_plane_dic[self.color][0], (WIDTH * 0.5, WIDTH * 0.5 * 2 / 3))
        else:
            self.image = pygame.transform.scale(self.enemy_plane_dic[self.color][0], (WIDTH * 0.1, WIDTH * 0.1 * 2 / 3))
        self.rect = self.image.get_rect()
        self.rect.x = random.randrange(0, WIDTH - self.rect.width)
        self.rect.y = random.randrange(5, 10)
        self.speedx = random.randrange(-3, 3)
        self.speedy = self.enemy_plane_dic[self.color][1]
        self.hp = 100
        if self.color == 'blue' or self.color == 'green':
            self.defense = self.enemy_plane_dic[self.color][2] + 5000 * level
        else:
            self.defense = self.enemy_plane_dic[self.color][2]
        self.damage = self.enemy_plane_dic[self.color][2]
        self.score = int(self.enemy_plane_dic[self.color][2] / 10)
        self.last_shoot = 0
        self.shoot_reload = self.enemy_plane_dic[self.color][3]
        self.total_hp = self.hp + self.defense

    def update(self):
        self.rect.x += self.speedx
        self.rect.y += self.speedy
        blood_bar(game_window, self.hp + self.defense, self.total_hp, self.rect.x, self.rect.y - 20, self.rect.width, 5)
        now_shoot_time = pygame.time.get_ticks()
        if now_shoot_time - self.last_shoot >= self.shoot_reload:
            self.shoot()
            self.last_shoot = now_shoot_time

        if self.rect.left <= 0 or self.rect.right >= WIDTH:
            self.speedx = -self.speedx

        if self.rect.bottom >= HEIGHT or self.rect.top <= 0:
            if self.color == 'blue' or self.color == 'green':
                self.speedy = -self.speedy
            else:
                self.kill()

    def shoot(self):
        bullet = Bullet('enemy_bullet', self.rect.centerx, self.rect.bottom)
        bullet.damage = bullet.damage + int(self.damage / 10)
        all_sprites.add(bullet)
        enemy_bullets.add(bullet)


class Bullet(pygame.sprite.Sprite):
    bullet_dict = {
        'player_bullet': [player_bullet, 200, -15],
        'enemy_bullet': [enemy_bullet, 20, 10]
    }

    def __init__(self, bullet_type, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = self.bullet_dict[bullet_type][0]
        self.rect = self.image.get_rect()
        self.rect.centerx = x
        self.rect.centery = y
        self.damage = self.bullet_dict[bullet_type][1]
        self.speed = self.bullet_dict[bullet_type][2]

    def update(self):
        self.rect.centery += self.speed
        if self.rect.top <= 0 or self.rect.bottom >= HEIGHT:
            self.kill()


class Buff(pygame.sprite.Sprite):
    buff_dict = {
        'bullet_buff': bullet_buff,
        'bomb_buff': bomb_buff,
        'new_life': new_life,
        'defence_buff': defence_buff
    }

    def __init__(self, buff_type):
        pygame.sprite.Sprite.__init__(self)
        self.buff_type = buff_type
        self.image = self.buff_dict[self.buff_type]
        self.rect = self.image.get_rect()
        self.rect.x = random.randrange(0, WIDTH - self.rect.width)
        self.rect.y = 10
        self.speedx = random.randrange(-3, 3)
        self.speedy = 5

    def update(self):
        self.rect.x += self.speedx
        self.rect.y += self.speedy

        if self.rect.left <= 0 or self.rect.right >= WIDTH:
            self.speedx = -self.speedx
        if self.rect.top <= 0 or self.rect.bottom >= HEIGHT:
            self.speedy = - self.speedy


class Explosion:
    def __init__(self, surface, x, y, size='small'):
        self.explosions = []
        self.last_bom = 0
        self.bom_reload = 200
        self.surface = surface
        self.size = size
        for i in range(6):
            if self.size == 'small':
                self.image = pygame.image.load(os.path.join('image', 'bomb' + str(i + 1) + '.png'))
            if self.size == 'big':
                self.image = pygame.image.load(os.path.join('image', 'big_bomb' + str(i + 1) + '.png'))
            self.explosions.append(self.image)
            self.rect = self.image.get_rect()
            self.rect.x = x
            self.rect.y = y

    def explosion(self):
        now_time = pygame.time.get_ticks()
        if now_time - self.last_bom >= self.bom_reload:
            for i in range(len(self.explosions)):
                self.surface.blit(self.explosions[i], (self.rect.x, self.rect.y))
                self.last_bom = now_time


class BackGround:
    def __init__(self, surface):
        self.surface = surface
        self.image1 = pygame.transform.scale(pygame.image.load(os.path.join('image', 'bg.png')), (WIDTH, HEIGHT))
        self.image2 = pygame.transform.scale(pygame.image.load(os.path.join('image', 'bg.png')), (WIDTH, HEIGHT))
        self.rect1 = self.image1.get_rect()
        self.rect2 = self.image2.get_rect()
        self.rect1.x = 0
        self.rect1.y = 0
        self.rect2.x = 0
        self.rect2.y = - HEIGHT

    def background_move(self):
        self.surface.blit(self.image1, (self.rect1.x, self.rect1.y))
        self.surface.blit(self.image2, (self.rect2.x, self.rect2.y))
        self.rect1.y += 1
        if self.rect1.top >= HEIGHT:
            self.rect1.top = -HEIGHT
        self.rect2.y += 1
        if self.rect2.top >= HEIGHT:
            self.rect2.top = -HEIGHT


def mini_icon(surface):
    for i in range(life_number):
        surface.blit(player_plane_mini, (WIDTH - 35 - i * 35, 10))

    for i in range(bomb_number):
        surface.blit(bomb_buff_mini, (WIDTH - 25 - i * 35, 40))


def buff_produce():
    global new_buff
    if new_buff:
        game_buff = Buff(random.choice(['bullet_buff', 'bullet_buff', 'defence_buff', 'new_life', 'bomb_buff']))
        all_sprites.add(game_buff)
        buff_group.add(game_buff)
        new_buff = False


def new_player(player):
    if life_number > 0:
        player.rect.centerx = WIDTH / 2
        player.rect.bottom = HEIGHT - 10
        player.hp = 100
        player.defense = 300
        all_sprites.add(player)


def new_enemy():
    global enemy_time, boss_time
    now_enemy_time = pygame.time.get_ticks()
    if 0 <= score < 1000:
        color = random.choice(['grey'])
    if 1000 <= score < 2500:
        color = random.choice(['grey', 'orange'])
    if score >= 2500:
        color = random.choice(['grey', 'orange', 'red'])

    if now_enemy_time - enemy_time >= max(1100 - level * 100, 500):
        enemy = Enemy(color)
        all_sprites.add(enemy)
        enemies.add(enemy)
        enemy_time = now_enemy_time

    if boss_time:
        enemy = Enemy(random.choice(['blue', 'green']))
        all_sprites.add(enemy)
        enemies.add(enemy)
        boss_time = False


def bomb():
    for b in enemy_bullets:
        b.kill()
    for e in enemies:
        bom = Explosion(game_window, e.rect.x, e.rect.y)
        bom.explosion()
        e.hp -= 2000
        if e.hp <= 0:
            e.kill()


def draw_text(surface, text, x, y, color, size):
    font = pygame.font.Font(os.path.join('font', 'simkai.ttf'), size)
    font_surf = font.render(text, True, color)
    font_surf_rect = font_surf.get_rect()
    font_surf_rect.x = x
    font_surf_rect.y = y
    surface.blit(font_surf, (x - font_surf_rect.width / 2, y))


def background_music():
    pygame.mixer.music.load(os.path.join('sound', 'bgm.mp3'))
    pygame.mixer.music.set_volume(0.5)
    pygame.mixer.music.play(-1)


def start_interface(surface):
    if state1:
        image1 = pygame.image.load(os.path.join('image', 'begin_button.png'))
        image2 = pygame.image.load(os.path.join('image', 'exit_button0.png'))
    else:
        image1 = pygame.image.load(os.path.join('image', 'begin_button0.png'))
        image2 = pygame.image.load(os.path.join('image', 'exit_button.png'))

    rect1 = image1.get_rect()
    rect1.x = WIDTH / 2 - rect1.width / 2
    rect1.y = HEIGHT * 0.25
    surface.blit(image1, (rect1.x, rect1.y))

    rect2 = image2.get_rect()
    rect2.x = WIDTH / 2 - rect2.width / 2
    rect2.y = HEIGHT * 0.35
    surface.blit(image2, (rect2.x, rect2.y))

    draw_text(surface, '按Tab键选择,按Enter键确认', WIDTH / 2, HEIGHT * 0.5, WHITE, 20)
    draw_text(surface, '按←↑↓→控制移动飞机', WIDTH / 2, HEIGHT * 0.55, WHITE, 20)
    draw_text(surface, '按空格键发射子弹,按b键释放炸弹', WIDTH / 2, HEIGHT * 0.6, WHITE, 20)


def restart(surface):
    global running, state1, state2, new_buff, level, score, life_number, bomb_number, enemy_time, bullet_buff, \
        bullet_buff_time
    surface.fill(BLACK)

    all_sprites.empty()
    enemies.empty()
    player_bullets.empty()
    enemy_bullets.empty()

    running = True
    state1 = True
    state2 = False
    new_buff = False

    level = 0
    score = 0
    life_number = 3
    bomb_number = 3

    enemy_time = 0
    bullet_buff_time = 0

    main()


def end_interface():
    draw_text(game_window, 'GAME OVER', WIDTH / 2, 300, RED, 50)
    draw_text(game_window, 'SCORE: ' + str(score), WIDTH / 2, 400, RED, 50)
    draw_text(game_window, '按 b 键重新开始游戏', WIDTH / 2, 500, RED, 20)


def blood_bar(surface, hp, total_hp, x, y, bar_length, bar_width):
    hp_max = max(hp, 0)
    blood_bar_fill = pygame.Rect(x, y, hp_max / total_hp * bar_length, bar_width)
    blood_bar_outline = pygame.Rect(x, y, bar_length, bar_width)
    if hp_max / total_hp >= 0.4:
        pygame.draw.rect(surface, GREEN, blood_bar_fill)
    else:
        pygame.draw.rect(surface, RED, blood_bar_fill)
    pygame.draw.rect(surface, WHITE, blood_bar_outline, 1)


def collision_detection(player):
    global score, level, life_number, bullet_buff_time, bomb_number

    hits = pygame.sprite.groupcollide(player_bullets, enemies, True, False, pygame.sprite.collide_mask)
    for hit in hits:
        if hits[hit][0].defense >= 0:
            hits[hit][0].defense -= hit.damage
        else:
            hits[hit][0].hp -= hit.damage

        if hits[hit][0].hp <= 0:
            if hits[hit][0].color == 'blue' or hits[hit][0].color == 'green':
                bom = Explosion(game_window, hits[hit][0].rect.x, hits[hit][0].rect.y, size='big')
            else:
                bom = Explosion(game_window, hits[hit][0].rect.x, hits[hit][0].rect.y, size='small')
            bom.explosion()
            hits[hit][0].kill()
            bomb_sound.play()
            score += hits[hit][0].score
            level = score // 5000 + 1

    hits = pygame.sprite.spritecollide(player, enemy_bullets, True, pygame.sprite.collide_mask)
    for hit in hits:
        if player.defense >= 0:
            player.defense -= hit.damage
        else:
            player.hp -= hit.damage

        if player.hp <= 0:
            bom = Explosion(game_window, player.rect.x, player.rect.y)
            bom.explosion()
            player.kill()
            new_player(player)
            life_number -= 1

    hits = pygame.sprite.spritecollide(player, enemies, False, pygame.sprite.collide_mask)
    for hit in hits:
        if hit.defense >= 0:
            hit.defense -= player.damage
        else:
            hit.hp -= player.damage

        if hit.hp <= 0:
            if hit.color == 'blue' or hit.color == 'green':
                bom = Explosion(game_window, hit.rect.x, hit.rect.y, size='big')
            else:
                bom = Explosion(game_window, hit.rect.x, hit.rect.y, size='small')
            bom.explosion()
            hit.kill()
            bomb_sound.play()
            score += hit.score

        if player.defense >= 0:
            player.defense -= hit.damage
        else:
            player.hp -= hit.damage

        if player.hp <= 0:
            bom = Explosion(game_window, player.rect.x, player.rect.y)
            bom.explosion()
            player.kill()
            new_player(player)
            life_number -= 1

    hits = pygame.sprite.spritecollide(player, buff_group, True)
    for hit in hits:
        if hit.buff_type == 'bullet_buff':
            bullet_buff_time = time.time()

        if hit.buff_type == 'bomb_buff' and bomb_number < 3:
            bomb_number += 1

        if hit.buff_type == 'new_life' and life_number < 5:
            life_number += 1

        if hit.buff_type == 'defence_buff' and player.defense <= 3000:
            player.defense += 3000
            player.total_hp = player.hp + player.defense


def control():
    global running, state1, state2, level, new_buff, bomb_number, boss_time
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        if event.type == pygame.USEREVENT + 1:
            new_buff = True

        if event.type == pygame.USEREVENT + 2:
            boss_time = True

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_TAB:
                state1, state2 = state2, state1

            if event.key == pygame.K_r and life_number <= 0:
                restart(game_window)

            if event.key == pygame.K_RETURN and state1 and level == 0:
                level = 1
            if event.key == pygame.K_RETURN and state2 and level == 0:
                running = False

            if event.key == pygame.K_b and life_number > 0 and bomb_number > 0:
                bomb()
                bomb_number -= 1


def main():
    background = BackGround(game_window)
    player = Player()
    background_music()

    while running:

        control()
        background.background_move()
        if life_number > 0:
            if level == 0:
                start_interface(game_window)

            if level == 1:
                blood_bar(game_window, player.hp + player.defense, player.total_hp, 10, 20, 150, 10)
                mini_icon(game_window)

                new_enemy()
                buff_produce()
                all_sprites.add(player)
                all_sprites.draw(game_window)
                all_sprites.update()

                collision_detection(player)

                draw_text(game_window, 'SCORE: ' + str(score),  WIDTH / 2, 10, RED, 25)
                draw_text(game_window, '第' + str(level) + '关', WIDTH / 2, 300, RED, 30)

            if level >= 2:
                blood_bar(game_window, player.hp + player.defense, player.total_hp, 10, 20, 150, 10)
                mini_icon(game_window)

                new_enemy()
                buff_produce()
                all_sprites.add(player)
                all_sprites.draw(game_window)
                all_sprites.update()

                collision_detection(player)

                draw_text(game_window, 'SCORE: ' + str(score), 70, 10, RED, 25)
                draw_text(game_window, '第' + str(level) + '关', WIDTH / 2, 300, RED, 30)

        else:
            background.background_move()
            end_interface()

        clock.tick(FPS)
        pygame.display.set_caption('飞机游戏   ' + 'FPS: ' + '{0:0.2F}'.format(clock.get_fps()))
        pygame.display.update()

    pygame.quit()
    sys.exit()


if __name__ == '__main__':
    main()

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值