设计模式与游戏开发:游戏循环中的模板方法、AI行为树中的策略、技能系统中的命令
游戏开发,说白了就是一场与性能和复杂度的博弈。我做了十几年游戏后端和引擎架构,最深的体会是:没有设计模式,游戏代码撑不过三个版本迭代。今天咱们就聊聊三个在游戏开发里高频出现的模式——模板方法、策略、命令。它们分别对应着游戏循环、AI行为树和技能系统这三个核心场景。
一、游戏循环中的模板方法模式
游戏循环是什么?就是那个“接收输入→更新逻辑→渲染画面”的死循环。每个游戏都有,但每个游戏的实现细节又不一样。这时候模板方法模式就派上用场了。
我习惯把游戏循环的骨架固定下来,把可变的部分留给子类去实现。你想想看,这样既保证了循环的稳定性,又给了具体游戏足够的灵活性。
Java 示例:游戏循环骨架
public abstract class GameLoop {
private boolean running = false;
// 模板方法——固定骨架
public final void run() {
init();
running = true;
while (running) {
long startTime = System.nanoTime();
processInput(); // 处理输入
update(); // 更新逻辑
render(); // 渲染画面
long elapsed = System.nanoTime() - startTime;
sleepIfNeeded(elapsed);
}
cleanup();
}
// 子类必须实现的步骤
protected abstract void init();
protected abstract void processInput();
protected abstract void update();
protected abstract void render();
protected abstract void cleanup();
private void sleepIfNeeded(long elapsed) {
long targetFrameTime = 16_666_666; // 60 FPS
if (elapsed < targetFrameTime) {
try {
Thread.sleep((targetFrameTime - elapsed) / 1_000_000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
具体游戏只需要继承这个类,实现那几个抽象方法就行。我曾经在一个RPG项目里用这个模式,把PC版和手机版的游戏循环统一了——PC版用垂直同步,手机版用自适应帧率,但骨架完全一样。
二、AI行为树中的策略模式
AI行为树,听着高大上,其实核心就是“根据条件选择行为”。但问题来了:行为的选择策略千变万化——有的AI喜欢优先攻击,有的喜欢猥琐发育,有的会根据玩家血量动态调整。
这时候策略模式就特别好用。把“选择行为”这个算法独立出来,让不同的策略类去实现。行为树只负责调用策略,不关心具体怎么选。
C++ 示例:AI行为选择策略
// 策略接口
class IBehaviorStrategy {
public:
virtual ~IBehaviorStrategy() = default;
virtual BehaviorNode* selectBehavior(Blackboard* board) = 0;
};
// 具体策略:攻击优先
class AggressiveStrategy : public IBehaviorStrategy {
public:
BehaviorNode* selectBehavior(Blackboard* board) override {
if (board->getHealth() > 50) {
return new AttackNode();
}
return new DefendNode();
}
};
// 具体策略:猥琐发育
class DefensiveStrategy : public IBehaviorStrategy {
public:
BehaviorNode* selectBehavior(Blackboard* board) override {
if (board->getHealth() < 80) {
return new RetreatNode();
}
return new FarmNode();
}
};
// 行为树节点——使用策略
class BehaviorTree {
private:
std::unique_ptr<IBehaviorStrategy> strategy_;
public:
void setStrategy(std::unique_ptr<IBehaviorStrategy> strategy) {
strategy_ = std::move(strategy);
}
void tick(Blackboard* board) {
BehaviorNode* node = strategy_->selectBehavior(board);
if (node) {
node->execute(board);
}
}
};
嗯,这里要注意:策略模式在AI系统里最大的好处是运行时切换。我记得有个项目,Boss在不同阶段会切换AI策略——第一阶段莽撞攻击,第二阶段猥琐召唤小怪,第三阶段狂暴。用策略模式,只需要在阶段切换时调一下setStrategy()就行,行为树本身不用动。
三、技能系统中的命令模式
技能系统,是游戏里最复杂的模块之一。一个技能可能涉及:伤害计算、动画播放、音效触发、冷却管理、状态效果……而且还要支持撤销(比如玩家反悔)、回放(比如观战模式)、队列(比如连招)。
命令模式简直就是为这种场景量身定做的。把每个技能封装成一个命令对象,包含执行所需的所有信息。然后由调用者统一管理这些命令的调度、撤销和记录。
Java 示例:技能命令系统
// 命令接口
public interface SkillCommand {
void execute();
void undo();
}
// 具体技能:火球术
public class FireballCommand implements SkillCommand {
private Player caster;
private Target target;
private int damage;
private int manaCost;
public FireballCommand(Player caster, Target target) {
this.caster = caster;
this.target = target;
this.damage = 50;
this.manaCost = 30;
}
@Override
public void execute() {
if (caster.getMana() >= manaCost) {
caster.spendMana(manaCost);
target.takeDamage(damage);
System.out.println("火球术!造成 " + damage + " 点伤害");
}
}
@Override
public void undo() {
target.heal(damage);
caster.addMana(manaCost);
System.out.println("撤销火球术");
}
}
// 命令管理器——支持撤销和回放
public class SkillManager {
private Stack<SkillCommand> history = new Stack<>();
private List<SkillCommand> replayBuffer = new ArrayList<>();
public void executeCommand(SkillCommand cmd) {
cmd.execute();
history.push(cmd);
replayBuffer.add(cmd);
}
public void undoLastCommand() {
if (!history.isEmpty()) {
SkillCommand cmd = history.pop();
cmd.undo();
}
}
public void replay() {
for (SkillCommand cmd : replayBuffer) {
cmd.execute();
}
}
}
我个人特别喜欢命令模式的一点是:它把“请求”和“执行”完全解耦了。客户端只需要创建命令对象,至于谁来执行、怎么执行、要不要记录,那是调用者的事。我在一个MOBA项目里用这个模式实现了技能连招系统——玩家按顺序释放技能,命令管理器把它们排队,然后按顺序执行,中间还可以插入取消操作。
四、三者关系与整体架构
这三个模式在游戏里不是孤立的。我画了一张图,帮你理清它们之间的关系:
从这张图你能看出来:游戏循环是顶层调度器,它驱动整个游戏的运转;在update()阶段,AI行为树根据策略选择行为;而技能系统则作为行为的具体实现,通过命令模式管理技能的释放和撤销。三层各司其职,又紧密配合。
- 模板方法——固定游戏循环骨架,避免重复代码,保证帧率稳定
- 策略模式——让AI行为选择灵活可变,支持运行时动态切换
- 命令模式——把技能封装成对象,解耦请求与执行,支持撤销和回放
这三个模式在游戏开发里几乎是标配。我建议你在设计游戏架构时,优先考虑它们——不是为了用模式而用模式,而是因为它们确实能解决实际问题。下次写游戏循环、AI或者技能系统时,不妨试试看。
公众号:蓝海资料掘金营,微信deep3321