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

一句话总结访问者模式:

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

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

相关推荐
nnsix7 小时前
Unity XR 编辑器VR设备模拟功能
unity·编辑器·xr
不定时总结的那啥7 小时前
Unity实现点击Console消息自动选中预制体的方法
unity·游戏引擎
nnsix8 小时前
Unity OpenXR 关闭手柄的震动
unity·游戏引擎
CreasyChan8 小时前
Unity 中的反射使用详解
unity·c#·游戏引擎·游戏开发
Jessica巨人8 小时前
Shader显示为黑色
unity·shader
天途小编8 小时前
无人机操控模式解析:美国手、日本手、中国手
游戏引擎·无人机·cocos2d
90后小陈老师21 小时前
Unity教学 项目2 2D闯关游戏
游戏·unity·游戏引擎
噗噗夹的TA之旅1 天前
Unity Shader 学习20:URP LitForwardPass PBR 解析
学习·unity·游戏引擎·图形渲染·技术美术
nnsix1 天前
Unity ReferenceFinder插件 多选资源查找bug解决
unity·游戏引擎·bug