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

一句话总结访问者模式:

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

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

相关推荐
陈言必行14 小时前
Unity 之 设备性能分级与游戏画质设置与设备自动适配指南
游戏·unity·游戏引擎
CreasyChan17 小时前
Unity DOTS技术栈详解
unity·c#·游戏引擎
gshh__17 小时前
SuperMap Hi-Fi 3D SDK for Unreal 如何实现横断面分析
3d·ue5·游戏引擎·supermap
在路上看风景19 小时前
1.1 Unity资源生命周期管理与内存机制
unity
CreasyChan20 小时前
Unity的ECS(Entity Component System)架构详解
unity·架构·游戏引擎
神码编程20 小时前
【Unity】 HTFramework框架(六十九)Log在编辑器日志中自定义点击事件
unity·编辑器·游戏引擎
TO_ZRG2 天前
Unity打包安卓、iOS知识点
android·unity·android studio
冰凌糕2 天前
Unity3D Shader 顶点动画 呼吸和水波
unity
呆呆敲代码的小Y2 天前
【Unity 实用工具篇】| UX Tool 工具 快速上手使用,提高日常开发效率
游戏·unity·游戏引擎·游戏程序·ux
世洋Blog2 天前
Unity开发微信小程序-避开新InputSystem有关坑
unity·微信小程序