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

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)


问题根源

  1. 射线未命中物体时直接访问transform:当Physics2D.Raycast没有命中任何碰撞体时,返回的raycastHit2D对象的transform属性为null,此时直接访问raycastHit2D.transform.gameObject必然抛出空引用错误。
  2. 射线方向参数错误:Physics2D.Raycast的第二个参数是射线的方向向量,但你传入的是鼠标位置转换后的世界坐标(目标点),这会导致射线方向计算错误,甚至可能超出设定的range范围。
  3. 潜在引用缺失: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 18:40:29