使用 Pygame 开发简易太空侵略者游戏

举报
Damon小智 发表于 2025/01/31 14:32:57 2025/01/31
206 0 0
【摘要】 在 2D 游戏开发中,“太空侵略者”是一款入门难度适中、却能覆盖多种常见游戏机制的项目。在本篇中,我们将使用 Python + Pygame 实现一个简化版本的 Space Invaders,涵盖:玩家移动、子弹发射、敌人生成与移动、碰撞检测、计分与游戏结束逻辑等。

1. 前言

在 2D 游戏开发中,“太空侵略者”是一款入门难度适中、却能覆盖多种常见游戏机制的项目:

  • 玩家控制飞船(Player)左右移动,发射子弹。
  • 敌人(Enemy)排列成一行或多行,从屏幕顶端缓慢移动或左右移动逼近玩家。
  • 当敌人被击中时,会被销毁并加分。若敌人到达玩家所在行或玩家被碰撞,则游戏结束。

在本篇中,我们将使用 Python + Pygame 实现一个简化版本的 Space Invaders,涵盖:玩家移动、子弹发射、敌人生成与移动、碰撞检测、计分与游戏结束逻辑等。


2. 开发环境

  1. Python 3.x
  2. Pygame
    如果尚未安装,可在命令行执行:
    pip install pygame
    
  3. 桌面系统:Windows、macOS 或大多数 Linux 系统都可正常运行。

确认 import pygame 无报错即可开始。


3. 游戏思路与关键点

  1. 玩家(Player)

    • 以飞船形象出现在屏幕下方,可左右移动(受屏幕边界限制)。
    • 按空格键或其他按键发射子弹。子弹往上移动,离开屏幕后可回收。
  2. 敌人(Enemy)

    • 可一次性生成若干敌人(如 3 行 × 6 列),排列在屏幕上方。
    • 敌人整体移动:
      • 可以先左右移动,到达边界后整体往下一行移动;
      • 或者在一定频率向玩家方向缓慢下降。
    • 当敌人到达玩家所在行(或接近底部),游戏结束。
  3. 子弹(Bullet)

    • 玩家发射的子弹以固定速度向上移动;
    • 敌人若与子弹发生碰撞,则敌人被销毁,玩家得分,子弹也随之消失。
  4. 碰撞检测

    • Rect 或基于距离的判断:当子弹矩形与敌人矩形重叠时,判定击中。
    • 当敌人矩形与玩家矩形重叠,或敌人到达屏幕下方,则游戏结束。
  5. 游戏循环

    • 每帧:处理输入事件(玩家移动、发射)、更新玩家位置、子弹与敌人位置,检测碰撞、绘制画面。
    • 当所有敌人消灭或玩家阵亡,即可结束游戏并显示结果。

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()

主要逻辑解析

  1. Player(玩家)

    • 只有左右移动逻辑,且在碰撞边界时保持在范围内。
    • 按空格键发射子弹(Bullet 对象),存入列表。
  2. Enemy(敌人)

    • 通过 create_enemies() 一次性生成多个敌人,按行列布局排列在上方。
    • 每帧都执行 update(),在水平方向移动;若检测到超出左右边界,就整体往下一行,并反转移动方向。
  3. Bullet(子弹)

    • 每帧向上移动,若飞出屏幕则被移除;
    • 碰撞到敌人后,敌人与子弹都被移除并加分。
  4. 碰撞检测

    • 使用 Rectcolliderect 方法判断子弹与敌人是否重叠。
    • 当任意敌人到达玩家所在行或越过玩家,则游戏结束。
  5. 游戏结束

    • 当敌人列表为空时,玩家成功消灭全部敌人,也退出游戏循环;
    • 或者当敌人到达玩家区域,表示玩家失败。
    • 最后进入 game_over() 界面做简单提示后退出。

5. 运行效果

image.png


6. 总结

通过本篇文章,你已经学会了如何使用 Pygame 编写一个简易版的 Space Invaders 游戏:从玩家移动与射击,到敌人群体移动与下落,再到碰撞检测与游戏结束逻辑,都得到了体现。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。