用 Pygame 写个飞机大战:从 0 到 1 教你做 2D 游戏

部署运行你感兴趣的模型镜像

目录

引言:让小白也可以写游戏

一、为什么学 Pygame?新手做游戏的最佳选择

二、环境搭建:3 步搞定 Pygame 开发环境(附避坑指南)

步骤 1:安装 Python(已安装可跳过)

步骤 2:创建虚拟环境(推荐但可选)

步骤 3:安装 Pygame

三、核心概念:用 “动画片” 理解 Pygame 的工作原理

四、实战:开发飞机大战游戏(分阶段实现,附完整代码)

阶段 1:创建游戏窗口和基本框架

步骤 1:编写基础代码

步骤 2:运行代码,查看效果

阶段 2:添加玩家飞机和移动控制

步骤 1:准备飞机图片(免费素材获取)

步骤 2:编写代码加载飞机并实现移动

步骤 3:测试飞机移动

阶段 3:添加子弹发射和敌机生成

步骤 1:准备子弹和敌机图片

步骤 2:实现子弹发射功能

步骤 3:测试子弹和敌机

阶段 4:添加碰撞检测和得分系统

步骤 1:修改代码,添加碰撞检测和得分

步骤 2:测试碰撞和得分

阶段 5:添加背景、音效和爆炸效果

步骤 1:准备资源

步骤 2:添加背景和音效

步骤 3:最终测试

五、常见问题与优化技巧(新手必看)

1. 图片加载失败或不显示

2. 中文显示乱码或方块

3. 游戏卡顿或帧率不稳定

4. 音效无法播放或报错

六、扩展功能:让你的游戏更丰富(练手建议)

七、免费资源网站推荐(避免版权问题)

总结:从玩游戏到做游戏的成就感


 

class 卑微码农:
    def __init__(self):
        self.技能 = ['能读懂十年前祖传代码', '擅长用Ctrl+C/V搭建世界', '信奉"能跑就别动"的玄学']
        self.发量 = 100  # 初始发量
        self.咖啡因耐受度 = '极限'
        
    def 修Bug(self, bug):
        try:
            # 试图用玄学解决问题
            if bug.严重程度 == '离谱':
                print("这一定是环境问题!")
            else:
                print("让我看看是谁又没写注释...哦,是我自己。")
        except Exception as e:
            # 如果try块都救不了,那就...
            print("重启一下试试?")
            self.发量 -= 1  # 每解决一个bug,头发-1
 
 
# 实例化一个我
我 = 卑微码农()

引言:让小白也可以写游戏

如果你小时候玩过《雷电》《1942》这类飞机射击游戏,可能会想:“这种看起来简单的 2D 游戏,自己能做出来吗?”

答案是肯定的。用 Python 的 Pygame 库,哪怕是编程新手,也能在一天内做出一个能玩的飞机大战 —— 不需要复杂的数学知识,不用懂 3D 建模,甚至不用会画画(免费素材网站能解决)。

今天这篇文章,我会带你从头到尾开发一个完整的飞机大战游戏,包含敌机生成、子弹发射、碰撞检测、得分系统和音效。全程用大白话解释,代码复制就能跑,每个步骤都有效果图,保证你看完就能上手。

一、为什么学 Pygame?新手做游戏的最佳选择

第一次用 Pygame 时,我惊讶于它的 “亲民”——一行代码就能弹出游戏窗口,十几行代码就能让图片动起来

和 Unity、Unreal 这些专业游戏引擎比,Pygame 的优势对新手太友好了:

  • 门槛低:纯 Python 语法,不用学新语言,几行代码就能看到效果;
  • 轻量简单:核心功能就几个模块(绘图、事件、音效),不用记复杂的 API;
  • 资源好找:2D 游戏素材(图片、音效)有很多免费网站,不用自己创作;
  • 适合练手:从小游戏(贪吃蛇、飞机大战)到中等复杂度(RPG、解谜)都能做。

简单说:想体验 “从 0 做出一个能玩的游戏” 的成就感,Pygame 是最好的起点

