Python Pygame 太空射击游戏开发:从零到一掌握游戏引擎核心原理

📅 2026/7/22 13:32:10
Python Pygame 太空射击游戏开发:从零到一掌握游戏引擎核心原理
1. 项目概述为什么选择Python和Pygame如果你对编程感兴趣尤其是想通过一个看得见、摸得着的项目来巩固Python基础那么从零开始开发一个太空射击游戏绝对是个经典且富有成就感的起点。我当年入门时也做过类似的项目它几乎涵盖了游戏开发最核心的循环逻辑、事件处理、碰撞检测和状态管理。Python以其简洁的语法降低了编程的门槛而Pygame作为一个专为2D游戏设计的库则提供了足够强大但又不过于复杂的工具集让你能专注于游戏逻辑本身而不是被底层图形API的复杂性劝退。这个项目最终会实现一个玩家控制飞船、躲避或击毁敌机、获取分数的基础射击游戏。它麻雀虽小五脏俱全。通过完成它你不仅能学会如何使用Pygame创建窗口、加载图像、播放音效更能深刻理解游戏主循环、精灵Sprite系统、事件驱动编程等通用概念。这些知识是相通的即便你未来转向其他更专业的游戏引擎这段经历也会让你对“游戏是如何跑起来的”有一个非常扎实的认知。无论你是编程新手想找个有趣的实践项目还是有一定基础想探索游戏开发领域这个教程都值得你花上几个下午的时间。2. 核心思路与项目架构设计在动手写代码之前花点时间理清思路至关重要。一个结构混乱的项目会随着代码量的增加而迅速变得难以维护。我们的太空射击游戏可以抽象为几个核心模块采用面向对象的思想来组织代码这样逻辑清晰也便于后续扩展。2.1 核心游戏对象设计游戏中的所有“活物”和可交互元素我们都可以抽象为“精灵”。在Pygame中pygame.sprite.Sprite类是我们的好朋友。我们将为三种主要对象创建类玩家飞船 (Player): 这是由玩家控制的实体。它需要响应键盘事件上下左右移动、发射子弹拥有生命值HP并且需要与敌机和敌机子弹进行碰撞检测。敌机 (Enemy): 由电脑控制的实体。它们会以一定的模式如直线下降、左右摆动从屏幕上方出现并可能发射子弹。它们也有生命值被玩家子弹击中后会爆炸、消失并为玩家增加分数。子弹 (Bullet): 由玩家或敌机发射的飞行物。它需要沿固定方向高速移动并在击中目标或飞出屏幕边界后消失。采用面向对象的方式每个类都继承自pygame.sprite.Sprite并至少拥有image外观、rect位置和碰撞区域、update()更新逻辑和可能有的draw()方法。我们将使用Pygame的精灵组pygame.sprite.Group来高效管理同一类对象例如一个all_sprites组管理所有要绘制的精灵一个enemy_bullets组管理所有敌机子弹方便进行统一的更新和碰撞检测。2.2 游戏主循环与状态管理游戏的核心是一个无限循环即“游戏主循环”。每一帧循环都会执行以下操作处理事件检查是否有键盘按下、鼠标点击、退出窗口等事件。更新游戏状态调用所有精灵的update()方法更新它们的位置、状态如子弹飞行、敌机移动。碰撞检测检查子弹是否击中飞船、敌机或者飞船是否撞到了敌机。渲染绘制用背景色清空屏幕然后按顺序绘制背景、所有精灵。刷新显示将绘制好的内容更新到显示器上。此外我们还需要管理游戏的整体状态比如“进行中”、“暂停”、“游戏结束”。这可以通过一个简单的状态变量如game_state和相应的条件判断来实现。2.3 资源管理与目录结构一个清晰的项目目录结构能让你的工作井井有条。建议在项目根目录下创建如下文件夹space_shooter/ ├── main.py # 游戏主程序入口 ├── player.py # 玩家飞船类 ├── enemy.py # 敌机类 ├── bullet.py # 子弹类 ├── settings.py # 游戏配置如屏幕尺寸、颜色、速度常量 ├── images/ # 存放所有图片素材飞船、敌机、子弹、背景、爆炸特效 │ ├── player.png │ ├── enemy1.png │ └── ... ├── sounds/ # 存放所有音效素材射击、爆炸、背景音乐 │ ├── shoot.wav │ ├── explode.wav │ └── ... └── fonts/ # 存放字体文件用于显示分数、生命值 └── simhei.ttf将配置参数如屏幕宽度SCREEN_WIDTH、玩家速度PLAYER_SPEED集中放在settings.py中而不是散落在代码各处这样当你需要调整游戏难度或外观时只需修改这一个文件非常方便。3. 环境搭建与Pygame基础工欲善其事必先利其器。在开始激动人心的编码之前我们需要把Python和Pygame环境准备好。3.1 Python安装与环境配置首先确保你的电脑上安装了Python。访问Python官网下载最新的稳定版本如Python 3.10。安装时务必勾选“Add Python to PATH”这个选项这能让你在命令行中直接使用python和pip命令省去后续手动配置环境变量的麻烦。安装完成后打开命令行Windows上是CMD或PowerShellmacOS/Linux上是Terminal输入python --version。如果能看到正确的版本号输出说明安装成功。注意很多初学者在这里会遇到“python不是内部或外部命令”的错误这几乎都是因为安装时没勾选“Add Python to PATH”或者PATH环境变量未正确设置。如果遇到可以搜索“Windows/Mac 手动添加Python到PATH”的教程解决。接下来是包管理工具pip它通常随Python一同安装。输入pip --version确认其可用。3.2 安装Pygame库与代码编辑器选择有了pip安装Pygame就一行命令的事pip install pygame这条命令会从Python的官方软件仓库下载并安装Pygame及其依赖。安装完成后可以在Python交互环境中输入import pygame来测试是否成功不报错即可。关于代码编辑器我强烈推荐VS Code。它轻量、免费、插件生态丰富。你需要安装两个核心插件Python由Microsoft官方提供提供代码高亮、智能提示、调试等功能。Pygame Snippets虽然不是必须但它能提供一些Pygame常用的代码片段提高编码效率。在VS Code中打开你的项目文件夹它会自动识别Python环境。你可以通过按F5键来运行和调试你的游戏非常方便。3.3 Pygame最小化程序框架让我们从一个能运行的“Hello Pygame”窗口开始理解最基础的框架。创建一个main.py文件输入以下代码import pygame import sys from settings import * # 我们从settings.py导入所有配置 # 初始化pygame的所有模块 pygame.init() # 创建游戏窗口尺寸来自settings.py中的SCREEN_WIDTH和SCREEN_HEIGHT screen pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) # 设置窗口标题 pygame.display.set_caption(太空射击游戏) # 创建一个时钟对象用于控制游戏帧率 clock pygame.time.Clock() # 游戏主循环 running True while running: # 1. 处理事件 for event in pygame.event.get(): if event.type pygame.QUIT: # 点击窗口关闭按钮 running False # 后续可以在这里添加键盘按下等事件处理 # 2. 更新游戏状态 (目前暂无内容) # ... # 3. 渲染绘制 screen.fill(BLACK) # 用黑色清空屏幕BLACK定义在settings.py中 # 后续在这里绘制精灵、文字等 # 4. 刷新显示 pygame.display.flip() # 控制帧率为60帧/秒使游戏在不同性能电脑上运行速度一致 clock.tick(60) # 退出游戏 pygame.quit() sys.exit()同时创建settings.py文件存放配置# 屏幕尺寸 SCREEN_WIDTH 800 SCREEN_HEIGHT 600 # 颜色定义 (R, G, B) BLACK (0, 0, 0) WHITE (255, 255, 255) GREEN (0, 255, 0) RED (255, 0, 0) BLUE (0, 120, 255) # 玩家基础速度 PLAYER_SPEED 5运行main.py你应该能看到一个黑色的窗口。这个循环就是游戏的心脏之后我们所有的功能都将在这个循环内添加。4. 核心模块实现详解有了框架我们就可以像搭积木一样一步步实现游戏的核心功能了。4.1 玩家飞船类的实现在player.py中我们创建玩家类。这个类需要处理移动、射击以及绘制自身。import pygame from settings import * from bullet import Bullet # 导入子弹类用于创建子弹 class Player(pygame.sprite.Sprite): def __init__(self, all_sprites_group, bullets_group): super().__init__() # 加载飞船图像并转换格式提升性能 self.image pygame.image.load(images/player.png).convert_alpha() # 获取图像的矩形区域用于定位和碰撞检测 self.rect self.image.get_rect() # 将飞船初始位置放在屏幕底部中央 self.rect.centerx SCREEN_WIDTH // 2 self.rect.bottom SCREEN_HEIGHT - 10 self.speed PLAYER_SPEED self.health 3 # 玩家生命值 # 传入精灵组用于将创建的子弹添加到组中统一管理 self.all_sprites all_sprites_group self.bullets bullets_group # 射击冷却时间防止子弹连发过快 self.shoot_delay 250 # 毫秒 self.last_shot pygame.time.get_ticks() def update(self): # 获取当前所有按键状态 keys pygame.key.get_pressed() # 根据按键更新飞船位置并限制其不超出屏幕 if keys[pygame.K_LEFT] and self.rect.left 0: self.rect.x - self.speed if keys[pygame.K_RIGHT] and self.rect.right SCREEN_WIDTH: self.rect.x self.speed if keys[pygame.K_UP] and self.rect.top 0: self.rect.y - self.speed if keys[pygame.K_DOWN] and self.rect.bottom SCREEN_HEIGHT: self.rect.y self.speed # 空格键射击 if keys[pygame.K_SPACE]: self.shoot() def shoot(self): # 检查是否过了射击冷却时间 now pygame.time.get_ticks() if now - self.last_shot self.shoot_delay: self.last_shot now # 创建一颗子弹位置在飞船顶部中央 bullet Bullet(self.rect.centerx, self.rect.top, -1) # -1表示向上飞玩家子弹 # 将子弹添加到所有精灵组和玩家子弹组 self.all_sprites.add(bullet) self.bullets.add(bullet) # 这里可以添加射击音效 # shoot_sound.play()这里的关键点convert_alpha(): 如果图片有透明背景PNG格式使用此方法可以显著提高绘制效率。pygame.key.get_pressed(): 这是处理持续按键如按住方向键移动的标准方法它返回一个包含所有按键状态的列表。射击冷却通过记录上次射击时间 (last_shot) 并与当前时间对比实现简单的冷却机制防止玩家按住空格键时子弹形成“激光”。4.2 敌机类的实现敌机 (enemy.py) 的逻辑与玩家类似但移动是自动的并且可能随机发射子弹。import pygame import random from settings import * from bullet import Bullet class Enemy(pygame.sprite.Sprite): def __init__(self, all_sprites_group, enemy_bullets_group): super().__init__() self.image pygame.image.load(images/enemy1.png).convert_alpha() self.rect self.image.get_rect() # 敌机从屏幕顶部随机位置出现 self.rect.x random.randrange(SCREEN_WIDTH - self.rect.width) self.rect.y random.randrange(-100, -40) # 从屏幕外上方出现 # 给敌机一个随机的下落速度增加多样性 self.speed_y random.randrange(1, 4) self.speed_x random.randrange(-2, 3) # 可能有的左右摆动速度 self.all_sprites all_sprites_group self.enemy_bullets enemy_bullets_group self.shoot_delay random.randrange(1000, 3000) # 随机射击间隔 self.last_shot pygame.time.get_ticks() self.health 1 # 敌机生命值 def update(self): self.rect.y self.speed_y self.rect.x self.speed_x # 如果敌机左右摆动超出屏幕则反转横向速度 if self.rect.right SCREEN_WIDTH or self.rect.left 0: self.speed_x * -1 # 敌机随机射击 now pygame.time.get_ticks() if now - self.last_shot self.shoot_delay and self.rect.top 0: # 只有敌机进入屏幕后才可能射击 self.last_shot now self.enemy_shoot() # 如果敌机飞出屏幕底部或生命值归零则移除 if self.rect.top SCREEN_HEIGHT or self.health 0: self.kill() # 从所有包含它的精灵组中移除自己 # 这里可以添加爆炸效果和音效 def enemy_shoot(self): # 敌机向下发射子弹 bullet Bullet(self.rect.centerx, self.rect.bottom, 1) # 1表示向下飞 self.all_sprites.add(bullet) self.enemy_bullets.add(bullet)敌机的移动逻辑可以设计得更复杂比如正弦波移动、追踪玩家等这取决于你想要的游戏难度。4.3 子弹类的实现子弹 (bullet.py) 是最简单的对象它只需要朝一个方向移动。import pygame from settings import * class Bullet(pygame.sprite.Sprite): def __init__(self, x, y, direction): # direction: -1 向上 (玩家子弹) 1 向下 (敌机子弹) super().__init__() self.image pygame.Surface((5, 10)) # 创建一个简单的矩形作为子弹 self.image.fill(GREEN if direction -1 else RED) # 玩家子弹绿色敌机子弹红色 self.rect self.image.get_rect() self.rect.centerx x self.rect.centery y self.speed 10 # 子弹速度 self.direction direction def update(self): self.rect.y self.speed * self.direction # 如果子弹飞出屏幕则销毁以节省资源 if self.rect.bottom 0 or self.rect.top SCREEN_HEIGHT: self.kill()这里我们用纯色矩形代替了图片方便快速原型开发。在实际项目中你可以加载子弹的图片素材。4.4 游戏主循环的整合与碰撞检测现在回到main.py我们将所有模块整合起来并实现最激动人心的部分——碰撞检测。import pygame import random from settings import * from player import Player from enemy import Enemy # ... 其他必要的导入 # 初始化 pygame.init() screen pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption(太空射击游戏 v1.0) clock pygame.time.Clock() # 创建字体对象用于显示分数和生命值 font pygame.font.Font(fonts/simhei.ttf, 24) # 创建精灵组 all_sprites pygame.sprite.Group() player_bullets pygame.sprite.Group() enemies pygame.sprite.Group() enemy_bullets pygame.sprite.Group() # 创建玩家并传入它需要管理的精灵组 player Player(all_sprites, player_bullets) all_sprites.add(player) # 游戏状态变量 score 0 game_over False enemy_spawn_timer 0 ENEMY_SPAWN_RATE 500 # 每500毫秒尝试生成一个敌机 running True while running: # 控制帧率 clock.tick(60) current_time pygame.time.get_ticks() # --- 事件处理 --- for event in pygame.event.get(): if event.type pygame.QUIT: running False if event.type pygame.KEYDOWN: if event.key pygame.K_ESCAPE: running False if event.key pygame.K_r and game_over: # 按R键重新开始游戏 # 重置所有变量和精灵组 score 0 game_over False for sprite in all_sprites: sprite.kill() player Player(all_sprites, player_bullets) all_sprites.add(player) if not game_over: # --- 更新 --- all_sprites.update() # 定期生成敌机 if current_time - enemy_spawn_timer ENEMY_SPAWN_RATE: enemy_spawn_timer current_time # 控制屏幕上敌机数量避免过多 if len(enemies) 10: new_enemy Enemy(all_sprites, enemy_bullets) all_sprites.add(new_enemy) enemies.add(new_enemy) # --- 碰撞检测 --- # 1. 玩家子弹 vs 敌机 hits pygame.sprite.groupcollide(enemies, player_bullets, True, True) for hit in hits: score 10 # 击中一个敌机得10分 # 这里可以添加敌机爆炸效果 # 2. 敌机子弹 vs 玩家 hits pygame.sprite.spritecollide(player, enemy_bullets, True) for hit in hits: player.health - 1 if player.health 0: game_over True # 玩家爆炸效果 # 3. 玩家 vs 敌机 (撞击) hits pygame.sprite.spritecollide(player, enemies, True) for hit in hits: player.health - 2 # 撞击伤害更高 if player.health 0: game_over True # --- 渲染 --- screen.fill(BLACK) all_sprites.draw(screen) # 绘制所有精灵 # 绘制UI分数和生命值 score_text font.render(f分数: {score}, True, WHITE) screen.blit(score_text, (10, 10)) health_text font.render(f生命: {player.health}, True, GREEN) screen.blit(health_text, (SCREEN_WIDTH - 100, 10)) if game_over: # 绘制游戏结束文字 go_text font.render(游戏结束! 按 R 键重新开始, True, RED) screen.blit(go_text, (SCREEN_WIDTH // 2 - go_text.get_width() // 2, SCREEN_HEIGHT // 2)) # --- 刷新显示 --- pygame.display.flip() pygame.quit()碰撞检测详解: Pygame提供了非常方便的碰撞检测函数。pygame.sprite.groupcollide(group1, group2, dokill1, dokill2): 检测两个精灵组之间的碰撞。dokill参数为True时碰撞发生后会自动从组中移除该精灵。它返回一个字典记录了发生碰撞的精灵对。pygame.sprite.spritecollide(sprite, group, dokill): 检测一个精灵与一个精灵组之间的碰撞。常用于检测玩家是否被任何敌机子弹击中。实操心得碰撞检测是性能消耗大户。如果精灵数量非常多比如上百个使用矩形碰撞 (rect.colliderect) 或更精确的圆形碰撞、掩码碰撞时需要优化算法比如使用空间划分如四叉树来减少不必要的两两检测。对于我们这个小游戏直接使用精灵组的碰撞检测函数完全足够。5. 音效、视觉增强与游戏性打磨一个只有方块和颜色的游戏是缺乏沉浸感的。接下来我们为游戏注入灵魂——音效和图像特效。5.1 添加音效与背景音乐声音能极大提升游戏体验。Pygame的pygame.mixer模块负责音频。首先在游戏初始化部分加载音效# 在 main.py 的初始化部分创建玩家后 pygame.mixer.init() shoot_sound pygame.mixer.Sound(sounds/laser1.wav) explosion_sound pygame.mixer.Sound(sounds/explosion.wav) background_music pygame.mixer.music.load(sounds/background.ogg) pygame.mixer.music.play(-1) # -1 表示循环播放注意背景音乐使用pygame.mixer.music模块它用于播放长音频流短音效则使用pygame.mixer.Sound对象。然后在适当的地方播放音效在Player.shoot()方法中添加shoot_sound.play()。在敌机被摧毁self.kill()前或玩家被击中时添加explosion_sound.play()。注意事项音效文件不宜过大格式推荐使用未压缩的.wav用于短音效压缩的.ogg或.mp3用于背景音乐。同时播放太多音效可能会造成延迟可以使用set_num_channels()来设置混音通道数。5.2 引入图像素材与动画特效是时候替换掉那些彩色方块了。准备一些PNG格式的素材确保背景透明player.png: 玩家飞船。enemy1.png,enemy2.png: 不同类型的敌机。bullet.png: 子弹。background.png: 可滚动的星空背景。explosion_frames.png: 一张包含爆炸动画多帧的雪碧图Sprite Sheet。加载背景并实现滚动# 在 main.py 中 background pygame.image.load(images/background.png).convert() background_rect background.get_rect() bg_y1 0 bg_y2 -SCREEN_HEIGHT # 在主循环的渲染部分之前更新背景位置 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(background, (0, bg_y1)) screen.blit(background, (0, bg_y2))通过绘制两张相同的背景图并让它们连续向下移动当一张移出屏幕时立即重置到顶部就形成了无限滚动的效果。对于爆炸动画我们需要创建一个Explosion精灵类它负责加载雪碧图并按帧播放动画播放完毕后自动销毁。class Explosion(pygame.sprite.Sprite): def __init__(self, center): super().__init__() self.explosion_frames [] # 存储每一帧图像 # 假设雪碧图是5x1的横向排列 sheet pygame.image.load(images/explosion_frames.png).convert_alpha() frame_width sheet.get_width() // 5 frame_height sheet.get_height() for i in range(5): frame sheet.subsurface(pygame.Rect(i*frame_width, 0, frame_width, frame_height)) self.explosion_frames.append(frame) self.image self.explosion_frames[0] self.rect self.image.get_rect(centercenter) self.frame 0 self.last_update pygame.time.get_ticks() self.frame_rate 50 # 每帧持续时间(毫秒) def update(self): now pygame.time.get_ticks() if now - self.last_update self.frame_rate: self.last_update now self.frame 1 if self.frame len(self.explosion_frames): self.kill() # 动画播放完销毁自己 else: center self.rect.center self.image self.explosion_frames[self.frame] self.rect self.image.get_rect(centercenter)然后在敌机或玩家被摧毁时在对应位置创建一个Explosion实例并添加到all_sprites组中即可。5.3 游戏性平衡与难度曲线一个好的游戏需要有合理的难度曲线。我们可以通过代码动态调整敌机生成速率: 随着分数增加逐渐缩短ENEMY_SPAWN_RATE。敌机类型与血量: 可以定义多种敌机类继承自Enemy拥有不同的图像、速度、血量和射击模式。随着游戏进行提高高级敌机的出现概率。道具系统: 击毁特定敌机后掉落加血包、武器升级等道具。这需要创建新的PowerUp精灵类并与玩家进行碰撞检测。关卡与Boss: 当分数达到一定值清空当前敌机生成一个大型的Boss敌机拥有多阶段攻击模式。这些扩展点能让你把一个简单的Demo变成一个真正可玩的游戏。6. 性能优化、打包与常见问题当游戏功能基本完成后我们需要关注一些工程化问题让项目更健壮、更易分享。6.1 性能优化技巧图像转换始终对加载的图像使用.convert()或.convert_alpha()。这会将图像转换为与当前显示模式最匹配的格式大幅提升blit绘制速度。避免频繁创建/销毁对象对于频繁使用的对象如子弹可以考虑使用对象池技术。预先创建一定数量的子弹对象并隐藏需要时激活并设置位置不需要时隐藏而非销毁以此减少内存分配和垃圾回收的开销。脏矩形更新对于复杂场景如果每一帧都重绘整个屏幕 (screen.fill() 全部重画) 效率较低。可以只更新屏幕上发生变化的部分区域 (pygame.display.update(dirty_rects))。但对于我们这个规模的项目全屏更新完全没问题。控制帧率clock.tick(60)确保了游戏以大约60FPS运行防止在性能过剩的电脑上循环过快导致CPU占用率飙升和游戏逻辑失控。6.2 将游戏打包成可执行文件你肯定希望把你的成果分享给没有安装Python的朋友。使用PyInstaller可以轻松将Python脚本打包成独立的.exe(Windows) 或.app(macOS) 文件。首先安装PyInstallerpip install pyinstaller然后在项目根目录下打开命令行执行pyinstaller --onefile --windowed --add-data images;images --add-data sounds;sounds --add-data fonts;fonts main.py--onefile: 打包成单个可执行文件。--windowed: 运行时不显示命令行窗口。--add-data: 将资源文件夹图片、声音、字体包含进打包文件。分号;前是源文件夹后是打包后的虚拟目录Windows用;macOS/Linux用:。main.py: 你的主程序入口。打包完成后在dist文件夹里就能找到可执行文件。注意你可能需要调整代码中加载资源的路径使其在打包后也能正确找到。通常使用以下方法import sys import os def resource_path(relative_path): 获取资源的绝对路径。在开发环境和打包后都有效 try: # PyInstaller创建的临时文件夹路径 base_path sys._MEIPASS except Exception: base_path os.path.abspath(.) return os.path.join(base_path, relative_path) # 使用方式 image pygame.image.load(resource_path(images/player.png)).convert_alpha()6.3 开发与调试中的常见问题图像不显示或显示为黑色检查路径确保文件路径正确区分大小写。检查图像格式Pygame对某些格式支持不好优先使用PNG或JPG。使用convert()忘记使用.convert()或.convert_alpha()可能导致性能低下或显示问题。音效不播放初始化混音器确保在播放声音前调用了pygame.mixer.init()。检查文件格式和路径.wav文件兼容性最好。同样检查路径。通道被占用短时间播放大量音效可能导致后续音效被忽略。可以尝试增加通道数pygame.mixer.set_num_channels(32)。游戏运行卡顿帧率问题检查是否在循环中调用了clock.tick(FPS)。图像过大确保使用的图片尺寸没有远大于实际显示尺寸。低效的碰撞检测如果实体数量巨大考虑优化碰撞检测逻辑。打包后找不到资源文件使用resource_path函数如上节所述这是解决此问题的标准方法。检查--add-data参数确保命令中的路径分隔符和源/目标目录设置正确。精灵闪烁或更新异常双缓冲Pygame默认使用双缓冲通常没问题。确保你的绘制顺序是先screen.fill()清屏然后按从后到前的顺序绘制所有元素如背景-精灵-UI最后调用pygame.display.flip()或pygame.display.update()一次性更新屏幕。开发游戏是一个不断迭代和调试的过程。遇到问题时善用print()语句输出关键变量值或者使用VS Code的调试功能设置断点是定位问题最直接的方法。当你看到自己亲手打造的游戏窗口运行起来飞船随着你的按键移动子弹击毁敌机并爆出绚丽的火花和音效时那种成就感是无与伦比的。从这个项目出发你可以尝试添加更多功能比如不同类型的武器、Boss战、关卡设计甚至尝试用更专业的游戏引擎如Godot或Unity重制它原理都是相通的。