【发布时间】:2016-06-12 12:22:12
【问题描述】:
我的碰撞检测遇到了一个奇怪的问题。我正在使用 Update 方法来移动播放器(我不想使用 FixedUpdate,因为这会产生不希望的奇怪移动)。固定时间步长设置为默认 0.02(我尝试使用时间设置,但也没有用)。我将两个物体刚体的碰撞检测设置为“连续动态”。另外,我将目标帧速率设置为 300,这并没有改变任何东西......
当帧速率较低或设备本身速度较慢时,碰撞检测并不总是有效。玩家可以很容易地从它应该碰撞的物体上掉下来,尽管有时它不会。
请告诉我我可以做些什么来解决这个问题,因为我已经发布了一个游戏,并且许多用户都报告了这个(严重的)错误。感谢您的支持。
这是应该发生的:
这就是实际发生的情况:
(如你所见,立方体从墙外移到另一边)
当用户释放鼠标按钮时我移动播放器:
脚本 1:
public Script2 Jumper;
public float TimeToJump;
public void Update()
{
if (Input.GetMouseButtonUp(0))
{
StartCoroutine (Delay (1f/50f)); //Don't mind the time.
}
}
IEnumerator Delay(float waitTime)
{
yield return new WaitForSeconds (waitTime);
if (Jumper != null)
{
Jumper.SetVelocityToJump (gameObject, TimeToJump);
}
}
脚本 2 附加到播放器(立方体):
public class Script2 : MonoBehaviour {
GameObject target;
private float timeToJump;
public bool isJumping = false;
public void SetVelocityToJump(GameObject goToJumpTo, float timeToJump)
{
StartCoroutine(jumpAndFollow(goToJumpTo, timeToJump));
this.timeToJump = timeToJump;
this.target = goToJumpTo;
}
private IEnumerator jumpAndFollow(GameObject goToJumpTo, float timeToJump)
{
var startPosition = transform.position;
var targetTransform = goToJumpTo.transform;
var lastTargetPosition = targetTransform.position;
var initialVelocity = getInitialVelocity(lastTargetPosition - startPosition, timeToJump);
var progress = 0f;
while (progress < timeToJump)
{
progress += Time.deltaTime;
if (targetTransform.position != lastTargetPosition)
{
lastTargetPosition = targetTransform.position;
initialVelocity = getInitialVelocity(lastTargetPosition - startPosition, timeToJump);
}
float percentage = progress * 100 / timeToJump;
GetComponent<Rigidbody>().isKinematic = percentage < 100.0f;
transform.position = startPosition + (progress * initialVelocity) + (0.5f * Mathf.Pow(progress, 2) * _gravity);
yield return null;
}
OnFinishJump (goToJumpTo, timeToJump);
}
private void OnFinishJump(GameObject target, float timeToJump)
{
if (stillJumping)
{
this.isJumping = false;
}
}
private Vector3 getInitialVelocity(Vector3 toTarget, float timeToJump)
{
return (toTarget - (0.5f * Mathf.Pow(timeToJump, 2) * _gravity)) / timeToJump;
}
}
立方体的目标是较大立方体(墙)的子对象。
如果您需要澄清,请在下方留言。如果您需要更多详细信息,我可能会提供我的游戏的链接。
引用here(感谢@Logman):“即使您使用连续动态碰撞检测,问题仍然存在,因为快速移动的对象可以移动得如此之快,以至于它们从一帧到下一帧与自身相距太远立即帧。就好像它们被传送并且不会触发任何碰撞检测,因为从每个帧的角度来看不存在碰撞,因此从所有处理的计算来看。”
在我的例子中,立方体的速度并不快,但你明白了这个概念。
【问题讨论】:
-
使用 FixedUpdate() 并修复实际的错误(“不受欢迎的奇怪运动”)。如果问题仍然存在,请在慢速设备上放大碰撞器或设置最低硬件要求。或者如果可以的话优化代码。哦!现在使用固定时间戳确实有效,因为(不足为奇)这与 FixedUpdate() 处理有关
-
您的大纲“延迟”是错误的。只需在 Unity 中使用 Invoke 作为计时器。
-
您是否有理由不使用内置的碰撞事件?如果只是不受欢迎的奇怪动作,那么我同意其他海报应该解决它们。之后,您可以简单地使用 FixedUpdate()、连续动态碰撞检测以及 MonoBehavior 对象模型中内置的标准碰撞事件来实现您想要的。另外一个好处是,如果您正确设置场景,您可能可以通过选择更简单的碰撞检测模型来节省一些资源。您最好的选择可能是针对您的“不受欢迎的奇怪动作”提出不同的问题。
-
您无法使用统一物理引擎解决此问题。看看这个answers.unity3d.com/questions/55179/…
-
是的,但这种情况非常罕见。我真正的意思是“按照设计的实现必要吗?”换句话说,我同意对于非常快速移动的物体,物理速度不够快......但最初的问题并没有说明存在是快速移动的物体。事实上,最初的问题表明它的 player(通常)不会移动得那么快。
标签: c# unity3d collision-detection