最近在项目中遇到一个unity input system内部的crash。大概会有类似以下报错:

Assertion failed
UnityEngine.InputSystem.LowLevel.<>c__DisplayClass7_0:<set_onUpdate>b__0(NativeInputUpdateType, NativeInputEventBuffer*)
UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate(NativeInputUpdateType, IntPtr)
ArgumentOutOfRangeException during event processing of Fixed update; resetting event buffer
UnityEngine.InputSystem.LowLevel.<>c__DisplayClass7_0:<set_onUpdate>b__0(NativeInputUpdateType, NativeInputEventBuffer*)
UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate(NativeInputUpdateType, IntPtr)
ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: index
UnityEngine.InputSystem.Utilities.InlinedArray`1[TValue].get_Item (System.Int32 index) (at Library/PackageCache/com.unity.inputsystem@1.0.0/InputSystem/Utilities/InlinedArray.cs:68)
UnityEngine.InputSystem.DynamicBitfield.ClearBit (System.Int32 bitIndex) (at Library/PackageCache/com.unity.inputsystem@1.0.0/InputSystem/Utilities/DynamicBitfield.cs:51)
UnityEngine.InputSystem.InputManager.FireStateChangeNotifications (System.Int32 deviceIndex, System.Double internalTime, UnityEngine.InputSystem.LowLevel.InputEvent* eventPtr) (at Library/PackageCache/com.unity.inputsystem@1.0.0/InputSystem/InputManager.cs:2924)
UnityEngine.InputSystem.InputManager.UpdateState (UnityEngine.InputSystem.InputDevice device, UnityEngine.InputSystem.LowLevel.InputUpdateType updateType, System.Void* statePtr, System.UInt32 stateOffsetInDevice, System.UInt32 stateSize, System.Double internalTime, UnityEngine.InputSystem.LowLevel.InputEventPtr eventPtr) (at Library/PackageCache/com.unity.inputsystem@1.0.0/InputSystem/InputManager.cs:3101)
UnityEngine.InputSystem.InputManager.UpdateState (UnityEngine.InputSystem.InputDevice device, UnityEngine.InputSystem.LowLevel.InputEvent* eventPtr, UnityEngine.InputSystem.LowLevel.InputUpdateType updateType) (at Library/PackageCache/com.unity.inputsystem@1.0.0/InputSystem/InputManager.cs:3017)
UnityEngine.InputSystem.InputManager.OnUpdate (UnityEngine.InputSystem.LowLevel.InputUpdateType updateType, UnityEngine.InputSystem.LowLevel.InputEventBuffer& eventBuffer) (at Library/PackageCache/com.unity.inputsystem@1.0.0/InputSystem/InputManager.cs:2707)
UnityEngine.InputSystem.LowLevel.NativeInputRuntime+<>c__DisplayClass7_0.<set_onUpdate>b__0 (UnityEngineInternal.Input.NativeInputUpdateType updateType, UnityEngineInternal.Input.NativeInputEventBuffer* eventBufferPtr) (at Library/PackageCache/com.unity.inputsystem@1.0.0/InputSystem/NativeInputRuntime.cs:64)
UnityEngine.InputSystem.LowLevel.<>c__DisplayClass7_0:<set_onUpdate>b__0(NativeInputUpdateType, NativeInputEventBuffer*)
UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate(NativeInputUpdateType, IntPtr)

原因是移动平台,使用 on-screen button来模拟输入设备事件,在事件触发后将on-screen button所在的game object deactive掉。可能是因为当on-screen button game object被deactive时,input system为其创建的input device被删除,而由于此时正在处理该input device的事件,最终导致input system内部数组越界了。

解决办法是要么不要deactive,但是你又想隐藏按钮怎么办?那就把Image组件disable掉。或者稍微等一下再进行deactive,我是采用await Task来解决的:

public async void OnTest(InputAction.CallbackContext context)
    {        
        if(context.phase == InputActionPhase.Performed)
        {            
            await System.Threading.Tasks.Task.Yield();
            testButton?.gameObject.SetActive(false);
        }
        
    }

通过await,让当前的OnTest方法暂时暂停一下,然后回来继续执行,此时再deactive button,因为事件已经处理完毕,就不会引发crash了。

遇到这个错误时,搜索引擎没有得到有用的信息,因此记录一下,帮助后来人出坑。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