3D移动平台碰撞异常求助:玩家可穿过平台(附Unity代码)
问题分析与解决方案
你的核心问题在于直接修改平台的transform.position会绕过Unity物理引擎的碰撞处理,导致物理系统无法正确识别平台的运动状态,进而让玩家穿过平台。同时手动计算玩家位置的逻辑存在缺陷(比如用velocity.magnitude这种速度大小判断,而非X方向的速度分量),且缺少触发器的添加/移除逻辑来维护contacts列表。
修正方案
1. 改用Rigidbody控制平台移动
给平台添加Rigidbody组件,勾选Is Kinematic(平台由脚本控制,不需要物理模拟外力),然后用Rigidbody.MovePosition移动平台,让物理引擎正确处理碰撞和带动玩家。
2. 完善触发器的接触列表维护
补充OnTriggerEnter和OnTriggerExit方法,正确更新contacts列表,确保只有玩家接触平台时才处理跟随逻辑。
3. 统一用FixedUpdate处理物理逻辑
物理相关操作必须放在FixedUpdate中,保证不同帧率下运动速度一致。
修改后的完整代码
using UnityEngine; using System.Collections.Generic; public class OscilateX : MonoBehaviour { private float startX; private float val; public float speed; public float distance; private Rigidbody rb; public List<GameObject> contacts = new List<GameObject>(); void Start() { startX = transform.position.x; val = 0; rb = GetComponent<Rigidbody>(); } void FixedUpdate() { val += Time.fixedDeltaTime; // 计算平台目标位置 float targetX = startX + Mathf.Sin(val * speed) * distance; Vector3 targetPos = new Vector3(targetX, transform.position.y, transform.position.z); // 用Rigidbody移动,物理引擎自动处理碰撞跟随 rb.MovePosition(targetPos); } // 触发器检测:玩家进入平台范围时加入列表 void OnTriggerEnter(Collider other) { if (other.CompareTag("Player")) { if (!contacts.Contains(other.gameObject)) { contacts.Add(other.gameObject); } } } // 触发器检测:玩家离开平台范围时移除列表 void OnTriggerExit(Collider other) { if (other.CompareTag("Player")) { contacts.Remove(other.gameObject); } } }
额外说明
- 玩家对象需要有Rigidbody组件(勾选Use Gravity)和正确的碰撞器,这样站在Kinematic平台上时,物理引擎会自动带动玩家跟随平台运动,无需手动修改玩家位置。
- 如果仍需手动控制玩家速度(不推荐,优先依赖物理引擎),可在
FixedUpdate中计算平台速度,叠加到玩家Rigidbody速度上:
// 在FixedUpdate的rb.MovePosition之后添加 Vector3 platformVelocity = (targetPos - rb.position) / Time.fixedDeltaTime; foreach (GameObject player in contacts) { Rigidbody playerRb = player.GetComponent<Rigidbody>(); if (playerRb != null) { // 叠加平台X方向速度到玩家身上 playerRb.velocity = new Vector3(platformVelocity.x, playerRb.velocity.y, playerRb.velocity.z); } }
内容的提问来源于stack exchange,提问作者Veerdex
相关产品推荐
相关产品推荐

