| 
 | 
 
 本帖最后由 夜行的猫仔 于 2015-9-25 15:41 编辑  
 
 
 
 
 
CarUserControl脚本 
[mw_shl_code=cpp,true]using System; 
using UnityEngine; 
using UnityStandardAssets.CrossPlatformInput; 
 
namespace UnityStandardAssets.Vehicles.Car 
{ 
    [RequireComponent(typeof (CarController))] 
    public class CarUserControl : MonoBehaviour 
    { 
        private CarController m_Car; //car的控制变量,通过这个变量控制汽车的行为 
 
 
        private void Awake() 
        { 
            // 获取控制器 
            m_Car = GetComponent<CarController>(); 
        } 
 
 
        private void FixedUpdate() 
        { 
            // 根据输入,将控制信号传入控制器 
            float h = CrossPlatformInputManager.GetAxis("Horizontal"); 
            float v = CrossPlatformInputManager.GetAxis("Vertical"); 
#if !MOBILE_INPUT             //非移动设备上运行 
            float handbrake = CrossPlatformInputManager.GetAxis("Jump"); 
            m_Car.Move(h, v, v, handbrake); 
#else 
            m_Car.Move(h, v, v, 0f); 
#endif 
        } 
    } 
} 
[/mw_shl_code] 
CarUserControl属于比较简单的一个控制类,在FixedUpdate()函数中将玩家的输入信息转发给CarController类。与之相对的是CarAIControl;CarAIControl是人工智能控制类较为复杂,将在后面讲解。 
 
CarController类    汽车控制器 
[mw_shl_code=csharp,true]using System; 
using UnityEngine; 
 
namespace UnityStandardAssets.Vehicles.Car 
{ 
    internal enum CarDriveType 
    { 
        FrontWheelDrive, 
        RearWheelDrive, 
        FourWheelDrive 
    } 
 
    internal enum SpeedType 
    { 
        MPH, 
        KPH 
    } 
 
    public class CarController : MonoBehaviour 
    { 
        [SerializeField] private CarDriveType m_CarDriveType = CarDriveType.FourWheelDrive; 
        [SerializeField] private WheelCollider[] m_WheelColliders = new WheelCollider[4]; 
        [SerializeField] private GameObject[] m_WheelMeshes = new GameObject[4]; 
        [SerializeField] private WheelEffects[] m_WheelEffects = new WheelEffects[4]; 
        [SerializeField] private Vector3 m_CentreOfMassOffset; 
        [SerializeField] private float m_MaximumSteerAngle; 
        [Range(0, 1)] [SerializeField] private float m_SteerHelper; // 0 is raw physics , 1 the car will grip in the direction it is facing 
        [Range(0, 1)] [SerializeField] private float m_TractionControl; // 0 is no traction control, 1 is full interference 
        [SerializeField] private float m_FullTorqueOverAllWheels; 
        [SerializeField] private float m_ReverseTorque; 
        [SerializeField] private float m_MaxHandbrakeTorque; 
        [SerializeField] private float m_Downforce = 100f; 
        [SerializeField] private SpeedType m_SpeedType; 
        [SerializeField] private float m_Topspeed = 200; 
        [SerializeField] private static int NoOfGears = 5; 
        [SerializeField] private float m_RevRangeBoundary = 1f; 
        [SerializeField] private float m_SlipLimit; 
        [SerializeField] private float m_BrakeTorque; 
 
        private Quaternion[] m_WheelMeshLocalRotations; 
        private Vector3 m_Prevpos, m_Pos; 
        private float m_SteerAngle; 
        private int m_GearNum; 
        private float m_GearFactor; 
        private float m_OldRotation; 
        private float m_CurrentTorque; 
        private Rigidbody m_Rigidbody; 
        private const float k_ReversingThreshold = 0.01f; 
 
        public bool Skidding { get; private set; } 
        public float BrakeInput { get; private set; } 
        public float CurrentSteerAngle{ get { return m_SteerAngle; }} 
        public float CurrentSpeed{ get { return m_Rigidbody.velocity.magnitude*2.23693629f; }} 
        public float MaxSpeed{get { return m_Topspeed; }} 
        public float Revs { get; private set; } 
        public float AccelInput { get; private set; } 
 
