人气 211

[游戏程序] Unity3d 虚拟摇杆实现 模拟摩托车行驶小Demo [复制链接]

九艺网 2017-3-4 00:43:57

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

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

1.新建unity3d 项目,然后自己可以合理搭一个场景,导入需要的资源,例如,我这边会导入一些摩托车的模型。
b719f6e1436a308a1211363a16c3a81f.png



2.首先考虑的是摩托车自身属性设置,然后可以给他们挂上脚本,属性:Pro_bike 5.js,控制声音:Bike_sound.js ;刹车控制:Skid Marks.js;
  然后具体的代码如下:
Pro_bike 5.js

  • #pragma strict
  • /// Writen by Boris Chuprin [email protected]
  • ///////////////////////////////////////////////////////// wheels ///////////////////////////////////////////////////////////
  • // defeine wheel colliders
  • var coll_frontWheel : WheelCollider;
  • var coll_rearWheel : WheelCollider;
  • // visual for wheels
  • var meshFrontWheel : GameObject;
  • var meshRearWheel : GameObject;
  • // check isn't front wheel in air for front braking possibility
  • private var isFrontWheelInAir : boolean = true;

  • //////////////////////////////////////// Stifness, CoM(center of mass), crahsed /////////////////////////////////////////////////////////////
  • //for stiffness counting when rear brake is on. Need that to lose real wheel's stiffness during time
  • private var stiffPowerGain : float = 0.0;
  • //for CoM moving along and across bike. Pilot's CoM.
  • private var tmpMassShift : float = 0.0;
  • // crashed status. To know when we need to desable controls because bike is too leaned.
  • public var crashed : boolean = false;
  • // there is angles when bike takes status crashed(too much lean, or too much stoppie/wheelie)
  • var crashAngle01: float;//crashed status is on if bike have more Z(side fall) angle than this                                                                                                // 70 sport, 55 chopper
  • var crashAngle02: float;//crashed status is on if bike have less Z(side fall) angle than this                                                                                                 // 290 sport, 305 chopper
  • var crashAngle03: float;//crashed status is on if bike have more X(front fall) angle than this                                                                                                 // 70 sport, 70 chopper
  • var crashAngle04: float;//crashed status is on if bike have more X(back fall) angle than this                                                                                                // 280 sport, 70 chopper

  • // define CoM of bike
  • var CoM : Transform; //CoM object
  • var normalCoM : float; //normalCoM is for situation when script need to return CoM in starting position                                                                                // -0.77 sport, -0.38 chopper
  • var CoMWhenCrahsed : float; //we beed lift CoM for funny bike turning around when crahsed                                                                                                        // -0.2 sport, 0.2 chopper



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

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

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

  • // temporary variable to restrict wheel angle according speed
  • private var tempMaxWheelAngle : float;

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

  • //for wheels vusials match up the wheelColliders
  • private var wheelCCenter : Vector3;
  • private var hit : RaycastHit;

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

  • var CurrentGear : int = 0; // current gear

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

  • ///////////////////////////////////////////////////  ESP system ////////////////////////////////////////////////////////
  • private var ESP : boolean = false;//ESP turned off by default


  • ////////////////////////////////////////////////  ON SCREEN INFO ///////////////////////////////////////////////////////
  • function OnGUI ()
  • {
  •         var biggerText = new GUIStyle("label");
  •           biggerText.fontSize = 40;
  •           var middleText = new GUIStyle("label");
  •           middleText.fontSize = 22;
  •           var smallerText = new GUIStyle("label");
  •           smallerText.fontSize = 14;

  •           //to show in on display interface: speed, gear, ESP status
  •         GUI.color = Color.black;
  •     GUI.Label(Rect(Screen.width*0.9,Screen.height*0.67, 120, 80), String.Format(""+ "{0:0.}", bikeSpeed), biggerText);
  •     GUI.Label (Rect (Screen.width*0.725,Screen.height*0.64, 60, 80), "" + (CurrentGear+1),biggerText);
  •     if (!ESP){
  •                 GUI.color = Color.grey;
  •                 GUI.Label (Rect (Screen.width*0.885, Screen.height*0.55,60,40), "ESP", middleText);
  •         } else {
  •                 GUI.color = Color.green;
  •                 GUI.Label (Rect (Screen.width*0.885, Screen.height*0.86,60,40), "ESP", middleText);
  •         }
  •          if (!isReverseOn){
  •                 GUI.color = Color.grey;
  •                 GUI.Label (Rect (Screen.width*0.885, Screen.height*0.96,60,40), "REAR", smallerText);
  •         } else {
  •                 GUI.color = Color.red;
  •                 GUI.Label (Rect (Screen.width*0.885, Screen.height*0.96,60,40), "REAR", smallerText);
  •         }

  •     // user info help lines
  •     GUI.color = Color.white;
  •     GUI.Box (Rect (10,10,180,20), "A,W,S,D - main control", smallerText);
  •     GUI.Box (Rect (10,25,220,20), "2 - more power to accelerate", smallerText);
  •     GUI.Box (Rect (10,40,120,20), "X - rear brake", smallerText);
  •     GUI.Box (Rect (10,55,320,20), "Q,E,F,V - shift center of mass of biker", smallerText);
  •     GUI.Box (Rect (10,70,320,20), "R - restart / RightShift+R - full restart", smallerText);
  •     GUI.Box (Rect (10,85,180,20), "RMB - rotate camera around", smallerText);
  •           GUI.Box (Rect (10,100,120,20), "Z - turn on/off ESP", smallerText);
  •           GUI.Box (Rect (10,115,320,20), "C - toggle reverse", smallerText);
  •           GUI.color = Color.black;


  • }


  • function Start () {

  •         ctrlHub = GameObject.Find("gameScenario");//link to GameObject with script "controlHub"
  •         outsideControls = ctrlHub.GetComponent(controlHub);//to connect c# mobile control script to this one

  •         var setInitialTensor : Vector3 = GetComponent.().inertiaTensor;//this string is necessary for Unity 5.3 with new PhysX feature when Tensor decoupled from center of mass
  •         GetComponent.().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);// now Center of Mass(CoM) is alligned to GameObject "CoM"
  •         GetComponent.().inertiaTensor = setInitialTensor;////this string is necessary for Unity 5.3 with new PhysX feature when Tensor decoupled from center of mass

  •         // wheel colors for understanding of accelerate, idle, brake(white is idle status)
  •         meshFrontWheel.GetComponent.().material.color = Color.black;
  •         meshRearWheel.GetComponent.().material.color = Color.black;

  •         //for better physics of fast moving bodies
  •         GetComponent.().interpolation = RigidbodyInterpolation.Interpolate;

  •         // too keep EngineTorque variable like "real" horse powers
  •         EngineTorque = EngineTorque * 20;

  •         //*30 is for good braking to keep frontBrakePower = 100 for good brakes. So, 100 is like sportsbike's Brembo
  •         frontBrakePower = frontBrakePower * 30;//30 is abstract but necessary for Unity5

  •         //tehcnical variables
  •         normalRearSuspSpring = coll_rearWheel.suspensionSpring.spring;
  •         normalFrontSuspSpring = coll_frontWheel.suspensionSpring.spring;

  •         baseDistance = coll_frontWheel.transform.localPosition.z - coll_rearWheel.transform.localPosition.z;// now we know distance between two wheels
  • }


  • function FixedUpdate (){

  •         // if RPM is more than engine can hold we should shift gear up
  •         EngineRPM = coll_rearWheel.rpm * GearRatio[CurrentGear];
  •         if (EngineRPM > EngineRedline){
  •                 EngineRPM = MaxEngineRPM;
  •         }
  •         ShiftGears();
  •         // turn ESP on (no stoppie, no wheelie, no falls when brake is on when leaning)
  •         ESP = outsideControls.ESPMode;

  •         ApplyLocalPositionToVisuals(coll_frontWheel);
  •         ApplyLocalPositionToVisuals(coll_rearWheel);


  •          //////////////////////////////////// part where rear pendulum, wheelbar and wheels meshes matched to wheelsColliers and so on
  •          //beauty - rear pendulumn is looking at rear wheel
  •          rearPendulumn.transform.localRotation.eulerAngles.x = 0-8+(meshRearWheel.transform.localPosition.y*100);
  •          //beauty - wheel bar rotating by front wheel
  •         suspensionFront_down.transform.localPosition.y =(meshFrontWheel.transform.localPosition.y - 0.15);
  •         meshFrontWheel.transform.localPosition.z = meshFrontWheel.transform.localPosition.z - (suspensionFront_down.transform.localPosition.y + 0.4)/5;

  •         // debug - all wheels are white in idle(no accelerate, no brake)
  •         meshFrontWheel.GetComponent.().material.color = Color.black;
  •         meshRearWheel.GetComponent.().material.color = Color.black;

  •         // drag and angular drag for emulate air resistance
  •         if (!crashed){
  •                 GetComponent.().drag = GetComponent.().velocity.magnitude / 210  * airRes; // when 250 bike can easy beat 200km/h // ~55 m/s
  •                 GetComponent.().angularDrag = 7 + GetComponent.().velocity.magnitude/20;
  •         }

  •         //determinate the bike speed in km/h
  •         bikeSpeed = Mathf.Round((GetComponent.().velocity.magnitude * 3.6)*10) * 0.1; //from m/s to km/h

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

  •                         // debug - rear wheel is green when accelerate
  •                         meshRearWheel.GetComponent.().material.color = Color.green;

  •                         // when normal accelerating CoM z is averaged
  •                         CoM.localPosition.z = 0.0 + tmpMassShift;
  •                         CoM.localPosition.y = normalCoM;
  •                         GetComponent.().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);
  •                 }
  •                 //case for reverse
  •                 if (!crashed && outsideControls.Vertical >0 && isReverseOn){
  •                         coll_rearWheel.motorTorque = EngineTorque * -outsideControls.Vertical/10+(bikeSpeed*50);//need to make reverse really slow

  •                         // debug - rear wheel is green when accelerate
  •                         meshRearWheel.GetComponent.().material.color = Color.green;

  •                         // when normal accelerating CoM z is averaged
  •                         CoM.localPosition.z = 0.0 + tmpMassShift;
  •                         CoM.localPosition.y = normalCoM;
  •                         GetComponent.().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);
  •                 }

  • //////////////////////////////////// ACCELERATE full throttle ///////////////////////////////////////////////////////
  •                 if (!crashed && outsideControls.Vertical >0.9 && !isReverseOn){// acceleration >0.9 throttle for wheelie
  •                         coll_frontWheel.brakeTorque = 0;//we need that to fix strange unity bug when bike stucks if you press "accelerate" just after "brake".
  •                         coll_rearWheel.motorTorque = EngineTorque * 1.2;//1.2 mean it's full throttle
  •                         meshRearWheel.GetComponent.().material.color = Color.green;
  •                         GetComponent.().angularDrag  = 20;//for wheelie stability


  •                         if (!ESP){// when ESP we turn off wheelie
  •                                 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
  •                                 //still working om best wheelie code
  •                                 var stoppieEmpower : float = (bikeSpeed/3)/100;
  •                                 // need to supress wheelie when leaning because it's always fall and it't not fun at all
  •                                 if (this.transform.localEulerAngles.z < 70){
  •                                         var angleLeanCompensate = this.transform.localEulerAngles.z/30;
  •                                                 if (angleLeanCompensate > 0.5){
  •                                                         angleLeanCompensate = 0.5;
  •                                                 }
  •                                 }
  •                                 if (this.transform.localEulerAngles.z > 290){
  •                                         angleLeanCompensate = (360-this.transform.localEulerAngles.z)/30;
  •                                                 if (angleLeanCompensate > 0.5){
  •                                                         angleLeanCompensate = 0.5;
  •                                                 }
  •                                 }

  •                                 if (stoppieEmpower + angleLeanCompensate > 0.5){
  •                                         stoppieEmpower = 0.5;
  •                                 }
  •                                 CoM.localPosition.y =  -(1 - baseDistance/2.8) - stoppieEmpower ;
  •                                 CoM.localPosition.y = CoM.localPosition.y += 0.002;
  •                         }
  •                         GetComponent.().centerOfMass = Vector3(CoM.localPosition.x, CoM.localPosition.y, CoM.localPosition.z);

  •                         //this is attenuation for rear suspension targetPosition
  •                         //I've made it to prevent very strange launch to sky when wheelie in new Phys3
  •                         if (this.transform.localEulerAngles.x > 200.0){
  •                                 coll_rearWheel.suspensionSpring.spring = normalRearSuspSpring + (360-this.transform.localEulerAngles.x)*500;
  •                                 if (coll_rearWheel.suspensionSpring.spring >= normalRearSuspSpring + 20000) coll_rearWheel.suspensionSpring.spring = normalRearSuspSpring + 20000;
  •                         }
  •                 } else RearSuspensionRestoration();


  • //////////////////////////////////// BRAKING /////////////////////////////////////////////////////////////
  • //////////////////////////////////// front brake /////////////////////////////////////////////////////////
  •                 if (!crashed && outsideControls.Vertical =crashAngle01 && this.transform.localEulerAngles.z =crashAngle03 && this.transform.localEulerAngles.x = MaxEngineRPM ) {
  •                 var AppropriateGear : int = CurrentGear;

  •                 for ( var i = 0; i < GearRatio.length; i ++ ) {
  •                         if (coll_rearWheel.rpm * GearRatio < MaxEngineRPM ) {
  •                                 AppropriateGear = i;
  •                                 break;
  •                         }
  •                 }

  •                 CurrentGear = AppropriateGear;
  •         }

  •         if ( EngineRPM = 0; j -- ) {
  •                         if (coll_rearWheel.rpm * GearRatio[j] > MinEngineRPM ) {
  •                                 AppropriateGear = j;
  •                                 break;
  •                         }
  •                 }
  •                 CurrentGear = AppropriateGear;
  •         }
  • }

  • function ApplyLocalPositionToVisuals (collider : WheelCollider) {
  •                 if (collider.transform.childCount == 0) {
  •                         return;
  •                 }

  •                 var visualWheel : Transform = collider.transform.GetChild (0);
  •                 wheelCCenter = collider.transform.TransformPoint (collider.center);
  •                 if (Physics.Raycast (wheelCCenter, -collider.transform.up, hit, collider.suspensionDistance + collider.radius)) {
  •                         visualWheel.transform.position = hit.point + (collider.transform.up * collider.radius);
  •                         if (collider.name == "coll_front_wheel") isFrontWheelInAir = false;

  •                 } else {
  •                         visualWheel.transform.position = wheelCCenter - (collider.transform.up * collider.suspensionDistance);
  •                         if (collider.name == "coll_front_wheel") isFrontWheelInAir = true;
  •                 }
  •                 var position : Vector3;
  •                 var rotation : Quaternion;
  •                 collider.GetWorldPose (position, rotation);

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

  • }
  • //need to restore spring power for rear suspension after make it harder for wheelie
  • function RearSuspensionRestoration (){
  •         if (coll_rearWheel.suspensionSpring.spring > normalRearSuspSpring){
  •                 coll_rearWheel.suspensionSpring.spring = coll_rearWheel.suspensionSpring.spring -= 500;
  •         }
  • }
  • //need to restore spring power for front suspension after make it weaker for stoppie
  • function FrontSuspensionRestoration (sprWeakness : int){
  •         if (forgeBlocked) {//supress front spring power to avoid too much force back
  •                 coll_frontWheel.suspensionSpring.spring = sprWeakness;
  •                 forgeBlocked = false;
  •         }
  •         if (coll_frontWheel.suspensionSpring.spring < normalFrontSuspSpring){//slowly returning force to front spring
  •                 coll_frontWheel.suspensionSpring.spring = coll_frontWheel.suspensionSpring.spring += 500;
  •         }
  • }

