【Python实战】飞机大战

开发一个飞机大战游戏是Python学习的经典实战项目,尤其适合结合面向对象编程和游戏框架(如Pygame)进行实践。以下是游戏设计的核心考虑因素和模块划分建议:


一、游戏设计核心考虑因素

  1. 性能优化

    • Python游戏需注意帧率控制(如60FPS)
    • 避免频繁的对象创建/销毁(使用对象池管理子弹、敌机)
    • 减少图像缩放等实时计算操作(预加载缩放后的图片)
  2. 游戏循环(Game Loop)

    • 主循环需要处理:事件监听→状态更新→画面渲染→音效播放
    • 控制循环频率(如pygame.time.Clock().tick(60)
  3. 输入控制

    • 响应键盘事件(WSAD/方向键移动,空格发射子弹)
    • 支持手柄输入(可选扩展)
  4. 碰撞检测

    • 使用矩形碰撞(pygame.Rect.colliderect
    • 优化检测效率(分组检测:玩家子弹 vs 敌机、敌机 vs 玩家)
  5. 游戏状态管理

    • 区分不同场景:开始界面、游戏中、暂停、结束界面
    • 使用状态机或场景堆栈管理(如game_state = "playing"
  6. 资源管理

    • 集中加载图片、音效、字体(避免重复IO操作)
    • 使用相对路径确保跨平台兼容性
  7. 可扩展性

    • 模块化设计,方便新增敌机类型、武器系统
    • 配置数据分离(如敌机属性存于JSON文件)

二、游戏核心模块划分

1. 游戏主模块(Main Game)
# ====================== 游戏主逻辑 ======================
class Game:def __init__(self):# 初始化显示self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))pygame.display.set_caption("飞机大战")self.clock = pygame.time.Clock()# 加载资源self.load_resources()# 游戏状态self.running = Trueself.score = 0def load_resources(self):"""加载所有资源"""global shoot_sound, explosion_soundshoot_sound = load_sound("pew.wav")explosion_sound = load_sound("expl3.wav")# 初始化精灵组self.all_sprites = pygame.sprite.Group()self.enemies = pygame.sprite.Group()self.bullets = pygame.sprite.Group()# 创建玩家self.player = Player()self.all_sprites.add(self.player)# 创建敌机组self.enemy_spawn_timer = pygame.USEREVENT + 1pygame.time.set_timer(self.enemy_spawn_timer, 1000)  # 每秒生成敌机def handle_events(self):"""处理事件循环"""for event in pygame.event.get():if event.type == pygame.QUIT:self.running = Falseelif event.type == pygame.KEYDOWN:if event.key == pygame.K_ESCAPE:self.running = Falseelif event.type == self.enemy_spawn_timer:enemy = Enemy()self.all_sprites.add(enemy)self.enemies.add(enemy)def check_collisions(self):"""检测碰撞事件"""# 子弹击中敌机hits = pygame.sprite.groupcollide(self.enemies, self.bullets, True, True)for hit in hits:self.score += 50explosion_sound.play()# 敌机撞击玩家hits = pygame.sprite.spritecollide(self.player, self.enemies, True)for hit in hits:self.player.health -= 1if self.player.health <= 0:self.game_over()def draw_hud(self):"""绘制游戏界面HUD"""# 绘制得分font = pygame.font.Font(None, 36)score_text = font.render(f"Score: {self.score}", True, WHITE)self.screen.blit(score_text, (10, 10))# 绘制生命值health_text = font.render(f"Health: {self.player.health}", True, RED)self.screen.blit(health_text, (10, 50))def game_over(self):"""游戏结束处理"""font = pygame.font.Font(None, 74)text = font.render("GAME OVER", True, RED)text_rect = text.get_rect(center=(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2))self.screen.blit(text, text_rect)pygame.display.flip()pygame.time.wait(10000)  # 等待2秒self.running = Falsedef run(self):"""游戏主循环"""while self.running:# 控制帧率self.clock.tick(FPS)# 处理输入self.handle_events()keys = pygame.key.get_pressed()if keys[pygame.K_SPACE]:self.player.shoot(self.bullets, self.all_sprites)# 更新游戏状态self.all_sprites.update(keys)  # 更新所有精灵self.check_collisions()# 渲染画面self.screen.fill(BLACK)self.all_sprites.draw(self.screen)self.draw_hud()pygame.display.flip()pygame.quit()
2. 精灵类(Sprites)

使用面向对象设计游戏元素:

  • Player(玩家飞机)

      """玩家飞机类"""def __init__(self):super().__init__()self.image = load_image("player.png")self.rect = self.image.get_rect(center=(SCREEN_WIDTH / 2, SCREEN_HEIGHT - 50))self.speed = PLAYER_SPEEDself.health = 3self.shoot_delay = 250  # 射击间隔(毫秒)self.last_shot = pygame.time.get_ticks()def update(self, keys):"""根据键盘输入更新位置"""# 水平移动if keys[pygame.K_LEFT] or keys[pygame.K_a]:self.rect.x -= self.speedif keys[pygame.K_RIGHT] or keys[pygame.K_d]:self.rect.x += self.speed# 垂直移动(可选)if keys[pygame.K_UP] or keys[pygame.K_w]:self.rect.y -= self.speedif keys[pygame.K_DOWN] or keys[pygame.K_s]:self.rect.y += self.speed# 边界约束self.rect.clamp_ip(pygame.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))def shoot(self, bullets, all_sprites):"""发射子弹"""now = pygame.time.get_ticks()if now - self.last_shot > self.shoot_delay:self.last_shot = nowbullet = Bullet(self.rect.centerx, self.rect.top)all_sprites.add(bullet)bullets.add(bullet)shoot_sound.play()
    
  • Enemy(敌机)

      def __init__(self):super().__init__()self.image = load_image("enemy1.png")self.rect = self.image.get_rect()self.rect = self.image.get_rect(x=random.randrange(SCREEN_WIDTH - self.rect.width),y=random.randrange(-100, -40),)self.speed_y = random.randint(*ENEMY_SPEED_RANGE)self.speed_x = random.choice([-1, 0, 1])  # 横向移动def update(self, *args):"""自动向下移动"""self.rect.y += self.speed_yself.rect.x += self.speed_x# 移出屏幕后删除if self.rect.top > SCREEN_HEIGHT + 10:self.kill()
    
  • Bullet(子弹)

      def __init__(self, x, y):super().__init__()self.image = load_image("bullet3.png")self.rect = self.image.get_rect(center=(x, y))self.speed_y = BULLET_SPEEDdef update(self, *args):"""向上移动"""self.rect.y += self.speed_yif self.rect.bottom < 0:  # 移出屏幕后删除self.kill()
    

三、推荐技术栈

  1. 游戏框架

    • Pygame:最适合2D游戏入门,文档丰富
      Pygame官方文档
    • Arcade:现代Python游戏库,面向对象更友好
      Arcade官网
  2. 素材资源

    • 免费素材网站:OpenGameArt、Kenney Assets
    • 临时占位素材:可用简单几何图形代替
  3. 代码结构参考

    • GitHub经典项目:pygame-shmup
    • 教程:Pygame飞机大战教程

四、开发路线建议

  1. 基础版本(1-3天)

    • 实现玩家移动、发射子弹
    • 随机生成敌机,碰撞检测得分
    • 显示血量和分数
  2. 进阶版本(3-7天)

    • 添加不同敌机类型(普通/快速/BOSS)
    • 实现敌机发射子弹
    • 增加音效和爆炸动画
    • 支持游戏暂停/继续
  3. 扩展版本(可选)

    • 添加道具系统(护盾、连发武器)
    • 实现关卡进度和难度曲线
    • 支持本地高分榜(SQLite存储)
    • 打包为exe/APK文件

五、避坑指南

  1. 不要过早优化:先完成核心玩法,再考虑性能
  2. 善用精灵组(Sprite Groups)pygame.sprite.Group()管理同类对象
  3. 坐标系注意:Pygame的Y轴向下增大(与数学坐标系相反)
  4. 资源路径问题:使用os.path处理路径,避免绝对路径硬编码
  5. 调试技巧:用print输出变量或绘制调试矩形(pygame.draw.rect

通过分阶段实现,你将逐步掌握游戏开发的核心模式(状态机、对象池、事件驱动),同时巩固Python面向对象编程和模块化设计能力。

六、总体代码(单文件)

# -*- coding: utf-8 -*-
import pygame
import random
import os# 初始化Pygame和混音器
pygame.init()
pygame.mixer.init()# 游戏常量配置
SCREEN_WIDTH = 480
SCREEN_HEIGHT = 600
FPS = 60
PLAYER_SPEED = 5
ENEMY_SPEED_RANGE = (2, 4)
BULLET_SPEED = -8  # 玩家子弹速度(向上)# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)# 资源路径配置
game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, "images")
snd_folder = os.path.join(game_folder, "sounds")# 加载图形资源
def load_image(file):"""加载图像并转换格式,返回图像和矩形"""path = os.path.join(img_folder, file)try:image = pygame.image.load(path).convert()except pygame.error as e:print(f"无法加载图像: {path}")raise SystemExit(e)image.set_colorkey(BLACK)  # 设置透明色return image# 加载音效资源
def load_sound(file):"""加载音效文件"""path = os.path.join(snd_folder, file)try:return pygame.mixer.Sound(path)except pygame.error as e:print(f"无法加载音效: {path}")return None# ====================== 游戏精灵类 ======================
class Player(pygame.sprite.Sprite):"""玩家飞机类"""def __init__(self):super().__init__()self.image = load_image("player.png")self.rect = self.image.get_rect(center=(SCREEN_WIDTH / 2, SCREEN_HEIGHT - 50))self.speed = PLAYER_SPEEDself.health = 3self.shoot_delay = 250  # 射击间隔(毫秒)self.last_shot = pygame.time.get_ticks()def update(self, keys):"""根据键盘输入更新位置"""# 水平移动if keys[pygame.K_LEFT] or keys[pygame.K_a]:self.rect.x -= self.speedif keys[pygame.K_RIGHT] or keys[pygame.K_d]:self.rect.x += self.speed# 垂直移动(可选)if keys[pygame.K_UP] or keys[pygame.K_w]:self.rect.y -= self.speedif keys[pygame.K_DOWN] or keys[pygame.K_s]:self.rect.y += self.speed# 边界约束self.rect.clamp_ip(pygame.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))def shoot(self, bullets, all_sprites):"""发射子弹"""now = pygame.time.get_ticks()if now - self.last_shot > self.shoot_delay:self.last_shot = nowbullet = Bullet(self.rect.centerx, self.rect.top)all_sprites.add(bullet)bullets.add(bullet)shoot_sound.play()class Enemy(pygame.sprite.Sprite):"""敌机基类"""def __init__(self):super().__init__()self.image = load_image("enemy1.png")self.rect = self.image.get_rect()self.rect = self.image.get_rect(x=random.randrange(SCREEN_WIDTH - self.rect.width),y=random.randrange(-100, -40),)self.speed_y = random.randint(*ENEMY_SPEED_RANGE)self.speed_x = random.choice([-1, 0, 1])  # 横向移动def update(self, *args):"""自动向下移动"""self.rect.y += self.speed_yself.rect.x += self.speed_x# 移出屏幕后删除if self.rect.top > SCREEN_HEIGHT + 10:self.kill()class Bullet(pygame.sprite.Sprite):"""玩家子弹类"""def __init__(self, x, y):super().__init__()self.image = load_image("bullet3.png")self.rect = self.image.get_rect(center=(x, y))self.speed_y = BULLET_SPEEDdef update(self, *args):"""向上移动"""self.rect.y += self.speed_yif self.rect.bottom < 0:  # 移出屏幕后删除self.kill()# ====================== 游戏主逻辑 ======================
class Game:def __init__(self):# 初始化显示self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))pygame.display.set_caption("飞机大战")self.clock = pygame.time.Clock()# 加载资源self.load_resources()# 游戏状态self.running = Trueself.score = 0def load_resources(self):"""加载所有资源"""global shoot_sound, explosion_soundshoot_sound = load_sound("pew.wav")explosion_sound = load_sound("expl3.wav")# 初始化精灵组self.all_sprites = pygame.sprite.Group()self.enemies = pygame.sprite.Group()self.bullets = pygame.sprite.Group()# 创建玩家self.player = Player()self.all_sprites.add(self.player)# 创建敌机组self.enemy_spawn_timer = pygame.USEREVENT + 1pygame.time.set_timer(self.enemy_spawn_timer, 1000)  # 每秒生成敌机def handle_events(self):"""处理事件循环"""for event in pygame.event.get():if event.type == pygame.QUIT:self.running = Falseelif event.type == pygame.KEYDOWN:if event.key == pygame.K_ESCAPE:self.running = Falseelif event.type == self.enemy_spawn_timer:enemy = Enemy()self.all_sprites.add(enemy)self.enemies.add(enemy)def check_collisions(self):"""检测碰撞事件"""# 子弹击中敌机hits = pygame.sprite.groupcollide(self.enemies, self.bullets, True, True)for hit in hits:self.score += 50explosion_sound.play()# 敌机撞击玩家hits = pygame.sprite.spritecollide(self.player, self.enemies, True)for hit in hits:self.player.health -= 1if self.player.health <= 0:self.game_over()def draw_hud(self):"""绘制游戏界面HUD"""# 绘制得分font = pygame.font.Font(None, 36)score_text = font.render(f"Score: {self.score}", True, WHITE)self.screen.blit(score_text, (10, 10))# 绘制生命值health_text = font.render(f"Health: {self.player.health}", True, RED)self.screen.blit(health_text, (10, 50))def game_over(self):"""游戏结束处理"""font = pygame.font.Font(None, 74)text = font.render("GAME OVER", True, RED)text_rect = text.get_rect(center=(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2))self.screen.blit(text, text_rect)pygame.display.flip()pygame.time.wait(10000)  # 等待2秒self.running = Falsedef run(self):"""游戏主循环"""while self.running:# 控制帧率self.clock.tick(FPS)# 处理输入self.handle_events()keys = pygame.key.get_pressed()if keys[pygame.K_SPACE]:self.player.shoot(self.bullets, self.all_sprites)# 更新游戏状态self.all_sprites.update(keys)  # 更新所有精灵self.check_collisions()# 渲染画面self.screen.fill(BLACK)self.all_sprites.draw(self.screen)self.draw_hud()pygame.display.flip()pygame.quit()if __name__ == "__main__":game = Game()game.run()

附件:图片资源

请添加图片描述
请添加图片描述
请添加图片描述

音效资源无法放置在此处,如自行下载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/79326.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flowable7.x学习笔记(十八)拾取我的待办

前言 本文从解读源码到实现功能&#xff0c;完整的学习Flowable的【TaskService】-【claim】方法实现的任务拾取功能。 一、概述 当调用 TaskService.claim(taskId, userId) 时&#xff0c;Flowable 会先加载并校验任务实体&#xff0c;再判断该任务是否已被认领&#xff1b;若…

SQL经典实例

第1章 检索记录 1.1 检索所有行和列 知识点&#xff1a;使用SELECT *快速检索表中所有列&#xff1b;显式列出列名&#xff08;如SELECT col1, col2&#xff09;提高可读性和可控性&#xff0c;尤其在编程场景中更清晰。 1.2 筛选行 知识点&#xff1a;通过WHERE子句过滤符合条…

HTTPcookie与session实现

1.HTTP Cookie 定义 HTTP Cookie &#xff08;也称为 Web Cookie 、浏览器 Cookie 或简称 Cookie &#xff09;是服务器发送到 用户浏览器并保存在浏览器上的一小块数据&#xff0c;它会在浏览器之后向同一服务器再次发 起请求时被携带并发送到服务器上。通常&#xff0…

【算法基础】冒泡排序算法 - JAVA

一、算法基础 1.1 什么是冒泡排序 冒泡排序是一种简单直观的比较排序算法。它重复地走访待排序的数列&#xff0c;依次比较相邻两个元素&#xff0c;如果顺序错误就交换它们&#xff0c;直到没有元素需要交换为止。 1.2 基本思想 比较相邻元素&#xff1a;从头开始&#xf…

0902Redux_状态管理-react-仿低代码平台项目

文章目录 1 Redux 概述1.1 核心概念1.2 基本组成1.3 工作流程1.4 中间件&#xff08;Middleware&#xff09;1.5 适用场景1.6 优缺点1.7 Redux Toolkit&#xff08;现代推荐&#xff09;1.8 与其他工具的对比1.9 总结 2 todoList 待办事项案例3 Redux开发者工具3.1 核心功能3.2…

《ATPL地面培训教材13:飞行原理》——第6章:阻力

翻译&#xff1a;Leweslyh&#xff1b;工具&#xff1a;Cursor & Claude 3.7&#xff1b;过程稿 第6章&#xff1a;阻力 目录 引言寄生阻力诱导阻力减少诱导阻力的方法升力对寄生阻力的影响飞机总阻力飞机总重量对总阻力的影响高度对总阻力的影响构型对总阻力的影响速度稳…

C++总结01-类型相关

一、数据存储 1.程序数据段 • 静态&#xff08;全局&#xff09;数据区&#xff1a;全局变量、静态变量 • 堆内存&#xff1a;程序员手动分配、手动释放 • 栈内存&#xff1a;编译器自动分配、自动释放 • 常量区&#xff1a;编译时大小、值确定不可修改 2.程序代码段 •…

【Hot 100】94. 二叉树的中序遍历

目录 引言二叉树的中序遍历我的解题代码优化更清晰的表述建议&#xff1a; &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;算法专栏&#x1f4a5; 标题&#xff1a;【Hot 100】94. 二叉树的中序遍历❣️ 寄语&#xff1a;书到用时方恨少&#xff…

大语言模型(LLMs)微调技术总结

文章目录 全面总结当前大语言模型&#xff08;LLM&#xff09;微调技术1. 引言2. 为什么需要微调&#xff1f;3. 微调技术分类概览4. 各种微调技术详细介绍4.1 基础微调方法4.1.1 有监督微调&#xff08;Supervised Fine-Tuning, SFT&#xff09;4.1.2 全参数微调&#xff08;F…

解决Maven项目中报错“java不支持版本6即更高的版本 7”

错误背景 当Maven项目编译或运行时出现错误提示 Java不支持版本6即更高的版本7&#xff0c;通常是由于项目配置的JDK版本与当前环境或编译器设置不一致导致的。例如&#xff1a; 项目配置的Java版本为6或7&#xff0c;但实际使用的是JDK 17。Maven或IDE的编译器未正确指定目标…

C++笔记-多态(包含虚函数,纯虚函数和虚函数表等)

1.多态的概念 多态(polymorphism)的概念:通俗来说&#xff0c;就是多种形态。多态分为编译时多态(静态多态)和运行时多态(动态多态)&#xff0c;这里我们重点讲运行时多态&#xff0c;编译时多态(静态多态)和运行时多态(动态多态)。编译时多态(静态多态)主要就是我们前面讲的函…

【Unity】MVP框架的使用例子

在提到MVP之前&#xff0c;可以先看看这篇MVC的帖子&#xff1a; 【Unity】MVC的简单分享以及一个在UI中使用的例子 MVC的不足之处&#xff1a; 在MVC的使用中&#xff0c;会发现View层直接调用了Model层的引用&#xff0c;即这两个层之间存在着一定的耦合性&#xff0c;而MV…

前端js学算法-实践

1、两数之和 const twoSum (nums, target) > {const obj {}for (let m 0; m < nums.length; m) {const cur nums[m]const diff target - curif(obj.hasOwnProperty(diff)){ // 查询对象中是否存在目标值-当前值键值对console.log([obj[diff], m]) // 存在则直接获取…

《MATLAB实战训练营:从入门到工业级应用》趣味入门篇-用声音合成玩音乐:MATLAB电子琴制作(超级趣味实践版)

《MATLAB实战训练营&#xff1a;从入门到工业级应用》趣味入门篇-用声音合成玩音乐&#xff1a;MATLAB电子琴制作&#xff08;超级趣味实践版&#xff09; 开篇&#xff1a;当MATLAB遇见音乐 - 一场数字与艺术的浪漫邂逅 想象一下&#xff0c;你正坐在一台古老的钢琴前&#x…

实战探讨:为什么 Redis Zset 选择跳表?

在了解了跳表的原理和实现后&#xff0c;一个常见的问题&#xff08;尤其是在面试中&#xff09;随之而来&#xff1a;为什么像 Redis 的有序集合 (Zset) 这样的高性能组件会选择使用跳表&#xff0c;而不是大家熟知的平衡树&#xff08;如红黑树&#xff09;呢&#xff1f; 对…

数据结构-线性结构(链表、栈、队列)实现

公共头文件common.h #define TRUE 1 #define FALSE 0// 定义节点数据类型 #define DATA_TYPE int单链表C语言实现 SingleList.h #pragma once#include "common.h"typedef struct Node {DATA_TYPE data;struct Node *next; } Node;Node *initList();void headInser…

高中数学联赛模拟试题精选学数学系列第3套几何题

△ A B C \triangle ABC △ABC 的内切圆 ⊙ I \odot I ⊙I 分别与边 B C BC BC, C A CA CA, A B AB AB 相切于点 D D D, E E E, F F F, D D ′ DD DD′ 为 ⊙ I \odot I ⊙I 的直径, 过圆心 I I I 作直线 A D ′ AD AD′ 的垂线 l l l, 直线 l l l 分别与 D E DE…

使用 ossutil 上传文件到阿里云 OSS

在处理文件存储和传输时&#xff0c;阿里云的对象存储服务&#xff08;OSS&#xff09;是一个非常方便的选择。特别是在需要批量上传文件或通过命令行工具进行文件管理时&#xff0c;ossutil提供了强大的功能。本文将详细说明如何使用 ossutil 上传文件到阿里云 OSS&#xff0c…

DeepSeek与MySQL:开启数据智能新时代

目录 一、引言&#xff1a;技术融合的力量二、DeepSeek 与 MySQL&#xff1a;技术基石2.1 DeepSeek 技术探秘2.2 MySQL 数据库深度解析 三、DeepSeek 与 MySQL 集成&#xff1a;从理论到实践3.1 集成原理剖析3.2 集成步骤详解 四、应用案例&#xff1a;实战中的价值体现4.1 电商…

WebAPI项目从Newtonsoft.Json迁移到System.Text.Json踩坑备忘

1.控制器层方法返回类型不能为元组 控制器层方法返回类型为元组时&#xff0c;序列化结果为空。 因为元组没有属性只有field&#xff0c;除非使用IncludeFields参数专门指定&#xff0c;否则使用System.Text.Json进行序列化时不会序列化field var options new JsonSerializ…