        // Use this for initialization 
        private void Start() 
        { 
            m_WheelMeshLocalRotations = new Quaternion[4]; 
            //保存四个轮子的旋转矩阵 
            for (int i = 0; i < 4; i++) 
            { 
                m_WheelMeshLocalRotations = m_WheelMeshes.transform.localRotation; 
            } 
            m_WheelColliders[0].attachedRigidbody.centerOfMass = m_CentreOfMassOffset; 
 
            m_MaxHandbrakeTorque = float.MaxValue; 
 
            m_Rigidbody = GetComponent<Rigidbody>(); 
            m_CurrentTorque = m_FullTorqueOverAllWheels - (m_TractionControl*m_FullTorqueOverAllWheels); 
        } 
 
 
        //车辆变档---汽车的加速减速 
        private void GearChanging() 
        { 
            float f = Mathf.Abs(CurrentSpeed/MaxSpeed); 
            float upgearlimit = (1/(float) NoOfGears)*(m_GearNum + 1); 
            float downgearlimit = (1/(float) NoOfGears)*m_GearNum; 
 
            if (m_GearNum > 0 && f < downgearlimit) 
            { 
                m_GearNum--; 
            } 
 
            if (f > upgearlimit && (m_GearNum < (NoOfGears - 1))) 
            { 
                m_GearNum++; 
            } 
        } 
 
        //simple function to add a curved bias towards 1 for a value in the 0-1 range 
        // 曲线间增加斜角的简单函数 
        private static float CurveFactor(float factor) 
        { 
            return 1 - (1 - factor)*(1 - factor); 
        } 
 
        // unclamped version of Lerp, to allow value to exceed the from-to range 
        // 超越差值,允许插值在取值范围以外 
        private static float ULerp(float from, float to, float value) 
        { 
            return (1.0f - value)*from + value*to; 
        } 
 
        //计算齿轮系数 
        private void CalculateGearFactor() 
        { 
            float f = (1/(float) NoOfGears); 
            // gear factor is a normalised representation of the current speed within the current gear's range of speeds. 
            // We smooth towards the 'target' gear factor, so that revs don't instantly snap up or down when changing gear. 
            var targetGearFactor = Mathf.InverseLerp(f*m_GearNum, f*(m_GearNum + 1), Mathf.Abs(CurrentSpeed/MaxSpeed)); 
            m_GearFactor = Mathf.Lerp(m_GearFactor, targetGearFactor, Time.deltaTime*5f); 
        } 
 
        //转速计算 
        private void CalculateRevs() 
        { 
            // calculate engine revs (for display / sound)      计算发动机转速 
            // (this is done in retrospect - revs are not used in force/power calculations) 
            CalculateGearFactor(); 
            var gearNumFactor = m_GearNum/(float) NoOfGears; 
            var revsRangeMin = ULerp(0f, m_RevRangeBoundary, CurveFactor(gearNumFactor)); 
            var revsRangeMax = ULerp(m_RevRangeBoundary, 1f, gearNumFactor); 
            Revs = ULerp(revsRangeMin, revsRangeMax, m_GearFactor); 
        } 
 
        //运动控制 
        public void Move(float steering, float accel, float footbrake, float handbrake) 
        { 
            for (int i = 0; i < 4; i++) 
            { 
                Quaternion quat; 
                Vector3 position; 
                m_WheelColliders.GetWorldPose(out position, out quat);      //获取四个轮子碰撞区的数据 
                m_WheelMeshes.transform.position = position; 
                m_WheelMeshes.transform.rotation = quat; 
            } 
 
            //clamp input values   约束各个数据的取值范围 
            steering = Mathf.Clamp(steering, -1, 1); 
            AccelInput = accel = Mathf.Clamp(accel, 0, 1); 
            BrakeInput = footbrake = -1*Mathf.Clamp(footbrake, -1, 0); 
            handbrake = Mathf.Clamp(handbrake, 0, 1); 
 
            //Set the steer on the front wheels.   设置前轮的旋转角,其中编号0和1的轮子是前轮 
            //Assuming that wheels 0 and 1 are the front wheels. 
            m_SteerAngle = steering*m_MaximumSteerAngle; 
            m_WheelColliders[0].steerAngle = m_SteerAngle; 
            m_WheelColliders[1].steerAngle = m_SteerAngle; 
 
            SteerHelper(); 
            ApplyDrive(accel, footbrake); 
            CapSpeed(); 
 
            //Set the handbrake.   设置刹车,其中编号2和3的轮子是后轮 
            //Assuming that wheels 2 and 3 are the rear wheels. 
            if (handbrake > 0f) 
            { 
                var hbTorque = handbrake*m_MaxHandbrakeTorque; 
                m_WheelColliders[2].brakeTorque = hbTorque; 
                m_WheelColliders[3].brakeTorque = hbTorque; 
            } 
 
 
            CalculateRevs(); 
            GearChanging(); 
 
            AddDownForce(); 
            CheckForWheelSpin(); 
            TractionControl(); 
        } 
 
        //速度计算 
        private void CapSpeed() 
        { 
            float speed = m_Rigidbody.velocity.magnitude; 
            switch (m_SpeedType) 
            { 
                case SpeedType.MPH: 
 
                    speed *= 2.23693629f; 
                    if (speed > m_Topspeed) 
                        m_Rigidbody.velocity = (m_Topspeed/2.23693629f) * m_Rigidbody.velocity.normalized; 
                    break; 
 
                case SpeedType.KPH: 
                    speed *= 3.6f; 
                    if (speed > m_Topspeed) 
                        m_Rigidbody.velocity = (m_Topspeed/3.6f) * m_Rigidbody.velocity.normalized; 
                    break; 
            } 
        } 
 
        //设置车的驱动类型 
        private void ApplyDrive(float accel, float footbrake) 
        { 
 
            float thrustTorque; 
            switch (m_CarDriveType) 
            { 
                case CarDriveType.FourWheelDrive: 
                    thrustTorque = accel * (m_CurrentTorque / 4f); 
                    for (int i = 0; i < 4; i++) 
                    { 
                        m_WheelColliders.motorTorque = thrustTorque; 
                    } 
                    break; 
 
                case CarDriveType.FrontWheelDrive: 
                    thrustTorque = accel * (m_CurrentTorque / 2f); 
                    m_WheelColliders[0].motorTorque = m_WheelColliders[1].motorTorque = thrustTorque; 
                    break; 
 
                case CarDriveType.RearWheelDrive: 
                    thrustTorque = accel * (m_CurrentTorque / 2f); 
                    m_WheelColliders[2].motorTorque = m_WheelColliders[3].motorTorque = thrustTorque; 
                    break; 
 
            } 
 
            for (int i = 0; i < 4; i++) 
            { 
                if (CurrentSpeed > 5 && Vector3.Angle(transform.forward, m_Rigidbody.velocity) < 50f) 
                { 
                    m_WheelColliders.brakeTorque = m_BrakeTorque*footbrake; 
                } 
                else if (footbrake > 0) 
                { 
                    m_WheelColliders.brakeTorque = 0f; 
                    m_WheelColliders.motorTorque = -m_ReverseTorque*footbrake; 
                } 
            } 
        } 
 
 
        private void SteerHelper() 
        { 
            for (int i = 0; i < 4; i++) 
            { 
                WheelHit wheelhit; 
                m_WheelColliders.GetGroundHit(out wheelhit); 
                if (wheelhit.normal == Vector3.zero) 
                    return; // wheels arent on the ground so dont realign the rigidbody velocity 
            } 
 
            // this if is needed to avoid gimbal lock problems that will make the car suddenly shift direction 
            if (Mathf.Abs(m_OldRotation - transform.eulerAngles.y) < 10f) 
            { 
                var turnadjust = (transform.eulerAngles.y - m_OldRotation) * m_SteerHelper; 
                Quaternion velRotation = Quaternion.AngleAxis(turnadjust, Vector3.up); 
                m_Rigidbody.velocity = velRotation * m_Rigidbody.velocity; 
            } 
            m_OldRotation = transform.eulerAngles.y; 
        } 
 
 
        // this is used to add more grip in relation to speed 
        private void AddDownForce() 
        { 
            m_WheelColliders[0].attachedRigidbody.AddForce(-transform.up*m_Downforce* 
                                                         m_WheelColliders[0].attachedRigidbody.velocity.magnitude); 
        } 
 
 
        // checks if the wheels are spinning and is so does three things 
        // 1) emits particles 
        // 2) plays tiure skidding sounds 
        // 3) leaves skidmarks on the ground 
        // these effects are controlled through the WheelEffects class 
        private void CheckForWheelSpin() 
        { 
            // loop through all wheels 
            for (int i = 0; i < 4; i++) 
            { 
                WheelHit wheelHit; 
                m_WheelColliders.GetGroundHit(out wheelHit); 
 
                // is the tire slipping above the given threshhold 
                if (Mathf.Abs(wheelHit.forwardSlip) >= m_SlipLimit || Mathf.Abs(wheelHit.sidewaysSlip) >= m_SlipLimit) 
                { 
                    m_WheelEffects.EmitTyreSmoke(); 
 
                    // avoiding all four tires screeching at the same time 
                    // if they do it can lead to some strange audio artefacts 
                    if (!AnySkidSoundPlaying()) 
                    { 
                        m_WheelEffects.PlayAudio(); 
                    } 
                    continue; 
                } 
 
                // if it wasnt slipping stop all the audio 
                if (m_WheelEffects.PlayingAudio) 
                { 
                    m_WheelEffects.StopAudio(); 
                } 
                // end the trail generation 
                m_WheelEffects.EndSkidTrail(); 
            } 
        } 
 
