unity3d 三分鍾實現簡單的賽車漂移


提到賽車游戲,大家最關心的應該就是漂移吧?!

從學unity開始,我就一直在斷斷續續的研究賽車

因為自己技術太爛、悟性太差等原因,我走了不少彎路

也許你會說,網上那么多資料,你不會查啊

是啊!網上一搜一大把unity賽車例程,還有好幾篇被轉發了很多次的賽車漂移實現思路

 

【wheelcollider:自己技術太爛搞不定】

賽車例程幾乎都是用wheelcollider來實現的

我一直以為wheelcollider的參數簡直就不是人能調的

直到上個星期我才聽我好朋友 阿亮 說wheelcollider的參數不是隨便調的

它是按照真實賽車來實現的,所以參數也要按照真實賽車來調

比如賽車車輪的間距、賽車重量、懸掛高度......

就好比小轎車使用了大貨車的懸掛參數、大貨車使用了小轎車的車輪參數

好吧,我承認我自己也是聽得迷迷糊糊!

反正總而言之一句話:wheelcollider的參數的確是非常難調,但是懂的人還是能一下子就調好的(好像說的是廢話,我是不懂的- -)

 

【實現思路的文章:自己悟性太差搞不定】

然后是關於賽車漂移實現思路的文章

有幾篇被轉發了很多次的文章,被轉發了那么多次,那么漂移應該就是這個實現思路吧?可是大家的實現方式都不一樣

我根本不知道漂移的實現是否有一個唯一的標准,如果有,那這個標准又是什么呢?

看了這些文章,漂移我還是沒有研究出來,還是一點思路都沒有

 

后來我偶然得到了一份商業賽車游戲的代碼,然后漂移就實現出來了- -

聽我說起來好像挺容易的!其實研究那份代碼的過程特別煎熬!唉,不說了,都是淚啊

 

聲明:下文中我要實現出來的漂移僅僅是個簡單的漂移,非常簡單!!!一個思路而已,並沒有用到那份商業賽車游戲中的任何一句代碼

注意:請使用Unity4.X版本,5.X版本的wheelcollider參數又變了,要哭了

 

准備工作:

1、下載CarWaypoint插件,使用插件中的demo。地址:http://www.cnblogs.com/shenggege/p/4295616.html

2、easytouch插件

 

導入CarWaypoint插件和easytouch插件

打開CarWaypoints/demo/Car Physics 場景,可以看到一輛車

Hierarchy面板除了前四項其余全部隱藏,運行起來跑一下,還是挺有漂移的感覺的,這是調wheelcollider參數調出來的

我們現在需要做的是用搖桿操作賽車,用另外一個思路讓賽車轉彎時會漂移

 

創建一個虛擬搖桿取名為:MoveJoystick,InteractionType選擇Event Notification

