首页|行业资讯|企业名录|周边产品|数字城市|增强现实|工业仿真|解决方案|虚拟医疗|行业仿真|图形处理|军事战场
资讯首页
行业资讯 >> VR百科>>正文
unity3d的动力学汽车脚本
2010年1月22日    评论:    分享:

    这是从官网论坛上收集的一个汽车脚本,经过验证可以使用。由于skidmarks这个配套的脚本没有找到,所以把skidmarks相关的语句都屏蔽了,所以很遗憾没有刹车印的效果,其他的没有改。

    拿出来共享,感兴趣的一起研究下。

    汽车脚本代码看起来都比较复杂,主要是老外的编程底子牛,什么都写到代码里自动生成了。其实有些东西可以在编辑器里完成,这样就省不少代码了。还有制动和变速箱部分用了不少代码,这个可能要点汽车发动机知识,反正我是一点都没看懂。

    不想研究的可以直接拿来用。

    使用方法如下:

    1、把脚本直接连到汽车车身网格上,车身要有Rigidbody Component,要有四个轮子网格做子物体。 要想有声音的话还要有AudioSource Component。

    2、打开Inspector,选择汽车脚本,把四个轮子连接到相对应的Transform参数上。设置wheelRadius参数为你轮子网格的大小。WheelCollider是自动生成的,所以无需手动添加。这样就能保证运行了,其他的声音和灰尘可以再添加。

    脚本源代码如下:

#pragma strict

//maximal corner and braking acceleration capabilities
var maxCornerAccel=10.0;
var maxBrakeAccel=10.0;

//center of gravity height - effects tilting in corners
var cogY = 0.0;

//engine powerband
var minRPM = 700;
var maxRPM = 6000;

//maximum Engine Torque
var maxTorque = 400;

//automatic transmission shift points
var shiftDownRPM = 2500;
var shiftUpRPM = 5500;

//gear ratios
var gearRatios = [-2.66, 2.66, 1.78, 1.30, 1.00];
var finalDriveRatio = 3.4;

//a basic handling modifier:
//1.0 understeer
//0.0 oversteer
var handlingTendency = 0.7;

//graphical wheel objects
var wheelFR : Transform;
var wheelFL : Transform;
var wheelBR : Transform;
var wheelBL : Transform;

//suspension setup
var suspensionDistance = 0.3;
var springs = 1000;
var dampers = 200;
var wheelRadius = 0.45;

//particle effect for ground dust
var groundDustEffect : Transform;

private var queryUserInput = true;
private var engineRPM : float;
private var steerVelo = 0.0;
private var brake = 0.0;
private var handbrake = 0.0;
private var steer = 0.0;
private var motor = 0.0;
//private var skidTime = 0.0;
private var onGround = false;
private var cornerSlip = 0.0;
private var driveSlip = 0.0;
private var wheelRPM : float;
private var gear = 1;
//private var skidmarks : Skidmarks;
private var wheels : WheelData[];
private var wheelY = 0.0;
private var rev = 0.0;

//Functions to be used by external scripts
//controlling the car if required
//===================================================================

//return a status string for the vehicle
function GetStatus(gui : GUIText) {
   gui.text="v="+(rigidbody.velocity.magnitude * 3.6).ToString("f1") + " km/h\ngear= "+gear+"\nrpm= "+engineRPM.ToString("f0");
}

//return an information string for the vehicle
function GetControlString(gui : GUIText) {
   gui.text="Use arrow keys to control the jeep,\nspace for handbrake.";
}

//Enable or disable user controls
function SetEnableUserInput(enableInput)
{
   queryUserInput=enableInput;
}

//Car physics
//===================================================================

//some whee calculation data
class WheelData{
   var rotation = 0.0;
   var coll : WheelCollider;
   var graphic : Transform;
   var maxSteerAngle = 0.0;
   var lastSkidMark = -1;
   var powered = false;
   var handbraked = false;
   var originalRotation : Quaternion;
};