复制代码

Bike_sound.js

  • #pragma strict
  • /// Writen by Boris Chuprin [email&#160;protected]
  • var linkToBike : pro_bike5;// making a link to corresponding bike's script
  • //why it's here ? because you might use this script with many bikes in one scene

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

  • // creating sounds(Link it to real sound files at editor)
  • var engineStartSound : AudioClip;
  • var gearingSound : AudioClip;
  • var IdleRPM : AudioClip;
  • var highRPM : AudioClip;
  • var skid : AudioClip;

  • //we need to know is any wheel skidding
  • var isSkidingFront : boolean = false;
  • var isSkidingRear : boolean = false;

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


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

  •         //assign sound to audioSource
  •         highRPMAudio = gameObject.AddComponent(AudioSource);
  •         highRPMAudio.loop = true;
  •     highRPMAudio.playOnAwake = false;
  •     highRPMAudio.clip = highRPM;
  •     highRPMAudio.pitch = 0;
  •     highRPMAudio.volume = 0.0;
  •     //same assign for skid sound
  •     skidSound = gameObject.AddComponent(AudioSource);
  •         skidSound.loop = false;
  •     skidSound.playOnAwake = false;
  •     skidSound.clip = skid;
  •     skidSound.pitch = 1.0;
  •     skidSound.volume = 1.0;

  •         //real-time linking to current bike
  •          linkToBike = this.GetComponent(pro_bike5);
  •         GetComponent.().PlayOneShot(engineStartSound);
  •         playEngineWorkSound();
  •         lastGear = linkToBike.CurrentGear;
  • }


  • function Update(){

  •         //Idle plays high at slow speed and highRPM sound play silent at same time. And vice versa.
  •         GetComponent.().pitch = Mathf.Abs(linkToBike.EngineRPM  / linkToBike.MaxEngineRPM) + 1.0;
  •         GetComponent.().volume = 1.0 - (Mathf.Abs(linkToBike.EngineRPM  / linkToBike.MaxEngineRPM));
  •         highRPMAudio.pitch = Mathf.Abs(linkToBike.EngineRPM  / linkToBike.MaxEngineRPM);
  •         highRPMAudio.volume = Mathf.Abs(linkToBike.EngineRPM  / linkToBike.MaxEngineRPM);

  •         // all engine sounds stop when restart
  •         if (outsideControls.restartBike){
  •                 GetComponent.().Stop();
  •                 GetComponent.().pitch = 1.0;
  •                 GetComponent.().PlayOneShot(engineStartSound);
  •                 playEngineWorkSound();
  •         }

  •         //gear change sound
  •         if (linkToBike.CurrentGear != lastGear){
  •                 GetComponent.().PlayOneShot(gearingSound);//звук переключения передач
  •                 lastGear = linkToBike.CurrentGear;
  •         }
  •         //skids sound
  •         if (linkToBike.coll_rearWheel.sidewaysFriction.stiffness < 0.5 && !isSkidingRear && linkToBike.bikeSpeed >1){//почему 0.5 ? как бы лучше это обыграть ?
  •                         skidSound.Play();
  •                         isSkidingRear = true;
  •         } else if (linkToBike.coll_rearWheel.sidewaysFriction.stiffness >= 0.5 && isSkidingRear || linkToBike.bikeSpeed = (linkToBike.frontBrakePower-10) && !isSkidingFront && linkToBike.bikeSpeed >1){
  •                         skidSound.Play();
  •                         isSkidingFront = true;
  •         } else if (linkToBike.coll_frontWheel.brakeTorque < linkToBike.frontBrakePower && isSkidingFront || linkToBike.bikeSpeed 1){
  •                 if (linkToBike.coll_rearWheel.GetGroundHit(hit)){
  •                         skidMarkPos = hit.point;
  •                         skidMarkPos.y += 0.02;
  •                         skidMarkDecal.transform.localScale.x = 1.0;
  •                         if (lastSkidMarkPos != Vector3.zero){
  •                                 relativePos = lastSkidMarkPos - skidMarkPos;
  •                                 rotationToLastSkidmark = Quaternion.LookRotation(relativePos);
  •                                 Instantiate(skidMarkDecal, skidMarkPos, rotationToLastSkidmark);
  •                         }
  •                         lastSkidMarkPos = skidMarkPos;
  •                 }
  •         }
  •         //skidmarks for front wheel(braking)
  •         if (linkToBike.coll_frontWheel.brakeTorque >= (linkToBike.frontBrakePower-10) && linkToBike.bikeSpeed >1){
  •                 if (linkToBike.coll_frontWheel.GetGroundHit(hit)){
  •                         skidMarkPos = hit.point;
  •                         skidMarkPos.y += 0.02;
  •                         skidMarkDecal.transform.localScale.x = 0.6;
  •                         if (lastSkidMarkPos != Vector3.zero){
  •                                 relativePos = lastSkidMarkPos - skidMarkPos;
  •                                 rotationToLastSkidmark = Quaternion.LookRotation(relativePos);
  •                                 Instantiate(skidMarkDecal, skidMarkPos, rotationToLastSkidmark);
  •                         }
  •                         lastSkidMarkPos = skidMarkPos;
  •                 }
  •         }
  • }

  • function Update () {
  • }

