我有一個 IPawnInput 介面,它有一個 OnInput(object sender) 輸入方法。之前,我只是通過“main”類——Player.為其他組件(PlayerMovement、PlayerCamera)呼叫了這個方法。很快我就遇到了將所有必要的組件鏈接到主要組件的問題。我決定有一個輸入管理器,它在所有必需的組件上呼叫此方法。因為這個管理器本身應該從上面獲取輸入命令,所以我創建了一個 PlayerInputManagerSender 類,其中包含有關輸入請求的原始發送者的資訊。直接發送原始發送者不是一種選擇,因為某些組件需要知道它們是通過管理器使用的。由于某種原因,創建此類會導致 Stackoverflow 錯誤。我知道每幀呼叫方法并創建一個類并不是最好的解決方案,
using System.Collections.Generic;
using UnityEngine;
namespace LOK1game
{
public class PlayerInputManager : MonoBehaviour, IPawnInput
{
[HideInInspector] public List<IPawnInput> PawnInputs = new List<IPawnInput>();
[SerializeField] private List<MonoBehaviour> _actors;
private void Awake()
{
foreach (var actor in _actors)
{
if(actor is PlayerInputManager)
{
throw new System.Exception("Input manager can not calls itself!");
}
PawnInputs.Add(actor.GetComponent<IPawnInput>());
}
}
private void Update()
{
//Test temp solution
OnInput(this);
}
public void OnInput(object sender)
{
var managerSender = new PlayerInputManagerSender(sender, this);
foreach (var pawn in PawnInputs)
{
pawn.OnInput(managerSender);
}
}
}
public struct PlayerInputManagerSender
{
public object OriginSender;
public object ActualSender;
public PlayerInputManagerSender(object originSender, object actualSender)
{
OriginSender = originSender;
ActualSender = actualSender;
}
}
}
我剛剛嘗試將類更改為結構
uj5u.com熱心網友回復:
StackOverflow 例外通常是由無限遞回引起的。您的一個函式正在呼叫另一個函式,該函式以某種方式回呼到最初呼叫的函式。在 OnInput() 和 Update() 函式中使用斷點/寫入行,以確保它們被呼叫的次數符合您的期望。
uj5u.com熱心網友回復:
你的班級PlayerInputManager正在實作IPawnInput自己,所以當你這樣做時
foreach (var actor in _actors)
{
if(actor is PlayerInputManager)
{
throw new System.Exception("Input manager can not calls itself!");
}
PawnInputs.Add(actor.GetComponent<IPawnInput>());
}
很可能它actor本身不是PlayerInputManager組件,而是附加到同一組件的另一個組件GameObject。
=> 不阻止 aPlayerInputManager進入PawnInputs!
您應該在喜歡之后進行檢查 GetComponent<IPawnInput>
foreach (var actor in _actors)
{
if(actor.TryGetComponent<IPawnInput>(out var pawnInput))
{
if(pawnInput is PlayerInputManager)
{
// personally I would just ignore it and not throw an exception
// that seems a bit overkill ;)
continue;
}
PawnInputs.Add(pawnInput);
}
}
uj5u.com熱心網友回復:
我的猜測是你有回圈參考。PlayerInputManager是IPawnInput,并且擁有 的串列IPawnInput。所以有可能PawnInputs包含對擁有物件的參考。基本上形成了一個圖表。因此,當您呼叫時,OnInput您最終會出現無限遞回,并最終耗盡堆疊。
要檢查這一點,您可以遍歷圖形并檢查是否有任何物件出現兩次:
public static bool HasCycle<T>(T self, Func<T, IEnumerable<T>> selector, IEqualityComparer<T> comparer = default)
{
var stack = new Stack<T>();
stack.Push(self);
comparer ??= EqualityComparer<T>.Default;
var visited = new HashSet<T>(comparer);
while (stack.Count > 0)
{
var current = stack.Pop();
if (!visited.Add(current))
{
return true;
}
foreach (var child in selector(current))
{
stack.Push(child);
}
}
return false;
}
叫像
var result = HasCycle(this, p => p.PawnInputs);
您可以修改上面的迭代代碼,為您提供兩次出現的物件,或者在每次添加 pawn 時呼叫它以查找回圈的創建位置,并修復問題。
您也可以使用類似的方法來忽略圖表中的任何重復項,以防您實際上打算有回圈,但想要處理其中的每個專案一次。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/449490.html
上一篇:從多個網路抓取中提取單個資料點
下一篇:For回圈沒有完成
