Unity3d 虚拟摇杆实现 模拟摩托车行驶小Demo 

2016-12-09 16:31 发布

引擎学习交流 /[教程&源码]
今天,为大家分享一下,如何做到一个虚拟摇杆实现物体的移动和特定的操作。下面是简单通过虚拟摇杆可以实现摩托车的行驶。【PS:因为项目代码比较多,也许文章讲得不够全面清楚,希望大家能多多包涵。如果大家想要源码或者资源的话,可以直接加QQ群:575561285】
  好吧!废话不多讲,直接进入主题吧!

1.新建unity3d 项目,然后自己可以合理搭一个场景,导入需要的资源,例如,我这边会导入一些摩托车的模型。
图1.png
2.首先考虑的是摩托车自身属性设置,然后可以给他们挂上脚本,属性:Pro_bike 5.js,控制声音:Bike_sound.js ;刹车控制:Skid Marks.js;
  然后具体的代码如下:
Pro_bike 5.js
  1. #pragma strict
  2. /// Writen by Boris Chuprin smokerr@mail.ru
  3. ///////////////////////////////////////////////////////// wheels ///////////////////////////////////////////////////////////
  4. // defeine wheel colliders
  5. var coll_frontWheel : WheelCollider;
  6. var coll_rearWheel : WheelCollider;
  7. // visual for wheels
  8. var meshFrontWheel : GameObject;
  9. var meshRearWheel : GameObject;
  10. // check isn't front wheel in air for front braking possibility
  11. private var isFrontWheelInAir : boolean = true;

  12. //////////////////////////////////////// Stifness, CoM(center of mass), crahsed /////////////////////////////////////////////////////////////
  13. //for stiffness counting when rear brake is on. Need that to lose real wheel's stiffness during time
  14. private var stiffPowerGain : float = 0.0;
  15. //for CoM moving along and across bike. Pilot's CoM.
  16. private var tmpMassShift : float = 0.0;
  17. // crashed status. To know when we need to desable controls because bike is too leaned.
  18. public var crashed : boolean = false;
  19. // there is angles when bike takes status crashed(too much lean, or too much stoppie/wheelie)
  20. var crashAngle01: float;//crashed status is on if bike have more Z(side fall) angle than this                                                                                                // 70 sport, 55 chopper
  21. var crashAngle02: float;//crashed status is on if bike have less Z(side fall) angle than this                                                                                                 // 290 sport, 305 chopper
  22. var crashAngle03: float;//crashed status is on if bike have more X(front fall) angle than this                                                                                                 // 70 sport, 70 chopper
  23. var crashAngle04: float;//crashed status is on if bike have more X(back fall) angle than this                                                                                                // 280 sport, 70 chopper
  24.                                                                                        
  25. // define CoM of bike
  26. var CoM : Transform; //CoM object
  27. var normalCoM : float; //normalCoM is for situation when script need to return CoM in starting position                                                                                // -0.77 sport, -0.38 chopper
  28. var CoMWhenCrahsed : float; //we beed lift CoM for funny bike turning around when crahsed                                                                                                        // -0.2 sport, 0.2 chopper



  29. //////////////////// "beauties" of visuals - some meshes for display visual parts of bike ////////////////////////////////////////////
  30. var rearPendulumn : Transform; //rear pendulumn
  31. var steeringWheel : Transform; //wheel bar
  32. var suspensionFront_down : Transform; //lower part of front forge
  33. private var normalFrontSuspSpring : int; // we need to declare it to know what is normal front spring state is
  34. private var normalRearSuspSpring : int; // we need to declare it to know what is normal rear spring state is
  35. private var forgeBlocked : boolean  = true; // variable to lock front forge for front braking
  36. //why we need forgeBlocked ?
  37. //There is little bug in PhysX 3.3 wheelCollider - it works well only with car mass of 1600kg and 4 wheels.
  38. //If your vehicle is not 4 wheels or mass is not 1600 but 400 - you are in troube.
  39. //Problem is absolutely epic force created by suspension spring when it's full compressed, stretched or wheel comes underground between frames(most catastrophic situation)
  40. //In all 3 cases your spring will generate crazy force and push rigidbody to the sky.
  41. //so, my solution is find this moment and make spring weaker for a while then return to it's normal condition.

  42. private var baseDistance : float; // need to know distance between wheels - base. It's for wheelie compensate(dont want wheelie for long bikes)

  43. // we need to clamp wheelbar angle according the speed. it means - the faster bike rides the less angle you can rotate wheel bar
  44. var wheelbarRestrictCurve : AnimationCurve = new AnimationCurve(new Keyframe(0f, 20f), new Keyframe(100f, 1f));//first number in Keyframe is speed, second is max wheelbar degree

  45. // temporary variable to restrict wheel angle according speed
  46. private var tempMaxWheelAngle : float;

  47. //variable for cut off wheel bar rotation angle at high speed
  48. private var wheelPossibleAngle : float = 0.0;

  49. //for wheels vusials match up the wheelColliders
  50. private var wheelCCenter : Vector3;
  51. private var hit : RaycastHit;

  52. /////////////////////////////////////////// technical variables ///////////////////////////////////////////////////////
  53. static var bikeSpeed : float; //to know bike speed km/h
  54. static var isReverseOn : boolean = false; //to turn On and Off reverse speed
  55. // Engine
  56. var frontBrakePower : float; //brake power absract - 100 is good brakes                                                                                                                                                // 100 sport, 70 chopper
  57. var EngineTorque : float; //engine power(abstract - not in HP or so)                                                                                                                                                // 85 sport, 100 chopper
  58. // airRes is for wind resistance to large bikes more than small ones
  59. var airRes : float; //Air resistant                                                                                                                                                                                                                 // 1 is neutral
  60. /// GearBox
  61. var MaxEngineRPM : float; //engine maximum rotation per minute(RPM) when gearbox should switch to higher gear                                                                 // 12000 sport, 7000 chopper
  62. var EngineRedline : float;                                                                                                                                                                                                                                         // 12200 sport, 7200 chopper
  63. var MinEngineRPM : float; //lowest RPM when gear need to be switched down                                                                                                                                        // 6000 sport, 2500 chopper
  64. static var EngineRPM : float; // engine current rotation per minute(RPM)
  65. // gear ratios(abstract)
  66. var GearRatio: float[];//array of gears                                                                                                         // 6 sport, 5 chopper

  67. var CurrentGear : int = 0; // current gear

  68. private var ctrlHub : GameObject;// gameobject with script control variables
  69. private var outsideControls : controlHub;// making a link to corresponding bike's script

  70. ///////////////////////////////////////////////////  ESP system ////////////////////////////////////////////////////////
  71. private var ESP : boolean = false;//ESP turned off by default


  72. ////////////////////////////////////////////////  ON SCREEN INFO ///////////////////////////////////////////////////////
  73. function OnGUI ()
  74. {
  75.         var biggerText = new GUIStyle("label");
  76.           biggerText.fontSize = 40;
  77.           var middleText = new GUIStyle("label");
  78.           middleText.fontSize = 22;
  79.           var smallerText = new GUIStyle("label");
  80.           smallerText.fontSize = 14;
  81.          
  82.           //to show in on display interface: speed, gear, ESP status
  83.         GUI.color = Color.black;
  84.     GUI.Label(Rect(Screen.width*0.9,Screen.height*0.67, 120, 80), String.Format(""+ "{0:0.}", bikeSpeed), biggerText);
  85.     GUI.Label (Rect (Screen.width*0.725,Screen.height*0.64, 60, 80), "" + (CurrentGear+1),biggerText);
  86.     if (!ESP){
  87.                 GUI.color = Color.grey;
  88.                 GUI.Label (Rect (Screen.width*0.885, Screen.height*0.55,60,40), "ESP", middleText);
  89.         } else {
  90.                 GUI.color = Color.green;
  91.                 GUI.Label (Rect (Screen.width*0.885, Screen.height*0.86,60,40), "ESP", middleText);
  92.         }
  93.          if (!isReverseOn){
  94.                 GUI.color = Color.grey;
  95.                 GUI.Label (Rect (Screen.width*0.885, Screen.height*0.96,60,40), "REAR", smallerText);
  96.         } else {
  97.                 GUI.color = Color.red;
  98.                 GUI.Label (Rect (Screen.width*0.885, Screen.height*0.96,60,40), "REAR", smallerText);
  99.         }
  100.    
  101.     // user info help lines
  102.     GUI.color = Color.white;
  103.     GUI.Box (Rect (10,10,180,20), "A,W,S,D - main control", smallerText);
  104.     GUI.Box (Rect (10,25,220,20), "2 - more power to accelerate", smallerText);
  105.     GUI.Box (Rect (10,40,120,20), "X - rear brake", smallerText);
  106.     GUI.Box (Rect (10,55,320,20), "Q,E,F,V - shift center of mass of biker", smallerText);
  107.     GUI.Box (Rect (10,70,320,20), "R - restart / RightShift+R - full restart", smallerText);
  108.     GUI.Box (Rect (10,85,180,20), "RMB - rotate camera around", smallerText);
  109.           GUI.Box (Rect (10,100,120,20), "Z - turn on/off ESP", smallerText);
  110.           GUI.Box (Rect (10,115,320,20), "C - toggle reverse", smallerText);
  111.           GUI.color = Color.black;
  112.          
  113.          
  114. }


  115. function Start () {
  116.        
  117.         ctrlHub = GameObject.Find("gameScenario");//link to GameObject with script "controlHub"
  118.         outsideControls = ctrlHub.GetComponent(controlHub);//to connect c# mobile control script to this one

  119.         var setInitialTensor : Vector3 = GetComponent.<Rigidbody>().inertiaTensor;//this string is necessary for Unity 5.3 with new PhysX feature when Tensor decoupled from center of mass
  120.         GetComponent.<Rigidbody>().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);// now Center of Mass(CoM) is alligned to GameObject "CoM"
  121.         GetComponent.<Rigidbody>().inertiaTensor = setInitialTensor;////this string is necessary for Unity 5.3 with new PhysX feature when Tensor decoupled from center of mass
  122.        
  123.         // wheel colors for understanding of accelerate, idle, brake(white is idle status)
  124.         meshFrontWheel.GetComponent.<Renderer>().material.color = Color.black;
  125.         meshRearWheel.GetComponent.<Renderer>().material.color = Color.black;
  126.        
  127.         //for better physics of fast moving bodies
  128.         GetComponent.<Rigidbody>().interpolation = RigidbodyInterpolation.Interpolate;
  129.        
  130.         // too keep EngineTorque variable like "real" horse powers
  131.         EngineTorque = EngineTorque * 20;
  132.        
  133.         //*30 is for good braking to keep frontBrakePower = 100 for good brakes. So, 100 is like sportsbike's Brembo
  134.         frontBrakePower = frontBrakePower * 30;//30 is abstract but necessary for Unity5
  135.        
  136.         //tehcnical variables
  137.         normalRearSuspSpring = coll_rearWheel.suspensionSpring.spring;
  138.         normalFrontSuspSpring = coll_frontWheel.suspensionSpring.spring;
  139.        
  140.         baseDistance = coll_frontWheel.transform.localPosition.z - coll_rearWheel.transform.localPosition.z;// now we know distance between two wheels
  141. }


  142. function FixedUpdate (){
  143.        
  144.         // if RPM is more than engine can hold we should shift gear up
  145.         EngineRPM = coll_rearWheel.rpm * GearRatio[CurrentGear];
  146.         if (EngineRPM > EngineRedline){
  147.                 EngineRPM = MaxEngineRPM;
  148.         }
  149.         ShiftGears();
  150.         // turn ESP on (no stoppie, no wheelie, no falls when brake is on when leaning)
  151.         ESP = outsideControls.ESPMode;

  152.         ApplyLocalPositionToVisuals(coll_frontWheel);
  153.         ApplyLocalPositionToVisuals(coll_rearWheel);
  154.        
  155.        
  156.         //////////////////////////////////// part where rear pendulum, wheelbar and wheels meshes matched to wheelsColliers and so on
  157.         //beauty - rear pendulumn is looking at rear wheel
  158.         rearPendulumn.transform.localRotation.eulerAngles.x = 0-8+(meshRearWheel.transform.localPosition.y*100);
  159.         //beauty - wheel bar rotating by front wheel
  160.         suspensionFront_down.transform.localPosition.y =(meshFrontWheel.transform.localPosition.y - 0.15);
  161.         meshFrontWheel.transform.localPosition.z = meshFrontWheel.transform.localPosition.z - (suspensionFront_down.transform.localPosition.y + 0.4)/5;

  162.         // debug - all wheels are white in idle(no accelerate, no brake)
  163.         meshFrontWheel.GetComponent.<Renderer>().material.color = Color.black;
  164.         meshRearWheel.GetComponent.<Renderer>().material.color = Color.black;
  165.        
  166.         // drag and angular drag for emulate air resistance
  167.         if (!crashed){
  168.                 GetComponent.<Rigidbody>().drag = GetComponent.<Rigidbody>().velocity.magnitude / 210  * airRes; // when 250 bike can easy beat 200km/h // ~55 m/s
  169.                 GetComponent.<Rigidbody>().angularDrag = 7 + GetComponent.<Rigidbody>().velocity.magnitude/20;
  170.         }
  171.        
  172.         //determinate the bike speed in km/h
  173.         bikeSpeed = Mathf.Round((GetComponent.<Rigidbody>().velocity.magnitude * 3.6)*10) * 0.1; //from m/s to km/h

  174. //////////////////////////////////// acceleration & brake /////////////////////////////////////////////////////////////
  175. //////////////////////////////////// ACCELERATE /////////////////////////////////////////////////////////////
  176.                 if (!crashed && outsideControls.Vertical >0 && !isReverseOn){//case with acceleration from 0.0 to 0.9 throttle
  177.                         coll_frontWheel.brakeTorque = 0;//we need that to fix strange unity bug when bike stucks if you press "accelerate" just after "brake".
  178.                         coll_rearWheel.motorTorque = EngineTorque * outsideControls.Vertical;

  179.                         // debug - rear wheel is green when accelerate
  180.                         meshRearWheel.GetComponent.<Renderer>().material.color = Color.green;
  181.                        
  182.                         // when normal accelerating CoM z is averaged
  183.                         CoM.localPosition.z = 0.0 + tmpMassShift;
  184.                         CoM.localPosition.y = normalCoM;
  185.                         GetComponent.<Rigidbody>().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);
  186.                 }
  187.                 //case for reverse
  188.                 if (!crashed && outsideControls.Vertical >0 && isReverseOn){
  189.                         coll_rearWheel.motorTorque = EngineTorque * -outsideControls.Vertical/10+(bikeSpeed*50);//need to make reverse really slow

  190.                         // debug - rear wheel is green when accelerate
  191.                         meshRearWheel.GetComponent.<Renderer>().material.color = Color.green;
  192.                        
  193.                         // when normal accelerating CoM z is averaged
  194.                         CoM.localPosition.z = 0.0 + tmpMassShift;
  195.                         CoM.localPosition.y = normalCoM;
  196.                         GetComponent.<Rigidbody>().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);
  197.                 }
  198.                
  199. //////////////////////////////////// ACCELERATE full throttle ///////////////////////////////////////////////////////
  200.                 if (!crashed && outsideControls.Vertical >0.9 && !isReverseOn){// acceleration >0.9 throttle for wheelie       
  201.                         coll_frontWheel.brakeTorque = 0;//we need that to fix strange unity bug when bike stucks if you press "accelerate" just after "brake".
  202.                         coll_rearWheel.motorTorque = EngineTorque * 1.2;//1.2 mean it's full throttle
  203.                         meshRearWheel.GetComponent.<Renderer>().material.color = Color.green;
  204.                         GetComponent.<Rigidbody>().angularDrag  = 20;//for wheelie stability
  205.                        
  206.                
  207.                         if (!ESP){// when ESP we turn off wheelie
  208.                                 CoM.localPosition.z = -(2-baseDistance/1.4) + tmpMassShift;// we got 1 meter in case of sportbike: 2-1.4/1.4 = 1; When we got chopper we'll get ~0.8 as result
  209.                                 //still working om best wheelie code
  210.                                 var stoppieEmpower : float = (bikeSpeed/3)/100;
  211.                                 // need to supress wheelie when leaning because it's always fall and it't not fun at all
  212.                                 if (this.transform.localEulerAngles.z < 70){       
  213.                                         var angleLeanCompensate = this.transform.localEulerAngles.z/30;
  214.                                                 if (angleLeanCompensate > 0.5){
  215.                                                         angleLeanCompensate = 0.5;
  216.                                                 }
  217.                                 }
  218.                                 if (this.transform.localEulerAngles.z > 290){
  219.                                         angleLeanCompensate = (360-this.transform.localEulerAngles.z)/30;
  220.                                                 if (angleLeanCompensate > 0.5){
  221.                                                         angleLeanCompensate = 0.5;
  222.                                                 }
  223.                                 }
  224.                                        
  225.                                 if (stoppieEmpower + angleLeanCompensate > 0.5){
  226.                                         stoppieEmpower = 0.5;
  227.                                 }
  228.                                 CoM.localPosition.y =  -(1 - baseDistance/2.8) - stoppieEmpower ;
  229.                                 CoM.localPosition.y = CoM.localPosition.y += 0.002;
  230.                         }
  231.                         GetComponent.<Rigidbody>().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);
  232.                
  233.                         //this is attenuation for rear suspension targetPosition
  234.                         //I've made it to prevent very strange launch to sky when wheelie in new Phys3
  235.                         if (this.transform.localEulerAngles.x > 200.0){
  236.                                 coll_rearWheel.suspensionSpring.spring = normalRearSuspSpring + (360-this.transform.localEulerAngles.x)*500;
  237.                                 if (coll_rearWheel.suspensionSpring.spring >= normalRearSuspSpring + 20000) coll_rearWheel.suspensionSpring.spring = normalRearSuspSpring + 20000;
  238.                         }
  239.                 } else RearSuspensionRestoration();
  240.                
  241.                
  242. //////////////////////////////////// BRAKING /////////////////////////////////////////////////////////////
  243. //////////////////////////////////// front brake /////////////////////////////////////////////////////////
  244.                 if (!crashed && outsideControls.Vertical <0 && !isFrontWheelInAir){

  245.                         coll_frontWheel.brakeTorque = frontBrakePower * -outsideControls.Vertical;
  246.                         coll_rearWheel.motorTorque = 0; // you can't do accelerate and braking same time.
  247.                        
  248.                         //more user firendly gomeotric progession braking. But less stoppie and fun :( Boring...
  249.                         //coll_frontWheel.brakeTorque = frontBrakePower * -outsideControls.Vertical-(1 - -outsideControls.Vertical)*-outsideControls.Vertical;
  250.                        
  251.                         if (!ESP){ // no stoppie when ESP is on
  252.                                 if (bikeSpeed >1){// no CoM pull up when speed is zero
  253.                                        
  254.                                         //when rear brake is used it helps a little to prevent stoppie. Because in real life bike "stretch" a little when you using rear brake just moment before front.
  255.                                         if(outsideControls.rearBrakeOn){
  256.                                                 var rearBrakeAddon = 0.0025;
  257.                                         }
  258.                                         CoM.localPosition.y = CoM.localPosition.y += (frontBrakePower/200000)+tmpMassShift/50-rearBrakeAddon;
  259.                                        
  260.                                         CoM.localPosition.z = CoM.localPosition.z += 0.05;
  261.                                 }        
  262.                                         else if (bikeSpeed <=1 && !crashed && this.transform.localEulerAngles.z < 45 || bikeSpeed <=1 && !crashed && this.transform.localEulerAngles.z >315){
  263.                                                         if (this.transform.localEulerAngles.x < 5 || this.transform.localEulerAngles.x > 355){
  264.                                                                 CoM.localPosition.y = normalCoM;
  265.                                                         }
  266.                                                 }
  267.                
  268.                                 if (CoM.localPosition.y >= -0.1) CoM.localPosition.y = -0.1;
  269.                                
  270.                                 if (CoM.localPosition.z >= 0.2+(GetComponent.<Rigidbody>().mass/1100)) CoM.localPosition.z = 0.2+(GetComponent.<Rigidbody>().mass/1100);
  271.                                
  272.                                 ////////////
  273.                                 //this is attenuation for front suspension when forge spring is compressed
  274.                                 //I've made it to prevent very strange launch to sky when wheelie in new Phys3
  275.                                 //problem is launch bike to sky when spring must expand from compressed state. In real life front forge can't create such force.
  276.                                 var maxFrontSuspConstrain : float;//temporary variable to make constrain for attenuation ususpension(need to make it always ~15% of initial force)
  277.                                 maxFrontSuspConstrain = CoM.localPosition.z;
  278.                                 if (maxFrontSuspConstrain >= 0.5) maxFrontSuspConstrain = 0.5;
  279.                                 var springWeakness : int  = normalFrontSuspSpring-(normalFrontSuspSpring*1.5) * maxFrontSuspConstrain;
  280.                                
  281.                         }
  282.                         GetComponent.<Rigidbody>().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);
  283.                         // debug - wheel is red when braking
  284.                         meshFrontWheel.GetComponent.<Renderer>().material.color = Color.red;
  285.                        
  286.                         //we need to mark suspension as very compressed to make it weaker
  287.                         forgeBlocked = true;
  288.                 } else FrontSuspensionRestoration(springWeakness);//here is function for weak front spring and return it's force slowly
  289.                        
  290.                
  291. //////////////////////////////////// rear brake /////////////////////////////////////////////////////////
  292.                 // rear brake - it's all about lose side stiffness more and more till rear brake is pressed
  293.                 if (!crashed && outsideControls.rearBrakeOn){
  294.                         coll_rearWheel.brakeTorque = frontBrakePower / 2;// rear brake is not so good as front brake
  295.                        
  296.                         if (this.transform.localEulerAngles.x > 180 && this.transform.localEulerAngles.x < 350){
  297.                                 CoM.localPosition.z = 0.0 + tmpMassShift;
  298.                         }
  299.                        
  300.                         coll_frontWheel.sidewaysFriction.stiffness = 1.0 - ((stiffPowerGain/2)-tmpMassShift*3);
  301.                        
  302.                         stiffPowerGain = stiffPowerGain += 0.025 - (bikeSpeed/10000);
  303.                                 if (stiffPowerGain > 0.9 - bikeSpeed/300){ //orig 0.90
  304.                                         stiffPowerGain = 0.9 - bikeSpeed/300;
  305.                                 }
  306.                         coll_rearWheel.sidewaysFriction.stiffness = 1.0 - stiffPowerGain;
  307.                         meshRearWheel.GetComponent.<Renderer>().material.color = Color.red;
  308.                        
  309.                 } else{

  310.                         coll_rearWheel.brakeTorque = 0;

  311.                         stiffPowerGain = stiffPowerGain -= 0.05;
  312.                                 if (stiffPowerGain < 0){
  313.                                         stiffPowerGain = 0;
  314.                                 }
  315.                         coll_rearWheel.sidewaysFriction.stiffness = 1.0 - stiffPowerGain;// side stiffness is back to 2
  316.                         coll_frontWheel.sidewaysFriction.stiffness = 1.0 - stiffPowerGain;// side stiffness is back to 1
  317.                        
  318.                 }
  319.                
  320. //////////////////////////////////// reverse /////////////////////////////////////////////////////////
  321.                 if (!crashed && outsideControls.reverse && bikeSpeed <=0){
  322.                                 outsideControls.reverse = false;
  323.                                 if(isReverseOn == false){
  324.                                 isReverseOn = true;
  325.                                 } else isReverseOn = false;
  326.                 }
  327.                        
  328.                
  329. //////////////////////////////////// turnning /////////////////////////////////////////////////////////////                       
  330.                         // there is MOST trick in the code
  331.                         // the Unity physics isn't like real life. Wheel collider isn't round as real bike tyre.
  332.                         // so, face it - you can't reach accurate and physics correct countersteering effect on wheelCollider
  333.                         // For that and many other reasons we restrict front wheel turn angle when when speed is growing
  334.                         //(honestly, there was a time when MotoGP bikes has restricted wheel bar rotation angle by 1.5 degree ! as we got here :)                       
  335.                         tempMaxWheelAngle = wheelbarRestrictCurve.Evaluate(bikeSpeed);//associate speed with curve which you've tuned in Editor
  336.                
  337.                 if (!crashed && outsideControls.Horizontal !=0){       
  338.                 //if (!crashed && Input.GetAxis("Horizontal") !=0){//DEL OLD
  339.                         // while speed is high, wheelbar is restricted
  340.                        
  341.                         coll_frontWheel.steerAngle = tempMaxWheelAngle * outsideControls.Horizontal;
  342.                         //coll_frontWheel.steerAngle = tempMaxWheelAngle * Input.GetAxis("Horizontal");//DEL OLD
  343.                         steeringWheel.rotation = coll_frontWheel.transform.rotation * Quaternion.Euler (0, coll_frontWheel.steerAngle, coll_frontWheel.transform.rotation.z);
  344.                 } else coll_frontWheel.steerAngle = 0;
  345.                
  346.                
  347. /////////////////////////////////////////////////// PILOT'S MASS //////////////////////////////////////////////////////////
  348. // it's part about moving of pilot's center of mass. It can be used for wheelie or stoppie control and for motocross section in future
  349.                 //not polished yet. For mobile version it should back pilot's mass smooth not in one tick
  350.                 if (outsideControls.VerticalMassShift >0){
  351.                         tmpMassShift = outsideControls.VerticalMassShift/12.5;//12.5 to get 0.08m at final
  352.                         CoM.localPosition.z = tmpMassShift;       
  353.                         GetComponent.<Rigidbody>().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);
  354.                 }
  355.                 if (outsideControls.VerticalMassShift <0){
  356.                         tmpMassShift = outsideControls.VerticalMassShift/12.5;//12.5 to get 0.08m at final
  357.                         CoM.localPosition.z = tmpMassShift;
  358.                         GetComponent.<Rigidbody>().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);
  359.                 }
  360.                 if (outsideControls.HorizontalMassShift <0){
  361.                         CoM.localPosition.x = outsideControls.HorizontalMassShift/40;//40 to get 0.025m at final
  362.                         GetComponent.<Rigidbody>().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);
  363.                        
  364.                 }
  365.                 if (outsideControls.HorizontalMassShift >0){
  366.                         CoM.localPosition.x = outsideControls.HorizontalMassShift/40;//40 to get 0.025m at final
  367.                         GetComponent.<Rigidbody>().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);
  368.                 }
  369.                
  370.                
  371.                 //auto back CoM when any key not pressed
  372.                 if (!crashed && outsideControls.Vertical == 0 && !outsideControls.rearBrakeOn || (outsideControls.Vertical < 0 && isFrontWheelInAir)){
  373.                         CoM.localPosition.y = normalCoM;
  374.                         CoM.localPosition.z = 0.0 + tmpMassShift;
  375.                         coll_frontWheel.motorTorque = 0;
  376.                         coll_frontWheel.brakeTorque = 0;
  377.                         coll_rearWheel.motorTorque = 0;
  378.                         coll_rearWheel.brakeTorque = 0;
  379.                         GetComponent.<Rigidbody>().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);
  380.                 }
  381.                 //autoback pilot's CoM along
  382.                 if (outsideControls.VerticalMassShift == 0){
  383.                         CoM.localPosition.z = 0.0;
  384.                         tmpMassShift = 0.0;
  385.                 }
  386.                 //autoback pilot's CoM across
  387.                 if (outsideControls.HorizontalMassShift == 0){
  388.                         CoM.localPosition.x = 0.0;
  389.                 }
  390.                
  391. /////////////////////////////////////////////////////// RESTART KEY ///////////////////////////////////////////////////////////
  392.                 // Restart key - recreate bike few meters above current place
  393.                 if (outsideControls.restartBike){
  394.                         if (outsideControls.fullRestartBike){
  395.                                 transform.position = Vector3(0,1,-11);
  396.                                 transform.rotation=Quaternion.Euler( 0.0, 0.0, 0.0 );
  397.                         }
  398.                         crashed = false;
  399.                         transform.position+=Vector3(0,0.1,0);
  400.                         transform.rotation=Quaternion.Euler( 0.0, transform.localEulerAngles.y, 0.0 );
  401.                         GetComponent.<Rigidbody>().velocity=Vector3.zero;
  402.                         GetComponent.<Rigidbody>().angularVelocity=Vector3.zero;
  403.                         CoM.localPosition.x = 0.0;
  404.                         CoM.localPosition.y = normalCoM;
  405.                         CoM.localPosition.z = 0.0;
  406.                         //for fix bug when front wheel IN ground after restart(sorry, I really don't understand why it happens);
  407.                         coll_frontWheel.motorTorque = 0;
  408.                         coll_frontWheel.brakeTorque = 0;
  409.                         coll_rearWheel.motorTorque = 0;
  410.                         coll_rearWheel.brakeTorque = 0;
  411.                         GetComponent.<Rigidbody>().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);
  412.                 }
  413.                
  414.                
  415.                
  416. ///////////////////////////////////////// CRASH happens /////////////////////////////////////////////////////////
  417.         // conditions when crash is happen
  418.         if ((this.transform.localEulerAngles.z >=crashAngle01 && this.transform.localEulerAngles.z <=crashAngle02) || (this.transform.localEulerAngles.x >=crashAngle03 && this.transform.localEulerAngles.x <=crashAngle04)){
  419.                 GetComponent.<Rigidbody>().drag = 0.1; // when 250 bike can easy beat 200km/h // ~55 m/s
  420.                 GetComponent.<Rigidbody>().angularDrag = 0.01;
  421.                 crashed = true;
  422.                 CoM.localPosition.x = 0.0;
  423.                 CoM.localPosition.y = CoMWhenCrahsed;//move CoM a little bit up for funny bike rotations when fall
  424.                 CoM.localPosition.z = 0.0;
  425.                 GetComponent.<Rigidbody>().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);
  426.         }
  427.        
  428.         if (crashed) coll_rearWheel.motorTorque = 0;//to prevent some bug when bike crashed but still accelerating
  429. }

  430. //function Update () {
  431.         //not use that because everything here is about physics
  432. //}
  433. ///////////////////////////////////////////// FUNCTIONS /////////////////////////////////////////////////////////
  434. function ShiftGears() {
  435.         if ( EngineRPM >= MaxEngineRPM ) {
  436.                 var AppropriateGear : int = CurrentGear;
  437.                
  438.                 for ( var i = 0; i < GearRatio.length; i ++ ) {
  439.                         if (coll_rearWheel.rpm * GearRatio[i] < MaxEngineRPM ) {
  440.                                 AppropriateGear = i;
  441.                                 break;
  442.                         }
  443.                 }
  444.                
  445.                 CurrentGear = AppropriateGear;
  446.         }
  447.        
  448.         if ( EngineRPM <= MinEngineRPM ) {
  449.                 AppropriateGear = CurrentGear;
  450.                
  451.                 for ( var j = GearRatio.length-1; j >= 0; j -- ) {
  452.                         if (coll_rearWheel.rpm * GearRatio[j] > MinEngineRPM ) {
  453.                                 AppropriateGear = j;
  454.                                 break;
  455.                         }
  456.                 }
  457.                 CurrentGear = AppropriateGear;
  458.         }
  459. }
  460.        
  461. function ApplyLocalPositionToVisuals (collider : WheelCollider) {
  462.                 if (collider.transform.childCount == 0) {
  463.                         return;
  464.                 }
  465.                
  466.                 var visualWheel : Transform = collider.transform.GetChild (0);
  467.                 wheelCCenter = collider.transform.TransformPoint (collider.center);       
  468.                 if (Physics.Raycast (wheelCCenter, -collider.transform.up, hit, collider.suspensionDistance + collider.radius)) {
  469.                         visualWheel.transform.position = hit.point + (collider.transform.up * collider.radius);
  470.                         if (collider.name == "coll_front_wheel") isFrontWheelInAir = false;
  471.                        
  472.                 } else {
  473.                         visualWheel.transform.position = wheelCCenter - (collider.transform.up * collider.suspensionDistance);
  474.                         if (collider.name == "coll_front_wheel") isFrontWheelInAir = true;
  475.                 }
  476.                 var position : Vector3;
  477.                 var rotation : Quaternion;
  478.                 collider.GetWorldPose (position, rotation);

  479.                 visualWheel.localEulerAngles = Vector3(visualWheel.localEulerAngles.x, collider.steerAngle - visualWheel.localEulerAngles.z, visualWheel.localEulerAngles.z);
  480.                 visualWheel.Rotate (collider.rpm / 60 * 360 * Time.deltaTime, 0, 0);

  481. }
  482. //need to restore spring power for rear suspension after make it harder for wheelie
  483. function RearSuspensionRestoration (){
  484.         if (coll_rearWheel.suspensionSpring.spring > normalRearSuspSpring){
  485.                 coll_rearWheel.suspensionSpring.spring = coll_rearWheel.suspensionSpring.spring -= 500;
  486.         }
  487. }
  488. //need to restore spring power for front suspension after make it weaker for stoppie
  489. function FrontSuspensionRestoration (sprWeakness : int){
  490.         if (forgeBlocked) {//supress front spring power to avoid too much force back
  491.                 coll_frontWheel.suspensionSpring.spring = sprWeakness;
  492.                 forgeBlocked = false;
  493.         }
  494.         if (coll_frontWheel.suspensionSpring.spring < normalFrontSuspSpring){//slowly returning force to front spring
  495.                 coll_frontWheel.suspensionSpring.spring = coll_frontWheel.suspensionSpring.spring += 500;
  496.         }
  497. }
