猫史档案馆


【Python作品分享】飞机大战【教程贴】

用户:米窝NfZ6米窝NfZ6查看:0 回复:0 评论:0 创建时间:2022-05-14T15:33:16


【作品展示】

center_image

 

【作品介绍】

啊啊

 

【作品源代码】

import pygame
import random


class Game(object):
    def __init__(self):
        self.main_window = pygame.display.set_mode(SCREEN_RECT.size)
        pygame.display.set_caption("飞机大战")
        self.is_game_over = False
        self.is_pause = False
        self.all_group = pygame.sprite.Group()
        self.enemies_group = pygame.sprite.Group()
        self.supplies_group = pygame.sprite.Group()
        GameSprite("background.png", 1, self.all_group)
        self.all_group.add(Background(False), Background(True))
        # hero = GameSprite("/me1.png", 0, self.all_group)
        # hero.rect.center = SCREEN_RECT.center
        self.hud_panel = HudPanel(self.all_group)
        self.create_enemies()
        self.hero = Hero(self.all_group)
        self.hud_panel.show_bomb(self.hero.bomb_count)
        # for enemy in self.enemies_group.sprites():
        #     enemy.speed = 0
        #     enemy.rect.y += 400
        self.hero.speed = 1
        self.create_supplies()

    def reset_game(self):
        self.is_game_over = False
        self.is_pause = False
        self.hud_panel.reset_panel()
        self.hero.rect.midbottom = HERO_DEFAULT_MID_BOTTOM
        for enemy in self.enemies_group:
            enemy.喵()
        for bullet in self.hero.bullets_group:
            bullet.喵()
        self.create_enemies()

    def event_handler(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return True
            if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                return True
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                if self.is_game_over:
                    self.reset_game()
                else:
                    self.is_pause = not self.is_pause
            if not self.is_game_over and not self.is_pause:
                if event.type == BULLET_ENHANCED_OFF_EVENT:
                    self.hero.bullets_kind = 0
                    pygame.time.set_timer(BULLET_ENHANCED_OFF_EVENT, 0)
                if event.type == THROW_SUPPLY_EVENT:
                    supply = random.choice(self.supplies_group.sprites())
                    supply.throw_supply()
                if event.type == HERO_FIRE_EVENT:
                    self.hero.fire(self.all_group)
                if event.type == HERO_POWER_OFF_EVENT:
                    print("取消喵状态...")
                    self.hero.is_power = False
                    pygame.time.set_timer(HERO_POWER_OFF_EVENT, 0)
                if event.type == HERO_DEAD_EVENT:
                    print("英雄牺牲了...")
                    self.hud_panel.lives_count -= 1
                    self.hud_panel.show_lives()
                    self.hud_panel.show_bomb(self.hero.bomb_count)
                if event.type == pygame.KEYDOWN and event.key == pygame.K_b:
                    score = self.hero.blowup(self.enemies_group)
                    self.hud_panel.show_bomb(self.hero.bomb_count)
                    if self.hud_panel.increase_score(score):
                        self.create_enemies()
                    # self.hud_panel.show_bomb(random.randint(0, 100))
                    # self.hud_panel.lives_count = random.randint(0, 10)
                    # self.hud_panel.show_lives()
        return False

    def start(self):
        frame_counter = 0
        clock = pygame.time.Clock()
        while True:
            self.is_game_over = self.hud_panel.lives_count == 0
            if self.event_handler():
                self.hud_panel.save_best_score()
                return
            if self.is_game_over:
                # print("游戏已经结束,按空格键重新开始...")
                self.hud_panel.panel_pause(True, self.all_group)
            elif self.is_pause:
                # print("游戏已经暂停,按空格键继续...")
                self.hud_panel.panel_pause(False, self.all_group)
            else:
                self.hud_panel.panel_resume(self.all_group)
                self.check_collide()
                keys = pygame.key.get_pressed()
                move_hor = keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]
                move_ver = keys[pygame.K_DOWN] - keys[pygame.K_UP]
                # if self.hud_panel.increase_score(100):
                #   print("升级到 %d" % self.hud_panel.level)
                #    self.create_enemies()
                # self.hero.hp -= 30
                frame_counter = (frame_counter + 1) % FRAME_INTERVAL
                self.all_group.update(frame_counter == 0, move_hor, move_ver)
            self.all_group.draw(self.main_window)
            pygame.display.update()
            clock.tick(60)

    def create_enemies(self):
        count = len(self.enemies_group.sprites())
        groups = (self.all_group, self.enemies_group)
        if self.hud_panel.level == 1 and count == 0:
            for i in range(16):
                Enemy(0, 3, *groups)
        elif self.hud_panel.level == 2 and count == 16:
            for enemy in self.enemies_group.sprites():
                enemy.max_speed = 5
            for i in range(8):
                Enemy(0, 5, *groups)
            for i in range(2):
                Enemy(1, 1, *groups)
        elif self.hud_panel.level == 3 and count == 26:
            for enemy in self.enemies_group.sprites():
                enemy.max_speed = 7 if enemy.kind == 0 else 3
            for i in range(8):
                Enemy(0, 7, *groups)
            for i in range(2):
                Enemy(1, 3, *groups)
            for i in range(2):
                Enemy(2, 1, *groups)

    def check_collide(self):
        if not self.hero.is_power:
            enemies = pygame.sprite.spritecollide(self.hero,
                                                  self.enemies_group, False,
                                                  pygame.sprite.collide_mask)
            enemies = list(filter(lambda x: x.hp > 0, enemies))
            if enemies:
                self.hero.hp = 0
                # self.hud_panel.lives_count -= 1
                # self.hud_panel.lives_label = self.hud_panel.lives_count
            for enemy in enemies:
                enemy.hp = 0
        hit_enemies = pygame.sprite.groupcollide(self.enemies_group,
                                                 self.hero.bullets_group,
                                                 False, False,
                                                 pygame.sprite.collide_mask)
        for enemy in hit_enemies:
            if enemy.hp <= 0:
                continue
            for bullet in hit_enemies[enemy]:
                bullet.kill()
                enemy.hp -= bullet.damage
                if enemy.hp > 0:
                    continue
                if self.hud_panel.increase_score(enemy.value):
                    self.create_enemies()
                    break
        supplies = pygame.sprite.spritecollide(self.hero,
                                               self.supplies_group,
                                               False, pygame.sprite.collide_mask)
        if supplies:
            supply = supplies[0]
            supply.rect.y = SCREEN_RECT.h
            if supply.kind == 0:
                self.hero.喵_count += 1
                self.hud_panel.show_喵(self.hero.喵_count)
            else:
                self.hero.bullets_kind = 1
                pygame.time.set_timer(BULLET_ENHANCED_OFF_EVENT, 20000)

    def create_supplies(self):
        Supply(0, self.supplies_group, self.all_group)
        Supply(1, self.supplies_group, self.all_group)
        pygame.time.set_timer(THROW_SUPPLY_EVENT, 30000)


