【转】Unity3d 赛车车辆各类性能算法

致力于赛车性能算法已有多时,在确定赛车最终版本之时,做下总结。
文章还是不会非常详尽,点到为指,不想太多利用工作时间。
在制作前,必须先了解真实车辆的原理:
车辆分前轮驱动,后轮驱动和四驱动。动力由引擎提供,反应的力到轮胎上,因此产生转数,即RPM。
引擎的功率可以由RPM得到公式为 : RPM = 引擎功率×60/2×pi , 这些都是模拟,只为了更好的为下面的动作服务。还有大众关心的“漂移” ,所谓 漂移就是,在后驱车辆中,前轮方向旋转大角度,地面给于一定向心力,同时后轮又给予更多动力,导致“漂移”动作。
基于上面原理,就更容易理解下面的文章。 
我先说明,有非常多种方法来开发一款赛车。本人赛车版本经过无数多种方法,无数次改版后最终选了个大众接受的。这些方法,容我一个个道来。
首先,你要明白,车辆不可能整个套一个外壳,原因是在接触地面时,对车辆所使的力不可能达到你预期的目标,引起,必须在车辆轮胎以上做外壳碰撞,轮胎以下就需要有力来支持它始终保持不掉下来。
Unity3d里有个很神奇的东西 叫WheelCollider , 它是专门模拟轮胎支持力和轮胎转数,以及轮胎横向力,前进力,以及 悬架避震系统。
这个东西非常方便,只要你把这个东西套在4个轮胎上,调试下他的forwardFriction 和 sidewaysFriction
达到你想要的效果,然后对驱动轮的motorTorque进行赋值,你的车辆就能动了。
记得你需要无数次调试 前进摩擦力和横向摩擦力 。 至于悬架系统在你需要时也可以改变其值。还有,这两个摩擦力,是一个由低到高,再由高到稳定的一条曲线。
这个WheelCollider非常好用,曾一度沉迷于此。但后来发现,他有很多不合理的地方。想要得到最好的效果,还是抛弃了他。
为了支持车辆的碰撞外壳不接触地面,必须写一个悬架动态支持力,在4个轮胎位置,支持整辆车悬浮于地面之上。
关于这个悬架动态支持力在这奉献下:
void SuspensionHoldForce()
{
     float fullCompressionSpringForce = this.rigidbody.mass * 0.25f * 2.0f * -Physics.gravity.y;
     this.OnGround = true;
 
     foreach( GameObject item in FwheelModels )
    {
         RaycastHit hit;
         bool onGround = Physics.Raycast( item.transform.parent.position , -item.transform.parent.InverseTransformDirection(Vector3.up), out hit, this.suspensionTravel + this.radius);
 
         if (onGround && hit.collider.isTrigger)
        {
            onGround = false;
            float dist = this.suspensionTravel + this.radius;
            RaycastHit[] hits = Physics.RaycastAll( item.transform.parent.position , -item.transform.parent.InverseTransformDirection(Vector3.up) , this.suspensionTravel + this.radius );
            foreach(RaycastHit test in hits)
           {
                if (!test.collider.isTrigger && test.distance <= dist)
               {
                     hit = test;
                     onGround = true;
                     dist = test.distance;
               }
           }
        }
 
        if( onGround )
        {
             Vector3 wheelVelo = this.rigidbody.GetPointVelocity (item.transform.parent.position);
             Vector3 localVelo = transform.InverseTransformDirection (wheelVelo);
             Vector3 groundNormal = transform.InverseTransformDirection (hit.normal);
             float damperForce = Vector3.Dot(localVelo, groundNormal) * 5000f;
             float compression = 1.0f - ((hit.distance - radius) / suspensionTravel);
             Vector3 springForce = ( fullCompressionSpringForce*compression - damperForce ) * item.transform.parent.InverseTransformDirection(Vector3.up);
 
             springForce.z = springForce.x = 0f;
 
             this.rigidbody.AddForceAtPosition( springForce , item.transform.parent.position );
 
         }
         else
        {
            this.OnGround = false;
        }
    }
 
    foreach( GameObject item in BwheelModels )
    {
         RaycastHit hit;
         bool onGround = Physics.Raycast(  item.transform.parent.position, -item.transform.parent.InverseTransformDirection(Vector3.up), out hit, this.suspensionTravel + this.radius);
 
         if (onGround && hit.collider.isTrigger)
         {
               onGround = false;
               float dist = this.suspensionTravel + this.radius;
               RaycastHit[] hits = Physics.RaycastAll( item.transform.parent.position, -item.transform.parent.InverseTransformDirection(Vector3.up) , this.suspensionTravel + this.radius );
               foreach(RaycastHit test in hits)
               {
                     if (!test.collider.isTrigger && test.distance <= dist)
                     {
                           hit = test;
                           onGround = true;
                           dist = test.distance;
                      }
                }
           }
 
           if( onGround )
          {
                Vector3 wheelVelo = this.rigidbody.GetPointVelocity (item.transform.parent.position);
                Vector3 localVelo = transform.InverseTransformDirection (wheelVelo);
                Vector3 groundNormal = transform.InverseTransformDirection (hit.normal);
                float damperForce = Vector3.Dot(localVelo, groundNormal) * 5000f;
                float compression = 1.0f - ( ( hit.distance - radius ) / suspensionTravel );
                Vector3 springForce = ( fullCompressionSpringForce*compression - damperForce ) * item.transform.parent.InverseTransformDirection(Vector3.up);
                springForce.z = springForce.x = 0f;
                this.rigidbody.AddForceAtPosition( springForce , item.transform.parent.position );
          }
          else
         {
               this.OnGround = false;
          }
     }
}
那么在完成悬架支撑后,就该设计车辆动力了。
这里也有2种方法:一个方向是真实车辆行驶轨迹,另一个是模拟型车辆轨迹。
前者的方法是 , 将动力点放在车辆驱动轮上,例如后轮。用rigidbody的AddForceAtPosition可以做到,前轮只需要提供横向力就可以实现转弯的轨迹。但别看说说这么容易,这里面还涉及非常多的数值和曲线问题。在提供车辆动力时,你需要一条曲线,以致车辆不会匀加速,因为这样很不真实,还有在前轮横向力中,你必需是条由0到最高点,然后下降到平衡点的曲线。这样你的赛车才显得更真实。这些都需要用到几个数学知识。
后者,是用算法来模拟的一种车辆轨迹。这个算法所有作用力作用在车辆的中心点。
转弯轨迹,我是用转弯半径来表示,使得车辆在转弯时有相当的真实性,必须改变车辆转弯速度。当然,用到了些数学知识。代码奉献下:
#region 计算转弯角度
void Steering( bool canSteer , Vector3 relativeVelocity )
{
     if( canSteer && this.OnGround )
    {
          if( this.shiftthrottle == 1 )
         {
              this.transform.RotateAround( this.transform.TransformPoint( ( this.FwheelModels[0].transform.localPosition + this.FwheelModels[1].transform.localPosition) * 0.5f ) , this.transform.up , this.rigidbody.velocity.magnitude *2f* this.steeringInput * Time.deltaTime * 2f );
              //~ this.rigidbody.AddForceAtPosition( this.FwheelModels[0].transform.TransformDirection(Vector3.right*this.steeringInput) * 3f * this.rigidbody.mass, this.FwheelModels[0].transform.position);
             //~ this.rigidbody.AddForceAtPosition( this.FwheelModels[1].transform.TransformDirection(Vector3.right*this.steeringInput) * 3f * this.rigidbody.mass, this.FwheelModels[1].transform.position);
             return ;
         }
 
        if( this.throttle * this.transform.InverseTransformDirection(this.rigidbody.velocity).z < 0 )
             return ;
 
       float turnRadius = 3.0f / Mathf.Sin( (90f - this.steering) * Mathf.Deg2Rad );
       float minMaxTurn = EvaluateSpeedToTurn(this.rigidbody.velocity.magnitude);
       float turnSpeed = Mathf.Clamp(relativeVelocity.z / turnRadius, -minMaxTurn / 10, minMaxTurn / 10);
       this.transform.RotateAround( this.transform.position + this.transform.right * turnRadius * this.steeringInput , transform.up , turnSpeed * Mathf.Rad2Deg * Time.deltaTime * this.steeringInput );
 
       //~ Vector3 debugStartPoint = transform.position + transform.right * turnRadius * this.steeringInput;
       //~ Vector3 debugEndPoint = debugStartPoint + Vector3.up * 5f;
 
       //~ Debug.DrawLine(debugStartPoint, debugEndPoint, Color.red);
    }
}
 
