You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity状态机模式下多个同类型GameObject的最优通信方式咨询

领地对象进攻阶段通信方案

针对你当前基于状态机实现的领地管理逻辑,可采用以下几种可落地的通信方案:

方案1:状态上下文携带目标领地引用

  • 触发进攻动作时(如玩家选中进攻领地后点击防守领地),在创建AttackState实例时直接将防守方Territory对象作为参数传入构造函数,让状态本身持有交互双方的引用
  • 代码示例:
// 自定义AttackState构造函数
public class AttackState : TerritoryBaseState
{
    private Territory _attacker;
    private Territory _defender;

    // 传入攻防双方实例
    public AttackState(Territory attacker, Territory defender)
    {
        _attacker = attacker;
        _defender = defender;
    }

    public override IEnumerator EnterState()
    {
        // 直接交互:调用防守方接口、读写双方属性
        int loss = _defender.CalculateDefendLoss(_attacker.AttackTroop);
        _defender.TroopCount -= loss;
        // 状态流转时可继续携带防守方引用
        _attacker.TransitionToState(new ExecutionState(_attacker, _defender));
        yield break;
    }
}

// 触发进攻时的调用示例
attackerTerritory.TransitionToState(new AttackState(attackerTerritory, defenderTerritory));
  • 优势:逻辑直观无额外依赖,调用链路清晰,适合一对一即时交互场景
  • 注意:必须做好空引用校验,避免目标领地销毁后触发空指针异常

方案2:全局事件中心(事件驱动)

  • 实现单例全局事件中心,定义进攻事件并携带攻防双方、兵力等参数,进攻方发布进攻事件,所有领地订阅事件后判断自身是否为目标防守方,再执行对应逻辑
  • 代码示例:
// 进攻事件参数定义
public class AttackEventArgs : EventArgs
{
    public Territory Attacker;
    public Territory Defender;
    public int AttackTroopCount;
}

// 全局事件中心
public static class GameEventCenter
{
    public static event EventHandler<AttackEventArgs> OnAttackLaunched;
    public static void PublishAttackEvent(AttackEventArgs args)
    {
        OnAttackLaunched?.Invoke(null, args);
    }
}

// 进攻方AttackState中发布事件
GameEventCenter.PublishAttackEvent(new AttackEventArgs
{
    Attacker = _attacker,
    Defender = targetDefender,
    AttackTroopCount = 15
});

// 防守方Territory中订阅事件
private void Start()
{
    GameEventCenter.OnAttackLaunched += HandleBeAttacked;
    TransitionToState(new TerritoryIdleState(this));
}

private void HandleBeAttacked(object sender, AttackEventArgs args)
{
    if (args.Defender == this)
    {
        // 切换到被攻击状态处理防守逻辑
        TransitionToState(new UnderAttackState(this, args.Attacker, args.AttackTroopCount));
    }
}

// 销毁时取消订阅避免内存泄漏
private void OnDestroy()
{
    GameEventCenter.OnAttackLaunched -= HandleBeAttacked;
}
  • 优势:完全解耦攻防双方,不需要互相持有引用,后续扩展UI提示、战报记录等监听逻辑不需要修改原有领地代码
  • 注意:对象销毁时必须取消事件订阅,避免内存泄漏

方案3:全局GameManager中介

  • 实现单例GameManager统一存储所有领地实例,进攻方需要交互时直接从GameManager中查询获取目标防守方实例
  • 代码示例:
public class GameManager : MonoBehaviour
{
    public static GameManager Instance;
    // 存储所有领地,Key可使用领地ID/坐标
    public Dictionary<int, Territory> AllTerritoryDict;

    private void Awake()
    {
        Instance = this;
    }

    public Territory GetTerritoryById(int territoryId)
    {
        AllTerritoryDict.TryGetValue(territoryId, out var territory);
        return territory;
    }
}

// AttackState中调用
var defender = GameManager.Instance.GetTerritoryById(targetDefenderId);
if (defender != null)
{
    defender.TakeDamage(_attacker, attackTroop);
}
  • 优势:适合需要批量操作领地、或多次查询不同目标的场景,统一管理所有领地生命周期
  • 注意:控制GameManager的职责范围,不要塞入过多无关逻辑

方案4:Unity内置消息系统

  • 使用Unity自带的SendMessage方法,获取防守方GameObject后直接调用其暴露的被攻击方法
  • 代码示例:
// 防守方Territory中暴露被攻击接口
public void OnBeAttacked(Territory attacker, int attackTroop)
{
    TransitionToState(new UnderAttackState(this, attacker, attackTroop));
}

// 进攻方调用
defenderObj.SendMessage("OnBeAttacked", new object[] { _attacker, attackTroop }, SendMessageOptions.DontRequireReceiver);
  • 优势:无需额外实现中间件,代码量小
  • 劣势:方法名用字符串绑定,重构容易出错,性能较差,仅适合小型项目使用

内容的提问来源于stack exchange,提问作者Yeleywale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 00:54:03