二、环境搭建:3 步搞定 Pygame 开发环境(附避坑指南)

开始写代码前,先把工具准备好。Pygame 支持 Windows、macOS、Linux,操作基本一致,这里以 “Windows 10+Python 3.9” 为例。

步骤 1:安装 Python(已安装可跳过)

Pygame 是 Python 库,首先得装 Python。去官网(https://www.python.org/)下载对应版本,安装时一定要勾选 “Add Python to PATH”(否则后面会报错 “python 不是内部命令”),然后一路 “Next” 完成安装。

验证是否安装成功:按下Win+R,输入cmd打开命令提示符,输入python --version,能看到 “Python 3.x.x” 就说明没问题。

步骤 2:创建虚拟环境(推荐但可选)

和开发其他 Python 项目一样,用虚拟环境隔离依赖更干净:

  1. 新建一个项目文件夹(比如D:\plane_war);
  2. 打开 cmd,用cd命令进入这个文件夹:cd D:\plane_war
  3. 输入python -m venv venv创建虚拟环境;
  4. 激活虚拟环境:
    • Windows:venv\Scripts\activate(激活后命令行前会出现(venv));
    • macOS/Linux:source venv/bin/activate

如果懒得搞虚拟环境,直接跳过这步也行,不影响后续开发。

步骤 3:安装 Pygame

在命令行输入pip install pygame==2.5.2(指定 2.5.2 版本,稳定且兼容性好)。

验证安装:输入python -m pygame.examples.aliens,如果弹出一个外星人射击的小游戏窗口,说明安装成功(关闭游戏窗口继续)。

常见坑点

  • 安装时报 “pip 不是内部命令”:没勾选 “Add Python to PATH”,重新安装并勾选即可;
  • 运行示例游戏黑屏 / 闪退:可能是显卡驱动问题,尝试更新驱动或换一个 Python 版本(3.8/3.9 比较稳定)。

三、核心概念:用 “动画片” 理解 Pygame 的工作原理

在写代码前,先搞懂游戏运行的基本逻辑。其实游戏本质上是 “快速切换的图片”,就像动画片:

  • 游戏窗口:相当于动画片的 “屏幕”,所有元素都在里面显示;
  • 游戏循环:相当于 “播放帧”,每秒刷新几十次(比如 60 帧),让画面动起来;
  • 精灵(Sprite):游戏中的角色(飞机、子弹、敌机),可以移动、碰撞;
  • 事件处理:监听键盘 / 鼠标操作(比如按方向键移动飞机);
  • 碰撞检测:判断两个精灵是否碰到一起(比如子弹打中小飞机)。

用一个简单的比喻:Pygame 就像一个 “动画制作工具”,你只需要告诉它 “每帧画什么、怎么动、响应用户什么操作”,它就会自动把这些帧连起来变成游戏

四、实战:开发飞机大战游戏(分阶段实现,附完整代码)

我们的目标是做一个这样的飞机大战:

  • 玩家控制一架飞机(上下左右移动);
  • 按空格发射子弹;
  • 屏幕上方不断出现敌机,碰到敌机或被敌机撞都会失败;
  • 打中敌机得分,分数越高难度越大;
  • 有背景音乐和音效。

全程分 5 个阶段,每个阶段都能独立运行,逐步增加功能。

阶段 1:创建游戏窗口和基本框架

先实现最基础的部分:弹出一个游戏窗口,显示标题和背景,能正常关闭。

步骤 1:编写基础代码

plane_war文件夹下新建game.py,代码如下:

import pygame
import sys

# 初始化Pygame
pygame.init()

# 游戏窗口设置
SCREEN_WIDTH = 480  # 窗口宽度
SCREEN_HEIGHT = 700  # 窗口高度
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))  # 创建窗口
pygame.display.set_caption("飞机大战")  # 设置窗口标题

# 颜色定义(RGB值)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

