Unity中随机生成目标边界与布娃娃碰撞穿模问题求助
问题描述
我正在使用ML-Agents库,尝试为随机生成的目标对象创建边界。已完成边界制作并修改脚本使其与目标同位置生成,但该边界经常与ragdoll(布娃娃)对象重叠穿模,导致布娃娃无法移动。我是Unity新手,欢迎提供任何基础修复方案。
已尝试的方法
- 添加rigidbody(刚体):边界出现严重问题,穿模仍存在
- 调整碰撞设置:对穿模问题毫无作用
- 计算目标与布娃娃的距离并重新生成随机位置:无效果
- 添加计时器触发位置重新生成:边界的四个光束开始疯狂瞬移
目标控制器脚本
using UnityEngine; using Random = UnityEngine.Random; using Unity.MLAgents; using UnityEngine.Events; namespace Unity.MLAgentsExamples { /// <summary> /// Utility class to allow target placement and collision detection with an agent /// Add this script to the target you want the agent to touch. /// Callbacks will be triggered any time the target is touched with a collider tagged as 'tagToDetect' /// </summary> public class TargetController : MonoBehaviour { [Header("Collider Tag To Detect")] public string tagToDetect = "agent"; //collider tag to detect [Header("Target Placement")] public float spawnRadius; //The radius in which a target can be randomly spawned. public bool respawnIfTouched; //Should the target respawn to a different position when touched [Header("Target Fell Protection")] public bool respawnIfFallsOffPlatform = true; //If the target falls off the platform, reset the position. public float fallDistance = 5; //distance below the starting height that will trigger a respawn private Vector3 m_startingPos; //the starting position of the target [System.Serializable] public class TriggerEvent : UnityEvent<Collider> { } [Header("Trigger Callbacks")] public TriggerEvent onTriggerEnterEvent = new TriggerEvent(); public TriggerEvent onTriggerStayEvent = new TriggerEvent(); public TriggerEvent onTriggerExitEvent = new TriggerEvent(); [System.Serializable] public class CollisionEvent : UnityEvent<Collision> { } [Header("Collision Callbacks")] public CollisionEvent onCollisionEnterEvent = new CollisionEvent(); public CollisionEvent onCollisionStayEvent = new CollisionEvent(); public CollisionEvent onCollisionExitEvent = new CollisionEvent(); public GameObject boundary; public GameObject ragdoll; // Start is called before the first frame update void OnEnable() { m_startingPos = transform.position; if (respawnIfTouched) { MoveTargetToRandomPosition(); } } void Update() { if (respawnIfFallsOffPlatform) { if (transform.position.y < m_startingPos.y - fallDistance) { Debug.Log($"{transform.name} Fell Off Platform"); MoveTargetToRandomPosition(); } } } /// <summary> /// Moves target to a random position within specified radius. /// </summary> public void MoveTargetToRandomPosition() { var newTargetPos = m_startingPos + (Random.insideUnitSphere * spawnRadius); float dis = Vector3.Distance(newTargetPos, ragdoll.transform.position); while (dis < 10){ newTargetPos = m_startingPos + (Random.insideUnitSphere * spawnRadius); dis = Vector3.Distance(newTargetPos, ragdoll.transform.position); } newTargetPos.y = m_startingPos.y; transform.position = newTargetPos; boundary.transform.position = newTargetPos + new Vector3(0f, -0.75f,-2f); } private void OnCollisionEnter(Collision col) { if (col.transform.CompareTag(tagToDetect)) { onCollisionEnterEvent.Invoke(col); if (respawnIfTouched) { MoveTargetToRandomPosition(); } } } private void OnCollisionStay(Collision col) { if (col.transform.CompareTag(tagToDetect)) { onCollisionStayEvent.Invoke(col); } } private void OnCollisionExit(Collision col) { if (col.transform.CompareTag(tagToDetect)) { onCollisionExitEvent.Invoke(col); } } private void OnTriggerEnter(Collider col) { if (col.CompareTag(tagToDetect)) { onTriggerEnterEvent.Invoke(col); } } private void OnTriggerStay(Collider col) { if (col.CompareTag(tagToDetect)) { onTriggerStayEvent.Invoke(col); } } private void OnTriggerExit(Collider col) { if (col.CompareTag(tagToDetect)) { onTriggerExitEvent.Invoke(col); } } } }
基础修复方案
1. 修正距离判断逻辑
你当前只检查了目标根节点和布娃娃的距离,但边界是偏移生成的,可能目标离得远,但边界还是和布娃娃重叠。把边界的最终位置纳入距离计算:
public void MoveTargetToRandomPosition() { Vector3 newTargetPos; Vector3 newBoundaryPos; float dis; do { newTargetPos = m_startingPos + (Random.insideUnitSphere * spawnRadius); newTargetPos.y = m_startingPos.y; newBoundaryPos = newTargetPos + new Vector3(0f, -0.75f,-2f); // 计算边界和布娃娃的距离,也可以用布娃娃碰撞体的包围盒中心更准确 dis = Vector3.Distance(newBoundaryPos, ragdoll.transform.position); // 根据边界实际大小调整阈值,比如边界尺寸是5,就设为5+2的安全距离 } while (dis < 12); transform.position = newTargetPos; boundary.transform.position = newBoundaryPos; }
2. 给边界设置正确的碰撞体
- 不要给边界加Rigidbody,把边界碰撞体的
Is Trigger设为false。 - 在Edit > Project Settings > Physics里,给布娃娃和边界分别设置专属层(比如"Ragdoll"和"Boundary"),并开启这两层的碰撞交互。
- 如果边界是多个光束组成,确保每个光束都有贴合模型的碰撞体。
3. 解决边界瞬移问题
计时器触发瞬移是因为重复调用了移动方法,给移动逻辑加冷却限制:
private float respawnCooldown = 2f; private float lastRespawnTime; public void MoveTargetToRandomPosition() { if (Time.time - lastRespawnTime < respawnCooldown) return; lastRespawnTime = Time.time; // 这里放原来的位置计算逻辑 }
4. 检查布娃娃的碰撞配置
- 确保布娃娃每个肢体的
CharacterJoint/ConfigurableJoint设置正确,避免僵硬卡死。 - 布娃娃的Rigidbody要设为
Kinematic = false,需要重力的话开启Use Gravity。
内容的提问来源于stack exchange,提问作者Zelix75
相关产品推荐
相关产品推荐

