飞机大战
使用pygame进行游戏开发
安装pygame
- “win”+R:输入cmd,打开黑窗口
- 输入:
pip install pygame
- 验证安装:
python -m pygame.examples.aliens
所遇问题
打开pycharm,输入import pygame
可能会遇到的问题:
ModuleNotFoundError: No module named 'pygame'
解决方法(这里只说我自己遇到的问题啦):
看pycharm中输入import pygame
所在文件是否与pygame安装环境匹配。
我最初把pygame安装到了base环境中,而写入的文件时pt环境,那如何进入pt环境:cmd中输入:activate pt 后再安装一次pygame,解决了上述问题。
飞机大战写成两个文件
两个文件
plane_sprites.py文件:封装游戏精灵文件
plane_main.py文件:游戏主程序(封装游戏主类,创建游戏对象,启动游戏)
代码展示
- plane_sprites.py文件
import pygame
import random
# 封装的游戏精灵文件
# 1.背景图片的尺寸
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
# 2.创建敌机的事件id、用户事件id
CREATE_ENEMY_EVENT = pygame.USEREVENT
HERO_FIRE_EVENT = pygame.USEREVENT + 1
# 游戏精灵
class Gamesprites(pygame.sprite.Sprite):
# 初始化方法
def __init__(self, image_name, speed = 1):
# 必须调用父类的init方法
super().__init__()
# 1.精灵的图片
self.image = pygame.image .load(image_name)
# 2.精灵的尺寸
self.rect = self.image.get_rect()
# 3.记录速度
self.speed = speed
def update(self, *args):
self.rect.y += self.speed
# 二.背景精灵
# 背景精灵,基础GameSprites
# 背景精灵有两张图片,first:(0, 0); second:(0, -自身高度)
# 循环动画
class BackgroundSprites(Gamesprites):
def update(self, *args):
super().update()
# 循环动画,使图片连续播放:判断图片位置,若>=自身高度(700),重新从-700开始
if self.rect.y >= self.rect.height:
self.rect.y = -self.rect.height
class Enemy(Gamesprites):
def __init__(self):
# 1.指定敌机的图片
super().__init__("../images/enemy1.png")
# 2.设置随机的初始速度
self.speed = random.randint(1, 3)
# 3.设置随机的初始位置
self.rect.bottom = 0
max_x = SCREEN_RECT.width - self.rect.width
self.rect.x = random.randint(0, max_x)
def update(self, *args):
# 1.调用父类,让敌机可以垂直移动
super().update()
# 2.如果敌机飞出屏幕,从精灵组删除
if self.rect.y >= SCREEN_RECT.height:
# print("敌机飞出屏幕...")
self.kill()
# 重写del方法,打印敌机销毁
def __del__(self):
print(f"本机挂了,{self.rect}")
class Hero(Gamesprites):
def __init__(self):
# 战机图片
super().__init__("../images/me1.png")
# 初始位置:水平居中,垂直方向距离底部120
self.rect.centerx = SCREEN_RECT.centerx
# self.rect.y = SCREEN_RECT.height - self.rect.height - 120
self.rect.bottom = SCREEN_RECT.bottom - 120
# 飞机的上下键移动方向:1(水平),2(垂直)
self.direction = 1
# 子弹精灵组
self.bullet_group = pygame.sprite.Group()
def update(self, *args):
if self.direction == 1:
self.rect.x += self.speed
# 定义飞机左右范围:坐标原点在左上角,self.rect.left是y坐标轴,而右边是无限大,选取SCREEN.RECT.right
if self.rect.left < 0:
self.rect.left = 0
elif self.rect.right > SCREEN_RECT.right:
self.rect.right = SCREEN_RECT.right
else:
super().update()
if self.rect.y < 0:
self.rect.y = 0
elif self.rect.bottom > SCREEN_RECT.bottom:
self.rect.bottom = SCREEN_RECT.bottom
def fire(self):
print("发射子弹...")
for i in (1, 2, 3, 4):
# 创建子弹精灵
bullet = Bullet()
# 子弹的位置:水平在飞机中间,垂直在飞机头部+20
bullet.rect.centerx = self.rect.centerx
bullet.rect.bottom = self.rect.top - 15*i
self.bullet_group.add(bullet)
# 子弹类
class Bullet(Gamesprites):
def __init__(self):
super().__init__("../images/bullet2.png", -2)
def update(self, *args):
super().update()
if self.rect.y <= 0:
self.kill()
- plane_main.py文件
import pygame
from plane_sprites import*
# 游戏主程序
# 1.封装游戏主类
# 2.创建 游戏对象
# 3.启动游戏
class PlaneGame(object):
# 1.初始化方法
def __init__(self):
print("游戏初始化")
pygame.init()
# (1)创建游戏窗口
# self.screen = pygame.display.set_mode((480, 700))
# size返回矩形区域的宽高,以元组形式返回
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
# (2)设置游戏时钟
self.clock = pygame.time.Clock()
# (3)调用创建精灵和精灵组的方法
self.__creat_sprites()
# 需求:通过定时器,每隔1s添加一架敌机
# pygame.time.set_timer(事件id, 间隔时间单位ms)
pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)
pygame.time.set_timer(HERO_FIRE_EVENT, 400)
# 1.1 私有方法:创建精灵,创建精灵组
def __creat_sprites(self):
# (1)背景组
# 背景精灵
bg1 = BackgroundSprites("../images/background.png")
bg2 = BackgroundSprites("../images/background.png")
# 第二张图片的位置是负的自身高度
bg2.rect.y = -bg2.rect.height
self.back_group = pygame.sprite.Group(bg1, bg2)
# (2)敌机组
self.enemy_group = pygame.sprite.Group()
# (3)英雄组
self.hero = Hero()
self.hero_group = pygame.sprite.Group(self.hero)
# 2. 开始游戏
def start_game(self):
print("开始游戏")
while True:
# (0).设置刷新帧率60
self.clock.tick(60)
# (1)事件监听
self.__event_handler()
# (2)碰撞检测
self.__check_collide()
# (3)更新精灵
self.__update_sprites()
# (4)更新屏幕
pygame.display.update()
# 2.1 事件监听
def __event_handler(self):
even_list = pygame.event.get()
for event in even_list:
if event.type == pygame.QUIT:
self.__game_over()
elif event.type == CREATE_ENEMY_EVENT:
print("敌机出场...")
# 给敌机组添加敌机
self.enemy_group.add(Enemy())
# 移动英雄的位置
# 方式一:event.type用户必须抬起按键才算一次,操作灵活性不高
elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
print("按下右键")
self.hero.speed = 3
self.hero.direction = 1
elif event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
print("按下左键")
self.hero.speed = -3
self.hero.direction = 1
elif event.type == pygame.KEYDOWN and event.key == pygame.K_UP:
print("按下上键")
self.hero.speed = -3
self.hero.direction = 2
elif event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN:
print("按下下键")
self.hero.speed = 3
self.hero.direction = 2
elif event.type == HERO_FIRE_EVENT:
self.hero.fire()
else:
self.hero.speed = 0
# 方式二:用户按住方向键不放,就能实现持续向某个方向移动,操作灵活性高
# keys_pressed = pygame.key.get_pressed() # 写在for循环外
# elif keys_pressed[pygame.K_RIGHT]:
# self.hero.speed = 2
# elif keys_pressed[pygame.K_LEFT]:
# self.hero.speed = -2
# else:
# self.hero.speed = 0
# 2.2 碰撞检测(子弹销毁敌机,敌机销毁英雄)
def __check_collide(self):
# 子弹摧毁敌机
pygame.sprite.groupcollide(self.hero.bullet_group, self.enemy_group, True, True)
# 敌机撞毁英雄
enemies = pygame.sprite.spritecollide(self.hero, self.enemy_group, True)
# 判断列表时候有内容
if len(enemies) > 0:
# 让英雄牺牲
self.hero.kill()
# 结束游戏
self.__game_over()
# 2.3 精灵组更新和绘制
def __update_sprites(self):
# # 更新精灵组的位置
# self.back_group.update()
# # 更新后的位置,传到屏幕上
# self.back_group.draw(self.screen)
#
# self.enemy_group.update()
# self.enemy_group.draw(self.screen)
#
# self.hero_group.update()
# self.hero_group.draw(self.screen)
# 优化方法:将各个组放入列表中。然后循环调用updata、draw
for group in [self.back_group, self.enemy_group, self.hero_group, self.hero.bullet_group]:
# 更新
group.update()
# 绘制
group.draw(self.screen)
# 2.4 游戏结束
def __game_over(self):
print("点击了右上角的按钮,退出游戏")
# 退出游戏
pygame.quit()
# 停止程序的运行
exit()
# 以下没有缩进,不是PlaneGame类的代码
if __name__ == "__main__":
game = PlaneGame()
game.start_game()