# 游戏主循环
running = True
while running:
    # 1. 处理事件(比如关闭窗口、按键操作)
    for event in pygame.event.get():
        # 如果点击窗口关闭按钮,退出游戏
        if event.type == pygame.QUIT:
            running = False

    # 2. 绘制画面(黑色背景)
    screen.fill(BLACK)

    # 3. 更新显示(刷新画面)
    pygame.display.flip()

# 退出游戏
pygame.quit()
sys.exit()

步骤 2:运行代码,查看效果

在 cmd 中运行python game.py,会弹出一个黑色窗口,标题是 “飞机大战”,点击右上角关闭按钮能正常退出 —— 这就是游戏的基础框架。

代码说明

  • pygame.init():初始化 Pygame 所有模块(必须放在最前面);
  • pygame.display.set_mode():创建游戏窗口,参数是宽高的元组;
  • 游戏主循环:这是所有游戏的核心,每秒运行几十次,包含三个关键步骤:
    1. 处理事件(用户输入);
    2. 更新游戏状态(移动角色、检测碰撞等);
    3. 绘制画面并刷新。

阶段 2:添加玩家飞机和移动控制

接下来让玩家飞机显示在屏幕上,并能用方向键控制移动。

步骤 1:准备飞机图片(免费素材获取)

游戏需要用到图片,这里推荐几个免费无版权的素材网站:

  • itch.io:搜索 “plane sprite”,很多开发者分享的免费飞机素材;
  • pixabay:有大量免费图片,适合做背景;
  • opengameart.org:专门的游戏素材网站。

我们用一张简单的玩家飞机图片(比如player_plane.png),放在项目文件夹下的images子文件夹里(先创建images文件夹)。

步骤 2:编写代码加载飞机并实现移动

修改game.py

import pygame
import sys

pygame.init()

SCREEN_WIDTH = 480
SCREEN_HEIGHT = 700
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("飞机大战")

# 加载玩家飞机图片
player_img = pygame.image.load("images/player_plane.png").convert_alpha()  # 支持透明背景
# 获取飞机图片的矩形区域(用于定位和碰撞检测)
player_rect = player_img.get_rect()
# 设置飞机初始位置(屏幕底部中间)
player_rect.centerx = SCREEN_WIDTH // 2  # 水平居中
player_rect.bottom = SCREEN_HEIGHT - 10  # 距离底部10像素

# 飞机移动速度
player_speed = 5

# 游戏主循环
running = True
while running:
    # 处理事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # 持续按键检测(方向键控制)
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT] and player_rect.left > 0:  # 左移,不超过左边界
        player_rect.x -= player_speed
    if keys[pygame.K_RIGHT] and player_rect.right < SCREEN_WIDTH:  # 右移,不超过右边界
        player_rect.x += player_speed
    if keys[pygame.K_UP] and player_rect.top > 0:  # 上移,不超过上边界
        player_rect.y -= player_speed
    if keys[pygame.K_DOWN] and player_rect.bottom < SCREEN_HEIGHT:  # 下移,不超过下边界
        player_rect.y += player_speed

    # 绘制背景(黑色)
    screen.fill(BLACK)
    # 绘制玩家飞机(将图片画在矩形位置)
    screen.blit(player_img, player_rect)

    # 刷新显示
    pygame.display.flip()

pygame.quit()
sys.exit()

步骤 3:测试飞机移动

运行代码,现在屏幕底部中间会显示你的飞机,按方向键可以移动,而且不会移出窗口边界 —— 角色控制就实现了!

关键代码解析

  • pygame.image.load():加载图片,convert_alpha()保留透明背景(飞机边缘不会有白边);
  • get_rect():获取图片的矩形对象(xy表示左上角坐标,centerxbottom等是便捷定位属性);
  • pygame.key.get_pressed():检测持续按键(比单次事件更适合移动控制);
  • screen.blit(图片, 位置):将图片绘制到屏幕上。

阶段 3:添加子弹发射和敌机生成

现在让飞机能发射子弹,同时让敌机从屏幕上方飞下来。

步骤 1:准备子弹和敌机图片

同样在images文件夹下放入子弹图片(bullet.png)和敌机图片(enemy_plane.png)。

步骤 2:实现子弹发射功能

