Unity访问者模式

在实际的游戏项目中,怪物往往作为底层对象长期稳定存在,但围绕怪物的各种行为逻辑(攻击、技能、结算规则)却会随着玩法不断变化,如何在不频繁修改怪物代码的前提下扩展新逻辑,是一个常见但容易被忽视的问题。

1.定义两个接口IMonsterVisitor和IMonster,一个表示访问者,他需要实现对各个对象的访问方法。然后一个访问对象,他需要实现应答方法,当别人访问它的时候它需要执行的方法。

cs 复制代码
public interface IMonsterVisitor
{
    void Visit(Slime slime);
    void Visit(Goblin goblin);
    void Visit(Boss boss);
    void Visit(Wolf  wolf);
}

public interface IMonster
{
    void Accept(IMonsterVisitor visitor);
}

2.定义4个怪物脚本Boss,Goblin,Slime,Wolf。他们分别实现了应答方法,接收一个访问者,然后引导访问者去调用对应的方法。这两个方法效果是等价的

public void Accept(IMonsterVisitor visitor) => visitor.Visit(this);

public void Accept(IMonsterVisitor visitor)

{

visitor.Visit(this);

}

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static Monster;

public class Boss : MonoBehaviour, IMonster
{
    public void Accept(IMonsterVisitor visitor) => visitor.Visit(this);
}
cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static Monster;

public class Goblin : MonoBehaviour, IMonster
{
    public void Accept(IMonsterVisitor visitor) => visitor.Visit(this);
}
cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static Monster;

public class Slime : MonoBehaviour, IMonster
{
    public void Accept(IMonsterVisitor visitor) => visitor.Visit(this);
}
cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static Monster;

public class Wolf : MonoBehaviour, IMonster
{
    public void Accept(IMonsterVisitor visitor) => visitor.Visit(this);
}

3.创建一个玩家访问者继承访问者接口,并实现访问者接口里面的所有方法访问,这样玩家就能知道攻击到不同的怪物该执行什么逻辑。

cs 复制代码
using UnityEngine;
using static Monster;

public class PlayerAttackVisitor : IMonsterVisitor
{
    public void Visit(Slime slime)
    {
        Debug.Log("Slime 受到伤害 + 弹跳");
    }

    public void Visit(Goblin goblin)
    {
        Debug.Log("Goblin 受到伤害 + 掉落金币");
    }

    public void Visit(Boss boss)
    {
        Debug.Log("Boss 受到伤害 + 进入狂暴状态");
    }
    public void Visit(Wolf wolf)
    {
        Debug.Log("狼被击中 → 流血效果 + 吼叫");
    }
}

4.创建一个玩家,当玩家碰到怪物后会尝试通过怪物接口去获取被访者的应答方法。

visitor = new PlayerAttackVisitor();相当于新建一个访问者。

monster.Accept(visitor);//相当于说那个怪物过来一下我有问题要问你

怪物中的这个方法public void Accept(IMonsterVisitor visitor) => visitor.Visit(this);//"我不关心你是什么怪物,你自己决定该怎么被我处理"

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerAttack : MonoBehaviour
{
    PlayerAttackVisitor visitor;

    void Start()
    {
         visitor = new PlayerAttackVisitor();
    }
    private void OnCollisionEnter2D(Collision2D other)
    {
        if (other.gameObject.TryGetComponent<IMonster>(out var monster))
        {
            monster.Accept(visitor);
        }
    }
}

创建场景将玩家PlayerAttack加到玩家身上,并创建4个怪物,并且将怪物脚本加到对应怪物身上。

运行游戏拖动玩家,就会发现玩家碰撞到怪物执行了不同的方法

5.这样以后如果需要添加新的访问者十分容易,但是要添加新的被访问者需要修改所有的访问者接口,相当于你去不同的医院体检假如每个人的体检项目都一样,那么医生作为访问者那么只需要按照流程问你问题就行了,但是来了一个特殊的病人,只有修改访问者的接口了,相当于医生要去学习新的理论知识。

一句话总结访问者模式:

一句话总结访问者模式:当"对象结构稳定,但操作经常变化"时,把操作抽离成访问者,让对象自己决定"我该调用你哪个方法"。

还有一种常见场景是:当怪物逻辑来自第三方库或他人代码时,可以通过访问者模式在尽量不修改原有代码的前提下扩展新功能。

相关推荐
叶帆15 小时前
【YFIOs】用C#开发硬件之设备上云
开发语言·unity·c#
久数君16 小时前
AI三维建模工具“造形家”:地理场景三维化的高效解决方案
unity·glb·ai算法·ai三维建模工具·地图框选·造形家·城市建筑模型
会思考的猴子1 天前
Unity VFX 属性 Postion 和 TargetPostion
unity
hai3152475431 天前
九章编程法 · 猜数字游戏 (GW-BASIC 重构版) *
人工智能·microsoft·游戏引擎·游戏程序
心前阳光1 天前
Unity资源导入之自动化资源导入
unity·自动化·游戏引擎
心前阳光1 天前
Unity之2021.3.45f2c1发布安卓程序遇到的问题
android·unity·游戏引擎
纪纯1 天前
PicoVR Unity Integration SDK 3.4 常用交互API
unity·游戏引擎·vr·pico
java_cj2 天前
从kubectl学Visitor模式:如何优雅处理多态数据结构的遍历
云原生·golang·k8s·访问者模式
龙智DevSecOps解决方案2 天前
3A 游戏优化技术栈:如何打通引擎级分析工具与 DevOps 持续集成管线?
unity·性能优化·游戏开发·技术美术·perforce·unrealengine
葛兰岱尔2 天前
从 SolidWorks 到 Three.js,从 Inventor 到 Unity——制造业CAD模型“几何-语义一体化“转换,不再是天方夜谭!
开发语言·javascript·unity