function Start () {
   //setup wheels
   wheels=new WheelData[4];
   for(i=0;i<4;i++)
      wheels[i] = new WheelData();
      
   wheels[0].graphic = wheelFL;
   wheels[1].graphic = wheelFR;
   wheels[2].graphic = wheelBL;
   wheels[3].graphic = wheelBR;

   wheels[0].maxSteerAngle=30.0;
   wheels[1].maxSteerAngle=30.0;
   wheels[2].powered=true;
   wheels[3].powered=true;
   wheels[2].handbraked=true;
   wheels[3].handbraked=true;

   for(w in wheels)
   {
      if(w.graphic==null)
         Debug.Log("You need to assign all four wheels for the car script!");
      if(!w.graphic.transform.IsChildOf(transform))   
         Debug.Log("Wheels need to be children of the Object with the car script");
         
      w.originalRotation = w.graphic.localRotation;

      //create collider
      colliderObject = new GameObject("WheelCollider");
      colliderObject.transform.parent = transform;
      colliderObject.transform.position = w.graphic.position;
      w.coll = colliderObject.AddComponent(WheelCollider);
      w.coll.suspensionDistance = suspensionDistance;
      w.coll.suspensionSpring.spring = springs;
      w.coll.suspensionSpring.damper = dampers;
      //no grip, as we simulate handling ourselves
      w.coll.forwardFriction.stiffness = 0;
      w.coll.sidewaysFriction.stiffness = 0;
      w.coll.radius = wheelRadius;
   }  

   //get wheel height (height forces are applied on)
   wheelY=wheels[0].graphic.localPosition.y;
   
   //setup center of gravity
   rigidbody.centerOfMass.y = cogY;
   
   //find skidmark object
//   skidmarks = FindObjectOfType(typeof(Skidmarks));
   
   //shift to first
   gear=1;
}

//update wheel status
function UpdateWheels()
{
   //calculate handbrake slip for traction gfx
    handbrakeSlip=handbrake*rigidbody.velocity.magnitude*0.1;
   if(handbrakeSlip>1)
      handbrakeSlip=1;
      
   totalSlip=0.0;
   onGround=false;
   for(w in wheels)
   {      
      //rotate wheel
      w.rotation += wheelRPM / 60.0 * -rev * 360.0 * Time.fixedDeltaTime;
      w.rotation = Mathf.Repeat(w.rotation, 360.0);      
      w.graphic.localRotation= Quaternion.Euler( w.rotation, w.maxSteerAngle*steer, 0.0 ) * w.originalRotation;

      //check if wheel is on ground
      if(w.coll.isGrounded)
         onGround=true;
         
      slip = cornerSlip+(w.powered?driveSlip:0.0)+(w.handbraked?handbrakeSlip:0.0);
      totalSlip += slip;
      
      var hit : WheelHit;
      var c : WheelCollider;
      c = w.coll;
      if(c.GetGroundHit(hit))
      {
         //if the wheel touches the ground, adjust graphical wheel position to reflect springs
         w.graphic.localPosition.y-=Vector3.Dot(w.graphic.position-hit.point,transform.up)-w.coll.radius;
         
         //create dust on ground if appropiate
         if(slip>0.5 && hit.collider.tag=="Dusty")
         {
            groundDustEffect.position=hit.point;
            groundDustEffect.particleEmitter.worldVelocity=rigidbody.velocity*0.5;
            groundDustEffect.particleEmitter.minEmission=(slip-0.5)*3;
            groundDustEffect.particleEmitter.maxEmission=(slip-0.5)*3;
            groundDustEffect.particleEmitter.Emit();                        
         }
         
         //and skid marks            
         /*if(slip>0.75 && skidmarks != null)
            w.lastSkidMark=skidmarks.AddSkidMark(hit.point,hit.normal,(slip-0.75)*2,w.lastSkidMark);
         else
            w.lastSkidMark=-1; */
      }
     // else w.lastSkidMark=-1;
   }
   totalSlip/=wheels.length;
}

//Automatically shift gears
function AutomaticTransmission()
{
   if(gear>0)
   {
      if(engineRPM>shiftUpRPM&&gear<gearRatios.length-1)
         gear++;
      if(engineRPM<shiftDownRPM&&gear>1)
         gear--;
   }

}

