Unity3D松鼠角色下坡时浮空问题求助
Unity松鼠角色下坡浮空问题解决方案
问题说明
开发以松鼠为角色的Unity3D游戏时,角色行走或奔跑下坡会出现浮空现象。尝试过AddForce、调整移动速度、设置重力,也通过CharacterController.isGrounded判断着地状态,但始终无法让角色紧密贴合坡面,怀疑问题与水平动画有关。
原角色控制脚本
using UnityEngine; using System.Collections; using UnityEngine.UI; using System; public class Squirrel : MonoBehaviour { Animator squirrel; public float gravity = 1.0f; private Vector3 moveDirection = Vector3.zero; float axisH, axisV; public static int munitions = 0; Rigidbody rb; [SerializeField] float walkSpeed = 2f, runSpeed = 8f, rotSpeed = 100f, jumpForce = 350; private bool isJumpKeyDown = false; [SerializeField] bool isJumping = false; Animator characterAnimator; int JumpCount = 0; public int MaxJumps = 1; //Maximum amount of jumps (i.e. 2 for double jumps) [SerializeField] GameObject nb_munitions; CharacterController characterController; // Use this for initialization void Start () { munitions = 0; squirrel = GetComponent<Animator>(); rb = GetComponentInChildren<Rigidbody>(); characterAnimator = GetComponent<Animator>(); JumpCount = MaxJumps; characterController = GetComponent<CharacterController>(); } // Update is called once per frame void Update() { GetInput(); nb_munitions.GetComponent<Text>().text = "Glands : " + munitions; //Affichage du score Move(); } private void FixedUpdate() { if (isJumpKeyDown) { squirrel.SetTrigger("jump"); JumpCount -= 1; isJumpKeyDown = false; } } public void GetInput() { axisV = Input.GetAxis("Vertical"); axisH = Input.GetAxis("Horizontal"); } private void Move() { if (characterController.isGrounded) { //On the ground } else { //on the air } if (axisV > 0) { if (Input.GetKeyDown(KeyCode.LeftControl)) { transform.position += Vector3.forward * walkSpeed * Time.deltaTime; squirrel.SetBool("walk", true); } else { transform.position += Vector3.forward * runSpeed * Time.deltaTime; squirrel.SetFloat("run", axisV); squirrel.SetBool("walk", false); } } else { squirrel.SetFloat("run", 0); } if (axisH != 0 && axisV == 0) { squirrel.SetFloat("h", axisH); } else { squirrel.SetFloat("h", 0); } if (axisH != 0) { transform.Rotate(Vector3.up * rotSpeed * Time.deltaTime * axisH); } if (Input.GetKeyDown(KeyCode.Space)) { if (JumpCount > 0) { isJumpKeyDown = true; } } //Call munitions if (Input.GetKeyDown(KeyCode.LeftShift)) { if (Squirrel.munitions > 0) { SpawnerScript.Instance.NewSpawnRequest(); munitions--; } } } }
核心问题与修复方案
1. 停止直接修改Transform位置
当前代码用transform.position += Vector3.forward * speed * Time.deltaTime直接移动角色,完全绕过了CharacterController的碰撞与地形贴合逻辑,这是浮空的核心原因。必须改用CharacterController.Move()方法执行移动,该方法会自动处理角色与坡面的碰撞贴合。
2. 正确实现重力与坡面贴合逻辑
在Move()方法中,需要根据角色是否着地动态调整重力,并基于输入计算世界空间下的移动方向:
- 着地时重置重力方向,计算移动方向并转换为世界空间
- 空中时持续施加重力
- 用
characterController.Move()执行移动
3. 移除冲突组件
同时使用CharacterController和Rigidbody会导致物理逻辑冲突,角色主体不需要Rigidbody,直接删除该组件(若子物体有物理需求保留即可)。
4. 同步动画与移动状态
动画触发逻辑需与实际移动状态绑定,而非单纯依赖输入轴,避免动画与移动脱节。
修改后的核心Move方法示例
private void Move() { if (characterController.isGrounded) { // 重置跳跃计数与状态 JumpCount = MaxJumps; isJumping = false; // 基于输入计算本地移动方向,转换为世界空间 moveDirection = new Vector3(axisH, 0, axisV); moveDirection = transform.TransformDirection(moveDirection); // 根据输入设置移动速度与动画 if (Input.GetKey(KeyCode.LeftControl) && axisV > 0) { moveDirection *= walkSpeed; squirrel.SetBool("walk", true); squirrel.SetFloat("run", 0); } else if (axisV > 0) { moveDirection *= runSpeed; squirrel.SetFloat("run", axisV); squirrel.SetBool("walk", false); } else { moveDirection = Vector3.zero; squirrel.SetFloat("run", 0); squirrel.SetBool("walk", false); } // 跳跃处理 if (Input.GetKeyDown(KeyCode.Space) && JumpCount > 0) { // 计算跳跃初速度(基于重力和跳跃力) moveDirection.y = Mathf.Sqrt(jumpForce * 2f * gravity); isJumping = true; squirrel.SetTrigger("jump"); JumpCount--; } } else { // 空中持续施加重力 moveDirection.y -= gravity * Time.deltaTime; isJumping = true; } // 水平旋转与动画控制 if (axisH != 0) { transform.Rotate(Vector3.up * rotSpeed * Time.deltaTime * axisH); squirrel.SetFloat("h", axisV == 0 ? axisH : 0); } else { squirrel.SetFloat("h", 0); } // 执行CharacterController移动 characterController.Move(moveDirection * Time.deltaTime); // 弹药调用逻辑 if (Input.GetKeyDown(KeyCode.LeftShift)) { if (munitions > 0) { SpawnerScript.Instance.NewSpawnRequest(); munitions--; } } }
额外优化建议
- 调整
gravity值:原1.0f过小,建议设置为9.8f模拟真实重力,或根据游戏手感调整至5-15之间 - 检查
CharacterController参数:确保Slope Limit不低于坡面角度,否则角色无法正常上下坡 - 动画根运动设置:若用代码控制移动,关闭动画的根运动选项,避免与代码移动冲突
内容的提问来源于stack exchange,提问作者Sans
相关产品推荐
相关产品推荐

