Python Test之Game-Plane

2020-01-30  本文已影响0人  极客匠

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

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

项目结构

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

需要完成的内容:

代码如下:

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

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

上一篇下一篇

猜你喜欢

热点阅读