第7章 游戏开发智能化实践:从原型到完整游戏
第7章 游戏开发智能化实践:从原型到完整游戏
在前几章中,我们探索了桌面应用、Web应用开发的AI辅助模式。本章将进入一个更具挑战性和创造性的领域——游戏开发。游戏开发融合了图形学、物理模拟、交互设计、音效系统等多个技术领域,传统上被认为是编程的"硬核"方向。然而,随着AI辅助工具的成熟,游戏开发的门槛正在大幅降低。
据2025年的行业数据显示,使用AI辅助的游戏开发者,其原型开发速度平均提升300%以上。掌趣科技联合蓝亚盒子发布的LayaIdea工具,实现了从策划文档到3D游戏项目的自动化生成,将互动试玩广告的开发周期从一周缩短至一天。网易接入通义千问后,游戏测试系统的开发效率提升了50%。甚至有开发者完全借助AI工具,三个月内完成了一款100%由AI生成的游戏《Codex Mortis》。
本章将通过一系列由浅入深的案例,展示如何利用ChatGPT和GitHub Copilot加速游戏开发。我们将从简单的视觉效果开始,逐步构建完整的游戏项目。所有代码均采用Allman风格,使用驼峰命名,确保在VS Code和VS 2022中可直接运行。
7.1 视觉特效:奠定游戏的美学基础
游戏开发的第一步通常是视觉效果。AI可以帮助我们快速生成粒子系统、纹理动画等基础特效。
7.1.1 旋转星系:粒子系统的AI实现
旋转星系是一个经典的粒子特效案例,通过粒子的螺旋运动模拟星系的旋转效果。使用Pygame实现这一特效,需要理解粒子系统的基本原理:每个粒子具有位置、速度、角度等属性,在每帧中更新这些属性并绘制。
需求描述:
向ChatGPT提出需求:"请用Python和Pygame实现一个旋转星系特效。要求:
- 在窗口中心生成数千个粒子,形成螺旋形状
- 粒子围绕中心旋转,内圈速度快,外圈速度慢
- 粒子颜色从中心向外渐变(中心白/黄,外围蓝/紫)
- 添加淡淡的拖尾效果
- 帧率稳定在60FPS"
ChatGPT会生成如下代码(我们调整为Allman风格并添加详细注释):
import pygame
import math
import random
# 初始化Pygame
pygame.init()
# 窗口设置
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("旋转星系 - AI生成特效")
# 颜色常量
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
YELLOW = (255, 255, 100)
BLUE = (100, 150, 255)
PURPLE = (180, 100, 255)
class Particle:
"""
单个粒子类
"""
def __init__(self, distance, angle, speed):
"""
初始化粒子
Parameters:
distance (float): 粒子到中心的距离
angle (float): 初始角度(弧度)
speed (float): 旋转速度
"""
self.distance = distance
self.angle = angle
self.speed = speed
self.size = random.uniform(1.0, 2.5)
# 根据距离计算颜色(中心暖色,外围冷色)
self.color = self.CalculateColor(distance)
def CalculateColor(self, distance):
"""
根据距离计算颜色
Parameters:
distance (float): 粒子到中心的距离
Returns:
tuple: RGB颜色值
"""
maxDist = 250.0
t = min(distance / maxDist, 1.0)
if t < 0.3:
# 中心区域:白到黄
r = 255
g = 255 - int(t * 155) # 从255降到200左右
b = 200 - int(t * 150) # 从200降到50左右
else:
# 外围区域:蓝到紫
localT = (t - 0.3) / 0.7
r = 150 + int(localT * 105) # 150 -> 255
g = 100 - int(localT * 60) # 100 -> 40
b = 255
return (r, g, b)
def Update(self, centerX, centerY):
"""
更新粒子位置
Parameters:
centerX (int): 旋转中心X坐标
centerY (int): 旋转中心Y坐标
"""
# 角度随时间增加(旋转)
self.angle += self.speed
# 计算笛卡尔坐标
self.x = centerX + math.cos(self.angle) * self.distance
self.y = centerY + math.sin(self.angle) * self.distance
def Draw(self, surface, trailSurface):
"""
绘制粒子
Parameters:
surface (Surface): 主绘制表面
trailSurface (Surface): 拖尾效果的表面
"""
# 在主表面绘制粒子
pygame.draw.circle(surface, self.color, (int(self.x), int(self.y)), int(self.size))
# 在拖尾表面绘制半透明粒子(用于拖尾效果)
alphaColor = (*self.color, 30) # 添加alpha通道
trailSurface.set_at((int(self.x), int(self.y)), alphaColor)
class Galaxy:
"""
星系特效类
"""
def __init__(self, particleCount=3000):
"""
初始化星系
Parameters:
particleCount (int): 粒子数量
"""
self.particles = []
self.centerX = WIDTH // 2
self.centerY = HEIGHT // 2
# 创建拖尾表面
self.trailSurface = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
# 生成粒子
self.GenerateParticles(particleCount)
def GenerateParticles(self, count):
"""
生成粒子
Parameters:
count (int): 粒子数量
"""
for _ in range(count):
# 随机距离,分布偏向中心
distance = random.gauss(120, 80)
distance = max(10, min(350, abs(distance)))
# 随机角度
angle = random.uniform(0, math.pi * 2)
# 旋转速度:内圈快,外圈慢
speed = 0.01 * (250 / max(distance, 50))
self.particles.append(Particle(distance, angle, speed))
def Update(self):
"""更新所有粒子"""
for particle in self.particles:
particle.Update(self.centerX, self.centerY)
def Draw(self, screen):
"""
绘制星系
Parameters:
screen (Surface): 屏幕表面
"""
# 每帧轻微淡化拖尾表面(制造拖尾效果)
self.trailSurface.fill((0, 0, 0, 10)) # 半透明黑色填充
# 先绘制粒子到拖尾表面
for particle in self.particles:
particle.Draw(screen, self.trailSurface)
# 将拖尾表面混合到主屏幕
screen.blit(self.trailSurface, (0, 0), special_flags=pygame.BLEND_ALPHA_SDL2)
# 在中心绘制一个亮核
pygame.draw.circle(screen, (255, 255, 200), (self.centerX, self.centerY), 8)
pygame.draw.circle(screen, (255, 200, 100), (self.centerX, self.centerY), 5)
def main():
"""主函数"""
clock = pygame.time.Clock()
galaxy = Galaxy(4000)
running = True
while running:
# 事件处理
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
# 更新
galaxy.Update()
# 绘制
screen.fill(BLACK)
galaxy.Draw(screen)
# 显示FPS
font = pygame.font.SysFont("Arial", 16)
fpsText = font.render(f"FPS: {int(clock.get_fps())}", True, WHITE)
screen.blit(fpsText, (10, 10))
pygame.display.flip()
clock.tick(60)
pygame.quit()
if __name__ == "__main__":
main()
代码解析:
这段AI生成的代码展示了几个关键的游戏开发概念:
- 粒子系统:
Particle类封装了单个粒子的属性(距离、角度、速度、颜色)和行为(更新、绘制)。 - 颜色渐变:
CalculateColor方法根据粒子到中心的距离计算颜色,实现中心暖色、外围冷色的效果。 - 运动规律:旋转速度与距离成反比,内圈快外圈慢,模拟星系旋转的物理特性。
- 拖尾效果:使用一个带Alpha通道的表面存储上一帧的粒子轨迹,通过每帧半透明填充实现拖尾。
运行这段代码,可以看到数千个粒子在中心周围旋转,形成美丽的螺旋星系效果。
AI辅助心得:生成这段代码时,ChatGPT正确理解了"内圈快外圈慢"的物理规律,并实现了颜色渐变。如果对效果不满意,可以继续与AI对话,例如要求"增加一些随机闪烁的星星"或"让中心更亮一些",AI会给出相应的修改建议。
7.1.2 移动的纹理:动态背景生成
第二个案例实现移动的纹理效果,常用于游戏背景或动态菜单。我们将创建一个流动的星云纹理,通过噪声函数生成动态图案。
与Copilot协作:
在VS Code中新建文件moving_texture.py,输入导入语句和类定义,观察Copilot的补全。
import pygame
import numpy as np
import math
import random
class MovingTexture:
"""
移动纹理类 - 生成动态流动的星云效果
"""
def __init__(self, width, height):
"""
初始化纹理
Parameters:
width (int): 纹理宽度
height (int): 纹理高度
"""
self.width = width
self.height = height
self.time = 0
# 创建表面
self.surface = pygame.Surface((width, height))
# 预计算一些噪声参数
self.octaves = 4
self.persistence = 0.5
self.lacunarity = 2.0
def Noise(self, x, y):
"""
生成简单的噪声值
Parameters:
x, y (float): 坐标
Returns:
float: 噪声值在0-1之间
"""
# 使用正弦函数组合模拟噪声
return (math.sin(x * 0.01) * math.cos(y * 0.01) +
math.sin(x * 0.02 + 1.0) * math.cos(y * 0.02 + 2.0) * 0.5 +
math.sin(x * 0.05 + 3.0) * math.cos(y * 0.05 + 4.0) * 0.25)
def FractalNoise(self, x, y):
"""
生成分形噪声
Parameters:
x, y (float): 坐标
Returns:
float: 噪声值在0-1之间
"""
value = 0.0
amplitude = 1.0
frequency = 1.0
maxAmplitude = 0.0
for _ in range(self.octaves):
value += amplitude * self.Noise(x * frequency + self.time * 0.1,
y * frequency)
maxAmplitude += amplitude
amplitude *= self.persistence
frequency *= self.lacunarity
return value / maxAmplitude
def Update(self):
"""更新纹理状态"""
self.time += 1
# 创建像素数组
pixels = pygame.surfarray.pixels3d(self.surface)
# 遍历每个像素
for x in range(self.width):
for y in range(self.height):
# 生成三个通道的噪声
r = self.FractalNoise(x, y)
g = self.FractalNoise(x + 100, y + 50)
b = self.FractalNoise(x - 50, y + 100)
# 映射到0-255范围并设置颜色
pixels[x, y] = [
int(r * 255),
int(g * 255),
int(b * 255)
]
# 释放像素数组
del pixels
def Draw(self, screen, offsetX=0, offsetY=0):
"""
绘制纹理到屏幕
Parameters:
screen (Surface): 目标屏幕
offsetX, offsetY (int): 偏移量
"""
screen.blit(self.surface, (offsetX, offsetY))
def main():
pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("移动纹理 - 动态星云")
clock = pygame.time.Clock()
# 创建两个纹理实现无缝滚动
texture1 = MovingTexture(WIDTH, HEIGHT)
texture2 = MovingTexture(WIDTH, HEIGHT)
offset = 0
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# 更新纹理
texture1.Update()
texture2.Update()
# 清除屏幕
screen.fill((0, 0, 0))
# 绘制两个纹理,实现滚动效果
texture1.Draw(screen, 0, offset - HEIGHT)
texture2.Draw(screen, 0, offset)
# 更新偏移量
offset += 1
if offset >= HEIGHT:
offset = 0
pygame.display.flip()
clock.tick(60)
pygame.quit()
if __name__ == "__main__":
main()
Copilot在编写过程中发挥了重要作用:在输入def FractalNoise后,它自动补全了分形噪声的实现;在像素循环部分,它建议了使用pygame.surfarray进行快速像素操作的方法。
7.1.3 随机运动的小球:物理模拟入门
第三个案例模拟多个小球在屏幕内的随机运动,包含简单的物理特性:碰撞检测、反弹、摩擦力等。
需求描述:
向ChatGPT提出:"用Pygame实现一个随机运动的小球模拟。要求:
- 创建20个小球,随机大小(10-30像素)、随机颜色、随机初始位置和速度
- 小球之间发生碰撞时,根据物理规律改变速度
- 小球与窗口边界碰撞时反弹(能量损失系数0.8)
- 添加简单的摩擦力,使小球逐渐减速
- 用鼠标点击可以在点击位置生成新小球"
ChatGPT生成的代码需要包含向量运算和碰撞检测。我们整理后的代码采用面向对象设计:
import pygame
import math
import random
# 初始化Pygame
pygame.init()
# 窗口设置
WIDTH, HEIGHT = 900, 700
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("随机运动的小球 - 物理模拟")
# 颜色
BLACK = (0, 0, 0)
class Vector2:
"""
二维向量类,用于表示位置、速度等
"""
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector2(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Vector2(self.x - other.x, self.y - other.y)
def __mul__(self, scalar):
return Vector2(self.x * scalar, self.y * scalar)
def Length(self):
"""向量长度"""
return math.sqrt(self.x * self.x + self.y * self.y)
def Normalize(self):
"""归一化"""
length = self.Length()
if length > 0:
return Vector2(self.x / length, self.y / length)
return Vector2(0, 0)
class Ball:
"""
小球类
"""
def __init__(self, x, y, radius=None, color=None):
"""
初始化小球
Parameters:
x, y (float): 初始位置
radius (int, optional): 半径
color (tuple, optional): 颜色
"""
self.pos = Vector2(x, y)
# 随机半径
if radius is None:
self.radius = random.randint(8, 25)
else:
self.radius = radius
# 随机颜色
if color is None:
self.color = (
random.randint(50, 255),
random.randint(50, 255),
random.randint(50, 255)
)
else:
self.color = color
# 随机速度
angle = random.uniform(0, math.pi * 2)
speed = random.uniform(2, 8)
self.vel = Vector2(math.cos(angle) * speed, math.sin(angle) * speed)
# 物理参数
self.mass = self.radius # 质量与半径成正比
self.friction = 0.995 # 摩擦力系数
def Update(self):
"""更新位置"""
# 应用摩擦力
self.vel = self.vel * self.friction
# 更新位置
self.pos = self.pos + self.vel
def CheckBoundaryCollision(self):
"""检查与边界的碰撞并反弹"""
bounceFactor = 0.8 # 能量损失系数
if self.pos.x - self.radius < 0:
self.pos.x = self.radius
self.vel.x = abs(self.vel.x) * bounceFactor
elif self.pos.x + self.radius > WIDTH:
self.pos.x = WIDTH - self.radius
self.vel.x = -abs(self.vel.x) * bounceFactor
if self.pos.y - self.radius < 0:
self.pos.y = self.radius
self.vel.y = abs(self.vel.y) * bounceFactor
elif self.pos.y + self.radius > HEIGHT:
self.pos.y = HEIGHT - self.radius
self.vel.y = -abs(self.vel.y) * bounceFactor
def CheckBallCollision(self, other):
"""
检查与另一个小球的碰撞
Parameters:
other (Ball): 另一个小球
Returns:
bool: 是否发生碰撞
"""
# 计算距离
delta = self.pos - other.pos
distance = delta.Length()
if distance == 0 or distance > self.radius + other.radius:
return False
# 发生碰撞,计算新的速度
# 使用弹性碰撞公式
normal = delta.Normalize()
# 相对速度
relativeVel = self.vel - other.vel
# 计算冲击速度
velAlongNormal = relativeVel.x * normal.x + relativeVel.y * normal.y
if velAlongNormal > 0:
return False # 正在分离,不处理
# 弹性系数
e = 0.8
# 计算冲量标量
impulseScalar = -(1 + e) * velAlongNormal
impulseScalar /= (1 / self.mass + 1 / other.mass)
# 应用冲量
impulse = normal * impulseScalar
self.vel = self.vel + impulse * (1 / self.mass)
other.vel = other.vel - impulse * (1 / other.mass)
# 分离重叠(避免粘在一起)
overlap = self.radius + other.radius - distance
if overlap > 0:
displacement = normal * (overlap * 0.5)
self.pos = self.pos + displacement
other.pos = other.pos - displacement
return True
def Draw(self, surface):
"""绘制小球"""
pygame.draw.circle(surface, self.color,
(int(self.pos.x), int(self.pos.y)),
self.radius)
# 绘制高光
highlightPos = (int(self.pos.x - self.radius * 0.3),
int(self.pos.y - self.radius * 0.3))
pygame.draw.circle(surface, (255, 255, 255, 100),
highlightPos, self.radius // 4)
class BallSimulation:
"""
小球模拟主类
"""
def __init__(self, ballCount=20):
"""
初始化模拟
Parameters:
ballCount (int): 初始小球数量
"""
self.balls = []
for _ in range(ballCount):
# 随机位置,避免重叠
while True:
x = random.randint(50, WIDTH - 50)
y = random.randint(50, HEIGHT - 50)
radius = random.randint(8, 25)
# 检查与现有小球的重叠
overlapping = False
for ball in self.balls:
dx = x - ball.pos.x
dy = y - ball.pos.y
distance = math.sqrt(dx * dx + dy * dy)
if distance < radius + ball.radius + 10:
overlapping = True
break
if not overlapping:
self.balls.append(Ball(x, y, radius))
break
def AddBall(self, x, y):
"""
添加新小球
Parameters:
x, y (int): 鼠标点击位置
"""
self.balls.append(Ball(x, y))
def Update(self):
"""更新所有小球"""
# 更新位置
for ball in self.balls:
ball.Update()
# 边界碰撞
for ball in self.balls:
ball.CheckBoundaryCollision()
# 小球间碰撞检测
for i in range(len(self.balls)):
for j in range(i + 1, len(self.balls)):
self.balls[i].CheckBallCollision(self.balls[j])
def Draw(self, surface):
"""绘制所有小球"""
surface.fill(BLACK)
for ball in self.balls:
ball.Draw(surface)
def main():
clock = pygame.time.Clock()
sim = BallSimulation(15)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # 左键
x, y = event.pos
sim.AddBall(x, y)
sim.Update()
sim.Draw(screen)
# 显示小球数量
font = pygame.font.SysFont("Arial", 18)
countText = font.render(f"小球数量: {len(sim.balls)}", True, (255, 255, 255))
screen.blit(countText, (10, 10))
pygame.display.flip()
clock.tick(60)
pygame.quit()
if __name__ == "__main__":
main()
物理模拟的关键点:
- 向量运算:
Vector2类简化了位置、速度的计算。 - 碰撞检测:基于距离检测,使用弹性碰撞公式计算碰撞后的速度。
- 分离重叠:碰撞后移动小球以避免粘在一起。
- 边界反弹:检测是否超出边界,反转速度分量并乘以能量损失系数。
运行这段代码,可以看到小球在屏幕内自由运动,相互碰撞,点击鼠标可以添加新小球。AI生成的物理代码虽然不如专业物理引擎精确,但对于学习和原型验证已经足够。
7.2 经典游戏实现:从太空大战到水果忍者
掌握了基础特效和物理模拟后,我们可以尝试实现完整的经典游戏。这部分案例将展示如何用AI辅助构建游戏的核心玩法。
7.2.1 太空大战:飞船射击小行星
太空大战(类似《小蜜蜂》或《太空侵略者》)是2D射击游戏的经典原型。我们将实现玩家控制飞船,发射子弹击碎小行星的功能。
与ChatGPT讨论架构:
首先向ChatGPT描述游戏需求:"用Pygame实现一个太空大战游戏,包含以下要素:
- 玩家飞船在屏幕底部,可以左右移动并发射子弹
- 小行星从屏幕顶部随机位置生成,向下运动
- 子弹击中行星时,行星碎裂成更小的碎片(如果碎片足够小则消失)
- 玩家与行星碰撞则游戏结束
- 分数显示
- 随着分数增加,难度逐渐提高"
ChatGPT会建议采用实体-组件架构,将游戏对象分为Player、Bullet、Asteroid等类。我们使用Copilot逐步实现这些类。
核心类实现:
import pygame
import math
import random
# 初始化
pygame.init()
WIDTH, HEIGHT = 900, 700
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("太空大战 - AI辅助开发")
clock = pygame.time.Clock()
# 颜色
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
class Player:
"""
玩家飞船类
"""
def __init__(self):
self.width = 40
self.height = 30
self.x = WIDTH // 2 - self.width // 2
self.y = HEIGHT - 80
self.speed = 5
self.bullets = []
self.shootCooldown = 0
self.shootDelay = 10 # 帧数间隔
def Update(self, keys):
"""更新玩家状态"""
# 左右移动
if keys[pygame.K_LEFT] and self.x > 0:
self.x -= self.speed
if keys[pygame.K_RIGHT] and self.x < WIDTH - self.width:
self.x += self.speed
# 射击
if self.shootCooldown > 0:
self.shootCooldown -= 1
if keys[pygame.K_SPACE] and self.shootCooldown == 0:
self.Shoot()
self.shootCooldown = self.shootDelay
# 更新子弹
for bullet in self.bullets[:]:
bullet.Update()
if bullet.y < 0:
self.bullets.remove(bullet)
def Shoot(self):
"""发射子弹"""
bullet = Bullet(self.x + self.width // 2 - 2, self.y)
self.bullets.append(bullet)
def Draw(self, surface):
"""绘制玩家"""
# 绘制飞船(三角形)
points = [
(self.x + self.width // 2, self.y),
(self.x, self.y + self.height),
(self.x + self.width, self.y + self.height)
]
pygame.draw.polygon(surface, WHITE, points, 0)
# 绘制子弹
for bullet in self.bullets:
bullet.Draw(surface)
def GetRect(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.width = 4
self.height = 10
self.speed = 8
def Update(self):
self.y -= self.speed
def Draw(self, surface):
pygame.draw.rect(surface, YELLOW, (self.x, self.y, self.width, self.height))
def GetRect(self):
return pygame.Rect(self.x, self.y, self.width, self.height)
class Asteroid:
"""
小行星类
"""
def __init__(self, x=None, y=None, size=3):
"""
初始化小行星
Parameters:
x, y (float, optional): 位置
size (int): 大小等级 3=大, 2=中, 1=小
"""
if x is None:
self.x = random.randint(50, WIDTH - 50)
else:
self.x = x
if y is None:
self.y = random.randint(-100, -40)
else:
self.y = y
self.size = size
# 根据大小设置属性
if size == 3:
self.radius = 30
self.speed = random.uniform(1.0, 2.0)
self.points = 20
elif size == 2:
self.radius = 20
self.speed = random.uniform(1.5, 2.5)
self.points = 50
else:
self.radius = 10
self.speed = random.uniform(2.0, 3.0)
self.points = 100
# 随机运动方向(略微左右飘移)
self.dx = random.uniform(-0.5, 0.5)
self.dy = self.speed
# 随机旋转角度
self.angle = 0
self.rotationSpeed = random.uniform(-2, 2)
# 生成随机形状的顶点(使小行星看起来不规则)
self.vertices = []
vertexCount = random.randint(6, 10)
for i in range(vertexCount):
angle = (i / vertexCount) * math.pi * 2
r = self.radius * random.uniform(0.7, 1.3)
self.vertices.append((
math.cos(angle) * r,
math.sin(angle) * r
))
def Update(self):
"""更新位置"""
self.x += self.dx
self.y += self.dy
self.angle += self.rotationSpeed
# 如果移出屏幕,重新从顶部出现
if self.y > HEIGHT + 100:
self.y = random.randint(-100, -40)
self.x = random.randint(50, WIDTH - 50)
def Draw(self, surface):
"""绘制小行星"""
# 旋转顶点
rotatedVerts = []
cosA = math.cos(math.radians(self.angle))
sinA = math.sin(math.radians(self.angle))
for vx, vy in self.vertices:
rx = vx * cosA - vy * sinA
ry = vx * sinA + vy * cosA
rotatedVerts.append((self.x + rx, self.y + ry))
pygame.draw.polygon(surface, (150, 150, 150), rotatedVerts, 2)
def GetRect(self):
"""获取碰撞矩形(简化用圆形检测,但返回矩形供sprite.collide使用)"""
return pygame.Rect(self.x - self.radius, self.y - self.radius,
self.radius * 2, self.radius * 2)
def CheckCollision(self, other):
"""圆形碰撞检测"""
dx = self.x - other.x
dy = self.y - other.y
distance = math.sqrt(dx * dx + dy * dy)
return distance < self.radius + other.radius
class Game:
"""
游戏主类
"""
def __init__(self):
self.player = Player()
self.asteroids = []
self.score = 0
self.level = 1
self.gameOver = False
self.font = pygame.font.SysFont("Arial", 24)
self.bigFont = pygame.font.SysFont("Arial", 48)
# 初始化小行星
for _ in range(5):
self.asteroids.append(Asteroid(size=3))
def Update(self):
"""更新游戏状态"""
if self.gameOver:
return
keys = pygame.key.get_pressed()
self.player.Update(keys)
# 更新小行星
for asteroid in self.asteroids[:]:
asteroid.Update()
# 检查与子弹的碰撞
for bullet in self.player.bullets[:]:
if asteroid.CheckCollision(bullet):
# 分数增加
self.score += asteroid.points
# 子弹消失
if bullet in self.player.bullets:
self.player.bullets.remove(bullet)
# 小行星碎裂
if asteroid.size > 1:
# 生成两个更小的碎片
for _ in range(2):
newSize = asteroid.size - 1
newAsteroid = Asteroid(
asteroid.x + random.randint(-20, 20),
asteroid.y + random.randint(-20, 20),
newSize
)
self.asteroids.append(newAsteroid)
# 移除原小行星
if asteroid in self.asteroids:
self.asteroids.remove(asteroid)
break
# 检查与玩家的碰撞
if asteroid.CheckCollision(self.player):
self.gameOver = True
# 控制小行星数量
if len(self.asteroids) < 5 + self.level * 2:
if random.random() < 0.01: # 1%概率生成新小行星
size = random.choices([3, 2, 1], weights=[0.5, 0.3, 0.2])[0]
self.asteroids.append(Asteroid(size=size))
# 难度随分数增加
self.level = 1 + self.score // 500
def Draw(self, surface):
"""绘制游戏"""
surface.fill(BLACK)
if not self.gameOver:
self.player.Draw(surface)
for asteroid in self.asteroids:
asteroid.Draw(surface)
# 显示分数和等级
scoreText = self.font.render(f"分数: {self.score}", True, WHITE)
levelText = self.font.render(f"等级: {self.level}", True, WHITE)
surface.blit(scoreText, (10, 10))
surface.blit(levelText, (10, 40))
else:
# 游戏结束画面
gameOverText = self.bigFont.render("游戏结束", True, RED)
finalScoreText = self.font.render(f"最终分数: {self.score}", True, WHITE)
restartText = self.font.render("按R重新开始", True, WHITE)
textRect = gameOverText.get_rect(center=(WIDTH//2, HEIGHT//2 - 50))
scoreRect = finalScoreText.get_rect(center=(WIDTH//2, HEIGHT//2))
restartRect = restartText.get_rect(center=(WIDTH//2, HEIGHT//2 + 50))
surface.blit(gameOverText, textRect)
surface.blit(finalScoreText, scoreRect)
surface.blit(restartText, restartRect)
def Reset(self):
"""重置游戏"""
self.__init__()
def main():
game = Game()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r and game.gameOver:
game.Reset()
game.Update()
game.Draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
if __name__ == "__main__":
main()
AI辅助的关键点:
- 小行星的不规则形状:ChatGPT建议用随机顶点生成不规则多边形,使小行星看起来更自然。
- 碎裂逻辑:子弹击中较大行星时生成两个小行星,Copilot自动补全了递归碎裂的代码。
- 难度平衡:根据分数动态调整小行星生成概率和数量。
这个游戏已经具备了基本的可玩性,可以在此基础上继续添加特效、音效等。
7.2.2 粒子爆炸效果
在太空大战的基础上,我们为小行星碎裂添加粒子爆炸效果。这需要实现一个简单的粒子系统,在碎裂位置生成大量短暂存在的小粒子。
粒子类实现:
class ExplosionParticle:
"""
爆炸粒子类
"""
def __init__(self, x, y):
self.x = x
self.y = y
self.vx = random.uniform(-3, 3)
self.vy = random.uniform(-3, 3)
self.size = random.randint(2, 5)
self.color = random.choice([(255, 200, 0), (255, 100, 0), (200, 200, 200)])
self.life = random.randint(20, 40)
self.maxLife = self.life
def Update(self):
self.x += self.vx
self.y += self.vy
self.vy += 0.1 # 重力
self.life -= 1
def Draw(self, surface):
if self.life > 0:
alpha = int(255 * self.life / self.maxLife)
color = (self.color[0], self.color[1], self.color[2])
pygame.draw.circle(surface, color, (int(self.x), int(self.y)), self.size)
def IsAlive(self):
return self.life > 0
在Asteroid碎裂时,生成一批粒子加入游戏主循环:
# 在Game类中添加
self.particles = []
# 在小行星碎裂时
for _ in range(15):
self.particles.append(ExplosionParticle(asteroid.x, asteroid.y))
# 在Update中更新粒子
for particle in self.particles[:]:
particle.Update()
if not particle.IsAlive():
self.particles.remove(particle)
7.2.3 音乐播放器与游戏的结合
第6.5节提到"基于pygame的音乐播放器",这展示了游戏引擎的另一个用途:制作音乐可视化工具。我们可以结合之前的粒子系统,实现一个随音乐节奏变化的视觉效果。
核心思路:
- 使用
pygame.mixer.music加载并播放音乐 - 分析音频数据(需要
numpy和audioop)获取频谱 - 根据频谱强度调整粒子系统的参数(颜色、速度、数量)
由于音频分析较为复杂,这部分可以先用模拟数据演示,然后逐步完善。
7.2.4 《水果忍者》的简化实现
《水果忍者》的核心玩法是手指划过屏幕切割抛出的水果。在PC上用鼠标模拟手指,实现简化版本。
需求分解:
- 水果从底部向上抛出,呈抛物线运动
- 玩家用鼠标画线,检测线与水果的碰撞
- 切割成功时水果碎裂(粒子效果)
- 炸弹混在其中,切到炸弹游戏结束
使用Copilot生成水果类:
class Fruit:
"""
水果类
"""
def __init__(self, fruitType="apple"):
self.type = fruitType
self.radius = 25
# 初始位置(底部随机)
self.x = random.randint(50, WIDTH - 50)
self.y = HEIGHT - 20
# 抛物线运动参数
self.vx = random.uniform(-2, 2)
self.vy = random.uniform(-12, -8)
self.gravity = 0.4
# 颜色
if fruitType == "apple":
self.color = (255, 0, 0)
elif fruitType == "banana":
self.color = (255, 255, 0)
elif fruitType == "watermelon":
self.color = (0, 255, 0)
else: # bomb
self.color = (50, 50, 50)
self.radius = 20
# 是否被切割
self.cut = False
def Update(self):
"""更新位置"""
self.x += self.vx
self.y += self.vy
self.vy += self.gravity
def Draw(self, surface):
"""绘制水果"""
if not self.cut:
pygame.draw.circle(surface, self.color, (int(self.x), int(self.y)), self.radius)
# 高光
highlightPos = (int(self.x - self.radius * 0.3), int(self.y - self.radius * 0.3))
pygame.draw.circle(surface, (255, 255, 255), highlightPos, self.radius // 4)
def IsOffscreen(self):
"""判断是否移出屏幕"""
return self.y > HEIGHT + 100 or self.x < -100 or self.x > WIDTH + 100
def CheckSlice(self, lineStart, lineEnd):
"""
检查是否被线段切割
Parameters:
lineStart, lineEnd (tuple): 鼠标移动的线段起点和终点
Returns:
bool: 是否被切割
"""
if self.cut:
return False
# 简化为检测圆心到线段的距离是否小于半径
# 这里使用点到线段距离公式
x1, y1 = lineStart
x2, y2 = lineEnd
# 计算点到线段的最短距离
dx = x2 - x1
dy = y2 - y1
# 线段长度平方
l2 = dx * dx + dy * dy
if l2 == 0:
# 线段退化为点
dist = math.sqrt((self.x - x1) ** 2 + (self.y - y1) ** 2)
return dist < self.radius
# 计算投影参数t
t = ((self.x - x1) * dx + (self.y - y1) * dy) / l2
t = max(0, min(1, t))
# 投影点
projX = x1 + t * dx
projY = y1 + t * dy
# 计算距离
dist = math.sqrt((self.x - projX) ** 2 + (self.y - projY) ** 2)
return dist < self.radius
鼠标画线的实现需要记录每一帧的鼠标位置,连接成线段:
# 在Game类中
self.mouseTrail = [] # 存储鼠标历史位置
self.trailLength = 5 # 保留最近5帧
# 在事件处理中
if event.type == pygame.MOUSEMOTION:
self.mouseTrail.append(event.pos)
if len(self.mouseTrail) > self.trailLength:
self.mouseTrail.pop(0)
# 在切割检测中
for i in range(len(self.mouseTrail) - 1):
for fruit in self.fruits:
if fruit.CheckSlice(self.mouseTrail[i], self.mouseTrail[i + 1]):
fruit.cut = True
# 生成粒子等
7.2.5 《雷电》风格的纵版射击游戏
《雷电》是经典的纵版STG游戏。实现完整版工作量较大,但我们可以用AI构建核心框架:
- 玩家飞机:移动、射击(多种子弹类型)
- 敌机:多种类型(直线、追踪、发射子弹)
- 碰撞检测:玩家子弹 vs 敌机,敌机子弹 vs 玩家
- 道具系统:增强火力、保险等
架构建议:
使用组件模式,定义Entity基类,派生出Player、Enemy、Bullet、PowerUp等。使用Sprite组管理碰撞。
Copilot生成子弹模式:
class Bullet:
def __init__(self, x, y, angle, speed, damage, owner="player"):
self.x = x
self.y = y
self.vx = math.cos(angle) * speed
self.vy = math.sin(angle) * speed
self.damage = damage
self.owner = owner # "player" 或 "enemy"
def Update(self):
self.x += self.vx
self.y += self.vy
敌机AI:
class Enemy:
def __init__(self, enemyType="basic"):
self.type = enemyType
if enemyType == "basic":
# 直线下飞
self.pattern = "straight"
self.speed = 3
elif enemyType == "zigzag":
# 之字形
self.pattern = "zigzag"
self.speed = 2
self.amplitude = 50
self.frequency = 0.05
self.startX = self.x
elif enemyType == "shooter":
# 会射击
self.pattern = "straight"
self.speed = 1.5
self.shootCooldown = 0
self.shootDelay = 60
def Update(self):
if self.pattern == "straight":
self.y += self.speed
elif self.pattern == "zigzag":
self.y += self.speed
self.x = self.startX + math.sin(self.y * self.frequency) * self.amplitude
def CanShoot(self):
if self.type == "shooter":
if self.shootCooldown <= 0:
self.shootCooldown = self.shootDelay
return True
else:
self.shootCooldown -= 1
return False
7.3 AI游戏开发的行业现状与未来展望
7.3.1 工业级AI游戏开发工具
2025年9月,掌趣科技联合蓝亚盒子发布了LayaIdea,这是业界首个真正可商用的3D游戏AIGC开发工具。它实现了从策划文档到完整3D游戏项目的自动化生成,主要聚焦于两大场景:
- 互动试玩广告:将开发周期从一周缩短至一天,大幅节省程序开发成本,同时保证生成的代码符合各大广告平台规范。
- 游戏原型验证:帮助游戏制作人快速完成玩法验证、试错、迭代修改,降低试错成本。
网易则接入通义千问,打造游戏自动测试系统,帮助游戏研发提效50%。其伏羲实验室联合阿里云全球首发了游戏Copilot队友功能,AI队友能自主完成跑图、搜寻物资、参与战斗,还能通过自然语音与玩家互动。
7.3.2 100% AI生成游戏的尝试与争议
2025年底,开发者Grolaf发布了《Codex Mortis》,宣称该游戏100%由AI驱动:美术素材由ChatGPT创作,动画通过Claude Code编写的着色器实现,代码完全由TypeScript编写,未使用任何传统游戏引擎。
开发者的体会是:"与传统应用开发相比,这种方式对精神消耗要小得多,感觉就像给建筑工人装上了外骨骼。"然而,游戏在Steam上获得"褒贬不一"的评价,评论区充斥着负面声音,反映出市场对纯AI生成内容的态度仍存分歧。
7.3.3 AI辅助游戏开发的最佳实践
综合本章案例和行业动态,可以总结出AI辅助游戏开发的有效模式:
- 原型快速验证:用ChatGPT讨论设计思路,生成可运行的原型代码,快速测试核心玩法。
- 分步实现复杂功能:将游戏分解为多个模块(粒子系统、物理引擎、AI行为),逐个用AI生成并测试。
- 代码审查与优化:将生成的代码发给ChatGPT进行审查,发现潜在问题并提出优化建议。
- 资源生成:使用DALL-E、Midjourney等工具生成游戏素材。有开发者反馈,保持风格一致性是最大挑战,需要精心设计提示词。
- 调试与完善:将错误信息贴给AI,快速定位并修复问题。学生开发者反映,“利用AIGC工具来debug解决代码中报错的问题十分省事省心”。
7.4 本章小结
通过本章的八个实战案例,我们从简单的视觉特效开始,逐步构建了完整的游戏项目,探索了AI在游戏开发全流程中的应用:
- 旋转星系和移动纹理展示了AI生成粒子系统和动态背景的能力
- 随机运动的小球实现了基础的物理模拟
- 太空大战构建了完整的射击游戏框架,包含碰撞检测、分数系统和难度平衡
- 粒子爆炸增强了游戏的视觉反馈
- 水果忍者和雷电则展示了更复杂玩法的实现思路
这些案例证明:AI辅助工具不仅能生成代码片段,还能帮助开发者理解游戏开发的核心理念——状态管理、物理模拟、碰撞检测、粒子系统等。正如一位学生在开发心得中写道:“用AIGC生成程序主框架十分好用,如果遇到不懂的地方让AIGC工具来解释,十分高效易懂。”
游戏开发曾经是编程中最具挑战性的领域之一,需要掌握图形学、物理模拟、交互设计等多方面知识。AI辅助编程正在降低这一门槛,让创意能够快速转化为可玩的游戏。无论你是希望开发独立游戏的学生,还是需要快速验证原型的专业人士,本章介绍的方法都能帮助你大幅提升效率,将更多精力投入到游戏创意和玩法设计上。
在下一章,我们将探讨AI在办公自动化领域的应用,展示如何用自然语言生成处理Excel、Word、PPT的代码,进一步提升工作效率。
更多推荐

所有评论(0)