Unity开发:自动移动的玩家球体到达平台边缘不坠落的实现问题
问题描述
我通过脚本实现了一个可自动向前移动的球体(玩家角色),现在希望该球体符合正常运动逻辑:到达平台边缘时不会坠落,直接停在边缘位置。我的场景示意图如下:
当前使用的控制脚本如下,第一个为滑动输入系统脚本:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SwerveInputSystem : MonoBehaviour { private float _lastFrameFingerPositionX; private float _moveFactorX; public float MoveFactorX => _moveFactorX; void Start(){ } // Update is called once per frame void Update() { if (Input.GetMouseButtonDown(0)) { _lastFrameFingerPositionX = Input.mousePosition.x; } else if (Input.GetMouseButton(0)) { _moveFactorX = Input.mousePosition.x - _lastFrameFingerPositionX; _lastFrameFingerPositionX = Input.mousePosition.x; } else if (Input.GetMouseButtonUp(0)) { _moveFactorX = 0f; } } }
第二个为玩家控制脚本:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerController : MonoBehaviour{ private SwerveInputSystem _swerveInputSystem; [SerializeField] private float swerveSpeed = 5f; [SerializeField] private float maxSwerveAmount = 1f; [SerializeField] private float verticalSpeed; void Start(){ _swerveInputSystem = GetComponent<SwerveInputSystem>(); } void Update(){ float swerveAmount = Time.deltaTime * swerveSpeed * _swerveInputSystem.MoveFactorX; swerveAmount = Mathf.Clamp(swerveAmount, -maxSwerveAmount, maxSwerveAmount); transform.Translate(swerveAmount, 0, 0); float verticalDelta = verticalSpeed * Time.deltaTime; transform.Translate(swerveAmount, verticalDelta, 0.1f); } }
解决方案
你现有PlayerController脚本中连续两次调用transform.Translate时都传入了swerveAmount作为X轴参数,会导致实际横向移动速度是参数设定值的2倍,建议先修正该逻辑。下面提供两种实现边缘停驻的方案:
方案1:固定边界钳位(适配规则矩形平台)
如果你的平台是左右边界固定的规则矩形,直接限制球体X轴坐标范围是成本最低的实现方式。
修改后的PlayerController代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerController : MonoBehaviour{ private SwerveInputSystem _swerveInputSystem; [SerializeField] private float swerveSpeed = 5f; [SerializeField] private float maxSwerveAmount = 1f; [SerializeField] private float verticalSpeed; // 新增平台左右边界参数,可在Inspector面板手动设置 [SerializeField] private float minX; [SerializeField] private float maxX; void Start(){ _swerveInputSystem = GetComponent<SwerveInputSystem>(); } void Update(){ float swerveAmount = Time.deltaTime * swerveSpeed * _swerveInputSystem.MoveFactorX; swerveAmount = Mathf.Clamp(swerveAmount, -maxSwerveAmount, maxSwerveAmount); float verticalDelta = verticalSpeed * Time.deltaTime; // 修正重复添加swerveAmount的问题,单次Translate即可完成移动 transform.Translate(swerveAmount, verticalDelta, 0.1f); // 钳位X轴坐标,不让球体超出平台范围 Vector3 currentPos = transform.position; currentPos.x = Mathf.Clamp(currentPos.x, minX, maxX); transform.position = currentPos; } }
使用说明:脚本挂载完成后,在Inspector面板将minX设为平台左边缘对应的X坐标,maxX设为平台右边缘对应的X坐标即可。
方案2:射线检测(适配任意形状平台)
如果平台形状不规则,或者后续会有动态变化,可以通过射线检测判断移动方向上是否存在地面,无地面时停止对应方向的移动即可。
修改后的PlayerController代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerController : MonoBehaviour{ private SwerveInputSystem _swerveInputSystem; [SerializeField] private float swerveSpeed = 5f; [SerializeField] private float maxSwerveAmount = 1f; [SerializeField] private float verticalSpeed; // 边缘检测射线长度,可根据球体半径调整 [SerializeField] private float edgeCheckRayLength = 0.6f; private float _sphereRadius; void Start(){ _swerveInputSystem = GetComponent<SwerveInputSystem>(); // 自动获取球体碰撞器半径 _sphereRadius = GetComponent<SphereCollider>().radius; } void Update(){ float swerveAmount = Time.deltaTime * swerveSpeed * _swerveInputSystem.MoveFactorX; swerveAmount = Mathf.Clamp(swerveAmount, -maxSwerveAmount, maxSwerveAmount); // 边缘检测:判断移动方向上是否有地面 if (swerveAmount < 0) // 向左移动 { Vector3 rayStart = transform.position + Vector3.left * _sphereRadius; if (!Physics.Raycast(rayStart, Vector3.down, edgeCheckRayLength)) { swerveAmount = 0; } } else if (swerveAmount > 0) // 向右移动 { Vector3 rayStart = transform.position + Vector3.right * _sphereRadius; if (!Physics.Raycast(rayStart, Vector3.down, edgeCheckRayLength)) { swerveAmount = 0; } } float verticalDelta = verticalSpeed * Time.deltaTime; transform.Translate(swerveAmount, verticalDelta, 0.1f); } }
使用说明:确保平台对象已经挂载了碰撞器组件,调整edgeCheckRayLength参数保证射线可以正常检测到脚下的平台即可。
内容的提问来源于stack exchange,提问作者user16240688
相关产品推荐
相关产品推荐

