一、功能描述
1、基于路线,每条路线定时生成车辆,车辆沿着路线预设好的点移动。
2、轻量级,没有使用物理系统,车辆的运动使用的API是transform.Translate()。
3、可以实现曲线路线(为了真实需要设置更多的点位)。
4、在路口可以设置通行规则,目前只实现了十字路口。
5、随机车辆类型、随机生成车辆间隔、随机初始车速。
6、没有实现上下坡,只能在同一水平面。
二、初始化场景
1、搭建场景。
2、在Hierarchy窗口创建一个空物体命名为“TrafficSystem”,在下面再创建三个空物体分布命名为CarPool、PathCollection、CrossingCollection,用来归类存放车辆预制体、行驶路线和路口。
三、行驶路线
1、新建脚本CarPathPair
using System.Collections; using System.Collections.Generic; using UnityEngine; public class CarPathPair : MonoBehaviour { public float Duration;//生成车辆的间隔 private GameObject[] CarPrefabs;//汽车预制体 private Transform spawnPoint;//生成点 private float timer;//计时器 [SerializeField] private List<Vector3> wayPoints = new List<Vector3>(); void Start() { Init(); SpawnCar(); } void Update() { timer += Time.deltaTime; if(timer >= Duration) { timer = 0; SpawnCar(); } } private void Init() { spawnPoint = transform.GetChild(0); CarPrefabs = CarPool.Instance.AllCars; for (int i=0;i<transform.childCount;i++) { wayPoints.Add(transform.GetChild(i).position); } } private void SpawnCar() { int carType = Random.Range(0, CarPrefabs.Length); GameObject tempCar = Instantiate(CarPrefabs[carType],spawnPoint.position,spawnPoint.rotation,transform); tempCar.SetActive(true); CarMovement carMove = tempCar.AddComponent<CarMovement>(); carMove.WayPoints = wayPoints; } #if UNITY_EDITOR private void OnDrawGizmosSelected() { Gizmos.color = Color.yellow; for(int i=0;i<transform.childCount-1;i++) { Gizmos.DrawLine(transform.GetChild(i).position, transform.GetChild(i+1).position); } } #endif }
2、在PathCollection下面新建空物体挂载‘CarPathPair.cs’,重命名该物体为Path1(或者其他可以区分不同路线的名字)。
3、在Path1下面相继创建空物体作为这条路线的路径点,在拐角处多放置一些可以让车辆运动平滑一些。
4、在最后一个点上添加BoxCollider,车辆再达到终点时候会自动销毁,如果不添加则会一直沿着最后的方向移动,90秒后再销毁。
四、车辆预制体
1、在CarPool下面添加自己的车辆模型,把车头方向调整为z轴方向。
2、在Project窗口中添加CarMovement脚本,脚本不需要挂载到车辆上,它在实例化车辆的时候自动添加上去。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class CarMovement : MonoBehaviour { private float carSpeed = 10f;//车速 private float initSpeed;//初始车速 private bool isWaitTraffic = false;//是否在路口等待 private float detectDis = 5.5f;//向前检测距离 public List<Vector3> WayPoints { get; set; } private int pointIndex = 1; private void Start() { initSpeed = Random.Range(15f, 20f); carSpeed = initSpeed; Destroy(gameObject, 90); } private void Update() { //SimpleMovement(); Movement(); DetectForward(); } private void ResetCarSpeed() { if(!isWaitTraffic) carSpeed += 2.5f; } //simple move 走直线 private void SimpleMovement() { transform.Translate(Vector3.forward * Time.deltaTime * carSpeed); } private void Movement() { Vector3 dir = WayPoints[pointIndex] - WayPoints[pointIndex - 1]; transform.Translate(dir.normalized * Time.deltaTime * carSpeed,Space.World); transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(dir,Vector3.up), Time.deltaTime*10); if(Vector3.SqrMagnitude(WayPoints[pointIndex]-transform.position) < 0.2f)//根据速度设置检测距离 过小会检测已经到了点位导致车辆不再转向 { pointIndex++; if(pointIndex>=WayPoints.Count) { Destroy(gameObject); } } } //向前探测 private void DetectForward() { Ray ray = new Ray(transform.position, transform.forward); RaycastHit hitInfo; if (Physics.Raycast(ray, out hitInfo, detectDis)) { switch (hitInfo.transform.tag) { case "Car": CarMovement preCar = hitInfo.transform.GetComponent<CarMovement>(); if(preCar.isWaitTraffic) { carSpeed = 0; this.isWaitTraffic = true; } else { this.carSpeed = preCar.carSpeed; preCar.ResetCarSpeed(); } preCar.ResetCarSpeed(); break; case "Traffic": isWaitTraffic = true; carSpeed = 0; break; default: Destroy(gameObject); break; } } else { isWaitTraffic = false; carSpeed = initSpeed; } } #if UNITY_EDITOR private void OnDrawGizmos() { if (Application.isPlaying) { Gizmos.DrawRay(transform.position, transform.forward * detectDis); } } #endif }
3、在Project窗口添加CarPool脚本,负责添加各种车辆模型。。
using System.Collections; using System.Collections.Generic; using UnityEngine; using DataPaddyBoot.Runtime.Singleton; public class CarPool : MonoSingletonBase<CarPool> { public GameObject[] AllCars; }
4、把上面的脚本挂载到CarPool物体上,并为AllCars拖拽赋值。
五、设置路口
1、在CrossingCollection下面新建一个空物体名称为Crossing,再在下面创建四个碰撞体(分别命名为Up/Down/Left/Right),把它们分布放在停止线上。
2、添加脚本CrossingController,挂载到Crossing上。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class CrossingController : MonoBehaviour { public float duration;//切换红绿灯间隔 private float timer = 0; private bool vertical = true; private void Update() { timer += Time.deltaTime; if(timer>=duration) { timer = 0; vertical = !vertical; if(vertical) { StartCoroutine(ChangeVCrossing()); } else { StartCoroutine(ChangeUCrossing()); } } } private IEnumerator ChangeVCrossing() { transform.Find("Up").gameObject.SetActive(true); transform.Find("Down").gameObject.SetActive(true); yield return new WaitForSeconds(1.5f); transform.Find("Left").gameObject.SetActive(false); transform.Find("Right").gameObject.SetActive(false); } private IEnumerator ChangeUCrossing() { transform.Find("Left").gameObject.SetActive(true); transform.Find("Right").gameObject.SetActive(true); yield return new WaitForSeconds(1.5f); transform.Find("Up").gameObject.SetActive(false); transform.Find("Down").gameObject.SetActive(false); } }
3、为Crossing设置切换间隔。
大哥,能给下资源么,你的untiy城市这个
我这个是公司的项目,你可以在资源商店上找类似的场景。