项目实训(八)——汽车路线规划和自动行驶脚本的编写与添加(二)

本文详细介绍了针对不同交通工具(火车、道路车辆、船舶和飞机)的Unity脚本编写,包括最大速度、加速度、路径寻路等关键功能。对于火车,脚本涉及检查站路径规划;对于道路车辆,实现了随机目的地寻路和闭合循环路径;船舶和飞机则沿预设路径行驶。此外,还展示了CarBehavior和PlaneBehavior类的实现,涉及交通灯、交叉口和飞机路径控制等交互逻辑。
摘要由CSDN通过智能技术生成

一、前言

在编写车辆寻路以及道路类型的相关脚本后,我对交通工具比如道路车辆、船舶、飞机等的具体控制脚本也进行了编写和完善。

二、编写的脚本模块和功能的简单介绍

1.Trains

机车和所有货车的tag都设置为“Train”。
Wagons
火车可以有从零到64节车厢。每个wagon游戏对象必须附有引用box collider的wagon脚本和Box collider必须设置为匹配网格的长度)。
Max speed
确定机车可以达到的最大速度(以km/h为单位)。
Acceleration
火车的加速度。
Checkpoints
检查站是场景中各地的位置,pathfinder通过它尝试为火车找到一条路径。
火车开始行驶时尝试找到通往第一个检查站的路径。当火车到达终点时,它会通过相同的检查站返回。

2.Road Vehicles

Road Vehicles
每辆车都有PathFinding和CarBehavior脚本,以及设置为kinematic和gravity关闭的刚体组件。box collider设置为在车辆前方触发,以检测前方的车辆/交通灯/人行横道。
脚本和碰撞器所连接的游戏对象的tag必须设置为Car。
Random destination
启用时,从当前位置查找到随机可访问tile的路径。禁用时,通过设置检查点查找路径。
Closed Circuit
仅在“随机目标”处于禁用状态时可见。如果为true,则从检查点创建的路径共享开始和结束。如果为false,则路径通过检查点。当车辆到达终点时,它会通过相同的检查点返回。
Max speed
车辆的最高速度。
Checkpoints
仅在“随机目标”处于禁用状态时可见。检查站是pathfinder尝试为车辆找到路径的场景位置。在开始时,它最先尝试寻找到达第一个检查点的路径。

3.Ships

Ships
船只不会沿着pathfinder创造的路径前进,而是沿着预定的路径前进。
Trajectory
船将要走的路径。
Max speed
确定船舶可以达到的最大速度(以km/h为单位)。
Acceleration
船的加速度。
Ship Tipping
船可以倾斜的最大角度(以度为单位)。

4.Planes

Planes
飞机和船一样,不会沿着pathfinder创建的路径飞行,而是沿着预定的路径飞行。
Trajectory
飞机将沿着这个路径飞行。当它到达路径的终点时,它将从起点继续。
Max speed
确定飞机可以达到的最大速度(以km/h为单位)。
Acceleration
飞机的加速度。

三、主要脚本编写

