Unity3D 车轮自适应车辆平衡

因为项目需要,所以根据需求做了一个简单的车轮自适应代码,看着像那么回事应该就够了

这里车轮自适应是指车辆在行驶途中,为了保持车辆的平衡,车轮需要根据传感器参数设备自动调整车轮的高低。

而在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);
            }
        }  
}

最终实现后运行效果图:

可以看到车轮已经有了高低差(个别车轮没有完全落地,可能是射线检测精确度不够或者计算问题,可以按实现思路改一改)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值