复制代码
【脚本参数设置如图】
a2a34f725de4afbe98813eaf7dc53a4d.png




69eb29325666dc62e919e1f2e83df3e7.png




3.接下来,我们需要在场景中,新建一个gameScenario游戏对象GameObject,作为整个游戏控制中心,并且在gameScenario对象中附加 速度控制:Speedometer.js
  控制整个游戏对象:controlHub.cs
Speedometer.js

  • //speedometer
  • var GUIDashboard : Texture2D;
  • var dashboardArrow : Texture2D;
  • private var topSpeed: float;//220 for sport/ 180 for chopper
  • private var stopAngle: float;//-200 for sport/ ... for chopper
  • private var topSpeedAngle: float;
  • var speed: float;

  • //tachometer
  • var chronoTex: Texture2D;
  • private var topRPM: float;// 14000 for sport/ ... for chopper
  • private var stopRPMAngle: float;//-200 for sport/... ... for chopper
  • private var topRPMAngle: float;
  • var RPM: float;

  • //link to bike script
  • var linkToBike : pro_bike5;


  • function Start () {
  •         linkToBike = GameObject.Find("rigid_bike").GetComponent("pro_bike5");
  •          findCurrentBike();
  • }


  • function OnGUI() {
  •         // speedometer
  •         GUI.DrawTexture(Rect(Screen.width*0.85, Screen.height*0.55, GUIDashboard.width/2, GUIDashboard.height/2), GUIDashboard);
  •         var centre = Vector2(Screen.width*0.85 + GUIDashboard.width / 4, Screen.height*0.55 + GUIDashboard.height / 4);
  •         var savedMatrix = GUI.matrix;
  •         var speedFraction = speed / topSpeed;
  •         var needleAngle = Mathf.Lerp(stopAngle, topSpeedAngle, speedFraction);
  •         GUIUtility.RotateAroundPivot(needleAngle, centre);
  •         GUI.DrawTexture(Rect(centre.x, centre.y - dashboardArrow.height/4, dashboardArrow.width/2, dashboardArrow.height/2), dashboardArrow);
  •         GUI.matrix = savedMatrix;

  •         //tachometer
  •         GUI.DrawTexture(Rect(Screen.width*0.65, Screen.height*0.5, chronoTex.width/1.5, chronoTex.height/1.5), chronoTex);
  •         var centreTacho = Vector2(Screen.width*0.65 + chronoTex.width / 3, Screen.height*0.5+ chronoTex.height / 3);
  •         var savedTachoMatrix = GUI.matrix;
  •         var tachoFraction = RPM / topRPM;
  •         var needleTachoAngle = Mathf.Lerp(stopRPMAngle, topRPMAngle, tachoFraction);
  •         GUIUtility.RotateAroundPivot(needleTachoAngle, centreTacho);
  •         GUI.DrawTexture(Rect(centreTacho.x, centreTacho.y - dashboardArrow.height/3, dashboardArrow.width/1.5, dashboardArrow.height/1.5), dashboardArrow);
  •         GUI.matrix = savedTachoMatrix;
  • }
  • function FixedUpdate(){
  •          speed = linkToBike.bikeSpeed;
  •          RPM = linkToBike.EngineRPM;
  • }
  • function findCurrentBike(){
  •         var curBikeName : GameObject;
  •         curBikeName = GameObject.Find("rigid_bike");
  •         if (curBikeName != null){
  •                 SetSpeedometerSettings("sport");
  •                 return;
  •         }

  • }
  • function SetSpeedometerSettings(par : String){
  •         if (par == "sport"){
  •                 topSpeed = 210;
  •                 stopAngle = -215;
  •                 topSpeedAngle = 0;
  •                 topRPM = 12000;
  •                 stopRPMAngle = -200;
  •                 topRPMAngle = 0;
  •                 yield WaitForSeconds(0.5);
  •                 var linkToBike1 = GameObject.Find("rigid_bike").GetComponent("pro_bike5");
  •                 linkToBike = linkToBike1;
  •         }
  • }

