【03】做一个精美的打飞机小游戏,规划游戏项目目录-分门别类所有的资源-库-类-逻辑-打包为可玩的exe-练习python打包为可执行exe-优雅草卓伊凡-持续更新-分享源代码和游戏包供游玩-1.0.2版本
背景
之前卓伊凡在AE特效制作处博文已经完整介绍了本款游戏的素材开发,本文开始把素材利用起来放进去,本游戏命名为鹰击长空,Eagles strike across the sky,简称名字ESAS!自从卓伊凡找到了人生的方向,每天就是不停的工作学习工作学习,拒接一切享乐,这就是道,感谢各位看官,涨粉也是对卓伊凡的鼓励。
章节内容03
【03】做一个精美的打飞机小游戏,规划游戏项目目录-分门别类所有的资源-库-类-逻辑-打包为可玩的exe-练习python打包为可执行exe
内容概要
·规划游戏项目目录
·打包为可玩的exe-练习python打包为可执行exe
开源源代码下载地址
https://gitee.com/youyacao/esas
游戏运行包
https://youyacao.lanzouq.com/i60sA2lht5mh
完善飞机大战小游戏-换上制作的特效序列png图片-加入boss机
规划目录结构
常规用python开发游戏我们需要建立以下这样的目录
my_game_project/ ├── assets/ // 游戏资源文件(图像、音效、字体等) │ ├── images/ │ │ ├── player.png │ │ ├── enemy.png │ │ └── background.jpg │ ├── sounds/ │ │ ├── background.mp3 │ │ └── hit.wav │ └── fonts/ │ ├── main.ttf │ └── secondary.ttf ├── config/ // 配置文件 │ └── settings.py ├── data/ // 数据文件(如保存文件) │ └── scores.json ├── docs/ // 文档 │ └── README.md ├── src/ // 源代码 │ ├── __init__.py │ ├── main.py // 主程序入口 │ ├── game.py // 游戏主逻辑 │ ├── player.py // 玩家类 │ ├── enemy.py // 敌人类 │ ├── settings.py // 游戏设置 │ └── utils.py // 辅助函数 ├── tests/ // 单元测试 │ ├── __init__.py │ ├── test_game.py │ ├── test_player.py │ └── test_enemy.py └── requirements.txt // 项目依赖
目录结构解释:
- assets/:存放游戏资源文件,包括图像、音效和字体等。
- config/:存放配置文件,如游戏设置和参数。
- data/:存放数据文件,如保存文件、分数记录等。
- docs/:存放项目文档,如 README 文件。
- src/:存放源代码,包括游戏主逻辑、玩家类、敌人类、游戏设置和辅助函数等。
- tests/:存放单元测试文件,用于测试游戏的各个模块。
- requirements.txt:记录项目依赖的库和版本信息。
目前我们就开始把已有资源进行归类,由于此前我们都是用的一个文件 显然就是不合理的,根据目前已有资源和内容我们应该规划为:
planegame/ │ ├── main.py # 主程序入口 ├── assets/ │ ├── png/ │ │ ├── boss00.png # BOSS 动画帧 │ │ ├── ... │ │ ├── player_100.png # 玩家动画帧 │ │ ├── ... │ │ ├── enemy_10.png # 敌人动画帧 │ │ ├── ... │ │ ├── bullet0.png # 子弹动画帧 │ │ ├── ... │ │ ├── explosion00.png # 爆炸动画帧 │ │ ├── ... │ └── sounds/ │ ├── bullet.wav # 子弹发射音效 │ ├── boss.wav # BOSS 出现背景音乐 │ └── ... ├── src/ │ ├── __init__.py # 使 src 成为一个包 │ ├── game.py # 游戏逻辑代码 │ ├── sprites.py # 精灵类定义 │ └── utils.py # 辅助函数和常量 └── README.md # 项目说明文档
资源文件夹改为assets ,对应代码中也修改,
建立 main.py # 主程序入口 文件,并且内容如下:
import pygame from src.game import Game def main(): pygame.init() game = Game() game.run() pygame.quit() if __name__ == "__main__": main()
新建src目录,下面新建game.py,写入游戏的主逻辑
import pygame from src.sprites import Player, Enemy, Bullet, Boss, Explosion import random import os import sys class Game: def __init__(self): self.screen_width = 720 self.screen_height = 1280 self.screen = pygame.display.set_mode((self.screen_width, self.screen_height)) pygame.display.set_caption("鹰击长空-Eagles strike across the sky-优雅草央千澈") self.clock = pygame.time.Clock() self.running = True self.all_sprites = pygame.sprite.Group() self.all_enemies = pygame.sprite.Group() self.bullets = pygame.sprite.Group() self.player = Player() self.all_sprites.add(self.player) self.all_sprites.add(self.bullets) self.boss_spawned = False self.boss_spawn_time = 10000 # 10秒后生成BOSS self.load_sounds() def load_sounds(self): self.bullet_sound = pygame.mixer.Sound(os.path.join("assets", "sounds", "bullet.wav")) def run(self): while self.running: self.events() self.update() self.draw() self.clock.tick(60) def events(self): for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: self.player.shoot() def update(self): self.all_sprites.update() self.all_enemies.update() # 生成敌人 if random.randint(1, 100) < 5: enemy = Enemy() self.all_enemies.add(enemy) self.all_sprites.add(enemy) # 检测碰撞 hits = pygame.sprite.groupcollide(self.all_enemies, self.bullets, True, True) for hit in hits: explosion = Explosion(hit.rect.center) self.all_sprites.add(explosion) # 检测 BOSS 是否生成 if not self.boss_spawned and pygame.time.get_ticks() > self.boss_spawn_time: boss = Boss() self.all_sprites.add(boss) self.all_enemies.add(boss) self.boss_spawned = True pygame.mixer.music.load(os.path.join("assets", "sounds", "boss.wav")) pygame.mixer.music.play(-1) def draw(self): self.screen.fill((0, 0, 0)) self.all_sprites.draw(self.screen) pygame.display.flip()
下一步,新建sprites.py 文件夹 定义游戏中的所有精灵类,如 Player, Enemy, Bullet, Boss, Explosion均放在此处,
对了有人不知道什么是精灵类,
扩展知识
在游戏开发中,“精灵类”(Sprite)是指游戏中的可视对象,通常用于表示角色、物品、背景等。精灵类的主要职责是管理和渲染这些可视对象,并处理它们的属性和行为。它是2D游戏开发中的一个重要概念。以下是关于精灵类的一些详细介绍:
精灵类的属性
- 图像:精灵通常由一幅或多幅图像组成,用于在屏幕上显示。
- 位置:精灵在屏幕上的坐标位置(x, y)。
- 大小:精灵的宽度和高度。
- 速度:精灵的移动速度和方向。
- 动画帧:如果精灵是动画的,可以包含多个帧来创建动画效果。
精灵类的行为
- 移动:根据速度和方向更新位置。
- 绘制:在游戏的每一帧中将精灵绘制到屏幕上。
- 碰撞检测:检测与其他精灵或环境的碰撞。
- 动画更新:如果是动画精灵,根据时间或事件更新动画帧。
把精灵类代码归纳到本文件:
import pygame import random import os class Boss(pygame.sprite.Sprite): def __init__(self): super().__init__() self.frames = [pygame.image.load(os.path.join("assets", "png", f"boss{i:02d}.png")).convert_alpha() for i in range(10)] self.frame = 0 self.image = self.frames[self.frame] self.rect = self.image.get_rect(center=(360, -100)) self.last_update = pygame.time.get_ticks() self.frame_rate = 100 self.health = 100 self.move_direction = 1 self.move_speed = 2 self.shoot_delay = 1000 self.last_shot = pygame.time.get_ticks() def update(self): self.rect.y += 2 if self.rect.top > 0: self.rect.x += self.move_speed * self.move_direction if self.rect.right > 720 or self.rect.left < 0: self.move_direction *= -1 now = pygame.time.get_ticks() if now - self.last_update > self.frame_rate: self.last_update = now self.frame = (self.frame + 1) % len(self.frames) self.image = self.frames[self.frame] if now - self.last_shot > self.shoot_delay: self.last_shot = now self.shoot() def shoot(self): bullet = Bullet(self.rect.centerx, self.rect.bottom) self.bullets.add(bullet) class Player(pygame.sprite.Sprite): # 类似于 Boss 类的定义 pass class Bullet(pygame.sprite.Sprite): # 类似于 Boss 类的定义 pass class Enemy(pygame.sprite.Sprite): # 类似于 Boss 类的定义 pass class Explosion(pygame.sprite.Sprite): # 类似于 Boss 类的定义 pass
新建辅助函数文件utils.py
import pygame import os def load_image(filename): return pygame.image.load(os.path.join("assets", "png", filename)).convert_alpha() def load_sound(filename): return pygame.mixer.Sound(os.path.join("assets", "sounds", filename))
整理完毕 运行
报错,
这个错误表明 Python 无法找到 src 模块。这通常是由于 Python 解释器无法正确识别 src 目录为一个包。以下是一些可能的解决方案:
确保 src 目录包含 init.py 文件:
init.py 文件可以是空的,但它的存在告诉 Python 这个目录是一个包。
确保 src 目录下有一个 init.py 文件。
也就是说我必须建立 init.py 文件,哪怕为空,ok建立好了再次运行
继续报错,这个是因为 Player 对象没有 image 属性。在 Pygame 中,pygame.sprite.Sprite 类要求每个精灵对象必须有一个 image 属性,因为 draw 方法会使用这个属性来绘制精灵。
让我们检查 Player 类的定义,确保它正确地设置了 image 属性。
修改game.py
# src/game.py import pygame from src.sprites import Player, Enemy, Bullet, Boss, Explosion import random import os import sys # 加载图像 player_frames = [] for i in range(12): # 假设有12帧,从player_100.png到player_111.png frame = pygame.image.load(os.path.join("assets", "png", f"player_{100 + i:03d}.png")).convert_alpha() frame = pygame.transform.scale(frame, (150, 150)) # 调整为150x150像素 player_frames.append(frame) class Game: def __init__(self): self.screen_width = 720 self.screen_height = 1280 self.screen = pygame.display.set_mode((self.screen_width, self.screen_height)) pygame.display.set_caption("鹰击长空-Eagles strike across the sky-优雅草央千澈") self.clock = pygame.time.Clock() self.running = True self.all_sprites = pygame.sprite.Group() self.all_enemies = pygame.sprite.Group() self.bullets = pygame.sprite.Group() self.player = Player() self.all_sprites.add(self.player) self.all_sprites.add(self.bullets) self.boss_spawned = False self.boss_spawn_time = 10000 # 10秒后生成BOSS self.load_sounds() def load_sounds(self): self.bullet_sound = pygame.mixer.Sound(os.path.join("assets", "sounds", "bullet.wav")) def run(self): while self.running: self.events() self.update() self.draw() self.clock.tick(60) def events(self): for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: self.player.shoot() def update(self): self.all_sprites.update() self.all_enemies.update() # 生成敌人 if random.randint(1, 100) < 5: enemy = Enemy() self.all_enemies.add(enemy) self.all_sprites.add(enemy) # 检测碰撞 hits = pygame.sprite.groupcollide(self.all_enemies, self.bullets, True, True) for hit in hits: explosion = Explosion(hit.rect.center) self.all_sprites.add(explosion) # 检测 BOSS 是否生成 if not self.boss_spawned and pygame.time.get_ticks() > self.boss_spawn_time: boss = Boss() self.all_sprites.add(boss) self.all_enemies.add(boss) self.boss_spawned = True pygame.mixer.music.load(os.path.join("assets", "sounds", "boss.wav")) pygame.mixer.music.play(-1) def draw(self): self.screen.fill((0, 0, 0)) self.all_sprites.draw(self.screen) pygame.display.flip()
然后几经折腾,基本上就是 类没有初始化之类的问题,或者 Enemy 类的 init 方法中,enemy_frames 未被定义。同样地,boss_frames 和 bullet_frames 也会遇到类似的问题,经过了 1个小时的处理,终于好了
处理好了以后可以正常运行了终于,成功了,
由于文章篇幅问题,我们开始进行打包工作,python 游戏 项目 如何 直接打包为可执行exe
要将一个 Python 游戏项目打包为可执行的 EXE 文件,可以使用 PyInstaller
这个工具:
安装 PyInstaller
首先,你需要安装 PyInstaller
。你可以通过 pip
来安装:
pip install pyinstaller
安装成功
项目主文件是 main.py
,
使用 PyInstaller 打包项目
进入你的项目目录,然后运行以下命令:
pyinstaller --onefile main.py
直接执行,在卓伊凡的目录下,
这个命令将生成一个单独的 EXE 文件。--onefile
选项表示将所有内容打包到一个文件中,ok 现在分享蓝奏云
直接成功 15993 INFO: Copying bootloader EXE to G:\clone\esas\dist\main.exe
15995 INFO: Copying icon to EXE
想必通过此文,也知道python项目如何打包exe了吧