在 Update() 中创建新类会导致 StackOverflow 异常 Unity
我有一个 IPawnInput 接口,它有一个 OnInput(object sender) 方法用于输入。之前,我只是通过“主”类 - 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;
}
}
}
我刚刚尝试将类更改为结构
I have an IPawnInput interface that has an OnInput(object sender) method for input. Before, I just called this method for the other components (PlayerMovement, PlayerCamera) through the "main" class - Player. Soon I had problems linking all the necessary components to the main one. I decided to have an input manager that calls this method on all the required components. Because this manager itself should get the input command from above, I created a class PlayerInputManagerSender that has information about the original sender of the input request. Sending the original sender directly is not an option, because some components need to know that they were used through the manager. For some reason creating this class causes a Stackoverflow error. I understand that calling method and creating a class every frame isn't the best solution, but I have no other solution, because input in some components must be read every frame.
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;
}
}
}
I've just tried to change class to struct
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我的猜测是你有循环引用。
PlayerInputManager
是一个IPawnInput
,并拥有一个IPawnInput
列表。因此,其他一些 IPawnInput 对象可能包含对所属对象的引用。本质上形成一个图表。因此,当您调用OnInput
时,您最终会陷入无限递归,并最终耗尽堆栈。要检查这一点,您可以迭代图表并检查是否有任何对象出现两次:
调用方式
您可以修改上面的迭代代码以给出出现两次的对象,或者在每次添加 pawn 时调用它以查找循环的位置创建并解决问题。
您还可以使用类似的方法来忽略图中的任何重复项,以防您实际上打算有循环,但希望处理其中的每个项一次。
My guess is that you have cyclic references.
PlayerInputManager
is aIPawnInput
, and owns a list ofIPawnInput
. So there is the possibility that some other IPawnInput object contains a reference to the owning object. Essentially forming a graph. So when you callOnInput
you end up with infinite recursion, and eventually run out of stack.To check for this you may iterate over the graph and check if any object occurs twice:
Called like
You could modify the iteration code above to give you what object occurs twice, or call it every time you add a pawn to find where the cycle is created, and fix the issue.
You can also use a similar approach to just ignore any duplicated items in the graph in case you actually intend to have cycles, but want to process each item in it once.
StackOverflow异常通常是由无限递归引起的。您的一个函数正在调用另一个函数,该函数以某种方式回调最初调用的函数。在 OnInput() 和 Update() 函数中使用断点/写入行,以确保它们被调用的次数符合您的预期。
StackOverflow exceptions are often causes by infinite recursion. One of your functions is calling another function that calls back to the originally called function somehow. Use breakpoints/writelines in your OnInput() and Update() functions to make sure they're being called the appropriate number of times for what you expect.
您的类
PlayerInputManager
正在实现IPawnInput
本身,因此当您这样做时,
actor
本身很可能不是PlayerInputManager
组件,但另一个附加到同一GameObject
的组件。=>不会阻止
PlayerInputManager
将其放入PawnInputs
!您应该像 after
GetComponent
那样进行检查Your class
PlayerInputManager
is implementingIPawnInput
itself so when you doit is very possible that
actor
itself is not thePlayerInputManager
component but another one that is attached to the sameGameObject
.=> It is not prevented that a
PlayerInputManager
makes it into thePawnInputs
!You should do the check rather after
GetComponent<IPawnInput>
like