游戏开发论坛

 找回密码
 立即注册
搜索
查看: 6527|回复: 0

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

[复制链接]

15

主题

16

帖子

102

积分

注册会员

Rank: 2

积分
102
发表于 2016-12-9 14:19:33 | 显示全部楼层 |阅读模式
    今天,为大家分享一下,如何做到一个虚拟摇杆实现物体的移动和特定的操作。下面是简单通过虚拟摇杆可以实现摩托车的行驶。【PS:因为项目代码比较多,也许文章讲得不够全面清楚,希望大家能多多包涵。
另外受帖子字数限制,代码只能发部分,可以加群:575561285 讨论】
  好吧!废话不多讲,直接进入主题吧!

1.新建unity3d 项目,然后自己可以合理搭一个场景,导入需要的资源,例如,我这边会导入一些摩托车的模型。
图1.png
2.首先考虑的是摩托车自身属性设置,然后可以给他们挂上脚本,属性:Pro_bike 5.js,控制声音:Bike_sound.js ,刹车控制:Skid Marks.js;
  然后具体的代码如下:
Pro_bike 5.js
pro_bike5.png

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;  
mobilecontroller.png

图5.png


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

speedometer.png
skidMarks.png
controllhub.png
camSwitcher.png
bike_sound.png
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-2-25 02:00

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表