新建一個C#腳本:RockerController,復制以下代碼

  1 #region HeadComments
  2 /* ========================================================================
  3 * Copyright (C) 2015 ArthunGame
  4 *
  5 * 作    者:Arthun
  6 * 文件名稱:RockerController
  7 * 功    能:搖桿控制器
  8 * 
  9 * =========================================================================
 10 */
 11 #endregion
 12 
 13 using UnityEngine;
 14 
 15 public class RockerController : MonoBehaviour
 16 {
 17     public static RockerController Instance;
 18 
 19     /// <summary>
 20     /// 搖桿移動回調
 21     /// </summary>
 22     /// <param name="isMove"></param>
 23     /// <param name="angle"></param>
 24     /// <param name="move"></param>
 25     public delegate void RockerMoveCallback(bool isMove, float angle, MovingJoystick move);
 26     public RockerMoveCallback rockerMoveCallback;
 27 
 28     void Awake()
 29     {
 30         if (Instance != null)
 31             Debug.LogError("Instance RockerController x2");
 32 
 33         Instance = this;
 34     }
 35 
 36     /// <summary>
 37     /// 當搖桿可用時注冊事件(程序啟動執行)
 38     /// </summary>
 39     void OnEnable()
 40     {
 41         EasyJoystick.On_JoystickMove += OnJoystickMove;
 42         EasyJoystick.On_JoystickMoveEnd += OnJoystickMoveEnd;
 43     }
 44 
 45     /// <summary>
 46     /// 當搖桿不可用時移除事件(程序關閉時執行) 
 47     /// </summary>
 48     void OnDisable()
 49     {
 50         EasyJoystick.On_JoystickMove -= OnJoystickMove;
 51         EasyJoystick.On_JoystickMoveEnd -= OnJoystickMoveEnd;
 52     }
 53 
 54     /// <summary>
 55     /// 當搖桿銷毀時移除事件 (程序關閉時執行) 
 56     /// </summary>
 57     void OnDestroy()
 58     {
 59         EasyJoystick.On_JoystickMove -= OnJoystickMove;
 60         EasyJoystick.On_JoystickMoveEnd -= OnJoystickMoveEnd;
 61     }
 62 
 63     /// <summary>
 64     /// 移動搖桿結束
 65     /// </summary>
 66     /// <param name="move"></param>
 67     void OnJoystickMoveEnd(MovingJoystick move)
 68     {
 69         OnRockerMoveInfo(false, -1f, move);
 70     }
 71 
 72     /// <summary>
 73     /// 正在移動搖桿
 74     /// </summary>
 75     /// <param name="move"></param>
 76     void OnJoystickMove(MovingJoystick move)
 77     {
 78         if (move.joystickAxis.x != 0 || move.joystickAxis.y != 0)
 79         {
 80             OnRockerMoveInfo(true, circularAngle(move), move);
 81         }
 82     }
 83 
 84     /// <summary>
 85     /// 獲取搖桿全角度 0~360
 86     /// </summary>
 87     /// <param name="move"></param>
 88     /// <returns> 左邊0 上90 右180 下 270</returns>
 89     float circularAngle(MovingJoystick move)
 90     {
 91         Vector2 pos = new Vector2
 92         {
 93             x = move.joystickAxis.x * 90f + 90f,
 94             y = move.joystickAxis.y * 90f + 90f
 95         };
 96 
 97         if (pos.y < 90f)
 98         {
 99             if (pos.x < 90f)
100             {
101                 return 270f + pos.y;
102             }
103             else if (pos.x > 90f)
104             {
105                 return 180f + (90f - pos.y);
106             }
107         }
108 
109         return pos.x;
110     }
111 
112     /// <summary>
113     /// 搖桿移動信息
114     /// </summary>
115     /// <param name="isMove"></param>
116     /// <param name="angle">當前搖桿角度 取值范圍0~360 -1為未操作</param>
117     void OnRockerMoveInfo(bool isMove, float angle, MovingJoystick move)
118     {
119         if (rockerMoveCallback != null)
120         {
121             rockerMoveCallback(isMove, angle, move);
122         }
123     }
124 }

 RockerController掛到MoveJoystick上

 

新建一個腳本:FollowCamera並復制以下代碼

 1 #region HeadComments
 2 /* ========================================================================
 3 * Copyright (C) 2016 ArthunGame
 4 *
 5 * 作    者:Arthun
 6 * 文件名稱:FollowCamera
 7 * 功    能:跟隨攝像機
 8 * 創建時間:2016/03/11 19:38:35
 9 * 
10 * =========================================================================
11 */
12 #endregion
13 
14 using UnityEngine;
15 
16 public class FollowCamera : MonoBehaviour
17 {
18     static FollowCamera _instance;
19     public static FollowCamera GetInstance()
20     {
21         return _instance;
22     }
23 
24     public Transform Target;
25     public float Distance = 10f;
26     public float Height = 20f;
27     public float HeightDamping = 2f;
28 
29     void Awake()
30     {
31         if (_instance != null)
32             Debug.LogError("Instance FollowCamera x2");
33 
34         _instance = this;
35     }
36 
37     void LateUpdate()
38     {
39         float currentHeight = Mathf.Lerp(transform.position.y, Target.position.y + Height, HeightDamping * Time.deltaTime);
40 
41         transform.position = Target.position;
42         transform.position -= Vector3.forward * Distance;
43         transform.position = new Vector3(transform.position.x, currentHeight, transform.position.z);
44 
45         transform.LookAt(Target);
46     }
47 
48     public void SetTarget(Transform target)
49     {
50         Target = target;
51     }
52 
53     public void SetParame(float dis, float height, float heightDamp)
54     {
55         Distance = dis;
56         Height = height;
57         HeightDamping = heightDamp;
58     }
59 }

