Python Test之Game-Plane
简介:使用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
每天多努力那么一点点,积少成多