Unity中C#脚本UnassignedReferenceException错误及角色无法跳跃问题修复
错误信息(中文翻译)
UnassignedReferenceException: PlayerController的rb变量未被赋值。
你可能需要在检视面板中为PlayerController脚本的rb变量赋值。
UnityEngine.Rigidbody.AddForce (UnityEngine.Vector3 force, UnityEngine.ForceMode mode) (at :0)
UnityEngine.Rigidbody.AddForce (UnityEngine.Vector3 force) (at :0)
PlayerController.GetInput () (at Assets/Scripts/PlayerController.cs:77)
PlayerController.Update () (at Assets/Scripts/PlayerController.cs:23)
错误原因
PlayerController脚本中的rb是公开的Rigidbody引用变量,但未被赋值。当触发跳跃逻辑调用rb.AddForce()时,空引用导致异常,直接造成跳跃功能失效。
修复方法
方法1:手动在检视面板赋值
- 选中挂载了
PlayerController脚本的角色 GameObject - 在Inspector面板中找到
PlayerController组件 - 将角色身上的Rigidbody组件拖拽到
rb字段的赋值框中
方法2:自动赋值(推荐)
修改脚本,在Awake方法中自动获取当前对象上的Rigidbody组件,避免手动操作遗漏:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerController : MonoBehaviour { [Header("移动速度")] public float speed = 7f; [Header("是否在地面")] [SerializeField] private bool ground; [Header("跳跃力量")] public float jumpPower = 200f; [Header("奔跑速度")] public float runSpeed = 15f; public Rigidbody rb; private void Awake() { // 自动获取当前对象的Rigidbody组件 rb = GetComponent<Rigidbody>(); } private void Update() { GetInput(); } // 其余原有代码保持不变... }
额外优化建议
移动逻辑适配物理引擎:
原有直接修改transform.localPosition的方式会绕过物理引擎,容易出现穿模、碰撞异常问题。建议改用Rigidbody.MovePosition实现移动:private void GetInput() { Vector3 movement = Vector3.zero; if (Input.GetKey(KeyCode.W)) movement += transform.forward; if (Input.GetKey(KeyCode.S)) movement -= transform.forward; if (Input.GetKey(KeyCode.A)) movement -= transform.right; if (Input.GetKey(KeyCode.D)) movement += transform.right; // 归一化向量,避免斜向移动速度过快 if (movement.magnitude > 1f) movement.Normalize(); float currentSpeed = Input.GetKey(KeyCode.LeftShift) ? runSpeed : speed; rb.MovePosition(transform.position + movement * currentSpeed * Time.deltaTime); // 跳跃逻辑保持不变... }优化地面检测逻辑:
原有OnCollisionEnter/Exit在角色快速移动时可能出现误判,可改用OnCollisionStay或者射线检测来更稳定地判断地面状态:private void OnCollisionStay(Collision collision) { if (collision.gameObject.CompareTag("Ground")) { ground = true; } } private void OnCollisionExit(Collision collision) { if (collision.gameObject.CompareTag("Ground")) { ground = false; } }变量权限优化:
将ground变量改为private并添加[SerializeField],避免在检视面板被误修改,仅通过碰撞事件维护状态。
内容的提问来源于stack exchange,提问作者Vova Leksakov

