Unity3d 赛车车辆各类性能算法---总结(转)

致力于赛车性能算法已有多时,在确定赛车最终版本之时,做下总结。
文章还是不会非常详尽,点到为指,不想太多利用工作时间。

在制作前,必须先了解真实车辆的原理:
车辆分前轮驱动,后轮驱动和四驱动。动力由引擎提供,反应的力到轮胎上,因此产生转数,即RPM。
引擎的功率可以由RPM得到公式为 : RPM = 引擎功率×60/2×pi , 这些都是模拟,只为了更好的为下面的动作服务。还有大众关心的“漂移” ,所谓 漂移就是,在后驱车辆中,前轮方向旋转大角度,地面给于一定向心力,同时后轮又给予更多动力,导致“漂移”动作。

基于上面原理,就更容易理解下面的文章。 

我先说明,有非常多种方法来开发一款赛车。本人赛车版本经过无数多种方法,无数次改版后最终选了个大众接受的。这些方法,容我一个个道来。

首先,你要明白,车辆不可能整个套一个外壳,原因是在接触地面时,对车辆所使的力不可能达到你预期的目标,引起,必须在车辆轮胎以上做外壳碰撞,轮胎以下就需要有力来支持它始终保持不掉下来。

Unity3d里有个很神奇的东西 叫WheelCollider , 它是专门模拟轮胎支持力和轮胎转数,以及轮胎横向力,前进力,以及 悬架避震系统。
这个东西非常方便,只要你把这个东西套在4个轮胎上,调试下他的
forwardFriction 和 sidewaysFriction
达到你想要的效果,然后对驱动轮的
motorTorque进行赋值,你的车辆就能动了。
记得你需要无数次调试 前进摩擦力和横向摩擦力 。 至于悬架系统在你需要时也可以改变其值。还有,这两个摩擦力,是一个由低到高,再由高到稳定的一条曲线。

这个WheelCollider非常好用,曾一度沉迷于此。但后来发现,他有很多不合理的地方。想要得到最好的效果,还是抛弃了他。

为了支持车辆的碰撞外壳不接触地面,必须写一个悬架动态支持力,在4个轮胎位置,支持整辆车悬浮于地面之上。
关于这个悬架动态支持力在这奉献下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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到最高点,然后下降到平衡点的曲线。这样你的赛车才显得更真实。这些都需要用到几个数学知识。
后者,是用算法来模拟的一种车辆轨迹。这个算法所有作用力作用在车辆的中心点。
转弯轨迹,我是用转弯半径来表示,使得车辆在转弯时有相当的真实性,必须改变车辆转弯速度。当然,用到了些数学知识。代码奉献下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#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,如此而已。

最后,再介绍下,所有车辆都需要模拟的,行驶时,轮胎随速度旋转这个关系到车辆看起来真实性的东西。其实非常简单。不多说,发代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#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

 

 

