美文网首页
Python Test之Game-Plane

Python Test之Game-Plane

作者: 极客匠 | 来源:发表于2020-01-30 14:48 被阅读0次

    简介:使用pygame库来做打飞机的小游戏,由键盘控制飞机的移动,消灭敌机,声音效果展示。代码参考网上,自己也做了一些优化。掌握核心知识pygame的API使用,python代码模块化,面向对象编程思想,通过这些练习来增加python经验值。。

    基础知识

    • 基于python面向对象编程思想
    • pygame知识了解
    • python代码模块化

    在下面的代码中会大量见到pygame.sprite模块。“sprite”在游戏动画中一般指一个独立运动的画面元素。在pygame中,就可以是一个带有图像(Surface)和大小位置(Rect)的对象,简称:一个会动的图片。它的两个成员变量:

    - self.image : 要显示的图片的Surface
    - Self.rect : 显示Surface的区域
    

    对于self.rect,常用的设置方法:self.rect = self.image.get_rect()。pygame.sprite.Sprite是pygame.sprite的基类,一般来说,总是需要写一个自己的精灵类继承它,然后加入自己的代码。

    需求描述

    在屏幕上我们能看见得就是自己的飞机、子弹、敌人的飞机。因此整个游戏的核心就是:

    - 把这三个东西的图像展示在屏幕上
    - 判断和处理子弹撞击敌机和敌机撞击玩家飞机这两种情况
    

    整体框架

    这个游戏设计用到了面向对象的编程思想。

    游戏主体为:玩家飞机(plane)、子弹(bullet)、敌机(enemy)。

    通过面向对象思想把这三个游戏主体划分为三个主要的类:

    • 玩家飞机类 class Plane
    • 子弹类 class Bullet
    • 敌机类 class SmallEnemyPlane

    项目结构

    python代码模块化开发

    """
    GamePlane/
    |-- bin/
    |  |-- main.py     程序运行主体程序
    |-- conf/
    |  |-- settings.py   程序配置(例如: 游戏背景音乐的加载等)
    |-- res      程序素材放置(打飞机游戏素材放置)
      ``|-- ...
    |-- src/        程序主体模块存放
    |  |-- __init__.py
    |  |-- bullet.py    我方飞机发射子弹实现代码存放
    |  |-- enemy.py    敌方飞机实现代码存放
    |  |-- plane.py    我方飞机实现代码存放
    |-- manage.py      程序启动文件
    |-- README.md     
    """
    

    代码示例

    一、在conf/setting.py中实现以下功能:

    - 游戏初始化
    - 游戏混音器初始化
    - 背景音乐初始化
    - 子弹发射声音初始化
    - 玩家飞机声音初始化
    - 敌机声音初始化
    
    import pygame
    import os
    
    # 学习python常量开发 相对路径 pygame资源加载 初始化 混音器初始化
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    
    BG_IMG = "res/image/background.png"
    GAME_MUSIC = "res/sound/game_music.wav"
    BULLET_MUSIC = "res/sound/bullet.wav"
    GAME_OVER_MUSIC = "res/sound/game_over.wav"
    ENEMY_OVER_MUSIC = "res/sound/enemy1_down.wav"
    
    #游戏初始化,混音器初始化
    pygame.init()
    pygame.mixer.init()
    
    
    
    #加载资源
    game_sound = pygame.mixer.music.load(GAME_MUSIC)  # 背景音乐声音设置
    pygame.mixer.music.set_volume(0.2)
    
    
    bullet_sound = pygame.mixer.Sound(BULLET_MUSIC) # 子弹发射声音设置
    bullet_sound.set_volume(0.3)
    
    game_over_sound = pygame.mixer.Sound(GAME_OVER_MUSIC)  # 游戏结束声音设置
    game_over_sound.set_volume(0.3)
    
    enemy_over_sound = pygame.mixer.Sound(ENEMY_OVER_MUSIC) # 敌军被消灭声音设置
    enemy_over_sound.set_volume(0.3)
    

    初始化配置好了,我们来测试一下。那么首先我们要在屏幕上制作一个游戏板,根据上面setting.py配置,并让她有声音播放。如下展示:

    import sys
    
    from conf.setting import *
    
    bg_size = 480, 852  # 初始化游戏背景大小(宽, 高)
    screen = pygame.display.set_mode(bg_size)  # 设置背景对话框
    pygame.display.set_caption("飞机大战")  # 设置标题
    
    background = pygame.image.load(os.path.join(BASE_DIR, "res/image/background.png"))  # 加载背景图片,并设置为不透明
    
    
    def main():
        pygame.mixer.music.play(-1)  # loops 对应的值为 -1 则音乐会无限循环播放
    
        while True:
            # 绘制背景图
            screen.blit(background, (0, 0))
    
            # 响应用户的操作(一定要有响应的用户操作)
            for event in pygame.event.get():
                if event.type == 12:  # 如果用户按下屏幕上的关闭按钮,触发QUIT事件,程序退出
                    pygame.quit()
                    sys.exit()
    
            # 再而我们将背景图像并输出到屏幕上面
            pygame.display.flip()
    
    
    if __name__ == '__main__':
        main()
    
    image

    二、子弹类 class Bullet

    需要完成的内容:子弹按照我方飞机正中上方发射及频率调控,重置。代码如下:

    import pygame
    
    
    class Bullet(pygame.sprite.Sprite):
    
        def __init__(self, position):
            super(Bullet, self).__init__()
            self.image = pygame.image.load("res/image/bullet1.png")
            self.rect = self.image.get_rect()
            self.rect.left, self.rect.top = position
            self.speed = 30
            self.active = True
            self.mask = pygame.mask.from_surface(self.image)
    
        def move(self):
            if self.rect.top < 0:
                self.active = False
    
            else:
                self.rect.top -= self.speed
    
        def reset(self, position):
            self.rect.left, self.rect.top = position
            self.active = True
    
    

    三、飞机类Plane

    需要完成的内容:

    • 飞机的初始位置
    • 通过按键来控制飞机的位置移动,上下左右,wasd
    • 飞机只能在游戏画布中移动
    • 飞机的速度
    • 飞机死亡加载
    • 飞机喷气式效果
    • 飞机的存活状态

    代码如下:

    import pygame
    
    # 学习pygame image load mask
    class Plane(pygame.sprite.Sprite):
    
        def __init__(self, bg_size):
            super(Plane, self).__init__()
            self.image_one = pygame.image.load("res/image/hero1.png")
            self.image_two = pygame.image.load("res/image/hero2.png")
            self.rect = self.image_one.get_rect()
            self.width,self.height=bg_size[0],bg_size[1]
            self.mask = pygame.mask.from_surface(self.image_one)
            self.rect.left,self.rect.top = (self.width - self.rect.width) // 2, (self.height - self.rect.height - 60)
            self.speed = 10
            self.active = True
            self.destroy_images = []
            self.destroy_images.extend(
                [
                    pygame.image.load("res/image/hero_blowup_n1.png"),
                    pygame.image.load("res/image/hero_blowup_n2.png"),
                    pygame.image.load("res/image/hero_blowup_n3.png"),
                    pygame.image.load("res/image/hero_blowup_n4.png")
                ]
            )
    
        def move_up(self):
            if self.rect.top > 0:
                self.rect.top -= self.speed
            else:
                self.rect.top = 0
    
        def move_down(self):
            if self.rect.bottom < self.height - 60:
                self.rect.bottom += self.speed
            else:
                self.rect.bottom = self.height - 60
        def move_left(self):
            if self.rect.left > 0 :
                self.rect.left -= self.speed
            else:
                self.rect.left = 0
        def move_right(self):
            if self.rect.right < self.width:
                self.rect.right += self.speed
            else:
                self.rect.right = self.width
    
        def reset(self):
            self.rect.left, self.rect.top = (self.width - self.rect.width) // 2, (self.height - self.rect.height - 60)
            self.active = True
    

    四、敌机类 class SmallEnemyPlane

    需要完成的内容:

    • 敌机随机出现,移动及重置
    from random import randint
    import pygame
    
    
    # 学习random,randint
    class SmallEnemyPlane(pygame.sprite.Sprite):
    
        def __init__(self, bg_size):
            super(SmallEnemyPlane, self).__init__()
            self.image = pygame.image.load("res/image/enemy1.png")
            self.rect = self.image.get_rect()
            self.width, self.height = bg_size[0], bg_size[1]
            self.mask = pygame.mask.from_surface(self.image)  # 获取图像的掩膜用以更加精确得碰撞检测
            self.speed = 2
            self.rect.left, self.rect.top = (randint(0, self.width - self.rect.width), randint(-5 * self.rect.height, -5))
            self.active = True
            self.destroy_images = []
            self.destroy_images.extend(
                [
                    pygame.image.load("res/image/enemy1_down1.png"),
                    pygame.image.load("res/image/enemy1_down2.png"),
                    pygame.image.load("res/image/enemy1_down3.png"),
                    pygame.image.load("res/image/enemy1_down4.png")
                ])
    
        def move(self):
            if self.rect.top < self.height:
                self.rect.top += self.speed
            else:
                self.reset()
    
        def reset(self):
            self.rect.left, self.rect.top = (randint(0, self.width - self.rect.width), randint(-5 * self.rect.height, -5))
            self.active = True
    
    

    五、在main.py中实现主要游戏的逻辑功能

    • 初始化背景图大小

    • 游戏主体循环及帧率设定

    • 游戏飞机的大小、移动及子弹发射

    • 敌方飞机移动

    • 游戏飞机及敌方飞机的碰撞检测及效果

    • 子弹和敌方飞机的碰撞检测及效果

    • 键盘按键监听,并做对应操作

    import sys
    import pygame
    
    from pygame.constants import *
    
    from conf.setting import *
    from src.plane import Plane
    from src.enemy import SmallEnemyPlane
    from src.bullet import Bullet
    
    # 学习pygame 音频循环 游戏画面渲染 键盘事件处理  clock
    bg_size = 480, 852
    screen = pygame.display.set_mode(bg_size)  # 设置窗口的宽高
    pygame.display.set_caption("Game-Plane")
    bg_img = pygame.image.load(os.path.join(BASE_DIR, BG_IMG))
    
    
    def add_small_enemy(enemy_groups1, enemy_groups2, num):
        for i in range(num):
            small_enemy = SmallEnemyPlane(bg_size)
            enemy_groups1.add(small_enemy)
            enemy_groups2.add(small_enemy)
    
    
    def add_bullet(our_plane, bullets_group, num):
        for i in range(num):
            bullet = Bullet(our_plane.rect.midtop)
            bullets_group.append(bullet)
    
    
    def main():
        pygame.mixer.music.play(-1)
        our_plane = Plane(bg_size)
        switch_image = False  # 定义飞机的切图效果标识
        delay_time = 60
        running = True
    
        enemies = pygame.sprite.Group()
        small_enemies = pygame.sprite.Group()
        add_small_enemy(enemies, small_enemies, 4)
    
        bullet_index = 0
        e1_destroy_index = 0
        plane_destroy_index = 0
    
        bullet1 = []
        bullet_num = 10
        add_bullet(our_plane, bullet1, bullet_num)
    
        #游戏循环
        while running:
            screen.blit(bg_img, (0, 0))
            
                    #帧率设定
            clock = pygame.time.Clock()
            clock.tick(60)
    
            if not delay_time % 3:
                switch_image = not switch_image
    
            for small_enemy in small_enemies:
                if small_enemy.active:
                    for e in small_enemies:
                        e.move()
                        screen.blit(e.image, e.rect)
                else:
                    if e1_destroy_index == 0:
                        enemy_over_sound.play()
                    screen.blit(small_enemy.destroy_images[e1_destroy_index], small_enemy.rect)
                    e1_destroy_index = (e1_destroy_index + 1) % 4
                    if e1_destroy_index == 0:
                        small_enemy.reset()
    
            if our_plane.active:
                if switch_image:
                    screen.blit(our_plane.image_one, our_plane.rect)
                else:
                    screen.blit(our_plane.image_two, our_plane.rect)
                if not (delay_time % 10):
                    bullet_sound.play()
                    bullets = bullet1
                    bullets[bullet_index].reset(our_plane.rect.midtop)
                    bullet_index = (bullet_index + 1) % bullet_num
    
                for bullet in bullets:
                    if bullet.active:
                        bullet.move()
                        screen.blit(bullet.image, bullet.rect)
                        enemies_hit = pygame.sprite.spritecollide(bullet, enemies, False, pygame.sprite.collide_mask)
                        if enemies_hit:
                            bullet.active = False
                            for e in enemies_hit:
                                e.active = False
            else:
                if not (delay_time % 3):
                    screen.blit(our_plane.destroy_images[plane_destroy_index], our_plane.rect)
                    plane_destroy_index = (plane_destroy_index + 1) % 4
                    if plane_destroy_index == 0:
                        game_over_sound.play()
                        our_plane.reset()
            plane_enemy_hit = pygame.sprite.spritecollide(our_plane, enemies, False, pygame.sprite.collide_mask)
            if plane_enemy_hit:
                our_plane.active = False
                for e in enemies:
                    e.active = False
            if delay_time == 0:
                delay_time = 60
            delay_time -= 1
    
            key_pressed = pygame.key.get_pressed()
            if key_pressed[K_a] or key_pressed[K_LEFT]:
                our_plane.move_left()
            elif key_pressed[K_w] or key_pressed[K_UP]:
                our_plane.move_up()
            elif key_pressed[K_d] or key_pressed[K_RIGHT]:
                our_plane.move_right()
            elif key_pressed[K_s] or key_pressed[K_DOWN]:
                our_plane.move_down()
            if key_pressed[K_j]:
                our_plane.active = False
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
            # 再而我们将背景图像并输出到屏幕上面
            pygame.display.flip()
    
    
    if __name__ == "__main__":
        main()
    
    

    六、运行main()就可以打飞机了

    from bin.main import main
    
    # 学习python 模块化架构开发
    if __name__ == "__main__":
        main()
    

    实际效果

    Foxmail20200130024017.png

    ](/Users/huangdaju/Desktop/Foxmail20200130024017.png)

    代码链接:https://github.com/trk-huang/Game-plane

    每天多努力那么一点点,积少成多

    相关文章

      网友评论

          本文标题:Python Test之Game-Plane

          本文链接:https://www.haomeiwen.com/subject/iyvithtx.html