using UnityEngine; using System.Collections; public class CarScript : MonoBehaviour { public float maxCornerAccel = 10; //最大转角加速度 public float maxBrakeAccel = 10;//最大制动加速度 public float cogY;//重心的高度,影响倾斜 public int minRPM = 700; //发动机最小转速,最大转速 public int maxRPM = 6000; public int maxTorque = 300;//最大扭矩 public int shiftDownRPM = 2000; //自动降档的转速 public int shiftUpRPM = 3000;//自动升档的转速 float[] gearRatios; //齿轮比 float finalDriveRatio = 3.4f;//最终转动比 //基础的手动调节器 //1.0 转向不足 //0.0 转向过度 float handlingTendency = 0.7f;//处理趋势 public Transform wheelFR; public Transform wheelFL; public Transform wheelBR; public Transform wheelBL; public float suspensionDistance = 0.3f; //悬挂高度 int springs = 1000; //弹簧 int dampers = 200; //减震 public float[] wheelRadius; public bool queryUserInput; //是否允许用户控制 public float engineRPM;//发动机转速 float steerVelo;//转向速度 //获取用户输入 public float brake; //制动 public float handbrake;//手刹 public float steer;//转向 public float motor;//动力 public float Engine; public bool onGround;//是否在地面上 private float cornerSlip;//转弯滑行 private float driveSlip;//驾驶滑行 private float wheelRPM;//车轮转速 public int gear; //档位 private WheelData[] wheels; private float wheelY;//车轮高度,车轮模型Y初始值 private float rev; Vector3 tempPos; public bool ifStop; public Vector3 speed; float torqueCurve; void SetEnableUserInput() //允许用户控制 { queryUserInput = true; } class WheelData { public float rotation;//旋转 public WheelCollider coll; //车轮碰撞 public Transform graphic; //车轮模型transform public float maxSteerAngle;//最大转向角 public bool powered = false; //是否为驱动轮 public bool handbraked = false; //是否手刹 public Quaternion originalRotation; //初始旋转参数 } void Start()//创建车轮数据数组 { gearRatios = new float[4] { 1, 0, -1.2f, -2 };//齿轮比初始化 wheels = new WheelData[4];//4个车轮数据 for (int i = 0; i < 4; i++) wheels[i] = new WheelData(); wheels[0].graphic = wheelFL; //车轮模型 wheels[1].graphic = wheelFR; wheels[2].graphic = wheelBL; wheels[3].graphic = wheelBR; wheels[2].maxSteerAngle = 45; //两前轮最大转向角度 wheels[3].maxSteerAngle = 45; wheels[2].powered = true; //后轮驱动 wheels[3].powered = true; wheels[0].handbraked = true; wheels[1].handbraked = true; wheels[2].handbraked = true; //四轮可手刹 wheels[3].handbraked = true; for (int i = 0; i < 4; i++) { if (wheels[i].graphic == null) //车轮模型为空 Debug.Log("You need to assign all four wheels for the car script!"); if (!wheels[i].graphic.transform.IsChildOf(transform))//车轮必须为当前脚本车体子物体 Debug.Log("Wheels need to be children of the Object with the car script"); wheels[i].originalRotation = wheels[i].graphic.localRotation;//初始旋转参数为运行前的状态 //创建空物体 GameObject colliderObject = new GameObject("WheelCollider"); colliderObject.transform.parent = transform;//为车体的子物体,不是车轮 colliderObject.transform.position = wheels[i].graphic.position; //空物体位置=车轮位置 wheels[i].coll = colliderObject.AddComponent(); //空物体添加车轮碰撞组件并赋值给数组 wheels[i].coll.suspensionDistance = suspensionDistance; //车轮碰撞的悬挂高度 JointSpring js = new JointSpring();//新建关节弹簧 js.spring = springs;//弹簧 js.damper = dampers;//减震 wheels[i].coll.suspensionSpring = js;//碰撞体的弹簧赋值 wheels[i].coll.radius = wheelRadius[i];//车轮半径 } wheelY = wheels[0].graphic.localPosition.y; //刚体重心设置,高度 GetComponent().centerOfMass.Set(GetComponent().centerOfMass.x, cogY, GetComponent().centerOfMass.z); float x = (1 * (engineRPM / maxRPM) - 1); //返回基本的扭矩曲线float x = (2 * (engineRPM / maxRPM) - 1); torqueCurve = 0.5f * (-x * x + 2); } void FixedUpdate() { if (!ifStop) { if (GetComponent().isKinematic)//是否静止 GetComponent().isKinematic = false; if (queryUserInput) { brake = Mathf.Clamp01(Input.GetAxis("Vertical"));//限制在0-1,上下方向 handbrake = Input.GetButton("Jump") ? 3 : 0; steer = -Input.GetAxis("Horizontal");//水平方向,转向 motor = Mathf.Clamp01(-Input.GetAxis("Vertical"));//动力 } else { //motor = 0; //steer = 0; //brake = 0; //handbrake = 0; } //如果汽车在接触地面则处理物理,否则只计算动力 if (onGround) HandlePhysics(); else CalcEngine(); UpdateWheels();//更新车轮数据 speed = GetComponent().velocity; } else GetComponent().isKinematic = true; } void UpdateWheels() { //给牵引力加入手刹 float handbrakeSlip = handbrake * GetComponent().velocity.magnitude * 0.1f; if (handbrakeSlip > 1) handbrakeSlip = 1; float totalSlip = 0; onGround = false;//初始为悬空状态 for (int i = 0; i < 4; i++) { //rotate wheel wheels[i].rotation += wheelRPM / 60 * rev * 360 * Time.fixedDeltaTime; //计算车轮旋转角 wheels[i].rotation = Mathf.Repeat(wheels[i].rotation, 360);//限定取值范围值360之间,赋值到车轮模型上 wheels[i].graphic.localRotation = Quaternion.Euler(wheels[i].rotation, wheels[i].maxSteerAngle * steer, 0) * wheels[i].originalRotation; //检查是否悬空 if (wheels[i].coll.isGrounded) onGround = true; float slip = cornerSlip + (wheels[i].powered ? driveSlip : 0f) + (wheels[i].handbraked ? handbrakeSlip : 0f); totalSlip += slip; WheelHit hit; WheelCollider c; c = wheels[i].coll; if (c.GetGroundHit(out hit))//车轮与地面射线检测 { //如果车轮碰到地面,将反馈给弹簧 tempPos = new Vector3(wheels[i].graphic.transform .position .x , hit .point .y + wheels[i].coll.radius, wheels[i].graphic.transform.position.z); wheels[i].graphic.transform .position = tempPos; } } totalSlip = totalSlip / wheels.Length; } //void AutomaticTransmission()//自动换挡 //{ // if (gear > 0) // { // if (engineRPM > shiftUpRPM && gear < gearRatios.Length - 1) // gear++; // if (engineRPM < shiftDownRPM && gear > 1) // gear--; // } //} float CalcEngine() //根据当前转速计算加速度 { if (brake + handbrake > 0.1)//刹车时没有动力 motor = 0; //如果悬空 if (!onGround) { engineRPM += (motor - 0.3f) * 2500 * Time.deltaTime;//engineRPM += (motor - 0.3f) * 2500 * Time.deltaTime; engineRPM = Mathf.Clamp(engineRPM, minRPM, maxRPM); return 0; } else { //AutomaticTransmission(); engineRPM = wheelRPM * gearRatios[gear] * finalDriveRatio; if (steer != 0) engineRPM = engineRPM * 0.5f; if (engineRPM < minRPM) engineRPM = minRPM; if (engineRPM < maxRPM) { float torqueToForceRatio = gearRatios[gear] * finalDriveRatio*0.5f / wheelRadius[2]; Debug.Log(motor + "," + maxTorque + ',' + torqueCurve + ',' + torqueToForceRatio); return motor * maxTorque * torqueCurve * torqueToForceRatio; } else return 0; } } void HandlePhysics()//物理处理 { Vector3 velo = GetComponent().velocity;//刚体速度 wheelRPM = velo.magnitude * 60 * 0.5f;//刚体速度向量的长度 GetComponent().angularVelocity = new Vector3(GetComponent().angularVelocity.x, 0, GetComponent().angularVelocity.z);//刚体Y向的角速度向量为0 Vector3 dir = transform.TransformDirection(Vector3.forward);//行驶方向 Vector3 flatDir = Vector3.Normalize(new Vector3(dir.x, 0, dir.z));//Y为0,成平地上的目标 Vector3 flatVelo = new Vector3(velo.x, 0, velo.z);//平地上的速度 rev = Mathf.Sign(Vector3.Dot(flatVelo, flatDir));//返回1或-1 //当向后或刹车时转换到反方向 if ((rev < 0 || flatVelo.sqrMagnitude < 0.5) && brake > 0.1) gear = 0; if (gear == 0) { //反向时翻转力 float tmp = brake; brake = motor; motor = tmp; //切换到驾驶 if ((rev > 0 || flatVelo.sqrMagnitude < 0.5) && brake > 0.1) gear = 1; } Engine =CalcEngine(); Vector3 engineForce = flatDir * Engine; float totalbrake = brake + handbrake * 0.5f; if (totalbrake > 1.0) totalbrake = 1; Vector3 brakeForce = -flatVelo.normalized * totalbrake * GetComponent().mass * maxBrakeAccel; flatDir *= flatVelo.magnitude; flatDir = Quaternion.AngleAxis(steer * 30, Vector3.up) * flatDir; flatDir *= rev; float diff = (flatVelo - flatDir).magnitude; float cornerAccel = maxCornerAccel; if (cornerAccel > diff) cornerAccel = diff; Vector3 cornerForce = -(flatVelo - flatDir).normalized * cornerAccel * GetComponent().mass; cornerSlip = Mathf.Pow(cornerAccel / maxCornerAccel, 3); GetComponent().AddForceAtPosition(brakeForce + engineForce + cornerForce, transform.position + transform.up * wheelY); float handbrakeFactor = 1 + handbrake * 4; if (rev < 0) handbrakeFactor = 1; float veloSteer = ((15 / (2 * velo.magnitude + 1)) + 1) * handbrakeFactor; float steerGrip = (1 - handlingTendency * cornerSlip); if (rev * steer * steerVelo < 0) steerGrip = 1; float maxRotSteer = 2 * Time.fixedDeltaTime * handbrakeFactor * steerGrip; float fVelo = velo.magnitude; float veloFactor = fVelo < 1 ? fVelo : Mathf.Pow(velo.magnitude, 0.3f); float steerVeloInput = rev * steer * veloFactor * 0.5f * Time.fixedDeltaTime * handbrakeFactor; if (velo.magnitude < 0.1) steerVeloInput = 0; if (steerVeloInput > steerVelo) { steerVelo += 0.02f * Time.fixedDeltaTime * veloSteer; if (steerVeloInput < steerVelo) steerVelo = steerVeloInput; } else { steerVelo -= 0.02f * Time.fixedDeltaTime * veloSteer; if (steerVeloInput > steerVelo) steerVelo = steerVeloInput; } steerVelo = Mathf.Clamp(steerVelo, -maxRotSteer, maxRotSteer); transform.Rotate(Vector3.up * steerVelo * 57.295788f); } }