float EvaluateSpeedToTurn( float speed )
{
     if(speed > this.topSpeed / 2)
         return minimumTurn;
     float speedIndex = 1 - ( speed / ( this.topSpeed / 2 ) );
     return minimumTurn + speedIndex * (maximumTurn - minimumTurn);
}
#endregion
这个模拟车辆轨迹,不能达到漂移的性能,但我加了一个滑动比例计算的算法,用车辆横向移动速度,和前进速度,的比例来确定,该车辆是否处于漂移状态,如处于,则启动漂移滑动程序。当然,我的赛车是很自然的,不做做。至于轮胎痕迹,就是判断是否触底后,在该点生成轮胎痕迹gameobject,如此而已。
最后,再介绍下,所有车辆都需要模拟的,行驶时,轮胎随速度旋转这个关系到车辆看起来真实性的东西。其实非常简单。不多说,发代码:
#region 轮胎滚动与旋转模拟
void WheelRoll()
{
      float averageAngularVelo = ( this.rigidbody.GetPointVelocity(this.BwheelModels[0].transform.parent.position).magnitude + this.rigidbody.GetPointVelocity(this.BwheelModels[0].transform.parent.position).magnitude )/2f;
      float engineAngularVelo = averageAngularVelo * 3f;
 
      float rpm = engineAngularVelo * (60.0f/(2*Mathf.PI)) * (this.transform.InverseTransformDirection(this.rigidbody.velocity).z > 0f ? 1f : -1f );
 
      //~ Debug.Log(this.transform.InverseTransformDirection(this.rigidbody.velocity).z);
 
      FwheelModels[0].transform.rotation = FwheelModels[0].transform.parent.rotation *     Quaternion.Euler (RotationValue, this.steering , 0);//旋转
      FwheelModels[1].transform.rotation = FwheelModels[1].transform.parent.rotation * Quaternion.Euler (RotationValue, this.steering , 0);//旋转
 
      BwheelModels[0].transform.rotation = BwheelModels[0].transform.parent.rotation * Quaternion.Euler (RotationValue, 0, 0);//旋转
      BwheelModels[1].transform.rotation = BwheelModels[1].transform.parent.rotation * Quaternion.Euler (RotationValue, 0, 0);//旋转
 
      RotationValue += rpm * ( 360f/60f ) * Time.deltaTime;
}
#endregion
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity3D赛车游戏可以通过使用Unity引擎的功能和脚本来创建。你可以使用Unity的物理引擎来模拟赛车的运动和碰撞,使用Unity的渲染功能来创建逼真的赛车场景和特效。 在游戏中,你可以创建赛车模型,并将其添加到场景中。你可以使用脚本来控制赛车的移动和操纵,例如使用键盘或触摸控制赛车的方向和速度。 你还可以创建赛车道路和赛道障碍物,使用Unity的碰撞检测功能来检测赛车与障碍物的碰撞,并实现相应的物理效果。 此外,你可以使用Unity的粒子系统来创建火花、烟雾和爆炸效果,以增加游戏的视觉效果。 综上所述,通过使用Unity引擎的功能和脚本,你可以创建一个逼真的赛车游戏,包括赛车模型、赛道、碰撞检测、物理效果和特效。希望这些信息能对你有所帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [使用Unity3D 自主实战开发的赛车游戏实例,关键点记录 (一)之赛车游戏总体介绍](https://blog.csdn.net/narutojzm1/article/details/51308894)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Unity3D赛车游戏+脚本基础](https://blog.csdn.net/m0_58367586/article/details/127901530)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值