复制代码

Bike_sound.js
  1. #pragma strict
  2. /// Writen by Boris Chuprin smokerr@mail.ru
  3. var linkToBike : pro_bike5;// making a link to corresponding bike's script
  4. //why it's here ? because you might use this script with many bikes in one scene

  5. var lastGear : int;//we need to know what gear is now
  6. private var highRPMAudio : AudioSource;// makeing second audioSource for mixing idle and high RPMs
  7. private var skidSound : AudioSource;// makeing another audioSource for skidding sound

  8. // creating sounds(Link it to real sound files at editor)
  9. var engineStartSound : AudioClip;
  10. var gearingSound : AudioClip;
  11. var IdleRPM : AudioClip;
  12. var highRPM : AudioClip;
  13. var skid : AudioClip;

  14. //we need to know is any wheel skidding
  15. var isSkidingFront : boolean = false;
  16. var isSkidingRear : boolean = false;

  17. private var ctrlHub : GameObject;// gameobject with script control variables
  18. private var outsideControls : controlHub;// making a link to corresponding bike's scriptt


  19. function Start () {
  20.         ctrlHub = GameObject.Find("gameScenario");//link to GameObject with script "controlHub"
  21.         outsideControls = ctrlHub.GetComponent(controlHub);//to connect c# mobile control script to this one
  22.        
  23.         //assign sound to audioSource
  24.         highRPMAudio = gameObject.AddComponent(AudioSource);
  25.         highRPMAudio.loop = true;
  26.     highRPMAudio.playOnAwake = false;
  27.     highRPMAudio.clip = highRPM;
  28.     highRPMAudio.pitch = 0;
  29.     highRPMAudio.volume = 0.0;
  30.     //same assign for skid sound
  31.     skidSound = gameObject.AddComponent(AudioSource);
  32.         skidSound.loop = false;
  33.     skidSound.playOnAwake = false;
  34.     skidSound.clip = skid;
  35.     skidSound.pitch = 1.0;
  36.     skidSound.volume = 1.0;
  37.    
  38.         //real-time linking to current bike
  39.         linkToBike = this.GetComponent(pro_bike5);
  40.         GetComponent.<AudioSource>().PlayOneShot(engineStartSound);
  41.         playEngineWorkSound();
  42.         lastGear = linkToBike.CurrentGear;
  43. }


  44. function Update(){
  45.        
  46.         //Idle plays high at slow speed and highRPM sound play silent at same time. And vice versa.
  47.         GetComponent.<AudioSource>().pitch = Mathf.Abs(linkToBike.EngineRPM  / linkToBike.MaxEngineRPM) + 1.0;
  48.         GetComponent.<AudioSource>().volume = 1.0 - (Mathf.Abs(linkToBike.EngineRPM  / linkToBike.MaxEngineRPM));
  49.         highRPMAudio.pitch = Mathf.Abs(linkToBike.EngineRPM  / linkToBike.MaxEngineRPM);
  50.         highRPMAudio.volume = Mathf.Abs(linkToBike.EngineRPM  / linkToBike.MaxEngineRPM);

  51.         // all engine sounds stop when restart
  52.         if (outsideControls.restartBike){
  53.                 GetComponent.<AudioSource>().Stop();
  54.                 GetComponent.<AudioSource>().pitch = 1.0;
  55.                 GetComponent.<AudioSource>().PlayOneShot(engineStartSound);
  56.                 playEngineWorkSound();
  57.         }
  58.        
  59.         //gear change sound
  60.         if (linkToBike.CurrentGear != lastGear){
  61.                 GetComponent.<AudioSource>().PlayOneShot(gearingSound);//звук переключения передач
  62.                 lastGear = linkToBike.CurrentGear;
  63.         }
  64.         //skids sound
  65.         if (linkToBike.coll_rearWheel.sidewaysFriction.stiffness < 0.5 && !isSkidingRear && linkToBike.bikeSpeed >1){//почему 0.5 ? как бы лучше это обыграть ?
  66.                         skidSound.Play();
  67.                         isSkidingRear = true;
  68.         } else if (linkToBike.coll_rearWheel.sidewaysFriction.stiffness >= 0.5 && isSkidingRear || linkToBike.bikeSpeed <=1){
  69.                                 skidSound.Stop();
  70.                                 isSkidingRear = false;
  71.         }
  72.         if (linkToBike.coll_frontWheel.brakeTorque >= (linkToBike.frontBrakePower-10) && !isSkidingFront && linkToBike.bikeSpeed >1){
  73.                         skidSound.Play();
  74.                         isSkidingFront = true;
  75.         } else if (linkToBike.coll_frontWheel.brakeTorque < linkToBike.frontBrakePower && isSkidingFront || linkToBike.bikeSpeed <=1){
  76.                                 skidSound.Stop();
  77.                                 isSkidingFront = false;
  78.         }
  79. }

  80. function playEngineWorkSound(){
  81.         yield WaitForSeconds(1);//need a pause to hear ingnition sound first
  82.         GetComponent.<AudioSource>().clip = IdleRPM;
  83.         GetComponent.<AudioSource>().Play();
  84.         highRPMAudio.Play();
  85. }
