用23种设计模式打造一个cocos creator的游戏框架----(二十)解析器模式

1、模式标准

模式名称:解析器模式

模式分类:行为型

模式意图:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

结构图:

适用于:

当有一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象语法树时,以下情况效果最好:

1、该文法简单。对于复杂的发文,文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是更好的选择。它们无须构建抽象语法树即可解释表达式,这样可以节省空间还可能节省时间。

2、效率不是一个关键问题。最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换成另一种形式。不过,即使在这种情况下,转换器仍然可用该模式实现。

2、分析与设计

这里假设我们希望以文本的方式记录游戏命令过程比如:\[UnitItem]{{attack}}\[UnitItem] ,类似这种\[单位]{{命令}}为格式,然后通过解析器解析成实际的命令

意图:给定一个语言(命令备忘录语言),定义它的文法的一种表示(\[单位]{{命令}}),并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

3、开始打造

表达式接口

TypeScript 复制代码
export interface IExpression {
    interpret(context: UnitCommandUnitContext): void;
}

单位表达式及解析方法

TypeScript 复制代码
export class UnitItemExpression implements IExpression {
    private unitItemId: string;
    constructor(unitItemId: string) {
        this.unitItemId = unitItemId;
    }
    interpret(context: UnitCommandUnitContext): void {
        // 执行与终结符相关的解释操作
        let unitItem = context.getUnitItem(this.unitItemId)
        console.log("解析到单位项:", unitItem);
        context.setUnitItem(unitItem)
    }
}

"命令"表达式及解析方法

TypeScript 复制代码
export class CommandExpression implements IExpression {
    private commandId: string;

    constructor(commandId: string) {
        this.commandId = commandId;
    }
    interpret(context: UnitCommandUnitContext): void {
        // 执行与终结符相关的解释操作
        let command = context.getCommand(this.commandId)
        console.log("解析到命令:", command);
        context.setCommand(command);
    }
}

"遍历解析"表达式及解析方法

TypeScript 复制代码
export class CommandSequenceExpression implements IExpression {
    private expressions: IExpression[];

    constructor(expressions: IExpression[]) {
        this.expressions = expressions;
    }

    interpret(context: UnitCommandUnitContext): void {
        for (const expression of this.expressions) {
            expression.interpret(context);
        }
        context.executeCommand()
    }
}

单位 操作命令 另一个单位 的context

TypeScript 复制代码
// 单位 操作命令 另一个单位 的context
export class UnitCommandUnitContext {
    command: ICommand = null
    fromUnitItem: UnitItem<any> = null
    toUnitItem: UnitItem<any> = null
    getUnitItem(unitItemId: string) {
        return xhgame.game.battleEntity.model.unitItemMap.get(unitItemId)
    }
    getCommand(commandId: string) {
        // todo 其他补充
        return new AttackCommand(null, null)
    }
    setCommand(command: ICommand) {
        this.command = command
    }
    setUnitItem(unitItem: UnitItem<any>) {
        if (this.fromUnitItem == null) {
            this.fromUnitItem = unitItem
        }
        if (this.toUnitItem == null) {
            this.toUnitItem = unitItem
        }
    }
    executeCommand() {
        if (this.command instanceof AttackCommand) {
            this.command.setUnitItem(this.fromUnitItem)
            this.command.setTargetUnitItem(this.toUnitItem)
            this.command.execute()
        }
    }
}

4、开始使用

TypeScript 复制代码
// 创建一个 单位 操作命令 另一个单位的上下文
const unitCommandUnitContext = new UnitCommandUnitContext();
// 解析文本为 UnitItem.20 的单位对 UnitItem.21 的单位发动攻击
// 目前为了后期拓展下列以:[[单位]]{{命令}}为格式
const commandText = "[[UnitItem.20]]{{attack}}[[UnitItem.21]]";
// 构建抽象语法树
const expressions: IExpression[] = [];
const regex = /\[\[([^\]]+)\]\]|\{\{([^\}]+)\}\}|\[\{([^\}]+)\}\]|\[<([^\>]+)>\]/g;
let match;
while ((match = regex.exec(commandText)) !== null) {
    console.log(match)
    const token = match[0];
    const unitItemId = match[1]; // 捕获组1中的内容为单位项ID
    const commandId = match[2]; // 捕获组2中的内容为命令ID
    if (unitItemId !== undefined) {
        expressions.push(new UnitItemExpression(unitItemId));
    } else if (commandId !== undefined) {
        expressions.push(new CommandExpression(commandId));
    }
}
console.log('expressions', expressions)
// "遍历解析"表达式
const commandSequence = new CommandSequenceExpression(expressions);
commandSequence.interpret(unitCommandUnitContext);
相关推荐
沧沧凉凉1 小时前
一段需求、零素材,Claude Code 派了 33 个代理给我做了个 3D 动作游戏
游戏·ai编程·three.js
myshare20223 小时前
Dungeon Saga 套装加成与品质共鸣:影响英雄的哪一部分
游戏·dungeon saga·品质共鸣
晚安code8 小时前
设计模式入门:吃透 SOLID 原则与迪米特法则,再学 5 个高频模式
后端·设计模式
Martina_032112 小时前
同一片森林换个镜头就忽冷忽暖?用6步统一曝光、LUT与相机后处理
人工智能·游戏·数学建模·3d·自然语言处理·aigc·游戏策划
染指111012 小时前
135.Agent-多Agent框架-LangChain多智能体(SubAgents子代理)
数据库·人工智能·设计模式·langchain·agent·agents
外收内放13 小时前
08 | 优化篇③ 60 张动作立绘和 50 张特效贴图是怎么进游戏的
python·游戏·pygame
外收内放14 小时前
06 | 优化篇① 游戏改名《鳞光纪》了:这次翻新,把“脸“全换了
python·游戏·pygame
Liuchang091114 小时前
洛谷 P2670 [NOIP 2015 普及组] 扫雷游戏
c++·算法·游戏
路弥行至1 天前
【Head First 设计模式】第 2 章:观察者模式 —— 用现代 C++ 重新解读“交互对象的松耦合
c++·经验分享·笔记·观察者模式·设计模式·入门教程·headfirst
YYYing.1 天前
【设计模式系列 (九) 】装饰器模式
c++·后端·设计模式·装饰器模式·c/c++