用 pygame 做一个完整的小飞机大战:方向键控制飞机、空格发射子弹、敌机不断下落、碰撞判定、三条命和计分。全部用矩形和圆形绘制,不依赖任何图片素材。
1. 玩家飞机与键盘控制
飞机就是一个矩形,用方向键移动并限制在窗口内。用 pygame.key.get_pressed() 实现按住连续移动:
import pygame
W, H = 480, 640
plane = pygame.Rect(W // 2 - 25, H - 80, 50, 40)
def move_plane(keys):
if keys[pygame.K_LEFT] and plane.left > 0:
plane.move_ip(-6, 0)
if keys[pygame.K_RIGHT] and plane.right < W:
plane.move_ip(6, 0)
if keys[pygame.K_UP] and plane.top > 0:
plane.move_ip(0, -6)
if keys[pygame.K_DOWN] and plane.bottom < H:
plane.move_ip(0, 6)
2. 子弹与射击
子弹列表存矩形,空格键生成新子弹;每帧所有子弹向上移动,超出屏幕就移除:
bullets = []
def shoot(keys, now):
global next_shot
if keys[pygame.K_SPACE] and now >= next_shot:
bullets.append(pygame.Rect(plane.centerx - 2, plane.top, 4, 12))
next_shot = now + 200 # 200ms 一发
def update_bullets():
for b in bullets[:]:
b.move_ip(0, -10)
if b.bottom < 0:
bullets.remove(b)
3. 敌机与碰撞
敌机定时从顶部生成,随机横向位置,向下移动。子弹与敌机矩形相交(colliderect)就双双消失;敌机撞到飞机或飞出底部就扣命:
enemies = []
lives = 3
score = 0
def spawn_enemy(now):
if now >= next_spawn:
enemies.append(pygame.Rect(random.randrange(W - 40), -40, 40, 30))
next_spawn = now + 900
def update_enemies():
global lives, score
for e in enemies[:]:
e.move_ip(0, 4)
if e.top > H:
enemies.remove(e); lives -= 1
continue
for b in bullets[:]:
if e.colliderect(b):
enemies.remove(e); bullets.remove(b)
score += 10
break
if plane.colliderect(e):
enemies.remove(e); lives -= 1
4. 完整代码
import random, pygame
W, H = 480, 640
pygame.init()
screen = pygame.display.set_mode((W, H))
clock = pygame.time.Clock()
font = pygame.font.SysFont('simhei', 26)
plane = pygame.Rect(W // 2 - 25, H - 80, 50, 40)
bullets = []
enemies = []
lives = 3
score = 0
next_shot = 0
next_spawn = 0
game_over = False
while not game_over:
now = pygame.time.get_ticks()
keys = pygame.key.get_pressed()
for e in pygame.event.get():
if e.type == pygame.QUIT:
pygame.quit(); raise SystemExit
move_plane(keys)
shoot(keys, now)
update_bullets()
spawn_enemy(now)
update_enemies()
if lives <= 0:
game_over = True
break
screen.fill((10, 10, 25))
pygame.draw.rect(screen, (90, 200, 255), plane, border_radius=8)
for b in bullets:
pygame.draw.rect(screen, (255, 220, 80), b)
for e in enemies:
pygame.draw.rect(screen, (230, 80, 80), e, border_radius=6)
screen.blit(font.render('得分 %d 生命 %d' % (score, lives), True, (255, 255, 255)), (10, 10))
pygame.display.flip()
clock.tick(60)
print('游戏结束,最终得分:', score)
5. 运行与常见问题
保存为 plane.py,python3 plane.py 运行。常见问题:①子弹穿透敌机——检测到碰撞后要立刻 remove 并 break,防止一个子弹打多架;②敌机同时消失——遍历列表时用副本 [:];③卡顿——clock.tick(60) 限制帧率。
💡 改进方向:①爆炸粒子效果;②敌机分类型(血量/速度不同);③道具(双发、护盾);④关卡与 BOSS;⑤音效与最高分存档。