修改代码,添加子弹类和发射逻辑:

import pygame
import sys
import random  # 用于随机生成敌机位置

pygame.init()

SCREEN_WIDTH = 480
SCREEN_HEIGHT = 700
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("飞机大战")

# 加载素材
player_img = pygame.image.load("images/player_plane.png").convert_alpha()
bullet_img = pygame.image.load("images/bullet.png").convert_alpha()
enemy_img = pygame.image.load("images/enemy_plane.png").convert_alpha()

# 玩家飞机设置
player_rect = player_img.get_rect()
player_rect.centerx = SCREEN_WIDTH // 2
player_rect.bottom = SCREEN_HEIGHT - 10
player_speed = 5

# 子弹设置
bullet_speed = 10
bullets = []  # 存储所有子弹的列表
bullet_cooldown = 25  # 发射冷却(数值越大,射速越慢)
bullet_timer = 0  # 冷却计时器

# 敌机设置
enemy_speed = 3
enemies = []  # 存储所有敌机的列表
enemy_spawn_cooldown = 30  # 敌机生成间隔
enemy_spawn_timer = 0  # 生成计时器

# 游戏主循环
running = True
while running:
    # 控制游戏帧率(每秒60帧)
    pygame.time.Clock().tick(60)

    # 处理事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # 玩家移动
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT] and player_rect.left > 0:
        player_rect.x -= player_speed
    if keys[pygame.K_RIGHT] and player_rect.right < SCREEN_WIDTH:
        player_rect.x += player_speed
    if keys[pygame.K_UP] and player_rect.top > 0:
        player_rect.y -= player_speed
    if keys[pygame.K_DOWN] and player_rect.bottom < SCREEN_HEIGHT:
        player_rect.y += player_speed

    # 子弹发射(按空格键,带冷却)
    bullet_timer += 1
    if keys[pygame.K_SPACE] and bullet_timer >= bullet_cooldown:
        # 创建子弹,位置在飞机顶部中间
        bullet_rect = bullet_img.get_rect()
        bullet_rect.centerx = player_rect.centerx
        bullet_rect.bottom = player_rect.top  # 子弹从飞机头部射出
        bullets.append(bullet_rect)
        bullet_timer = 0  # 重置冷却计时器

    # 移动子弹,并移除出界的子弹
    for bullet in bullets[:]:  # 用切片遍历,避免修改列表时出错
        bullet.y -= bullet_speed  # 子弹向上飞
        if bullet.bottom < 0:  # 子弹飞出屏幕顶部
            bullets.remove(bullet)

    # 生成敌机(带间隔)
    enemy_spawn_timer += 1
    if enemy_spawn_timer >= enemy_spawn_cooldown:
        # 随机生成敌机x坐标(确保在屏幕内)
        enemy_x = random.randint(0, SCREEN_WIDTH - enemy_img.get_width())
        enemy_rect = enemy_img.get_rect()
        enemy_rect.x = enemy_x
        enemy_rect.y = -enemy_img.get_height()  # 从屏幕顶部外飞入
        enemies.append(enemy_rect)
        enemy_spawn_timer = 0  # 重置生成计时器

    # 移动敌机,并移除出界的敌机
    for enemy in enemies[:]:
        enemy.y += enemy_speed  # 敌机向下飞
        if enemy.top > SCREEN_HEIGHT:  # 敌机飞出屏幕底部
            enemies.remove(enemy)

    # 绘制画面
    screen.fill(BLACK)
    # 绘制玩家飞机
    screen.blit(player_img, player_rect)
    # 绘制所有子弹
    for bullet in bullets:
        screen.blit(bullet_img, bullet)
    # 绘制所有敌机
    for enemy in enemies:
        screen.blit(enemy_img, enemy)

    # 刷新显示
    pygame.display.flip()

pygame.quit()
sys.exit()

步骤 3:测试子弹和敌机

运行代码,按空格键发射子弹(有冷却,不会一次性射出一堆),屏幕上方会不断有敌机飞下来 —— 战斗系统的雏形就有了!