CarBehavior

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace PolyPerfect.City
{
    [RequireComponent(typeof(PathFinding)),RequireComponent(typeof(Rigidbody))]
    public class CarBehavior : MonoBehaviour
    {
        //[HideInInspector]
        public List<Path> trajectory = new List<Path>();
        public bool randomDestination = true;
        public bool closedCircuit = false;
        private PathFinding pathFinding;
        public float minDistance = 90f;
        public float maxspeed = 5.0f;
        public float acceleration = 0.5f;
        private const float KMHTOMS = 0.27777f;
        private float currentMaxSpeed;
        [HideInInspector]
        public float speed;
        int activepoint = 0;
        bool isMoving = false;
        bool drivingBihindCar = false;
        bool drivingTrafficLights = false;
        int activePath = 0;
        int randomPathTries = 10;
        private Vector3 targetDrivePoint;
        private Vector3 destination;
        public List<Vector3> checkpoints = new List<Vector3>();
        private Vector3 start;
        private CarBehavior carInFront;
        private void Awake()
        {
            pathFinding = GetComponent<PathFinding>();
        }

        void Start()
        {
            currentMaxSpeed = maxspeed;
            if(closedCircuit)
                checkpoints.Add(checkpoints[0]);
            StartDriving();
        }
        //Gets next target point of the trajectory
        public void MoveToNextPoint()
        {
            if (activePath == trajectory.Count - 1)
            {
                if (activepoint == trajectory[activePath].pathPositions.Count - 1)
                {
                    isMoving = false;
                    if(randomDestination)
                        StartDriving();
                    else
                    {
                        if(!closedCircuit)
                            checkpoints.Reverse();
                        trajectory = pathFinding.GetPathWithCheckpoints(checkpoints, PathType.Road);
                        if (trajectory != null)
                        {
                            trajectory.RemoveAt(trajectory.Count - 1);
                            activePath = 0;
                            activepoint = 0;
                            speed = 0;
                            isMoving = true;
                        }
                        else
                            return;
                    }
                }
                else
                {
                    activepoint++;
                }
            }
            else
            {
                if (activepoint == trajectory[activePath].pathPositions.Count - 1)
                {
                    activePath++;
                    if (trajectory[activePath].speed < maxspeed)
                    {
                        currentMaxSpeed = trajectory[activePath].speed;
                    }
                    else
                    {
                        currentMaxSpeed = maxspeed;
                    }
                       
                    activepoint = 1;
                }
                else
                {
                    activepoint++;
                }
            }
            if (trajectory != null)
            {
                if (trajectory.Count > activePath)
                    targetDrivePoint = trajectory[activePath].pathPositions[activepoint].transform.position;
            }

        }

        private void StartDriving()
        {
            if (randomDestination)
            {
                //Selects random tile which is at least minDistance away 
                start = transform.position;
                destination = start;
                int tries = 0;
                randomPathTries--;
                while (Vector3.Distance(start, destination) < minDistance && tries < Tile.tiles.Count)
                {
                    tries++;
                    Tile t = Tile.tiles[UnityEngine.Random.Range(0, Tile.tiles.Count - 1)];
                    if (t.tileType == Tile.TileType.Road || t.tileType == Tile.TileType.RoadAndRail)
                    {
                        if (t.verticalType == Tile.VerticalType.Bridge)
                        {
                            destination = t.transform.position + (Vector3.up * 12);
                        }
                        else
                        {
                            destination = t.transform.position;
                        }
                    }
                }
                if(tries == Tile.tiles.Count)
                {
                    Debug.Log(name + ": Path not found");
                    return;
                }
            }
            else
            {
                //Destination of the first checkpoint
                destination = checkpoints[0];
                start = transform.position;
            }
            //Pathfinder finds best path
            trajectory = pathFinding.GetPath(start,destination, PathType.Road);
            if (trajectory != null)
            {
                speed = 0;
                activePath = 0;
                activepoint = 0;
                float closest = float.MaxValue;
                for(int i = 0;i <trajectory[0].pathPositions.Count;i++)
                {
                    float tmp = Vector3.Distance(trajectory[0].pathPositions[i].position, transform.position);
                    if(tmp < closest)
                    {
                        closest = tmp;
                        activepoint = i;
                    }
                }
                targetDrivePoint = trajectory[0].pathPositions[activepoint].transform.position;
                isMoving = true;
                if(!closedCircuit)
                    checkpoints.Reverse();
            }
            else
            {
                Debug.Log(name + ": Path not found");
                if(randomDestination && randomPathTries>0)
                {
                    StartDriving();
                }
            }
        }


        void FixedUpdate()
        {
            if (isMoving && trajectory != null)
            {
                //Calculate remaing distance to current checkpoint and direction to it
                float pointDistance = Vector2.Distance(new Vector2(transform.position.x, transform.position.z), new Vector2(targetDrivePoint.x, targetDrivePoint.z));
                Vector3 direction = targetDrivePoint - transform.position;

                //If car reaches target it gets the next target
                if (pointDistance < 0.02f*speed)
                {
                    MoveToNextPoint();
                }
                if (!drivingBihindCar)
                {
                    speed = Mathf.Lerp(speed, maxspeed, acceleration * Time.deltaTime);
                }
                else
                {
                    if(carInFront.speed < speed)
                        speed = speed - carInFront.speed;
                }
                if (speed > currentMaxSpeed)
                {
                    speed = Mathf.Lerp(speed, currentMaxSpeed, 10 * Time.deltaTime);
                }

                Vector3 newPosition = transform.position + (direction.normalized * speed * KMHTOMS * Time.deltaTime);
                transform.position = newPosition;

                if(direction != Vector3.zero)
                    transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.LookRotation(direction, Vector3.up), maxspeed * Time.deltaTime *15);
            }
            else
            {
                speed = 0;
            }
        }

        private void OnTriggerEnter(Collider other)
        {
            if (other.CompareTag("TrafficLight") && !drivingTrafficLights )
            {
                TrafficLight trafic = other.GetComponent<TrafficLight>();
                if (Vector3.Angle(-trafic.transform.forward,transform.forward) < 25)
                {
                    if (!trafic.isGreen)
                    {
                        drivingTrafficLights = true;
                        isMoving = false;
                        trafic.lightChange += StartMoving;
                    }
                }
            }
            if (other.CompareTag("Crosswalk"))
            {
                Crosswalk crosswalk = other.GetComponent<Crosswalk>();
                if (crosswalk.PedestriansAreCrossing)
                {
                    crosswalk.stateChange += CrosswalkChange;
                    isMoving = false;
                }

            }
            else if (other.CompareTag("LevelCrossing"))
            {
                LevelCrossingController levelCrossing = other.GetComponent<LevelCrossingController>();
                if (levelCrossing.trainCrossing)
                {
                    levelCrossing.stateChange += LevelCrossingChange;
                    isMoving = false;
                }

            }
            else if (other.CompareTag("Car") && !other.isTrigger && activePath >1)
            {
                float direction = Vector3.Angle(transform.forward, other.transform.forward);
                float carDirection = Vector3.Angle(transform.right, (other.transform.position - transform.position).normalized);
                if (direction < 50)
                {
                    drivingBihindCar = true;
                    carInFront = other.GetComponentInParent<CarBehavior>();
                    speed = carInFront.speed *0.8f;
                }
               if (direction > 40 && carDirection < 80 && carDirection > 45)
                {
                    isMoving = false;
                }

            }
        }

        private void OnTriggerExit(Collider other)
        {
            if (other.CompareTag("Car") && !other.isTrigger)
            {
                StopCoroutine(StartMovingAfterWait(0.2f));
                StartCoroutine(StartMovingAfterWait(0.2f));
                drivingBihindCar = false;
            }
            else if (other.CompareTag("TrafficLight"))
            {
                TrafficLight trafic = other.GetComponent<TrafficLight>();
                trafic.lightChange -= StartMoving;
                drivingTrafficLights = false;
            }
            else if (other.CompareTag("Crosswalk"))
            {
                other.GetComponent<Crosswalk>().stateChange -= CrosswalkChange;
            }
            else if (other.CompareTag("LevelCrossing"))
            {
                other.GetComponent<LevelCrossingController>().stateChange -= LevelCrossingChange;
            }
        }
        void StartMoving(bool isGreen)
        {
            if (isGreen)
            {
                drivingTrafficLights = false;
                isMoving = true;
            }
        }
        void CrosswalkChange(bool crossing)
        {
            if (!crossing && !drivingTrafficLights)
            {
                isMoving = true;
            }
        }
        void LevelCrossingChange(bool crossing)
        {
            if (!crossing)
            {
                isMoving = true;
            }
        }

        IEnumerator StartMovingAfterWait(float seconds)
        {
            yield return new WaitForSeconds(seconds);
            isMoving = true;
        }

    }
}