复制代码

Skid Marks.js
  1. #pragma strict
  2. var linkToBike : pro_bike5;
  3. var skidMarkDecal : Transform;
  4. private var hit : WheelHit;       
  5. private var skidMarkPos : Vector3;
  6. private var rotationToLastSkidmark : Quaternion;
  7. private var lastSkidMarkPos : Vector3;
  8. private var relativePos : Vector3;

  9. function Start () {
  10.         linkToBike = this.GetComponent(pro_bike5);
  11. }
  12. function FixedUpdate(){
  13.         //skidmarks for rear wheel(braking drifting)
  14.         if (linkToBike.coll_rearWheel.sidewaysFriction.stiffness < 0.5 && linkToBike.bikeSpeed >1){
  15.                 if (linkToBike.coll_rearWheel.GetGroundHit(hit)){
  16.                         skidMarkPos = hit.point;
  17.                         skidMarkPos.y += 0.02;
  18.                         skidMarkDecal.transform.localScale.x = 1.0;
  19.                         if (lastSkidMarkPos != Vector3.zero){
  20.                                 relativePos = lastSkidMarkPos - skidMarkPos;
  21.                                 rotationToLastSkidmark = Quaternion.LookRotation(relativePos);
  22.                                 Instantiate(skidMarkDecal, skidMarkPos, rotationToLastSkidmark);
  23.                         }
  24.                         lastSkidMarkPos = skidMarkPos;
  25.                 }       
  26.         }
  27.         //skidmarks for front wheel(braking)
  28.         if (linkToBike.coll_frontWheel.brakeTorque >= (linkToBike.frontBrakePower-10) && linkToBike.bikeSpeed >1){
  29.                 if (linkToBike.coll_frontWheel.GetGroundHit(hit)){
  30.                         skidMarkPos = hit.point;
  31.                         skidMarkPos.y += 0.02;
  32.                         skidMarkDecal.transform.localScale.x = 0.6;
  33.                         if (lastSkidMarkPos != Vector3.zero){
  34.                                 relativePos = lastSkidMarkPos - skidMarkPos;
  35.                                 rotationToLastSkidmark = Quaternion.LookRotation(relativePos);
  36.                                 Instantiate(skidMarkDecal, skidMarkPos, rotationToLastSkidmark);
  37.                         }
  38.                         lastSkidMarkPos = skidMarkPos;
  39.                 }       
  40.         }
  41. }

  42. function Update () {
  43. }