//Calculate engine acceleration force for current RPM and trottle
function CalcEngine() : float
{
   //no engine when braking
   if(brake+handbrake>0.1)
      motor=0.0;
   
   //if car is airborne, just rev engine
   if(!onGround)
   {
      engineRPM += (motor-0.3)*25000.0*Time.deltaTime;
      engineRPM = Mathf.Clamp(engineRPM,minRPM,maxRPM);
      return 0.0;
   }
   else
   {
      AutomaticTransmission();
      engineRPM=wheelRPM*gearRatios[gear]*finalDriveRatio;
      if(engineRPM<minRPM)
         engineRPM=minRPM;
      if(engineRPM<maxRPM)
      {
         //fake a basic torque curve
         x = (2*(engineRPM/maxRPM)-1);
         torqueCurve = 0.5*(-x*x+2);
         torqueToForceRatio = gearRatios[gear]*finalDriveRatio/wheelRadius;
         return motor*maxTorque*torqueCurve*torqueToForceRatio;
      }
      else
         //rpm delimiter
         return 0.0;
   }
}

//Car physics
//The physics of this car are really a trial-and-error based extension of
//basic "Asteriods" physics -- so you will get a pretty arcade-like feel.
//This may or may not be what you want, for a more physical approach research
//the wheel colliders
function HandlePhysics () {
   var velo=rigidbody.velocity;
   wheelRPM=velo.magnitude*60.0*0.5;

   rigidbody.angularVelocity=new Vector3(rigidbody.angularVelocity.x,0.0,rigidbody.angularVelocity.z);
   dir=transform.TransformDirection(Vector3.forward);
   flatDir=Vector3.Normalize(new Vector3(dir.x,0,dir.z));
   flatVelo=new Vector3(velo.x,0,velo.z);
   rev=Mathf.Sign(Vector3.Dot(flatVelo,flatDir));
   //when moving backwards or standing and brake is pressed, switch to reverse
   if((rev<0||flatVelo.sqrMagnitude<0.5)&&brake>0.1)
      gear=0;
   if(gear==0)
   {   
      //when in reverse, flip brake and gas
      tmp=brake;
      brake=motor;
      motor=tmp;
      
      //when moving forward or standing and gas is pressed, switch to drive
      if((rev>0||flatVelo.sqrMagnitude<0.5)&&brake>0.1)
         gear=1;
   }
   engineForce=flatDir*CalcEngine();
   totalbrake=brake+handbrake*0.5;
   if(totalbrake>1.0)totalbrake=1.0;
   brakeForce=-flatVelo.normalized*totalbrake*rigidbody.mass*maxBrakeAccel;

   flatDir*=flatVelo.magnitude;
   flatDir=Quaternion.AngleAxis(steer*30.0,Vector3.up)*flatDir;
   flatDir*=rev;
   diff=(flatVelo-flatDir).magnitude;
   cornerAccel=maxCornerAccel;
   if(cornerAccel>diff)cornerAccel=diff;
   cornerForce=-(flatVelo-flatDir).normalized*cornerAccel*rigidbody.mass;
   cornerSlip=Mathf.Pow(cornerAccel/maxCornerAccel,3);
   
   rigidbody.AddForceAtPosition(brakeForce+engineForce+cornerForce,transform.position+transform.up*wheelY);
   
   handbrakeFactor=1+handbrake*4;
   if(rev<0)
      handbrakeFactor=1;
   veloSteer=((15/(2*velo.magnitude+1))+1)*handbrakeFactor;
   steerGrip=(1-handlingTendency*cornerSlip);
   if(rev*steer*steerVelo<0)
      steerGrip=1;
   maxRotSteer=2*Time.fixedDeltaTime*handbrakeFactor*steerGrip;
   fVelo=velo.magnitude;
   veloFactor=fVelo<1.0?fVelo:Mathf.Pow(velo.magnitude,0.3);
   steerVeloInput=rev*steer*veloFactor*0.5*Time.fixedDeltaTime*handbrakeFactor;
   if(velo.magnitude<0.1)
      steerVeloInput=0;
   if(steerVeloInput>steerVelo)
   {
      steerVelo+=0.02*Time.fixedDeltaTime*veloSteer;
      if(steerVeloInput<steerVelo)
         steerVelo=steerVeloInput;
   }
   else
   {
      steerVelo-=0.02*Time.fixedDeltaTime*veloSteer;
      if(steerVeloInput>steerVelo)
         steerVelo=steerVeloInput;
   }
   steerVelo=Mathf.Clamp(steerVelo,-maxRotSteer,maxRotSteer);   
   transform.Rotate(Vector3.up*steerVelo*57.295788);
}

