Unity中2D射线检测触发NullReferenceException问题求助
问题分析与解决:New Input System射击功能NullReferenceException错误
问题描述
尝试用New Input System为玩家添加射击功能,编写PlayerMovement脚本后运行触发NullReferenceException,错误指向第58行代码:
if (raycastHit2D.transform.gameObject.layer == LayerMask.GetMask("Enemy"))
已订阅Shoot事件,但无法定位问题原因。
相关脚本
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; public class PlayerMovement : MonoBehaviour { [Header("References")] [SerializeField] float speed; [SerializeField] float range; [SerializeField] GameObject Gun; [SerializeField] Camera cam; [Header("Component References")] Animator animator_C; SpriteRenderer spriteRenderer_C; Rigidbody2D rb2D_C; BoxCollider2D boxCollider2D_C; PlayerInput playerInput; // a class not a component private void Awake() { animator_C = GetComponent<Animator>(); playerInput = new PlayerInput(); spriteRenderer_C = GetComponent<SpriteRenderer>(); rb2D_C = GetComponent<Rigidbody2D>(); boxCollider2D_C = GetComponent<BoxCollider2D>(); } private void Start() { // Enable player input first playerInput.Player.Enable(); } #region Subscribe/Unsubscribe to Event and Methods void OnEnable() { playerInput.Player.Hit.performed += OnHit; playerInput.Player.Hit.canceled += OnUnHit; playerInput.Player.Shoot.performed += OnShoot; } private void OnDisable() { playerInput.Player.Hit.performed -= OnHit; playerInput.Player.Hit.canceled -= OnUnHit; playerInput.Player.Shoot.performed -= OnShoot; } private void OnShoot(InputAction.CallbackContext obj) { RaycastHit2D raycastHit2D = Physics2D.Raycast(Gun.transform.position, cam.ScreenToWorldPoint(Mouse.current.position.ReadValue()), range); // store info about target Debug.DrawLine(Gun.transform.position, cam.ScreenToWorldPoint(Mouse.current.position.ReadValue()), Color.white, 1); Debug.Log("ff"); /*58*/ if (raycastHit2D.transform.gameObject.layer == LayerMask.GetMask("Enemy")) { // Destroy enemy } } private void OnHit(InputAction.CallbackContext context) { animator_C.SetBool("hit", true); } private void OnUnHit(InputAction.CallbackContext context) { animator_C.SetBool("hit", false); } #endregion private void Update() { OnRun(); } void OnRun() { Vector2 velocity = playerInput.Player.Move.ReadValue<Vector2>(); Debug.Log(velocity); bool isRunning = Mathf.Abs(velocity.x) > 0; if (isRunning) { animator_C.SetBool("isRunning", true); transform.rotation = (Quaternion.Euler(new Vector3(0, Mathf.Sign(velocity.x) == 1 ? 0 : 180, 0))); } else { animator_C.SetBool("isRunning", false); } rb2D_C.velocity = velocity * speed; } }
错误日志(翻译后)
NullReferenceException: 对象引用未设置为对象的实例 PlayerMovement.OnShoot (UnityEngine.InputSystem.InputAction+CallbackContext obj) (at Assets/Scripts/PlayerMovement.cs:58) UnityEngine.InputSystem.Utilities.DelegateHelpers.InvokeCallbacksSafe[TValue] (UnityEngine.InputSystem.Utilities.CallbackArray`1[System.Action`1[TValue]]& callbacks, TValue argument, System.String callbackName, System.Object context) (at Library/PackageCache/com.unity.inputsystem@1.3.0/InputSystem/Utilities/DelegateHelpers.cs:46) UnityEngine.InputSystem.LowLevel.<>c__DisplayClass7_0:<set_onUpdate>b__0(NativeInputUpdateType, NativeInputEventBuffer*) UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate(NativeInputUpdateType, IntPtr)
执行'Player/Shoot[/Mouse/leftButton]'的'performed'回调时发生NullReferenceException
UnityEngine.InputSystem.LowLevel.NativeInputRuntime/<>c__DisplayClass7_0:<set_onUpdate>b__0
(UnityEngineInternal.Input.NativeInputUpdateType,UnityEngineInternal.Input.NativeInputEventBuffer*)
UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate
(UnityEngineInternal.Input.NativeInputUpdateType,intptr)
问题根源
- 射线未命中物体时直接访问transform:当
Physics2D.Raycast没有命中任何碰撞体时,返回的raycastHit2D对象的transform属性为null,此时直接访问raycastHit2D.transform.gameObject必然抛出空引用错误。 - 射线方向参数错误:
Physics2D.Raycast的第二个参数是射线的方向向量,但你传入的是鼠标位置转换后的世界坐标(目标点),这会导致射线方向计算错误,甚至可能超出设定的range范围。 - 潜在引用缺失:
Gun或cam如果没有在Inspector面板中赋值,访问Gun.transform或cam.ScreenToWorldPoint时也会触发空引用错误。
解决办法
1. 先判断射线是否命中物体
在访问raycastHit2D的任何属性前,先检查是否命中:
// 先判断射线是否命中 if (raycastHit2D) { if (raycastHit2D.transform.gameObject.layer == LayerMask.GetMask("Enemy")) { // 销毁敌人等逻辑 } }
或者更严谨地检查collider:
if (raycastHit2D.collider != null) { // 后续逻辑 }
2. 修复射线方向计算
将鼠标世界位置减去Gun的位置,得到方向向量并归一化:
// 计算鼠标世界位置(注意Z轴设为0,避免2D场景中Z轴偏移) Vector3 mouseWorldPos = cam.ScreenToWorldPoint(Mouse.current.position.ReadValue()); mouseWorldPos.z = 0f; // 计算射线方向并归一化 Vector2 rayDirection = (mouseWorldPos - Gun.transform.position).normalized; // 执行射线检测 RaycastHit2D raycastHit2D = Physics2D.Raycast(Gun.transform.position, rayDirection, range);
3. 检查Inspector引用
确保Gun和cam变量已在Inspector面板中拖入对应的GameObject,避免空引用。
完整修改后的OnShoot方法
private void OnShoot(InputAction.CallbackContext obj) { // 先检查Gun和cam是否赋值,避免空引用 if (Gun == null || cam == null) { Debug.LogError("Gun或Camera未在Inspector中赋值!"); return; } // 计算鼠标世界位置,固定Z轴为0 Vector3 mouseWorldPos = cam.ScreenToWorldPoint(Mouse.current.position.ReadValue()); mouseWorldPos.z = 0f; // 计算射线方向并归一化 Vector2 rayDirection = (mouseWorldPos - Gun.transform.position).normalized; // 执行射线检测 RaycastHit2D raycastHit2D = Physics2D.Raycast(Gun.transform.position, rayDirection, range); // 绘制射线调试 Debug.DrawLine(Gun.transform.position, Gun.transform.position + (Vector3)rayDirection * range, Color.white, 1f); Debug.Log("射击触发"); // 先判断是否命中物体 if (raycastHit2D) { // 检查是否是敌人图层 if (raycastHit2D.transform.gameObject.layer == LayerMask.GetMask("Enemy")) { Debug.Log("命中敌人"); // 在这里添加销毁敌人的逻辑 // Destroy(raycastHit2D.transform.gameObject); } } }
内容的提问来源于stack exchange,提问作者Khoaoaoa
相关产品推荐
相关产品推荐

