gpt4 book ai didi

c# - 低帧率下的缓慢碰撞检测

转载 作者:太空狗 更新时间:2023-10-29 18:24:31 27 4
gpt4 key购买 nike

我的碰撞检测遇到了一个奇怪的问题。我正在使用 Update 方法移动播放器(我不想使用 FixedUpdate,因为这会产生不需要的奇怪移动)。固定时间步长设置为默认值 0.02(我尝试使用时间设置,但也没有用)。我将两个物体的刚体碰撞检测设置为“连续动态”。此外,我将目标帧速率设置为 300,这并没有改变任何东西......

当帧率较低或设备本身速度较慢时,碰撞检测并不总是有效。玩家可以很容易地穿过它应该碰撞的物体,但有时不会。

请告诉我我能做些什么来解决这个问题,因为我已经发布了一个游戏并且许多用户报告了这个(严重的)错误。感谢您的支持。

这是应该发生的事情:

enter image description here

这是实际发生的事情:

enter image description here

(如您所见,立方体离开墙并到达另一侧)

我在用户释放鼠标按钮时移动播放器:

脚本 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;
}
}

立方体的目标是更大的立方体(墙)的 child 。

如果您需要说明,请在下方发表评论。如果您需要更多详细信息,我可能会提供我的游戏链接。

引自 here (感谢@Logman 发现):“即使您使用连续的动态碰撞检测,问题仍然存在,因为快速移动的物体可以移动得如此之快,以至于它们从一帧到下一帧与自身相距太远。就像它们传送一样不会触发碰撞检测,因为从每一帧的角度来看,从所有处理的计算来看,都不存在碰撞。”

在我的例子中,立方体的速度并不快,但你明白了。

最佳答案

您的代码存在多个问题。

  1. 您要求协程让步 1/50 秒。屈服必须发生的最短时间是一帧。如果Time.deltaTime > 0.02f这已经是问题之一。
  2. 您正在使用协程和 yield return null计算物理计算。本质上,您在 Update() 中计算物理,每帧只调用一次一次(null 等同于new WaitForEndOfFrame() :如 (1) 中所述,正在运行的协程不能在帧之间产生)。在低帧率下,物体在两帧之间进行的运动量可能会超过目标触发器的碰撞范围。假设线性、非加速运动:∆S = v∆t其中 v = 速度,ΔS 是在当前帧中覆盖的运动,Δt 是 Time.deltaTime .如您所见,ΔS 与 Δt 成比例。

  3. 你有GetComponent<T>()调用内部循环。始终避免这样做:将引用存储为成员变量(在 Start() 中对其进行初始化)。

我对最快的工作黑客的建议是不要太担心“干净”,而是创建您从 FixedUpdate() 调用的子例程, 和(创建和)使用成员 bool s 有条件地测试“执行”和“跳过”哪个子程序。您也可以使用成员(member) bool s 或 enum作为在各种“状态”之间切换的触发器。

更好的解决方案是让 Unity 处理运动学,而您使用 rigidbody 来处理突变器(而不是 transform.position s),但对于街机情况来说,这可能是完全不必要的,你的情况可能就是这样。在这种情况下,坚持上面的技巧。

如果您真的想手动控制运动学,请使用像 SFML 这样的引擎。粒子系统教程将是一个很好的起点。

关于c# - 低帧率下的缓慢碰撞检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37774204/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com