function FixedUpdate () {
   //query input axes if necessarry
   if(queryUserInput)
   {
      brake = Mathf.Clamp01(-Input.GetAxis("Vertical"));
      handbrake = Input.GetButton("Jump")?1.0:0.0;
      steer = Input.GetAxis("Horizontal");
       motor = Mathf.Clamp01(Input.GetAxis("Vertical"));
    }
   else
   {
      motor = 0;
      steer = 0;
      brake = 0;
      handbrake = 0;
   }


   //if car is on ground calculate handling, otherwise just rev the engine
    if(onGround)
      HandlePhysics();
   else
      CalcEngine();   
      
   //wheel GFX
   UpdateWheels();

   //engine sounds
   audio.pitch=0.5+0.2*motor+0.8*engineRPM/maxRPM;
   audio.volume=0.5+0.8*motor+0.2*engineRPM/maxRPM;
}

//Called by DamageReceiver if boat destroyed
function Detonate()
{
   //destroy wheels
   for( w in wheels )
      w.coll.gameObject.active=false;

   //no more car physics
   enabled=false;
}

@script RequireComponent (Rigidbody)
@script RequireComponent (AudioSource)

标签:unity3d动力学脚本
上一篇:立体摄像相关知识问答(FAQ)
下一篇:东方道迩机载LiDAR采集处理及应用技术
网友评论:unity3d的动力学汽车脚本
评论
留名: 验证码:
您可能还需要关注一下内容:
·柴油机曲柄连杆机构动力学仿真与瞬时转速分析
·基于 ADAMS 飞行动力学仿真
·基于Unity3D平台的三维虚拟城市研究与应用
·飞机弹射起飞起落架动力学仿真分析
·Unity3d 爆炸火焰特效教程
·Unity3d 基础特效教程-下雨
·基于Unity3D实现大件运输过程动态模拟
·基于Unity3D的虚拟水流墙系统的设计研究
·Unity3D实现3D立体游戏原理及过程
·在Unity3D中实现简单的碰撞检测
☏ 推荐产品

Ladybug5全景
商家:力方国际

ProJet®
商家:力方国际

ProJet®
商家:视科创新

Premium1.5
商家:视科创新

巴可HDX主动立体投
商家:德浩科视

巴可HDF-W26投
商家:德浩科视

巴可30000流明2
商家:德浩科视

巴可4万流明2K投影
商家:德浩科视
☞ 外设导航
☏ 企业名录
【广州】中科院广州电子技术有限公司
【北京】第二空间(北京)科技有限公司
【北京】幻维世界(北京)网络科技有限公司
【厦门】厦门惠拓动漫科技有限公司
【厦门】厦门幻眼信息科技有限公司
【深圳】深圳南方百捷文化传播有限公司
【北京】北京思源科安信息技术有限公司
【上海】上海殊未信息科技有限公司
【北京】北京赢康科技开发有限公司
【武汉】武汉科码软件有限公司
友情链接 关于本站 咨询策划 行业推广 广告服务 免责声明 网站建设 联系我们 融资计划
北京第三维度科技有限公司 版权所有 京ICP备09001338
2008-2016 Beijing The third dimension Inc. All Rights Reserved.
Tel:010-57255801 Mob:13371637112(24小时)
Email:d3dweb@163.com  QQ:496466882
扫一扫 第三维度
官方微信号