zoukankan      html  css  js  c++  java
  • 物理学——车辆碰撞检测

    车辆碰撞检测

    借助于前面的代码,我们已经知道如何检测汽车与护栏的碰撞。只需创建两个碰撞平面,每个护栏一个,然后检查四个轮子与这两个平面的碰撞。因为赛车不仅是一个球体,因此无法像小行星那样做简单的处理,四个面都必须检测,但只检测四轮的位置(或至少是赛车的最外层)仍能实现基本碰撞检测(见图13-15)。

    1
    Figure 13-15

    碰撞检测的代码在CarPhysics类的ApplyGravityAndCheckForCollisions方法中。此代码遍历了赛车的四个角并检测是否与平面碰撞(见图13-15中的道路旁边的两条线)。在实际车长和宽的基础上可计算赛车的四个角:

    // Check all 4 corner points of our car.
    Vector3 carRight = Vector3.Cross(carDir, carUp);
    Vector3 carLeft = -carRight;
    // Car dimensions are 2.6m (width) x 5.6m (length) x 1.8m (height)
    // Note: This could be improved by using more points or using
    // the actual car geometry.
    // Note: We ignore the height, this way the collision is simpler.
    // We then check the height above the road to see if we are flying
    // above the guard rails out into the landscape.
    Vector3[] carCorners = new Vector3[]
    {
      // Top left
      pos + carDir * 5.6f/2.0f - carRight * 2.6f/2.0f,
      // Top right
      pos + carDir * 5.6f/2.0f + carRight * 2.6f/2.0f,
      // Bottom right
      pos - carDir * 5.6f/2.0f + carRight * 2.6f/2.0f,
      // Bottom left
      pos - carDir * 5.6f/2.0f - carRight * 2.6f/2.0f,
    };

    借助于在此方法前计算过的辅助值,碰撞检测现在相对简单了:

    // Check for each corner if we collide with the guard rail
    for (int num = 0; num < carCorners.Length; num++)
    {
      // Hit any guardrail?
      float leftDist = Vector3Helper.DistanceToLine(
        carCorners[num], guardrailLeft, nextGuardrailLeft);
      float rightDist = Vector3Helper.DistanceToLine(
        carCorners[num], guardrailRight, nextGuardrailRight);
    
      // If we are closer than 0.1f, thats a collision!
      if (leftDist < 0.1f ||
        // Also include the case where we are farther away from rightDist
        // than the road is wide.
        rightDist > roadWidth)
      {
        // Handle collision with left guard rail here
      } // if (leftDist < 0.1f)
    
      if (rightDist < 0.1f ||
        // Also include the case where we are farther away from leftDist
        // than the road is wide.
        leftDist > roadWidth)
      {
        // Handle collision with right guard rail here
      } // if (rightDist < 0.1f)
    } // for (num)

    碰撞处理的最后部分是碰撞事件的反应。但在此之前,你需要在单元测试中设置一些字段来显示碰撞检测代码是否正常工作。或只在“if”代码块中设置断点,看看是否已进入条件。

    现在,所有要做的就是播放碰撞音效并根据车的哪个角碰撞选择车辆。汽车将减速,相机摇晃告知玩家他刚刚碰撞了。如果直行时碰撞(0~45度对墙),车将完全停住并播放完全碰撞的音效:

    // Force car back on the road, for that calculate impulse and
    // collision direction (same stuff as in Rocket Commander).
    Vector3 collisionDir =
      Vector3.Reflect(carDir, guardrailRightNormal);
    
    float collisionAngle =
      Vector3Helper.GetAngleBetweenVectors(
        carLeft, guardrailRightNormal);
    
    // Flip at 180 degrees (if driving in wrong direction)
    if (collisionAngle > MathHelper.Pi / 2)
      collisionAngle -= MathHelper.Pi;
    
    // Just correct rotation if collison happened at 0-45 degrees (slowly)
    if (Math.Abs(collisionAngle) < MathHelper.Pi / 4.0f)
    {
      // Play crash sound
      Sound.PlayCrashSound(false);
    
      // For front wheels to full collision rotation, for back half!
      if (num < 2)
      {
        rotateCarAfterCollision = +collisionAngle / 1.5f;
        speed *= 0.935f;//0.85f;
        if (viewDistance > 0.75f)
          viewDistance -= 0.1f;//0.15f;
      } // if (num)
      else
      {
        rotateCarAfterCollision = +collisionAngle / 2.5f;
        //slowdownCarAfterCollision = 0.8f;
        speed *= 0.96f;//0.9f;
        if (viewDistance > 0.75f)
          viewDistance -= 0.05f;//0.1f;
      } // else
      // Shake camera
      ChaseCamera.SetCameraWobbel(0.00075f * speed);
    } // if (collisionAngle)
    
    // If 90-45 degrees (in either direction), make frontal crash
    // + stop car + wobble camera
    else if (Math.Abs(collisionAngle) < MathHelper.Pi * 3.0f / 4.0f)
    {
      // Also rotate car if less than 60 degrees
      if (Math.Abs(collisionAngle) < MathHelper.Pi / 3.0f)
        rotateCarAfterCollision = +collisionAngle / 3.0f;
      // Play crash sound
      Sound.PlayCrashSound(true);
    
      // Shake camera
      ChaseCamera.SetCameraWobbel(0.005f * speed);
    
      // Just stop car!
      speed = 0;
    } // if (collisionAngle)
    
    // For all collisions, kill the current car force
    carForce = Vector3.Zero;
    
    // Always make sure we are OUTSIDE of the collision range for
    // the next frame. But first find out how much we have to move.
    float speedDistanceToGuardrails =
      speed * Math.Abs(Vector3.Dot(carDir, guardrailLeftNormal));
    
    if (rightDist > 0)
    {
      float correctCarPosValue = (rightDist + 0.01f +//0.11f +
        0.1f * speedDistanceToGuardrails * moveFactor);
      carPos += correctCarPosValue * guardrailRightNormal;
    } // if (rightDist)

    有了这些代码,现在你可以进行TestCarPhysicsOnPlaneWithGuardRails单元测试并调整与护栏的碰撞。该代码有点复杂,但规则相同,所有的碰撞代码和物理计算与单元测试中使用的的完全一样。

  • 相关阅读:
    1017 A除以B (20分)**
    剑指 Offer 11. 旋转数组的最小数字(简单)
    剑指 Offer 04. 二维数组中的查找(中等)
    剑指 Offer 53
    剑指 Offer 53
    剑指 Offer 03. 数组中重复的数字(简单)
    剑指 Offer 58
    剑指 Offer 05. 替换空格(简单)
    执行npm install命令出错问题
    剑指 Offer 35. 复杂链表的复制(中等)
  • 原文地址:https://www.cnblogs.com/AlexCheng/p/2120190.html
Copyright © 2011-2022 走看看