我的碰撞检测遇到了一个奇怪的问题。我使用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):&#34;即使您使用连续动态碰撞检测,问题仍然存在,因为快速移动的物体移动速度太快,以至于它们距离自身太远一帧到下一个直接帧。就像它们被传送一样,并且不会触发任何碰撞检测,因为从每个帧的角度来看都不存在碰撞,因此也就是所有处理过的计算都没有。&#34;
在我的情况下,立方体不会快速,但你得到了这个概念。
答案 0 :(得分:7)
您的代码存在一些问题。
Time.deltaTime > 0.02f
这已成为问题之一。您正在使用Coroutines和yield return null
来计算物理计算。从本质上讲,你是在Update()
中计算物理,每帧只调用一次(null
相当于new WaitForEndOfFrame()
:如(1)中所述,一个正在运行的Coroutine不能在帧之间屈服)。在低帧速率下,对象在两帧之间进行的运动量可能超过目标触发器的碰撞范围。假设线性,非加速运动:∆S = v∆t
其中v =速度,ΔS是在当前帧中覆盖的运动,Δt是Time.deltaTime
。如您所见,ΔS与Δt成比例。
你在循环中有GetComponent<T>()
个调用。始终避免这样做:将引用存储为成员变量(在Start()
中初始化)。
我对最快的工作黑客的建议是不要过于担心“干净”,而是创建从FixedUpdate()
调用的子例程,并(创建和)使用成员bool
有条件地测试哪个子程序“执行”以及哪个“跳过”。您还可以使用成员bool
或enum
作为触发器在各种“状态”之间切换。
更好的解决方案是让Unity处理运动学而你使用rigidbody
mutators(而不是transform.position
s),但对于街机情况来说这可能是完全没必要的,你可能会这样做是。在那种情况下坚持上面的黑客。
如果确实希望手动控制运动,请使用SFML之类的引擎。粒子系统教程将是一个很好的起点。
答案 1 :(得分:4)
这是你的浮动百分比等等。
“如果isKinematic已启用,则力,碰撞或关节将不再影响刚体。”
这是来自Unity文档的isKinematic页面。当进度达到100时,你将其设置为true。因此,在较低的帧速率下,由于Time.deltaTime步骤高得多,突然进展&gt; = 100,isKinematic设置为true并且玩家不再受到碰撞的影响。
我认为你将不得不在这里重新考虑很多代码并做一些重要的优化。但是其他海报已经把它们放好了,所以我不需要。
编辑:误解了最初的问题,认为这意味着你试图检测碰撞,但你的代码并不总是检测到它们。没有意识到它实际上意味着首先发生碰撞。