class HudPanel(object):
    margin = 10
    white = (255, 255, 255)
    gray = (喵, 喵, 喵)
    reward_score = 100000
    level2_score = 10000
    level3_score = 50000
    record_filename = 'record.txt'

    def __init__(self, display_group):
        self.score = 0
        self.lives_count = 3
        self.level = 1
        self.best_score = 0
        self.load_best_score()
        self.status_sprite = StatusButton(
            ("/pause_nor.png", "/resume_nor.png"), display_group)
        self.status_sprite.rect.topleft = (self.margin, self.margin)
        self.喵_sprite = GameSprite("/喵.png", 0, display_group)
        self.喵_sprite.rect.x = self.margin
        self.喵_sprite.rect.bottom = SCREEN_RECT.bottom - self.margin
        self.lives_sprite = GameSprite("/life.png", 0, display_group)
        self.lives_sprite.rect.right = SCREEN_RECT.right-self.margin
        self.lives_sprite.rect.bottom = SCREEN_RECT.bottom - self.margin
        self.score_lable = Label(
            "%d" % self.score, 32, self.gray, display_group)
        self.score_lable.rect.midleft = (self.status_sprite.rect.right +
                                         self.margin, self.status_sprite.rect.centery)
        self.喵_lable = Label("X 3", 32, self.gray, display_group)
        self.喵_lable.rect.midleft = (self.喵_sprite.rect.right +
                                        self.margin, self.喵_sprite.rect.centery)
        self.lives_label = Label(
            "X %d" % self.lives_count, 32, self.gray, display_group)
        self.lives_label.rect.midright = (SCREEN_RECT.right - self.margin,
                                          self.喵_lable.rect.centery)
        self.lives_sprite.rect.right = self.lives_label.rect.left - self.margin
        self.best_label = Label("Best %d" % self.best_score, 36, self.white)
        self.best_label.rect.center = SCREEN_RECT.center
        self.status_label = Label("Game over", 48, self.white)
        self.status_label.rect.midbottom = (self.best_label.rect.centerx,
                                            self.best_label.rect.y - 2 * self.margin)
        self.tip_label = Label("Press spacebar to play again", 22,
                               self.white)
        self.tip_label.rect.midtop = (self.best_label.rect.centerx,
                                      self.best_label.rect.bottom + 8 * self.margin)

    def show_bomb(self, count):
        self.bomb_lable.set_text("X %d" % count)
        self.bomb_lable.rect.midleft = (self.bomb_sprite.rect.right +
                                        self.margin, self.bomb_sprite.rect.centery)

    def show_lives(self):
        self.lives_label.set_text("X %d" % self.lives_count)
        self.lives_label.rect.midright = (SCREEN_RECT.right - self.margin,
                                          self.bomb_lable.rect.centery)
        self.lives_sprite.rect.right = self.lives_label.rect.left - self.margin

    def increase_score(self, enemy_score):
        score = self.score + enemy_score
        if score // self.reward_score != self.score // self.reward_score:
            self.lives_count += 1
            self.show_lives()
        self.score = score
        self.best_score = score if score > self.best_score else self.best_score
        if score < self.level2_score:
            level = 1
        elif score < self.level3_score:
            level = 2
        else:
            level = 3
        is_upgrade = level != self.level
        self.level = level
        self.score_lable.set_text("%d" % self.score)
        self.score_lable.rect.midleft = (self.status_sprite.rect.right +
                                         self.margin, self.status_sprite.rect.centery)
        return is_upgrade

    def save_best_score(self):
        file = open(self.record_filename, "w")
        file.write("%d" % self.best_score)
        file.close()

    def load_best_score(self):
        try:
            file = open(self.record_filename)
            txt = file.readline()
            file.close()
            self.best_score = int(txt)
        except (FileNotFoundError, ValueError):
            print("文件不存在或类型转换错误")

    def panel_pause(self, is_game_over, display_group):
        if display_group.has(self.status_label, self.tip_label, self.best_label):
            return
        text = "Game Over!" if is_game_over else "Game Paused"
        tip = "Press spacebar to "
        tip += "play again" if is_game_over else "continue"
        self.best_label.set_text("Best %d" % self.best_score)
        self.status_label.set_text(text)
        self.tip_label.set_text(tip)
        self.best_label.rect.center = SCREEN_RECT.center
        best_rect = self.best_label.rect
        self.status_label.rect.midbottom = (best_rect.centerx,
                                            best_rect.y - 2 * self.margin)
        self.tip_label.rect.midtop = (best_rect.centerx,
                                      best_rect.bottom + 8 * self.margin)
        display_group.add(self.best_label, self.status_label, self.tip_label)
        self.status_sprite.switch_status(True)

    def panel_resume(self, display_group):
        display_group.remove(self.status_label, self.tip_label,
                             self.best_label)
        self.status_sprite.switch_status(False)

    def reset_panel(self):
        self.score = 0
        self.lives_count = 3
        self.increase_score(0)
        self.show_bomb(3)
        self.show_lives()


SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
FRAME_INTERVAL = 10
HERO_BOMB_COUNT = 3
HERO_DEFAULT_MID_BOTTOM = (SCREEN_RECT.centerx, SCREEN_RECT.bottom - 90)
HERO_DEAD_EVENT = pygame.USEREVENT
HERO_POWER_OFF_EVENT = pygame.USEREVENT + 1
HERO_FIRE_EVENT = pygame.USEREVENT + 2
THROW_SUPPLY_EVENT = pygame.USEREVENT + 3
BULLET_ENHANCED_OFF_EVENT = pygame.USEREVENT + 4


class GameSprite(pygame.sprite.Sprite):
    res_path = "./res/images/"

    def __init__(self, image_name, speed, *groups):
        super().__init__(*groups)
        self.image = pygame.image.load(self.res_path+image_name)
        self.rect = self.image.get_rect()
        self.speed = speed
        self.mask = pygame.mask.from_surface(self.image)

    def update(self, *args):
        self.rect.y += self.speed


class Background(GameSprite):
    def __init__(self, is_alt, *groups):
        super().__init__("background.png", 1, *groups)
        if is_alt:
            self.rect.y = -self.rect.h

    def update(self, *args):
        super().update(*args)
        if self.rect.y >= self.rect.h:
            self.rect.y = -self.rect.h


