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

如何避免游戏中Character与SustainedAction的循环引用?

解决Character与SustainedAction循环引用的设计方案

针对你提出的循环引用问题,结合给定的三个约束条件,这里提供一个基于弱引用+动作管理器的无循环引用设计方案,同时保留原有性能特性:

核心设计思路

  1. 打破循环强引用:让SustainedAction持有Character的弱引用,而Character持有SustainedAction的强引用,避免双向强引用导致的GC回收障碍
  2. 保留本地列表性能:Character仍维护参与动作的强引用列表,保证ShowActionList()的调用效率
  3. 统一生命周期管理:新增动作管理器负责动作的创建、注册和全局更新,同时支持任意参与者触发动作结束

修改后的代码实现

Character类

public class Character
{
    public string Name { get; set; }

    // 保留本地强引用列表,满足ShowActionList的性能需求
    public List<SustainedAction> ActionsInParticipation = new();

    public void PlayTalk(IEnumerable<Character> targets) 
    { 
        ActionManager.Instance.CreateAction<Talk>(this, targets); 
    }

    public void PlayLecture(IEnumerable<Character> targets) 
    { 
        ActionManager.Instance.CreateAction<Lecture>(this, targets); 
    }

    public void ShowActionList()
    {
        foreach(var action in ActionsInParticipation) 
            Debug.Log(action.Name);
    }

    // 任意角色可调用此方法结束动作
    public void EndAction(SustainedAction action) 
    { 
        if (ActionsInParticipation.Contains(action))
        {
            action.End();
        }
    }

    // 供动作内部调用,移除自身引用
    internal void RemoveAction(SustainedAction action)
    {
        ActionsInParticipation.Remove(action);
    }
}

SustainedAction抽象类及子类

public abstract class SustainedAction
{
    // 用弱引用存储所有参与者,避免循环强引用
    private List<WeakReference<Character>> _participants = new();
    public string Name { get; protected set; }
    public int LeftTime { get; protected set; }

    protected SustainedAction(IEnumerable<Character> participants, string name, int leftTime = 5)
    {
        Name = name;
        LeftTime = leftTime;

        // 初始化参与者弱引用,并让每个角色持有动作的强引用
        foreach (var character in participants)
        {
            _participants.Add(new WeakReference<Character>(character));
            character.ActionsInParticipation.Add(this);
        }

        ActionManager.Instance.RegisterAction(this);
    }

    public void End()
    {
        // 执行自定义结束条件检查...

        // 通知所有存活的角色移除该动作
        foreach (var weakRef in _participants)
        {
            if (weakRef.TryGetTarget(out Character character))
            {
                character.RemoveAction(this);
            }
        }

        // 从管理器注销,释放资源
        ActionManager.Instance.UnregisterAction(this);
        _participants.Clear();
    }

    public void Update(int time)
    {
        // 执行动作逻辑...

        LeftTime -= time;
        if (LeftTime < 0) 
            End();
    }
}

public class Talk : SustainedAction
{
    public Talk(IEnumerable<Character> participants) 
        : base(participants, "Talk", 10) { }
}

public class Lecture : SustainedAction
{
    public Lecture(IEnumerable<Character> participants) 
        : base(participants, "Lecture", 90) { }
}

动作管理器(统一维护动作生命周期)

public class ActionManager
{
    public static ActionManager Instance { get; } = new ActionManager();
    private List<SustainedAction> _activeActions = new();

    // 创建动作,自动包含发起者和目标群体
    public T CreateAction<T>(Character initiator, IEnumerable<Character> targets) where T : SustainedAction
    {
        var allParticipants = new List<Character> { initiator };
        allParticipants.AddRange(targets);
        return Activator.CreateInstance(typeof(T), allParticipants) as T;
    }

    public void RegisterAction(SustainedAction action)
    {
        _activeActions.Add(action);
    }

    public void UnregisterAction(SustainedAction action)
    {
        _activeActions.Remove(action);
    }

    // 全局更新所有活跃动作
    public void UpdateAllActions(int time)
    {
        // 遍历列表副本,避免修改原集合时引发异常
        foreach (var action in _activeActions.ToList())
        {
            action.Update(time);
        }
    }
}

方案优势说明

  • 无循环引用:角色持有动作强引用,动作持有角色弱引用,GC可正常回收不再被引用的对象
  • 性能达标:ShowActionList()直接遍历本地列表,无需全局查询,满足高频率调用需求
  • 支持多参与者:通过参与者列表替代单个Player/Target,自然支持多玩家多目标场景
  • 灵活结束动作:任意角色可调用EndAction()触发动作结束,动作自身也会在时间耗尽时自动结束

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 04:08:10