Din*_*ovr 8 c# collision-detection unity-game-engine
我的碰撞检测遇到了一个奇怪的问题.我正在使用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);
}
}
Run Code Online (Sandbox Code Playgroud)
脚本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;
}
}
Run Code Online (Sandbox Code Playgroud)
立方体的目标是较大立方体(墙壁)的孩子.
如果您需要澄清,请在下面留言.如果您需要更多细节,我可能会给我的游戏链接.
从这里引用(感谢@Logman):"即使你使用连续动态碰撞检测也存在问题,因为快速移动的物体移动速度太快,以至于它们从一帧到下一帧的距离太远.就像它一样.它们被传送,并且不会触发任何碰撞检测,因为从每个帧的角度来看都不存在碰撞,因此也不会从所有处理过的计算中发生碰撞.
在我的情况下,立方体不会快速,但你得到了概念.
您的代码有几个问题.
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(),并且(创建和)使用成员bools来有条件地测试哪个子程序"执行"以及哪个"跳跃".您还可以使用成员bools或enums作为触发器在各种"状态"之间切换.
一个更好的解决方案是让Unity处理运动学,而你使用rigidbodymutators(而不是transform.positions),但对于你可能的街机情况来说,这可能是完全没必要的.在那种情况下坚持上面的黑客.
如果您真的想要手动控制运动,请使用像SFML这样的引擎.粒子系统教程将是一个很好的起点.
| 归档时间: |
|
| 查看次数: |
812 次 |
| 最近记录: |