核心逻辑

  • 子弹和敌机都用列表存储,方便批量处理;
  • 用计时器(bullet_timerenemy_spawn_timer)控制发射和生成频率,避免太密集;
  • 定期移除出界的子弹和敌机,防止列表无限变大导致卡顿。

阶段 4:添加碰撞检测和得分系统

现在需要判断 “子弹是否打中敌机”“玩家是否撞到敌机”,并统计得分。

步骤 1:修改代码,添加碰撞检测和得分

更新game.py

import pygame
import sys
import random

pygame.init()

SCREEN_WIDTH = 480
SCREEN_HEIGHT = 700
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("飞机大战")

# 加载素材
player_img = pygame.image.load("images/player_plane.png").convert_alpha()
bullet_img = pygame.image.load("images/bullet.png").convert_alpha()
enemy_img = pygame.image.load("images/enemy_plane.png").convert_alpha()

# 玩家设置
player_rect = player_img.get_rect()
player_rect.centerx = SCREEN_WIDTH // 2
player_rect.bottom = SCREEN_HEIGHT - 10
player_speed = 5
player_alive = True  # 玩家是否存活

# 子弹设置
bullet_speed = 10
bullets = []
bullet_cooldown = 25
bullet_timer = 0

# 敌机设置
enemy_speed = 3
enemies = []
enemy_spawn_cooldown = 30
enemy_spawn_timer = 0

# 得分系统
score = 0
# 初始化字体(显示得分)
pygame.font.init()
font = pygame.font.SysFont("SimHei", 30)  # 用黑体显示中文,字号30