class StatusButton(GameSprite):
    def __init__(self, image_names, *groups):
        super().__init__(image_names[0], 0, *groups)
        self.images = [pygame.image.load(self.res_path+name)
                       for name in image_names]

    def switch_status(self, is_pause):
        self.image = self.images[1 if is_pause else 0]


class Label(pygame.sprite.Sprite):
    font_path = "./res/font/VINERITC.TTF"

    def __init__(self, text, size, color, *groups):
        super().__init__(*groups)
        self.font = pygame.font.Font(self.font_path, size)
        self.color = color
        self.image = self.font.render(text, True, self.color)
        self.rect = self.image.get_rect()

    def set_text(self, text):
        self.image = self.font.render(text, True, self.color)
        self.rect = self.image.get_rect()


class Plane(GameSprite):

    def __init__(self, hp, speed, value, wav_name,
                 normal_names, hurt_name, destroy_names, *groups):
        super().__init__(normal_names[0], speed, *groups)
        self.hp = hp
        self.max_hp = hp
        self.value = value
        self.wav_name = wav_name
        self.normal_images = [pygame.image.load(self.res_path + name)
                              for name in normal_names]
        self.normal_index = 0
        self.hurt_image = pygame.image.load(self.res_path + hurt_name)
        self.destroy_images = [pygame.image.load(self.res_path + name)
                               for name in destroy_names]
        self.destroy_index = 0

    def reset_plane(self):
        self.hp = self.max_hp
        self.normal_index = 0
        self.destroy_index = 0
        self.image = self.normal_images[0]

    def update(self, *args):
        if not args[0]:
            return
        if self.hp == self.max_hp:
            self.image = self.normal_images[self.normal_index]
            count = len(self.normal_images)
            self.normal_index = (self.normal_index + 1) % count
        elif self.hp > 0:
            self.image = self.hurt_image
        else:
            if self.destroy_index < len(self.destroy_images):
                self.image = self.destroy_images[self.destroy_index]
                self.destroy_index += 1
            else:
                self.reset_plane()


class Enemy(Plane):
    def __init__(self, kind, max_speed, *groups):
        self.kind = kind
        self.max_speed = max_speed
        if kind == 0:
            super().__init__(1, 1, 1000, "enemy1_down.wav",
                             ["enemy1.png"], "enemy1.png",
                             ["enemy1_down%d.png" % i for i in range(1, 5)], *groups)
        elif kind == 1:
            super().__init__(6, 1, 6000, "enemy2_down.wav",
                             ["enemy2.png"], "enemy2_hit.png",
                             ["enemy2_down%d.png" % i for i in range(1, 5)], *groups)
        else:
            super().__init__(15, 1, 15000, "enemy3_down.wav",
                             ["enemy3_n1.png", "enemy3_n2.png"],
                             "enemy3_hit.png",
                             ["enemy3_down%d.png" % i for i in range(1, 7)], *groups)
        self.reset_plane()

    def reset_plane(self):
        self.speed = random.randint(1, self.max_speed)
        super().reset_plane()
        x = random.randint(0, SCREEN_RECT.w - self.rect.w)
        y = random.randint(0, SCREEN_RECT.h - self.rect.h) - SCREEN_RECT.h
        self.rect.topleft = (x, y)

    def update(self, *args):
        super().update(*args)
        if self.hp > 0:
            self.rect.y += self.speed
        elif self.rect.y >= SCREEN_RECT.h:
            self.reset_plane()