复制代码
【脚本参数设置如图】
图2_0.png

图2_1.png

3.接下来,我们需要在场景中,新建一个gameScenario游戏对象GameObject,作为整个游戏控制中心,并且在gameScenario对象中附加 速度控制:Speedometer.js
  控制整个游戏对象:controlHub.cs
Speedometer.js
  1. //speedometer
  2. var GUIDashboard : Texture2D;
  3. var dashboardArrow : Texture2D;
  4. private var topSpeed: float;//220 for sport/ 180 for chopper
  5. private var stopAngle: float;//-200 for sport/ ... for chopper
  6. private var topSpeedAngle: float;
  7. var speed: float;

  8. //tachometer
  9. var chronoTex: Texture2D;
  10. private var topRPM: float;// 14000 for sport/ ... for chopper
  11. private var stopRPMAngle: float;//-200 for sport/... ... for chopper
  12. private var topRPMAngle: float;
  13. var RPM: float;

  14. //link to bike script
  15. var linkToBike : pro_bike5;


  16. function Start () {
  17.         linkToBike = GameObject.Find("rigid_bike").GetComponent("pro_bike5");
  18.         findCurrentBike();
  19. }


  20. function OnGUI() {
  21.         // speedometer
  22.         GUI.DrawTexture(Rect(Screen.width*0.85, Screen.height*0.55, GUIDashboard.width/2, GUIDashboard.height/2), GUIDashboard);
  23.         var centre = Vector2(Screen.width*0.85 + GUIDashboard.width / 4, Screen.height*0.55 + GUIDashboard.height / 4);
  24.         var savedMatrix = GUI.matrix;
  25.         var speedFraction = speed / topSpeed;
  26.         var needleAngle = Mathf.Lerp(stopAngle, topSpeedAngle, speedFraction);
  27.         GUIUtility.RotateAroundPivot(needleAngle, centre);
  28.         GUI.DrawTexture(Rect(centre.x, centre.y - dashboardArrow.height/4, dashboardArrow.width/2, dashboardArrow.height/2), dashboardArrow);
  29.         GUI.matrix = savedMatrix;
  30.        
  31.         //tachometer
  32.         GUI.DrawTexture(Rect(Screen.width*0.65, Screen.height*0.5, chronoTex.width/1.5, chronoTex.height/1.5), chronoTex);
  33.         var centreTacho = Vector2(Screen.width*0.65 + chronoTex.width / 3, Screen.height*0.5+ chronoTex.height / 3);
  34.         var savedTachoMatrix = GUI.matrix;
  35.         var tachoFraction = RPM / topRPM;
  36.         var needleTachoAngle = Mathf.Lerp(stopRPMAngle, topRPMAngle, tachoFraction);
  37.         GUIUtility.RotateAroundPivot(needleTachoAngle, centreTacho);
  38.         GUI.DrawTexture(Rect(centreTacho.x, centreTacho.y - dashboardArrow.height/3, dashboardArrow.width/1.5, dashboardArrow.height/1.5), dashboardArrow);
  39.         GUI.matrix = savedTachoMatrix;
  40. }
  41. function FixedUpdate(){
  42.         speed = linkToBike.bikeSpeed;
  43.         RPM = linkToBike.EngineRPM;
  44. }
  45. function findCurrentBike(){
  46.         var curBikeName : GameObject;
  47.         curBikeName = GameObject.Find("rigid_bike");
  48.         if (curBikeName != null){
  49.                 SetSpeedometerSettings("sport");
  50.                 return;
  51.         }
  52.        
  53. }
  54. function SetSpeedometerSettings(par : String){
  55.         if (par == "sport"){
  56.                 topSpeed = 210;
  57.                 stopAngle = -215;
  58.                 topSpeedAngle = 0;
  59.                 topRPM = 12000;
  60.                 stopRPMAngle = -200;
  61.                 topRPMAngle = 0;
  62.                 yield WaitForSeconds(0.5);       
  63.                 var linkToBike1 = GameObject.Find("rigid_bike").GetComponent("pro_bike5");
  64.                 linkToBike = linkToBike1;
  65.         }
  66. }