將MainCamera上的SmoothFollowA腳本刪除,替換為剛才新建的FollowCamera腳本

 

打開CarController腳本,添加幾個變量

1     public float EngineTorque = 1500f;//引擎扭矩 
2     public WheelCollider WheelBL;//后左輪
3     public WheelCollider WheelBR;//后右輪
4     public Vector3 CenterOfMass = Vector3.zero;//質量中心
5 
6     bool mRockerIsMove = false;//搖桿是否移動
7     Vector3 mTargetBodyAngle = Vector3.zero;//目標車身角度
8     float mBodyRotateSpeed = 3f;//旋轉速度

在Start中設置賽車質量中心(越低越不容易翻車)和搖桿回調

 1     void Start()
 2     {
 3         rigidbody.centerOfMass = CenterOfMass;
 4         RockerController.Instance.rockerMoveCallback += rockerMoveCallback;
 5 
 6         //獲取路標點數據
 7         _WaypointsXML.GetXmlData(WaypointsModelAll, null, waypointsData.text);
 8 
 9         Debug.Log("賽道總長度:" + CalcTotalDis().ToString());//計算賽道長度
10     }
11 
12     /// <summary>
13     /// 搖桿移動回調
14     /// </summary>
15     /// <param name="isMove"></param>
16     /// <param name="angle"></param>
17     /// <param name="move"></param>
18     void rockerMoveCallback(bool isMove, float angle, MovingJoystick move)
19     {
20         if (move.joystickName != "MoveJoystick")
21             return;
22 
23         mRockerIsMove = isMove;
24         mTargetBodyAngle.y = move.Axis2Angle(true);
25     }

 

最后,在FixedUpdate中加入三句代碼

1         if (mRockerIsMove)
2         {
3             transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(mTargetBodyAngle), Time.fixedDeltaTime * mBodyRotateSpeed);
4         }
5 
6         WheelBL.motorTorque = WheelBR.motorTorque = -EngineTorque * (mRockerIsMove ? 0.7f : 0f) * 5000f * Time.fixedDeltaTime;

看到這里,是不是嚇了一跳,這漂移也太簡單了吧!一句代碼搞定漂移、一句代碼搞定動力

原理是根據搖桿旋轉的角度車身也相對應的旋轉,加上動力有慣性,就產生圓弧形的漂移了

思路就是這么簡單,也許你認為這實在是太簡單得離譜了,可我卻花費了一年多的時間才明白

現在,你只需要花幾分鍾看看這篇沒什么高深技術的文章,就能知道漂移實現的思路

 

運行跑一下,有漂移效果,但是似乎不怎么明顯,不夠順是不是?

解決方法很簡單,在后面兩個車輪處加一個向前推的力,在加一個目標方向側推的力,就能每次都畫出完美的漂移弧度

 

文章標題叫《三分鍾實現簡單的賽車漂移》,寫的過程中才發現三分鍾更本做不完

因為我自己在做的時候,很多代碼都是之前寫好了的,直接實現漂移部分的代碼就可以了,所以感覺三分鍾應該夠了,就幾句代碼

好吧,我就當一次標題黨吧!哈哈哈哈

 

原文鏈接:http://www.cnblogs.com/shenggege/p/5393815.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM