TaiZhouCangChu_VRanime/Assets/Script/CarScript.cs

302 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<WheelCollider>(); //空物体添加车轮碰撞组件并赋值给数组
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<Rigidbody>().centerOfMass.Set(GetComponent<Rigidbody>().centerOfMass.x, cogY, GetComponent<Rigidbody>().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<Rigidbody>().isKinematic)//是否静止
GetComponent<Rigidbody>().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<Rigidbody>().velocity;
}
else
GetComponent<Rigidbody>().isKinematic = true;
}
void UpdateWheels()
{
//给牵引力加入手刹
float handbrakeSlip = handbrake * GetComponent<Rigidbody>().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<Rigidbody>().velocity;//刚体速度
wheelRPM = velo.magnitude * 60 * 0.5f;//刚体速度向量的长度
GetComponent<Rigidbody>().angularVelocity = new Vector3(GetComponent<Rigidbody>().angularVelocity.x, 0, GetComponent<Rigidbody>().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<Rigidbody>().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<Rigidbody>().mass;
cornerSlip = Mathf.Pow(cornerAccel / maxCornerAccel, 3);
GetComponent<Rigidbody>().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);
}
}