使用Pygame制作“太空侵略者”游戏
1. 前言
在 2D 游戏开发中,“太空侵略者”是一款入门难度适中、却能覆盖多种常见游戏机制的项目:
- 玩家控制飞船(Player)左右移动,发射子弹。
- 敌人(Enemy)排列成一行或多行,从屏幕顶端缓慢移动或左右移动逼近玩家。
- 当敌人被击中时,会被销毁并加分。若敌人到达玩家所在行或玩家被碰撞,则游戏结束。
在本篇中,我们将使用 Python + Pygame 实现一个简化版本的 Space Invaders,涵盖:玩家移动、子弹发射、敌人生成与移动、碰撞检测、计分与游戏结束逻辑等。
2. 开发环境
- Python 3.x
- Pygame
如果尚未安装,可在命令行执行:pip install pygame
- 桌面系统:Windows、macOS 或大多数 Linux 系统都可正常运行。
确认 import pygame
无报错即可开始。
3. 游戏思路与关键点
-
玩家(Player)
- 以飞船形象出现在屏幕下方,可左右移动(受屏幕边界限制)。
- 按空格键或其他按键发射子弹。子弹往上移动,离开屏幕后可回收。
-
敌人(Enemy)
- 可一次性生成若干敌人(如 3 行 × 6 列),排列在屏幕上方。
- 敌人整体移动:
- 可以先左右移动,到达边界后整体往下一行移动;
- 或者在一定频率向玩家方向缓慢下降。
- 当敌人到达玩家所在行(或接近底部),游戏结束。
-
子弹(Bullet)
- 玩家发射的子弹以固定速度向上移动;
- 敌人若与子弹发生碰撞,则敌人被销毁,玩家得分,子弹也随之消失。
-
碰撞检测
Rect
或基于距离的判断:当子弹矩形与敌人矩形重叠时,判定击中。- 当敌人矩形与玩家矩形重叠,或敌人到达屏幕下方,则游戏结束。
-
游戏循环
- 每帧:处理输入事件(玩家移动、发射)、更新玩家位置、子弹与敌人位置,检测碰撞、绘制画面。
- 当所有敌人消灭或玩家阵亡,即可结束游戏并显示结果。
4. 完整示例代码
以下示例保存为 space_invaders.py
并运行即可。请根据自己的需求调节画面尺寸、敌人数量、速度等参数。
import pygame
import sys
import random
# 初始化 Pygame
pygame.init()
# ---------------------
# 全局配置
# ---------------------
WIDTH, HEIGHT = 600, 600
FPS = 60
# 颜色
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
# 创建窗口
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Space Invaders - Pygame 示例")
clock = pygame.time.Clock()
# 字体
font = pygame.font.SysFont("arial", 24)
# ---------------------
# 玩家类
# ---------------------
class Player:
def __init__(self):
self.width = 40
self.height = 40
self.x = (WIDTH - self.width) // 2
self.y = HEIGHT - 60
self.speed = 5
self.color = GREEN
def draw(self, surface):
pygame.draw.rect(surface, self.color, (self.x, self.y, self.width, self.height))
def move_left(self):
self.x -= self.speed
if self.x < 0:
self.x = 0
def move_right(self):
self.x += self.speed
if self.x + self.width > WIDTH:
self.x = WIDTH - self.width
def get_rect(self):
return pygame.Rect(self.x, self.y, self.width, self.height)
# ---------------------
# 敌人类
# ---------------------
class Enemy:
def __init__(self, x, y):
self.width = 30
self.height = 30
self.x = x
self.y = y
self.speed_x = 2 # 水平移动速度
self.speed_y = 20 # 到达边界后往下移动的距离
self.color = RED
def draw(self, surface):
pygame.draw.rect(surface, self.color, (self.x, self.y, self.width, self.height))
def update(self, enemies):
"""
水平移动敌人群,若到达左右边界,则整体向下移动
"""
self.x += self.speed_x
# 检测边界
if self.x < 0 or self.x + self.width > WIDTH:
# 改变方向,并让所有敌人往下移动 speed_y
for e in enemies:
e.speed_x = -e.speed_x
e.y += e.speed_y
return
def get_rect(self):
return pygame.Rect(self.x, self.y, self.width, self.height)
# ---------------------
# 子弹类
# ---------------------
class Bullet:
def __init__(self, x, y):
self.x = x
self.y = y
self.radius = 5
self.speed = 7
self.color = YELLOW
def update(self):
self.y -= self.speed # 向上移动
def draw(self, surface):
pygame.draw.circle(surface, self.color, (int(self.x), int(self.y)), self.radius)
def get_rect(self):
return pygame.Rect(self.x - self.radius, self.y - self.radius,
self.radius * 2, self.radius * 2)
# ---------------------
# 工具函数
# ---------------------
def create_enemies(rows=3, cols=6):
"""
生成敌人列表,分布在屏幕上方
"""
enemies = []
gap_x = 60
gap_y = 50
start_x = 50
start_y = 50
for row in range(rows):
for col in range(cols):
x = start_x + col * gap_x
y = start_y + row * gap_y
enemy = Enemy(x, y)
enemies.append(enemy)
return enemies
def main():
player = Player()
enemies = create_enemies(rows=3, cols=6)
bullets = []
score = 0
running = True
while running:
clock.tick(FPS)
# 1) 处理事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
# 发射子弹
bullet_x = player.x + player.width // 2
bullet_y = player.y
bullets.append(Bullet(bullet_x, bullet_y))
# 键盘输入
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.move_left()
if keys[pygame.K_RIGHT]:
player.move_right()
# 2) 更新子弹位置并检测越界
for b in bullets[:]:
b.update()
if b.y + b.radius < 0:
bullets.remove(b)
# 3) 更新敌人群位置
for e in enemies:
e.update(enemies)
# 4) 碰撞检测:子弹与敌人
for b in bullets[:]:
b_rect = b.get_rect()
for e in enemies[:]:
e_rect = e.get_rect()
if b_rect.colliderect(e_rect):
# 撞击 -> 敌人消失、子弹消失、得分
enemies.remove(e)
bullets.remove(b)
score += 10
break # 该子弹已被移除,无需再检测其它敌人
# 5) 检测敌人是否到达玩家或超越底部 -> 游戏结束
for e in enemies:
# 若敌人越过玩家所在 y,或者直接与玩家重叠
if e.y + e.height > player.y:
running = False
# 6) 如果敌人全部消灭 -> 获胜 or 提示
if not enemies:
# 可以自定义下一波敌人或结束游戏
running = False
# 7) 绘制
screen.fill(BLACK)
# 绘制玩家、敌人、子弹
player.draw(screen)
for e in enemies:
e.draw(screen)
for b in bullets:
b.draw(screen)
# 显示得分
score_surface = font.render(f"Score: {score}", True, WHITE)
screen.blit(score_surface, (10, 10))
pygame.display.flip()
game_over(score)
def game_over(score):
# 游戏结束界面
screen.fill(BLACK)
msg = f"Game Over! Your Score: {score}"
label = font.render(msg, True, WHITE)
rect = label.get_rect(center=(WIDTH // 2, HEIGHT // 2))
screen.blit(label, rect)
pygame.display.flip()
pygame.time.wait(3000)
pygame.quit()
sys.exit()
if __name__ == "__main__":
main()
主要逻辑解析
-
Player(玩家)
- 只有左右移动逻辑,且在碰撞边界时保持在范围内。
- 按空格键发射子弹(
Bullet
对象),存入列表。
-
Enemy(敌人)
- 通过
create_enemies()
一次性生成多个敌人,按行列布局排列在上方。 - 每帧都执行
update()
,在水平方向移动;若检测到超出左右边界,就整体往下一行,并反转移动方向。
- 通过
-
Bullet(子弹)
- 每帧向上移动,若飞出屏幕则被移除;
- 碰撞到敌人后,敌人与子弹都被移除并加分。
-
碰撞检测
- 使用
Rect
的colliderect
方法判断子弹与敌人是否重叠。 - 当任意敌人到达玩家所在行或越过玩家,则游戏结束。
- 使用
-
游戏结束
- 当敌人列表为空时,玩家成功消灭全部敌人,也退出游戏循环;
- 或者当敌人到达玩家区域,表示玩家失败。
- 最后进入
game_over()
界面做简单提示后退出。
5. 运行效果
6. 总结
通过本篇文章,你已经学会了如何使用 Pygame 编写一个简易版的 Space Invaders 游戏:从玩家移动与射击,到敌人群体移动与下落,再到碰撞检测与游戏结束逻辑,都得到了体现。