提到賽車游戲,大家最關心的應該就是漂移吧?!
從學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;
看到這里,是不是嚇了一跳,這漂移也太簡單了吧!一句代碼搞定漂移、一句代碼搞定動力
原理是根據搖桿旋轉的角度車身也相對應的旋轉,加上動力有慣性,就產生圓弧形的漂移了
思路就是這么簡單,也許你認為這實在是太簡單得離譜了,可我卻花費了一年多的時間才明白
現在,你只需要花幾分鍾看看這篇沒什么高深技術的文章,就能知道漂移實現的思路
運行跑一下,有漂移效果,但是似乎不怎么明顯,不夠順是不是?
解決方法很簡單,在后面兩個車輪處加一個向前推的力,在加一個目標方向側推的力,就能每次都畫出完美的漂移弧度
文章標題叫《三分鍾實現簡單的賽車漂移》,寫的過程中才發現三分鍾更本做不完
因為我自己在做的時候,很多代碼都是之前寫好了的,直接實現漂移部分的代碼就可以了,所以感覺三分鍾應該夠了,就幾句代碼
好吧,我就當一次標題黨吧!哈哈哈哈