复制代码

controlHub.cs
  1. using UnityEngine;
  2. using System.Collections;

  3. //this is script contains all variables translated to bike's script.
  4. //so, it's just a holder for all control variables
  5. //mobile/keyboard scripts sends nums(float, int, bools) to this one

  6. public class controlHub : MonoBehaviour  {//need that for mobile controls
  7.        

  8.         public float Vertical;//variable translated to bike script for bike accelerate/stop and leaning
  9.         public float Horizontal;//variable translated to bike script for pilot's mass shift
  10.        
  11.         public float VerticalMassShift;//variable for pilot's mass translate along bike
  12.         public float HorizontalMassShift;//variable for pilot's mass translate across bike

  13.         public bool ESPMode;//variable for turn ESP on and off

  14.         public bool rearBrakeOn;//this variable says to bike's script to use rear brake
  15.         public bool restartBike;//this variable says to bike's script restart
  16.         public bool fullRestartBike; //this variable says to bike's script to full restart

  17.         public bool reverse;//for reverse speed

  18. }
复制代码

图3.png

4.场景中相机的跟随和切换类:camSwitcher.cs;
  1. using UnityEngine;
  2. using System.Collections;

  3. public class camSwitcher : MonoBehaviour
  4. {

  5.         public Camera backCamera;
  6.         public Camera aroundCamera;
  7.         public Transform cameraTarget;
  8.         private Camera currentCamera;
  9.         //////////////////// for back Camera
  10.         float dist = 3.0f;
  11.         float height = 1.0f;
  12.         //////////////////// for around Camera
  13.         private float distance = 3.0f;
  14.         private float xSpeed = 10.0f;
  15.         private float ySpeed = 10.0f;
  16.        
  17.         private float yMinLimit = -90;
  18.         private float yMaxLimit = 90;
  19.        
  20.         private float distanceMin = 2;
  21.         private float distanceMax = 10;
  22.        
  23.         private float x = 0.0f;
  24.         private float y = 0.0f;
  25.        
  26.         private float smoothTime = 0.2f;
  27.        
  28.         private float xSmooth = 0.0f;
  29.         private float ySmooth = 0.0f;
  30.         private float xVelocity = 0.0f;
  31.         private float yVelocity = 0.0f;

  32.         //new camera behaviour
  33.         private float currentTargetAngle;
  34.        
  35.         private GameObject ctrlHub;// gameobject with script control variables
  36.         private controlHub outsideControls;// making a link to corresponding bike's script
  37.        
  38.         // Use this for initialization
  39.         void Start ()
  40.         {
  41.                 ctrlHub = GameObject.Find("gameScenario");//link to GameObject with script "controlHub"
  42.                 outsideControls = ctrlHub.GetComponent<controlHub>();//to connect c# mobile control script to this one

  43.                 backCamera.enabled = true;
  44.                 aroundCamera.enabled = false;
  45.                 currentCamera = backCamera;
  46.                
  47.                 if (GetComponent<Rigidbody> ()) GetComponent<Rigidbody> ().freezeRotation = true;
  48.        
  49.                 currentTargetAngle = cameraTarget.transform.eulerAngles.z;
  50.         }
  51.        
  52.         // Update is called once per frame
  53.         void LateUpdate ()
  54.         {
  55. #if UNITY_STANDALONE || UNITY_WEBPLAYER// turn camera rotaion ONLY for mobile for free touch screen anywhere
  56.                 if (Input.GetMouseButton (1)) {

  57.                         backCamera.enabled = false;
  58.                         aroundCamera.enabled = true;
  59.                         backCamera.gameObject.SetActive (false);
  60.                         aroundCamera.gameObject.SetActive (true);
  61.                         currentCamera = aroundCamera;
  62.                        
  63.                        
  64.                         x += Input.GetAxis ("Mouse X") * xSpeed;
  65.                         y -= Input.GetAxis ("Mouse Y") * ySpeed;
  66.                        
  67.                         y = Mathf.Clamp (y, yMinLimit, yMaxLimit);
  68.                        
  69.                        
  70.                        
  71.                         xSmooth = Mathf.SmoothDamp (xSmooth, x, ref xVelocity, smoothTime);
  72.                         ySmooth = Mathf.SmoothDamp (ySmooth, y, ref yVelocity, smoothTime);
  73.                        
  74.                        
  75.                         distance = Mathf.Clamp (distance + Input.GetAxis ("Mouse ScrollWheel") * distance, distanceMin, distanceMax);
  76.                        
  77.                        
  78.                         currentCamera.transform.localRotation = Quaternion.Euler (ySmooth, xSmooth, 0);
  79.                         currentCamera.transform.position = currentCamera.transform.rotation * new Vector3 (0.0f, 0.0f, -distance) + cameraTarget.position;


  80.                 } else {
  81. #endif
  82.                         backCamera.enabled = true;
  83.                         aroundCamera.enabled = false;
  84.                         backCamera.gameObject.SetActive (true);
  85.                         aroundCamera.gameObject.SetActive (false);
  86.                         currentCamera = backCamera;
  87.                        
  88.                         //////////////////// code for back Camera
  89.                         backCamera.fieldOfView = backCamera.fieldOfView + outsideControls.Vertical * 20f * Time.deltaTime;
  90.                         if (backCamera.fieldOfView > 85) {
  91.                                 backCamera.fieldOfView = 85;
  92.                         }
  93.                         if (backCamera.fieldOfView < 50) {
  94.                                 backCamera.fieldOfView = 50;
  95.                         }
  96.                         if (backCamera.fieldOfView < 60) {
  97.                                 backCamera.fieldOfView = backCamera.fieldOfView += 10f * Time.deltaTime;
  98.                         }
  99.                         if (backCamera.fieldOfView > 60) {
  100.                                 backCamera.fieldOfView = backCamera.fieldOfView -= 10f * Time.deltaTime;
  101.                         }
  102.                        
  103.                         float wantedRotationAngle = cameraTarget.eulerAngles.y;
  104.                         float wantedHeight = cameraTarget.position.y + height;
  105.                         float currentRotationAngle = currentCamera.transform.eulerAngles.y;
  106.                         float currentHeight = currentCamera.transform.position.y;
  107.                        
  108.                         currentRotationAngle = Mathf.LerpAngle (currentRotationAngle, wantedRotationAngle, 3 * Time.deltaTime);
  109.                         currentHeight = Mathf.Lerp (currentHeight, wantedHeight, 2 * Time.deltaTime);
  110.                        
  111.                         Quaternion currentRotation = Quaternion.Euler (0, currentRotationAngle, 0);
  112.                         currentCamera.transform.position = cameraTarget.position;
  113.                         currentCamera.transform.position -= currentRotation * Vector3.forward * dist;
  114.                         currentCamera.transform.position = new Vector3 (currentCamera.transform.position.x, currentHeight, currentCamera.transform.position.z);
  115.                         currentCamera.transform.LookAt (cameraTarget);

  116.                         //New camera features.
  117.                         //Now camera leaning with biker, so horizon is not always horizontal :)
  118.                         //If you don't like it, just disable
  119.                         //from this -----------------------------------------------------------------------

  120.                         // rotate camera according with bike leaning
  121.                         if (cameraTarget.transform.eulerAngles.z >0 && cameraTarget.transform.eulerAngles.z < 180) {
  122.                                 currentTargetAngle = cameraTarget.transform.eulerAngles.z/10;
  123.                         }
  124.                         if (cameraTarget.transform.eulerAngles.z >180){
  125.                                 currentTargetAngle = -(360-cameraTarget.transform.eulerAngles.z)/10;
  126.                         }
  127.                         currentCamera.transform.rotation = Quaternion.Euler (height*10, currentRotationAngle, currentTargetAngle);
  128.                         //to this -------------------------------------------------------------------------
  129.                 #if UNITY_STANDALONE || UNITY_WEBPLAYER// turn camera rotaion ONLY for mobile for free touch screen anywhere
  130.                 }
  131.                 #endif
  132.         }
  133. }
复制代码
图4.png


5.讲到这一步是比较关键的,正是通过GUI做出虚拟摇杆,虚拟摇杆控制类:mobileControls.cs;  
  1. using UnityEngine;
  2. using UnityEngine.UI;//need that for mobile controls
  3. using UnityEngine.EventSystems;//need that for mobile controls
  4. using System.Collections;


  5. public class mobileControls : MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler {//need that for mobile controls


  6.         public Image bgImgJoyRight; //UI object for right Joystick
  7.         public Image bgImgJoyLeft; //UI object for left Joystick
  8.         private Image joystickImg; //"picture" of stick itself
  9.         private Image joystickImgLeft;//"picture" of stick itself for joyLeft
  10.         private Vector3 inputVector; //this will be translated to bike script for bike accelerate/stop and leaning
  11.         private Vector3 inputVectorLeft;//this will be translated to bike script for pilot's mass shift
  12.        
  13.        
  14.         public bool rearBrakeOn;//this variable says to bike's script to use rear brake
  15.         public bool restartBike;//this variable says to bike's script restart
  16.         //public bool ESPMode;//this variable switch ESP on and off



  17.         private GameObject ctrlHub;// making a link to corresponding bike's script
  18.         private controlHub outsideControls;// making a link to corresponding bike's script



  19.         private void Start(){

  20.                 ctrlHub = GameObject.Find("gameScenario");//link to GameObject with script "controlHub"
  21.                 outsideControls = ctrlHub.GetComponent<controlHub>();// making a link to corresponding bike's script

  22.                 joystickImg = bgImgJoyRight.transform.GetChild(0).GetComponent<Image>();//find stick
  23.                 joystickImgLeft = bgImgJoyLeft.transform.GetChild(0).GetComponent<Image>();//find stick
  24.         }

  25.         //Uncomment it if you want to lean by device rotation :)
  26.         //from here---------------------------------------------------
  27.         //private void Update(){
  28.         //        outsideControls.Horizontal = Input.acceleration.x*1.25f;
  29.         //}
  30.         //to here---------------------------------------------------
  31.         //don't forget to comment standard leaning style few strings below

  32.         ///////////////////////////////////////// Joystick Section /////////////////////////////////////////////////////////////////////////////////////
  33.         public virtual void OnDrag(PointerEventData ped){
  34.                 Vector2 pos;//position for joystick Right
  35.                 if (RectTransformUtility.ScreenPointToLocalPointInRectangle (bgImgJoyRight.rectTransform, ped.position, ped.pressEventCamera, out pos)) {
  36.                         if (ped.position.x > Screen.width/2) {//use buttons should't take effect to joystics
  37.                                 pos.x = (pos.x / bgImgJoyRight.rectTransform.sizeDelta.x);
  38.                                 pos.y = (pos.y / bgImgJoyRight.rectTransform.sizeDelta.y);

  39.                                 inputVector = new Vector3 (pos.x * 2 + 1, 0, pos.y * 2 - 1);
  40.                                 inputVector = (inputVector.magnitude > 1.0f) ? inputVector.normalized : inputVector;

  41.                                 //move stick
  42.                                 joystickImg.rectTransform.anchoredPosition =
  43.                                         new Vector3 (inputVector.x * (bgImgJoyRight.rectTransform.sizeDelta.x / 2), inputVector.z * (bgImgJoyRight.rectTransform.sizeDelta.y / 2));
  44.                        
  45.                                 outsideControls.Vertical = inputVector.z;
  46.                                 //Comment it if you want to lean by device rotation :)
  47.                                 //from here---------------------------------------------------
  48.                                 outsideControls.Horizontal = inputVector.x;
  49.                                 //to here---------------------------------------------------
  50.                                 //don't forget to uncomment rotate leaning style few strings above
  51.                         }
  52.                 }

  53.                 Vector2 pos_j2;//position for joystick Left
  54.                 if (RectTransformUtility.ScreenPointToLocalPointInRectangle (bgImgJoyLeft.rectTransform, ped.position, ped.pressEventCamera, out pos_j2)){
  55.                         if (ped.position.x < Screen.width/2 && ped.position.y < 170){//use buttons should't take effect to joystics
  56.                                 pos_j2.x = (pos_j2.x / bgImgJoyLeft.rectTransform.sizeDelta.x);
  57.                                 pos_j2.y = (pos_j2.y / bgImgJoyLeft.rectTransform.sizeDelta.y);
  58.                        
  59.                                 inputVectorLeft = new Vector3(pos_j2.x*2 + 1,0,pos_j2.y*2 - 1);
  60.                                 inputVectorLeft = (inputVectorLeft.magnitude > 1.0f)?inputVectorLeft.normalized:inputVectorLeft;
  61.                        
  62.                                 //move stick
  63.                                 joystickImgLeft.rectTransform.anchoredPosition =
  64.                                         new Vector3(inputVectorLeft.x * (bgImgJoyLeft.rectTransform.sizeDelta.x/2) ,inputVectorLeft.z * (bgImgJoyLeft.rectTransform.sizeDelta.y/2));

  65.                                 outsideControls.VerticalMassShift = inputVectorLeft.z;
  66.                                 outsideControls.HorizontalMassShift = inputVectorLeft.x;
  67.                         }
  68.                 }
  69.         }

  70. /////////////////////////////////////////// pointer function ////////////////////////////////////////////////////////////////////
  71.         public virtual void OnPointerDown(PointerEventData ped){


  72.                 if (ped.pointerEnter.name == "Stick") OnDrag(ped);
  73.                 if (ped.pointerEnter.name == "Button_X") outsideControls.rearBrakeOn = true;
  74.                 if (ped.pointerEnter.name == "Button_R") outsideControls.restartBike = true;
  75.                 if (ped.pointerEnter.name == "Button_Rf") outsideControls.fullRestartBike = true;
  76.                 if (ped.pointerEnter.name == "Button_E") {//we need to switch ESP on and off after each press on the ESP key
  77.                         if(!outsideControls.ESPMode){
  78.                                 outsideControls.ESPMode = true;
  79.                         } else {
  80.                                 outsideControls.ESPMode = false;
  81.                         }
  82.                 }
  83.                 if (ped.pointerEnter.name == "Button_rev") outsideControls.reverse = true;

  84.         }


  85.         public virtual void OnPointerUp(PointerEventData ped){


  86.                 inputVector = Vector3.zero;
  87.                 joystickImg.rectTransform.anchoredPosition = Vector3.zero;
  88.                 inputVectorLeft = Vector3.zero;
  89.                 joystickImgLeft.rectTransform.anchoredPosition = Vector3.zero;
  90.                 outsideControls.rearBrakeOn = false;
  91.                 outsideControls.restartBike = false;
  92.                 outsideControls.fullRestartBike = false;
  93.                 outsideControls.reverse = false;

  94.                 outsideControls.Vertical = 0;
  95.                 outsideControls.Horizontal = 0;

  96.                 outsideControls.VerticalMassShift = 0;
  97.                 outsideControls.HorizontalMassShift = 0;
  98.         }
  99. }

复制代码
图5.png

6.最后直接运行看效果。【PS:HAHA!有空动手练练也是蛮有趣的】
图6_0.png
图6_1.png
图6_2.png
图6_3.png
  

TA的作品 TA的主页
B Color Smilies

全部评论3

你可能喜欢

Unity3d 虚拟摇杆实现 模拟摩托车行驶小Demo 
联系
我们
快速回复 返回顶部 返回列表