PlaneBehavior

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


namespace PolyPerfect.City
{
    public class PlaneBehavior : MonoBehaviour
    {

        public Path trajectory;
        public float maxspeed = 5.0f;
        private const float KMHTOMS = 0.27777f;
        private float currentMaxSpeed;
        [HideInInspector]
        public float speed;
        [Range(0f, 1f)]
        public float acceleration;
        [Range(0f, 5f)]
        public float brakePower;
        int activepoint = 0;
        private Vector3 targetDrivePoint;
        private bool isMoving;
        

        // Start is called before the first frame update
        void Start()
        {
            targetDrivePoint = trajectory.pathPositions[activepoint].position;
            isMoving = true;
            currentMaxSpeed = maxspeed;
        }

        private void FixedUpdate()
        {
            if (isMoving)
            {
                if (Vector3.Dot(targetDrivePoint - transform.position, transform.forward) < 0 && Vector3.Distance(targetDrivePoint, transform.position) < 20)
                {
                    MoveToNextPoint();
                }
                Vector3 direction = targetDrivePoint - transform.position;

                if(transform.position.y < 150 && activepoint > 5 && transform.position.y > 20)
                {
                    currentMaxSpeed = maxspeed * (transform.position.y) * 0.0075f;
                }
                else if(activepoint == trajectory.pathPositions.Count-1)
                {
                    currentMaxSpeed = 50;
                }

                if (speed < currentMaxSpeed)
                {
                    speed += ((maxspeed * Mathf.Cos((speed / maxspeed) * 0.5f * Mathf.PI)) * Time.deltaTime) * acceleration;
                }
                else
                {
                    speed = Mathf.Lerp(speed, currentMaxSpeed, brakePower * Time.deltaTime);
                }



               // if (direction != Vector3.zero)
               // {
                    
                    direction = direction.normalized;
                float angle = Vector3.SignedAngle(transform.forward, direction, transform.up);
                    //direction.y = speed / maxspeed * shipTipping;
                    if (activepoint == 0)
                    {
                        transform.rotation = Quaternion.LookRotation(direction, Vector3.up);
                    }
                    else
                        transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.LookRotation(direction, Quaternion.AngleAxis(-(angle > 10 ? angle : 0f), transform.forward) * Vector3.up), 1.75f);
                if(transform.localRotation.eulerAngles.x < 180)
                {
                    transform.GetChild(0).localRotation = Quaternion.Euler(-transform.localRotation.eulerAngles.x*1.5f,0f,0f);
                }
                else
                    transform.GetChild(0).localRotation = Quaternion.identity;
                //  }
                direction = transform.forward;
                Vector3 newPosition = transform.position + (direction * speed * KMHTOMS * Time.deltaTime);
                transform.position = newPosition;
            }
            else
            {
                speed = 0;
            }

        }
        public void MoveToNextPoint()
        {
            if (activepoint == trajectory.pathPositions.Count - 1)
            {
                activepoint = 0;
                currentMaxSpeed = maxspeed;
                speed = 0;
            }
            else
            {
                activepoint++;
            }
            targetDrivePoint = trajectory.pathPositions[activepoint].transform.position;
        }

    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LiuFangdi145

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值