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

一句话总结访问者模式:

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

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

相关推荐
派葛穆4 小时前
Unity-UI 输入框功能
ui·unity·游戏引擎
玖玥拾5 小时前
Unity3D RPG 入门项目(一)开场动画/人物移动/摄像机跟随场景切换
unity·游戏引擎
2401_894915536 小时前
GEO 搜索优化完整源码从零部署:环境配置、集群搭建全流程
开发语言·python·tcp/ip·算法·unity
WarPigs8 小时前
PC端加载安卓AB包资源显示紫色的问题
unity
scott.cgi10 小时前
Unity使用AndroidX获取,导航栏与虚拟键盘的高度
unity·androidx·keyboard·导航栏高度·虚拟键盘高度·判断键盘关闭·获取虚拟键盘高度
丁小未12 小时前
Unity车机地图Tile流式渲染系统高性能架构方案
unity·架构·ecs·dots·车机系统·车机系统架构图
LONGZETECH16 小时前
工业实训仿真设计实践:电机拆装软件的 DAG 流程建模、工具精度分级与数据体系搭建
大数据·算法·unity·架构·汽车
Python私教16 小时前
Godot 4 CharacterBody2D 角色移动:输入、碰撞与八方向控制实战
人工智能·游戏引擎·godot·gdscript·游戏开发
派葛穆1 天前
Unity-UI 按钮点击弹窗功能
unity·游戏引擎
toponad2 天前
Unity Ads Bidding 现已正式加入TopOn 聚合平台
unity·topon