        // crude traction control that reduces the power to wheel if the car is wheel spinning too much 
        private void TractionControl() 
        { 
            WheelHit wheelHit; 
            switch (m_CarDriveType) 
            { 
                case CarDriveType.FourWheelDrive: 
                    // loop through all wheels 
                    for (int i = 0; i < 4; i++) 
                    { 
                        m_WheelColliders.GetGroundHit(out wheelHit); 
 
                        AdjustTorque(wheelHit.forwardSlip); 
                    } 
                    break; 
 
                case CarDriveType.RearWheelDrive: 
                    m_WheelColliders[2].GetGroundHit(out wheelHit); 
                    AdjustTorque(wheelHit.forwardSlip); 
 
                    m_WheelColliders[3].GetGroundHit(out wheelHit); 
                    AdjustTorque(wheelHit.forwardSlip); 
                    break; 
 
                case CarDriveType.FrontWheelDrive: 
                    m_WheelColliders[0].GetGroundHit(out wheelHit); 
                    AdjustTorque(wheelHit.forwardSlip); 
 
                    m_WheelColliders[1].GetGroundHit(out wheelHit); 
                    AdjustTorque(wheelHit.forwardSlip); 
                    break; 
            } 
        } 
 
 
        private void AdjustTorque(float forwardSlip) 
        { 
            if (forwardSlip >= m_SlipLimit && m_CurrentTorque >= 0) 
            { 
                m_CurrentTorque -= 10 * m_TractionControl; 
            } 
            else 
            { 
                m_CurrentTorque += 10 * m_TractionControl; 
                if (m_CurrentTorque > m_FullTorqueOverAllWheels) 
                { 
                    m_CurrentTorque = m_FullTorqueOverAllWheels; 
                } 
            } 
        } 
 
 
        private bool AnySkidSoundPlaying() 
        { 
            for (int i = 0; i < 4; i++) 
            { 
                if (m_WheelEffects.PlayingAudio) 
                { 
                    return true; 
                } 
            } 
            return false; 
        } 
    } 
} 
[/mw_shl_code] 
 
 |   
 
 
 
 |