# 游戏主循环
running = True
while running:
    pygame.time.Clock().tick(60)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    if player_alive:  # 玩家存活时才处理移动和发射
        # 玩家移动(代码同上,略)
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT] and player_rect.left > 0:
            player_rect.x -= player_speed
        # 省略右、上、下移动代码...

        # 子弹发射(代码同上,略)
        bullet_timer += 1
        if keys[pygame.K_SPACE] and bullet_timer >= bullet_cooldown:
            # 省略子弹生成代码...

        # 子弹移动和移除(代码同上,略)

        # 生成敌机(代码同上,略)

        # 敌机移动和移除(代码同上,略)

        # 碰撞检测:子弹打中敌机
        for bullet in bullets[:]:
            for enemy in enemies[:]:
                if bullet.colliderect(enemy):  # 检测两个矩形是否碰撞
                    bullets.remove(bullet)
                    enemies.remove(enemy)
                    score += 10  # 打中一架敌机得10分
                    # 得分越高,敌机生成越快(增加难度)
                    if score % 100 == 0 and enemy_spawn_cooldown > 10:
                        enemy_spawn_cooldown -= 2  # 每得100分,生成间隔减2
                        enemy_speed += 0.5  # 敌机速度增加

        # 碰撞检测:玩家撞到敌机
        for enemy in enemies[:]:
            if player_rect.colliderect(enemy):
                player_alive = False  # 玩家死亡
                enemies.remove(enemy)

    # 绘制画面
    screen.fill(BLACK)
    # 绘制玩家飞机(存活时才显示)
    if player_alive:
        screen.blit(player_img, player_rect)
    else:
        # 玩家死亡时显示游戏结束文字
        game_over_text = font.render("游戏结束!按R重启", True, WHITE)
        screen.blit(game_over_text, (SCREEN_WIDTH//2 - 120, SCREEN_HEIGHT//2))

    # 绘制子弹和敌机(代码同上,略)
    for bullet in bullets:
        screen.blit(bullet_img, bullet)
    for enemy in enemies:
        screen.blit(enemy_img, enemy)

    # 绘制得分
    score_text = font.render(f"得分:{score}", True, WHITE)
    screen.blit(score_text, (10, 10))  # 显示在左上角

    # 重启游戏(按R键)
    if not player_alive and keys[pygame.K_r]:
        # 重置游戏状态
        player_alive = True
        player_rect.centerx = SCREEN_WIDTH // 2
        player_rect.bottom = SCREEN_HEIGHT - 10
        bullets.clear()
        enemies.clear()
        score = 0
        enemy_spawn_cooldown = 30
        enemy_speed = 3

    pygame.display.flip()

pygame.quit()
sys.exit()

步骤 2:测试碰撞和得分

运行代码,现在:

  • 子弹打中敌机时,敌机消失,得分增加;
  • 玩家撞到敌机后,飞机消失,显示 “游戏结束!按 R 重启”;
  • 得分越高,敌机出现得越快、飞得越快(难度递增);
  • 按 R 键可以重新开始游戏 —— 一个能玩的飞机大战基本成型了!

关键代码

  • colliderect():Pygame 内置的矩形碰撞检测函数,判断两个rect是否重叠;
  • pygame.font:用于显示文字(得分和游戏结束提示),SysFont("SimHei", 30)确保中文正常显示;
  • 难度递增逻辑:通过score % 100 == 0判断得分里程碑,动态调整敌机生成速度和移动速度。

阶段 5:添加背景、音效和爆炸效果

最后一步,给游戏加背景图、发射 / 爆炸音效和击中动画,让体验更完整。

步骤 1:准备资源

  • 背景图(background.png):放在images文件夹;
  • 发射音效(shoot.wav)、爆炸音效(explosion.wav):放在sound文件夹(新建);
  • 爆炸动画图片(explosion1.pngexplosion2.png...):放在images文件夹(可选,简单版可用一张图)。

步骤 2:添加背景和音效

修改代码,完整版本如下:

import pygame
import sys
import random

pygame.init()

# 初始化混音器(处理音效)
pygame.mixer.init()

SCREEN_WIDTH = 480
SCREEN_HEIGHT = 700
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("飞机大战")

# 加载素材
# 背景图(两张一样的图,用于滚动效果)
bg_img1 = pygame.image.load("images/background.png").convert()
bg_img2 = pygame.image.load("images/background.png").convert()
bg_y1 = 0  # 第一张背景y坐标
bg_y2 = -SCREEN_HEIGHT  # 第二张背景y坐标(初始在屏幕上方)

player_img = pygame.image.load("images/player_plane.png").convert_alpha()
bullet_img = pygame.image.load("images/bullet.png").convert_alpha()
enemy_img = pygame.image.load("images/enemy_plane.png").convert_alpha()
# 爆炸图片
explosion_img = pygame.image.load("images/explosion.png").convert_alpha()

# 加载音效
shoot_sound = pygame.mixer.Sound("sound/shoot.wav")  # 发射音效
explosion_sound = pygame.mixer.Sound("sound/explosion.wav")  # 爆炸音效
shoot_sound.set_volume(0.2)  # 降低音量(0-1)
explosion_sound.set_volume(0.2)

# 玩家设置
player_rect = player_img.get_rect()
player_rect.centerx = SCREEN_WIDTH // 2
player_rect.bottom = SCREEN_HEIGHT - 10
player_speed = 5
player_alive = True

# 子弹设置
bullet_speed = 10
bullets = []
bullet_cooldown = 25
bullet_timer = 0

# 敌机设置
enemy_speed = 3
enemies = []
enemy_spawn_cooldown = 30
enemy_spawn_timer = 0

# 爆炸效果存储(位置和动画帧)
explosions = []

# 得分系统
score = 0
font = pygame.font.SysFont("SimHei", 30)

# 游戏主循环
running = True
while running:
    pygame.time.Clock().tick(60)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # 背景滚动(模拟飞机向前飞)
    bg_y1 += 2
    bg_y2 += 2
    if bg_y1 >= SCREEN_HEIGHT:
        bg_y1 = -SCREEN_HEIGHT  # 第一张图滚出屏幕后,移到顶部
    if bg_y2 >= SCREEN_HEIGHT:
        bg_y2 = -SCREEN_HEIGHT  # 第二张图同理
    # 绘制背景(先画背景,再画角色,避免角色被遮挡)
    screen.blit(bg_img1, (0, bg_y1))
    screen.blit(bg_img2, (0, bg_y2))

    if player_alive:
        # 玩家移动
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT] and player_rect.left > 0:
            player_rect.x -= player_speed
        if keys[pygame.K_RIGHT] and player_rect.right < SCREEN_WIDTH:
            player_rect.x += player_speed
        if keys[pygame.K_UP] and player_rect.top > 0:
            player_rect.y -= player_speed
        if keys[pygame.K_DOWN] and player_rect.bottom < SCREEN_HEIGHT:
            player_rect.y += player_speed

        # 子弹发射(带音效)
        bullet_timer += 1
        if keys[pygame.K_SPACE] and bullet_timer >= bullet_cooldown:
            bullet_rect = bullet_img.get_rect()
            bullet_rect.centerx = player_rect.centerx
            bullet_rect.bottom = player_rect.top
            bullets.append(bullet_rect)
            bullet_timer = 0
            shoot_sound.play()  # 播放发射音效

        # 子弹移动和移除
        for bullet in bullets[:]:
            bullet.y -= bullet_speed
            if bullet.bottom < 0:
                bullets.remove(bullet)

        # 生成敌机
        enemy_spawn_timer += 1
        if enemy_spawn_timer >= enemy_spawn_cooldown:
            enemy_x = random.randint(0, SCREEN_WIDTH - enemy_img.get_width())
            enemy_rect = enemy_img.get_rect()
            enemy_rect.x = enemy_x
            enemy_rect.y = -enemy_img.get_height()
            enemies.append(enemy_rect)
            enemy_spawn_timer = 0

        # 敌机移动和移除
        for enemy in enemies[:]:
            enemy.y += enemy_speed
            if enemy.top > SCREEN_HEIGHT:
                enemies.remove(enemy)

        # 子弹打敌机碰撞检测
        for bullet in bullets[:]:
            for enemy in enemies[:]:
                if bullet.colliderect(enemy):
                    bullets.remove(bullet)
                    enemies.remove(enemy)
                    score += 10
                    # 记录爆炸位置
                    explosions.append({
                        "rect": pygame.Rect(enemy.x, enemy.y, enemy.width, enemy.height),
                        "frame": 0  # 动画帧(简单版用一张图,复杂版可循环切换)
                    })
                    explosion_sound.play()  # 播放爆炸音效
                    # 难度递增
                    if score % 100 == 0 and enemy_spawn_cooldown > 10:
                        enemy_spawn_cooldown -= 2
                        enemy_speed += 0.5

        # 玩家撞敌机碰撞检测
        for enemy in enemies[:]:
            if player_rect.colliderect(enemy):
                player_alive = False
                enemies.remove(enemy)
                # 玩家爆炸效果
                explosions.append({
                    "rect": pygame.Rect(player_rect.x, player_rect.y, player_rect.width, player_rect.height),
                    "frame": 0
                })
                explosion_sound.play()

    # 处理爆炸动画(简单版显示10帧后消失)
    for exp in explosions[:]:
        exp["frame"] += 1
        if exp["frame"] > 10:  # 控制爆炸显示时间
            explosions.remove(exp)
        else:
            # 绘制爆炸图片
            screen.blit(explosion_img, exp["rect"])

    # 绘制玩家飞机
    if player_alive:
        screen.blit(player_img, player_rect)
    else:
        game_over_text = font.render("游戏结束!按R重启", True, WHITE)
        screen.blit(game_over_text, (SCREEN_WIDTH//2 - 120, SCREEN_HEIGHT//2))

    # 绘制子弹和敌机
    for bullet in bullets:
        screen.blit(bullet_img, bullet)
    for enemy in enemies:
        screen.blit(enemy_img, enemy)

    # 绘制得分
    score_text = font.render(f"得分:{score}", True, WHITE)
    screen.blit(score_text, (10, 10))

    # 重启游戏
    keys = pygame.key.get_pressed()
    if not player_alive and keys[pygame.K_r]:
        player_alive = True
        player_rect.centerx = SCREEN_WIDTH // 2
        player_rect.bottom = SCREEN_HEIGHT - 10
        bullets.clear()
        enemies.clear()
        explosions.clear()
        score = 0
        enemy_spawn_cooldown = 30
        enemy_speed = 3

    pygame.display.flip()

pygame.quit()
sys.exit()

步骤 3:最终测试

现在运行游戏,你会看到:

  • 背景图不断向下滚动,模拟飞行感;
  • 发射子弹时有 “咻” 的音效,击中敌机有爆炸音效;
  • 敌机和玩家被击中时会显示爆炸图片;
  • 得分和难度动态变化,按 R 键可重启 —— 一个完整的飞机大战游戏就做好了!

五、常见问题与优化技巧(新手必看)

开发过程中难免遇到各种小问题,这里整理几个高频坑点和优化建议:

1. 图片加载失败或不显示

  • 原因:路径错误(比如图片放在images里,代码却写成"player_plane.png");
  • 解决:用绝对路径调试(比如"D:/plane_war/images/player.png"),确认路径正确后再改相对路径;
  • 技巧:用os.path.join处理路径,兼容不同系统(Windows 用\,Linux 用/):
import os
# 正确的路径写法
image_path = os.path.join("images", "player_plane.png")
player_img = pygame.image.load(image_path).convert_alpha()

2. 中文显示乱码或方块

  • 原因:Pygame 默认字体不支持中文;
  • 解决:指定支持中文的字体,如SimHei(黑体)、Microsoft YaHei(微软雅黑):
font = pygame.font.SysFont(["SimHei", "Microsoft YaHei"], 30)  # 多个字体备选

3. 游戏卡顿或帧率不稳定

  • 原因:没有控制帧率,或列表中存储了太多元素(比如没及时移除出界的子弹);
  • 解决
    • pygame.time.Clock().tick(60)固定每秒 60 帧;
    • 定期清理列表(如子弹、敌机),避免元素过多;
    • 复杂游戏可使用pygame.sprite.Sprite类管理角色,效率更高。

4. 音效无法播放或报错

  • 原因:音效文件格式不对(Pygame 支持 wav、ogg 等,不支持 mp3);
  • 解决:用格式转换工具(如格式工厂)将 mp3 转为 wav;
  • 技巧:降低音效音量(set_volume(0.2)),避免刺耳。

六、扩展功能:让你的游戏更丰富(练手建议)

学会基础版后,可以尝试添加这些功能,提升游戏复杂度:

  1. 多类型敌机:大型敌机(血厚、得分高)、小型敌机(速度快);
  2. 道具系统:随机掉落护盾(免伤)、双发子弹、减速等道具;
  3. 生命值和关卡:玩家有 3 条命,每过一关敌机难度提升;
  4. 排行榜:用文件存储最高分,显示历史最佳成绩;
  5. 动画优化:给飞机添加移动动画(多张图片切换),爆炸效果用多帧动画。

七、免费资源网站推荐(避免版权问题)

做游戏离不开素材,这些网站的资源可以免费商用,不用担心版权问题:

总结:从玩游戏到做游戏的成就感

回顾整个开发过程,我们从一个空白窗口,一步步添加了飞机移动、子弹发射、敌机生成、碰撞检测、音效背景,最终做出了一个能玩的飞机大战。这个过程中,你不仅学会了 Pygame 的用法,更理解了游戏开发的核心逻辑 —— 其实没那么神秘,就是 “循环刷新画面 + 响应用户操作”。

Pygame 的优势在于 “低门槛、高反馈”:哪怕是几行代码的修改(比如调整子弹速度、换一张敌机图片),都能立刻在游戏中看到效果,这种 “即时反馈” 正是学习编程的最佳动力。

如果你是编程新手,建议先照着本文的代码敲一遍,感受从 0 到 1 的过程;熟悉后再尝试修改参数(比如调整难度曲线),最后挑战添加新功能(如道具系统)。当你能独立完成一个小游戏时,不仅编程能力会提升,更能收获 “自己做的游戏真好玩” 的成就感。

祝你在游戏开发的路上,玩得开心,学得尽兴!

 

 

 

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值