class Hero(Plane):
    def __init__(self, *groups):
        super().__init__(1000, 5, 0, "me_down.wav",
                         ["me%d.png" % i for i in range(1, 3)], "me1.png",
                         ["me_destroy_%d.png" % i for i in range(1, 5)], *groups)
        self.is_power = False
        self.bomb_count = HERO_BOMB_COUNT
        self.bullets_kind = 0
        self.bullets_group = pygame.sprite.Group()
        self.rect.midbottom = HERO_DEFAULT_MID_BOTTOM
        self.bullets_kind = 0
        self.bullets_group = pygame.sprite.Group()
        self.rect.midbottom = HERO_DEFAULT_MID_BOTTOM
        pygame.time.set_timer(HERO_FIRE_EVENT, 200)

    def update(self, *args):
        super().update(*args)
        if len(args) != 3 or self.hp <= 0:
            return
        self.rect.x += args[1] * 3
        self.rect.y += args[2] * 3
        self.rect.x = 0 if self.rect.x < 0 else self.rect.x
        if self.rect.right > SCREEN_RECT.right:
            self.rect.right = SCREEN_RECT.right
        self.rect.y = 0 if self.rect.y < 0 else self.rect.y
        if self.rect.bottom > SCREEN_RECT.bottom:
            self.rect.bottom = SCREEN_RECT.bottom

    def blowup(self, enemies_group):
        if self.bomb_count <= 0 or self.hp <= 0:
            return 0
        self.bomb_count -= 1
        score = 0
        count = 0
        for enemy in enemies_group.sprites():
            score += enemy.value
            count += 1
            enemy.hp = 0
        print("炸毁了 %d 架敌机,得分 %d" % (count, score))
        return score

    def reset_plane(self):
        super().reset_plane()
        self.is_power = True
        self.bomb_count = HERO_BOMB_COUNT
        self.bullets_kind = 0
        pygame.event.post(pygame.event.Event(HERO_DEAD_EVENT))
        pygame.time.set_timer(HERO_POWER_OFF_EVENT, 3000)

    def fire(self, display_group):
        groups = (self.bullets_group, display_group)
        for i in range(3):
            bullet1 = Bullet(self.bullets_kind, *groups)
            y = self.rect.y - i * 15
            if self.bullets_kind == 0:
                bullet1.rect.midbottom = (self.rect.centerx, y)
            else:
                bullet1.rect.midbottom = (self.rect.centerx - 20, y)
                bullet2 = Bullet(self.bullets_kind, *groups)
                bullet2.rect.midbottom = (self.rect.centerx + 20, y)


class Bullet(GameSprite):
    def __init__(self, kind, *groups):
        image_name = "bullet1.png" if kind == 0 else "bullet2.png"
        super().__init__(image_name, -12, *groups)
        self.damage = 1

    def update(self, *args):
        super().update(*args)
        if self.rect.bottom < 0:
            self.kill()


class Supply(GameSprite):
    def __init__(self, kind, *groups):
        image_name = "%s_supply.png" % ("bomb" if kind == 0 else "bullet")
        super().__init__(image_name, 5, *groups)
        self.kind = kind
        self.rect.y = SCREEN_RECT.h

    def throw_supply(self):
        self.rect.bottom = 0
        self.rect.x = random.randint(0, SCREEN_RECT.w - self.rect.w)

    def update(self, *args):
        if self.rect.h > SCREEN_RECT.h:
            return
        super().update(*args)


if __name__ == '__main__':
    pygame.init()
    Game().start()
    pygame.quit()

 

【提示】

部分含有Python第三方库相关内容的作品,在海龟编辑器网页端无法运行哦!如遇到这种情况,可以打开下面的链接,下载海龟编辑器客户端:

https://python.codemao.cn


回复

上一页1 页 / 共 0下一页