转载:http://www.cnblogs.com/lm3515/archive/2010/09/21/1832324.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
网络视频资源,如有侵权请留言/举报,资源过大上传乃是下载链接!!!------ 『课程介绍』:1 S/ V q2 z {+ ~( j 相信男生们都喜欢玩爽快的赛车类游戏,那么你是否想要自己开发这样的一款游戏呢?在这里你将使用unity的开发技术,自己创建一个开发的,竞争性的赛车世界。同时可以让用户对汽车进行换装。- P8 z# u5 t' z1 @' w# c - F1 c. D: y3 c: o 『课程目录』: 任务1: 游戏演示 04:01 任务2: 创建工程,添加环境,添加车. n& c' W: j) [0 N 06:07 任务3: 给车添加碰撞器1 k: n' t- s0 ?7 _- |: }' e! O 03:17 任务4: 车的阴影设置* J, e. b0 _1 P( A7 C' x 03:29 任务5: 给车添加投影/ a5 \& I9 i& ~% d- R4 O 07:47 任务6: 关于WheelCollider车轮碰撞器% ^2 O% b' E" ?; U) K7 L1 O 06:10 任务7: 给车子添加车轮 05:29 任务8: 控制车子的前后行进 任务9: 控制车子的左右向 04:51 # C6 v5 _/ O1 V& q5 c 任务10: 控制摄像机的跟随移动2 J( j: W' N3 D( y) B 06:51 任务11: 控制摄像机的平滑跟随5 d( P' H# L' |9 F: R7 F+ p 09:31 任务12: 解决车子侧翻的问题7 l" J8 q3 T: u! V 06:01 3 {1 V6 c8 K% c6 B/ ?" O+ C 任务13: 显示车子的速度( c2 L4 C& @" T, I+ f- J$ E 13:24 任务14: 使用仪表盘显示速度# J/ n; ~/ R7 | 12:18 8 v+ V8 u4 x0 J, O8 M+ ? 任务15: 控制轮子的动- M* [) D$ D; I* z" ~1 A 08:22 任务16: 控制轮子的向 06:08 任务17: 控制车的最大速度和最小速度; u+ p" j$ z" A; h ? 08:42 任务18: 给车添加刹车的功能3 M* x1 q6 ^2 r' \ 05:26 任务19: 给游戏添加背景声音 03:21 3 m0 A* G' S+ Z 任务20: 给车子添加引擎声音$ F4 O8 y# Z7 ~: M9 u 07:02 + W$ S* Z" i/ h$ Q 任务21: 添加引擎加速效果的声音7 p' T8 }) r- |, M 07:34 任务22: 控制车子的漂移 05:48 任务23: 添加漂移的声音! j" b* {, k) T, F: } 02:42 + {5 J, }5 K* }* j5 `; i6 O | 任务24: 添加漂移的条件,判断轮子是否着地 07:02 任务25: 添加倒车的警示灯 04:41 任务26: 添加赛车到达终点的判定 11:57 ' D3 e) h1 i2 J4 ?/ E 任务27: 添加倒计时效果! x, y6 I( y! ?9 j- @; E$ ?! I 07:27 ! J0 F9 H; F% | 任务28: 开发计时期间的引擎发动效果5 \; v) f" w' F6 _! a+ g) ?2 B# o! i. M 10:16 任务29: 设计游戏开始的界面 07:02 1 r0 w- P; i# ^; l, c& E& I: a. H 任务30: 处理游戏用户名的存储和按钮的事件( O0 d7 p" _2 l, l4 l 06:06 5 {& N: C3 E* r; i5 n 任务31: 开发赛车选择界面, m; s q4 O# i1 {' v; p 10:44 任务32: 开发赛车的总用时计时 08:18 1 }$ x0 C% ^! i4 V7 k 任务33: 游戏数据的存储,把最快的时间存储起来 07:12 7 O) P8 \: C4 y9 r. D 任务34: 控制轮子位置随着悬挂系统的弹簧的伸缩而伸缩, d# `8 b5 x" j9 J 12:49 任务35: 添加车子的划痕! L$ A. Y" b1 j- b1 U3 R 19:31 任务36: 处理车子和墙体之间的碰撞! [5 I% d/ Z! M# ~: L8 g 04:21 . b) N! L% a% O! x 任务37: 实现第一人称视野的控制' n( R0 Y& h2 I4 C# _$ d 05:01 任务38: 学习Terraintoolkit地形编辑插件 10:23 ' w% J* U" f% y5 d3 b" l0 h8 r 任务39: 对代码进行结构优化 12:56 任务40: 修改赛车的控制方式,添加重力感应控制' {* c+ l( x" G, _( n4 N$ W 08:57 : H2 B! Y( w7 L- @. [" W: g \3 y; V) K 任务41: 控制不同平台下车辆控制的启用, L9 n9 l3 T7 B J% C 03:54 任务42: 控制某些脚本得到物体的方式) c( U, m0 ?. Q; A 05:29 任务43: 控制场景的在安卓平台导入设置 05:24 任务44: 设计安卓平台的游戏环境,发布游戏到安卓平台2 ?, K% k; b1 @ 04:56 任务45: 项目结束分析,游戏项目结束

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值