• 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

  • 相关阅读:
    插头DP专题
    HDU 4873 ZCC Loves Intersection(JAVA、大数、推公式)
    HDU 4865 Peter's Hobby(概率、dp、log)
    HDU 4870 Rating(概率、期望、推公式) && ZOJ 3415 Zhou Yu
    HDU 4862 Jump(最小K路径覆盖)
    codeforces 449B Jzzhu and Cities (Dij+堆优化)
    2014 12th GDCPC 总结
    HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)
    UVALive 4949 Risk(二分网络流、SAP)
    Codeforces 1105D(双层广搜)
  • 原文地址:https://www.cnblogs.com/shenggege/p/5393815.html
Copyright © 2020-2023  润新知