复制代码

controlHub.cs

  • using UnityEngine;
  • using System.Collections;

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

  • public class controlHub : MonoBehaviour  {//need that for mobile controls


  •         public float Vertical;//variable translated to bike script for bike accelerate/stop and leaning
  •         public float Horizontal;//variable translated to bike script for pilot's mass shift

  •         public float VerticalMassShift;//variable for pilot's mass translate along bike
  •         public float HorizontalMassShift;//variable for pilot's mass translate across bike

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

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

  •         public bool reverse;//for reverse speed

  • }

复制代码

ea1536633c9b5343ebdc9cc3341d48c5.png




4.场景中相机的跟随和切换类:camSwitcher.cs;

  • using UnityEngine;
  • using System.Collections;

  • public class camSwitcher : MonoBehaviour
  • {

  •         public Camera backCamera;
  •         public Camera aroundCamera;
  •         public Transform cameraTarget;
  •         private Camera currentCamera;
  •         //////////////////// for back Camera
  •         float dist = 3.0f;
  •         float height = 1.0f;
  •         //////////////////// for around Camera
  •         private float distance = 3.0f;
  •         private float xSpeed = 10.0f;
  •         private float ySpeed = 10.0f;

  •         private float yMinLimit = -90;
  •         private float yMaxLimit = 90;

  •         private float distanceMin = 2;
  •         private float distanceMax = 10;

  •         private float x = 0.0f;
  •         private float y = 0.0f;

  •         private float smoothTime = 0.2f;

  •         private float xSmooth = 0.0f;
  •         private float ySmooth = 0.0f;
  •         private float xVelocity = 0.0f;
  •         private float yVelocity = 0.0f;

  •         //new camera behaviour
  •         private float currentTargetAngle;

  •         private GameObject ctrlHub;// gameobject with script control variables
  •         private controlHub outsideControls;// making a link to corresponding bike's script

  •         // Use this for initialization
  •         void Start ()
  •         {
  •                 ctrlHub = GameObject.Find("gameScenario");//link to GameObject with script "controlHub"
  •                 outsideControls = ctrlHub.GetComponent();//to connect c# mobile control script to this one

  •                 backCamera.enabled = true;
  •                 aroundCamera.enabled = false;
  •                 currentCamera = backCamera;

  •                 if (GetComponent ()) GetComponent ().freezeRotation = true;

  •                 currentTargetAngle = cameraTarget.transform.eulerAngles.z;
  •         }

  •         // Update is called once per frame
  •         void LateUpdate ()
  •         {
  • #if UNITY_STANDALONE || UNITY_WEBPLAYER// turn camera rotaion ONLY for mobile for free touch screen anywhere
  •                 if (Input.GetMouseButton (1)) {

  •                         backCamera.enabled = false;
  •                         aroundCamera.enabled = true;
  •                         backCamera.gameObject.SetActive (false);
  •                         aroundCamera.gameObject.SetActive (true);
  •                         currentCamera = aroundCamera;


  •                         x += Input.GetAxis ("Mouse X") * xSpeed;
  •                         y -= Input.GetAxis ("Mouse Y") * ySpeed;

  •                         y = Mathf.Clamp (y, yMinLimit, yMaxLimit);



  •                         xSmooth = Mathf.SmoothDamp (xSmooth, x, ref xVelocity, smoothTime);
  •                         ySmooth = Mathf.SmoothDamp (ySmooth, y, ref yVelocity, smoothTime);


  •                         distance = Mathf.Clamp (distance + Input.GetAxis ("Mouse ScrollWheel") * distance, distanceMin, distanceMax);


  •                         currentCamera.transform.localRotation = Quaternion.Euler (ySmooth, xSmooth, 0);
  •                         currentCamera.transform.position = currentCamera.transform.rotation * new Vector3 (0.0f, 0.0f, -distance) + cameraTarget.position;


  •                 } else {
  • #endif
  •                         backCamera.enabled = true;
  •                         aroundCamera.enabled = false;
  •                         backCamera.gameObject.SetActive (true);
  •                         aroundCamera.gameObject.SetActive (false);
  •                         currentCamera = backCamera;

  •                         //////////////////// code for back Camera
  •                         backCamera.fieldOfView = backCamera.fieldOfView + outsideControls.Vertical * 20f * Time.deltaTime;
  •                         if (backCamera.fieldOfView > 85) {
  •                                 backCamera.fieldOfView = 85;
  •                         }
  •                         if (backCamera.fieldOfView < 50) {
  •                                 backCamera.fieldOfView = 50;
  •                         }
  •                         if (backCamera.fieldOfView < 60) {
  •                                 backCamera.fieldOfView = backCamera.fieldOfView += 10f * Time.deltaTime;
  •                         }
  •                         if (backCamera.fieldOfView > 60) {
  •                                 backCamera.fieldOfView = backCamera.fieldOfView -= 10f * Time.deltaTime;
  •                         }

  •                         float wantedRotationAngle = cameraTarget.eulerAngles.y;
  •                         float wantedHeight = cameraTarget.position.y + height;
  •                         float currentRotationAngle = currentCamera.transform.eulerAngles.y;
  •                         float currentHeight = currentCamera.transform.position.y;

  •                         currentRotationAngle = Mathf.LerpAngle (currentRotationAngle, wantedRotationAngle, 3 * Time.deltaTime);
  •                         currentHeight = Mathf.Lerp (currentHeight, wantedHeight, 2 * Time.deltaTime);

  •                         Quaternion currentRotation = Quaternion.Euler (0, currentRotationAngle, 0);
  •                         currentCamera.transform.position = cameraTarget.position;
  •                         currentCamera.transform.position -= currentRotation * Vector3.forward * dist;
  •                         currentCamera.transform.position = new Vector3 (currentCamera.transform.position.x, currentHeight, currentCamera.transform.position.z);
  •                         currentCamera.transform.LookAt (cameraTarget);

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

  •                         // rotate camera according with bike leaning
  •                         if (cameraTarget.transform.eulerAngles.z >0 && cameraTarget.transform.eulerAngles.z < 180) {
  •                                 currentTargetAngle = cameraTarget.transform.eulerAngles.z/10;
  •                         }
  •                         if (cameraTarget.transform.eulerAngles.z >180){
  •                                 currentTargetAngle = -(360-cameraTarget.transform.eulerAngles.z)/10;
  •                         }
  •                         currentCamera.transform.rotation = Quaternion.Euler (height*10, currentRotationAngle, currentTargetAngle);
  •                         //to this -------------------------------------------------------------------------
  •                 #if UNITY_STANDALONE || UNITY_WEBPLAYER// turn camera rotaion ONLY for mobile for free touch screen anywhere
  •                 }
  •                 #endif
  •         }
  • }

复制代码
895a809ca05fb4d379c35dd9473b3f41.png





5.讲到这一步是比较关键的,正是通过GUI做出虚拟摇杆,虚拟摇杆控制类:mobileControls.cs;  

  • using UnityEngine;
  • using UnityEngine.UI;//need that for mobile controls
  • using UnityEngine.EventSystems;//need that for mobile controls
  • using System.Collections;


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


  •         public Image bgImgJoyRight; //UI object for right Joystick
  •         public Image bgImgJoyLeft; //UI object for left Joystick
  •         private Image joystickImg; //"picture" of stick itself
  •         private Image joystickImgLeft;//"picture" of stick itself for joyLeft
  •         private Vector3 inputVector; //this will be translated to bike script for bike accelerate/stop and leaning
  •         private Vector3 inputVectorLeft;//this will be translated to bike script for pilot's mass shift


  •         public bool rearBrakeOn;//this variable says to bike's script to use rear brake
  •         public bool restartBike;//this variable says to bike's script restart
  •         //public bool ESPMode;//this variable switch ESP on and off



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



  •         private void Start(){

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

  •                 joystickImg = bgImgJoyRight.transform.GetChild(0).GetComponent();//find stick
  •                 joystickImgLeft = bgImgJoyLeft.transform.GetChild(0).GetComponent();//find stick
  •         }

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

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

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

  •                                 //move stick
  •                                 joystickImg.rectTransform.anchoredPosition =
  •                                         new Vector3 (inputVector.x * (bgImgJoyRight.rectTransform.sizeDelta.x / 2), inputVector.z * (bgImgJoyRight.rectTransform.sizeDelta.y / 2));

  •                                 outsideControls.Vertical = inputVector.z;
  •                                 //Comment it if you want to lean by device rotation :)
  •                                 //from here---------------------------------------------------
  •                                 outsideControls.Horizontal = inputVector.x;
  •                                 //to here---------------------------------------------------
  •                                 //don't forget to uncomment rotate leaning style few strings above
  •                         }
  •                 }

  •                 Vector2 pos_j2;//position for joystick Left
  •                 if (RectTransformUtility.ScreenPointToLocalPointInRectangle (bgImgJoyLeft.rectTransform, ped.position, ped.pressEventCamera, out pos_j2)){
  •                         if (ped.position.x < Screen.width/2 && ped.position.y < 170){//use buttons should't take effect to joystics
  •                                 pos_j2.x = (pos_j2.x / bgImgJoyLeft.rectTransform.sizeDelta.x);
  •                                 pos_j2.y = (pos_j2.y / bgImgJoyLeft.rectTransform.sizeDelta.y);

  •                                 inputVectorLeft = new Vector3(pos_j2.x*2 + 1,0,pos_j2.y*2 - 1);
  •                                 inputVectorLeft = (inputVectorLeft.magnitude > 1.0f)?inputVectorLeft.normalized:inputVectorLeft;

  •                                 //move stick
  •                                 joystickImgLeft.rectTransform.anchoredPosition =
  •                                         new Vector3(inputVectorLeft.x * (bgImgJoyLeft.rectTransform.sizeDelta.x/2) ,inputVectorLeft.z * (bgImgJoyLeft.rectTransform.sizeDelta.y/2));

  •                                 outsideControls.VerticalMassShift = inputVectorLeft.z;
  •                                 outsideControls.HorizontalMassShift = inputVectorLeft.x;
  •                         }
  •                 }
  •         }

  • /////////////////////////////////////////// pointer function ////////////////////////////////////////////////////////////////////
  •         public virtual void OnPointerDown(PointerEventData ped){


  •                 if (ped.pointerEnter.name == "Stick") OnDrag(ped);
  •                 if (ped.pointerEnter.name == "Button_X") outsideControls.rearBrakeOn = true;
  •                 if (ped.pointerEnter.name == "Button_R") outsideControls.restartBike = true;
  •                 if (ped.pointerEnter.name == "Button_Rf") outsideControls.fullRestartBike = true;
  •                 if (ped.pointerEnter.name == "Button_E") {//we need to switch ESP on and off after each press on the ESP key
  •                         if(!outsideControls.ESPMode){
  •                                 outsideControls.ESPMode = true;
  •                         } else {
  •                                 outsideControls.ESPMode = false;
  •                         }
  •                 }
  •                 if (ped.pointerEnter.name == "Button_rev") outsideControls.reverse = true;

  •         }


  •         public virtual void OnPointerUp(PointerEventData ped){


  •                 inputVector = Vector3.zero;
  •                 joystickImg.rectTransform.anchoredPosition = Vector3.zero;
  •                 inputVectorLeft = Vector3.zero;
  •                 joystickImgLeft.rectTransform.anchoredPosition = Vector3.zero;
  •                 outsideControls.rearBrakeOn = false;
  •                 outsideControls.restartBike = false;
  •                 outsideControls.fullRestartBike = false;
  •                 outsideControls.reverse = false;

  •                 outsideControls.Vertical = 0;
  •                 outsideControls.Horizontal = 0;

  •                 outsideControls.VerticalMassShift = 0;
  •                 outsideControls.HorizontalMassShift = 0;
  •         }
  • }



复制代码
7de096cc5b42a134cb1d5c85da64d316.png




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



a522652c4ee826fb24b7181d2ce90694.png



3845fa2aaf28fbebcf44dd872a1c7949.png



6e9c854933dcd57b666742ef41d80445.png



  

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

QQ|手机版|小黑屋|九艺游戏动画论坛 ( 津ICP备2022000452号-1 )

GMT+8, 2024-4-19 09:36 , Processed in 0.258923 second(s), 26 queries .

Powered by Discuz! X3.4  © 2001-2017 Discuz Team.