因为项目需要,所以根据需求做了一个简单的车轮自适应代码,看着像那么回事应该就够了
这里车轮自适应是指车辆在行驶途中,为了保持车辆的平衡,车轮需要根据传感器参数设备自动调整车轮的高低。
而在Unity中,因为没有现实生活中的各种力的约束,同时为了程序的实时性和成本考虑,所以这里就只是简单的让车辆绑定了碰撞体(Collider)和刚体(Rigidbody),并且冻结了xyz轴的旋转,避免旋转带来的额外干扰,那么就不需要额外去校正车辆的平衡,只需要注重车轮对地面的接触程度就好了。
根据需求和思路创建好场景:
地形采用Unity自带的Terrain物体,刷好高度,模拟不平整地面。
车辆整个车身使用Plane模拟,Wheel是个空对象,轮胎则使用四个Sphere,这里Sphere下面还有子对象可以不用管,是用于检测碰撞的。

设置物体参数:
车辆对象需要网格碰撞体和刚体,并且刚体中需要冻结其xyz轴的旋转。

轮胎按需求给上球形碰撞体即可。

CS脚本如下:
脚本创建好后需要绑定到车辆对象(Plane)上。
using System;
using System.Collections.Generic;
using UnityEngine;
public class WheelAdaptive : MonoBehaviour
{
//车轮最小高度
public float wheelMinHeight = 0;
//车轮最大高度
public float wheelMaxHeight = 2.0f;
//车轮目标最小高度
public float wheelTargetHeight = 0.5f;
//车轮中心离地面高度
public float wheelWidth = 0.0f;
//车轮液压杆每秒移动速率
public float wheelHydraulicSpeed = 0.4f;
// 所有需要监测的车轮
List<GameObject> wheels = new List<GameObject>();
// 车轮初始位置
List<Vector3> wheelsPosition = new List<Vector3>();
// Start is called before the first frame update
void Start()
{
// 找到子对象Wheel,Wheel可以是空白对象,应用于作为所有需要监测的车轮的父对象
Transform f = transform.Find("Wheel");
if (f != null)//以下找出所有车轮对象,同时获取其初始位置
{
Transform[] tmp = f.GetComponentsInChildren<Transform>();
foreach (var child in tmp)
{
if (child.name == "Sphere (4)")
continue;
wheels.Add(child.gameObject);
wheelsPosition.Add(child.localPosition);
child.gameObject.AddComponent<WheelSelfTrans>();
}
}
}
// Update is called once per frame
void Update()
{
float length = Math.Abs(wheelMaxHeight - wheelMinHeight);//长度
float minDis = 99999;//最小的距离
float maxDis = -99999;//最大的距离
List<float> dises = new List<float>();//车轮距离地面的距离
for (int i = 0; i < wheels.Count; i++)
{
GameObject wheel = wheels[i];
RaycastHit hit; // 碰撞信息
Ray ray = new Ray(wheel.transform.position, new Vector3(0, -1, 0));// 从物体位置向前发射射线
if (Physics.Raycast(ray, out hit, length + wheelWidth, 1 << 6)) // 射线长度为length, 只判断第6个layer(地面)
{
// 如果击中物体,那么求得车轮到物体的距离
float dis = Vector3.Distance(hit.point, wheel.transform.position);
//加上偏移量
dis -= wheelWidth;
if (dis < 0.01f)
dis = 0;
if (dis > length)
dis = length;
//最大、最小值判断
minDis = Math.Min(dis, minDis);
maxDis = Math.Max(dis, maxDis);
dises.Add(dis);
}
else
{
dises.Add(length); // 没有碰到地面的情况下,认为车轮离地面距离为最大伸展距离
minDis = Math.Min(length, minDis);
maxDis = length;
}
}
float wheelPositionBias = 0;
if (maxDis + wheelTargetHeight > length)// 如果车轮离地面的高度最大误差大于车轮指定高度允许误差,那么对车轮距离做出修正
{
wheelPositionBias = maxDis + wheelTargetHeight - length;
}
else
{
wheelPositionBias = 0;
}
for (int i = 0; i < wheels.Count; i++)
{
GameObject wheel = wheels[i];
float lastY = wheel.transform.localPosition.y;
float currentY = -(wheelTargetHeight + dises[i] - wheelPositionBias);
float y = (currentY - lastY) + wheelsPosition[i].y;
// 根据y的正负来判断车轮应该上升还是下降
if(y < 0)
y = -wheelHydraulicSpeed * Math.Min(1, Time.deltaTime);
else
y = wheelHydraulicSpeed * Math.Min(1, Time.deltaTime);
wheel.transform.localPosition = new Vector3(wheelsPosition[i].x, lastY + y, wheelsPosition[i].z);
}
}
}
最终实现后运行效果图:
可以看到车轮已经有了高低差(个别车轮没有完全落地,可能是射线检测精确度不够或者计算问题,可以按实现思路改一改)。


8787

被折叠的 条评论
为什么被折叠?



