using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Linq; namespace FCG { public class TrafficCar : MonoBehaviour { public enum StatusCar { transitingNormally, waitingForAnotherVehicleToPass, stoppedAtTrafficLights, bloked, // It's on a dead end street, stand still Undefined, crashed, } [HideInInspector] public StatusCar status; public GameObject BreakLight; public GameObject LightLeft = null; public GameObject LightRight = null; private bool lightDirection = false; [HideInInspector] public Transform mRayC1; [HideInInspector] public Transform mRayC2; private Vector3 mRayCenter; [HideInInspector] public Transform[] wheel; public WheelCollider[] wCollider; private int countWays; private Transform[] nodes; [HideInInspector] public int currentNode = 0; [HideInInspector] public float distanceToNode; private float steer = 0.0f; private float speed; private float brake = 0; private float motorTorque = 0; private Vector3 steerCurAngle = Vector3.zero; private Rigidbody myRigidbody; private Vector3 relativeVector; public CarWheelsTransform wheelsTransforms; private float timeStoped; private Transform myReference; private float iRC = 0; private float brake2 = 0; [HideInInspector] public Transform atualWay; [HideInInspector] public int sideAtual = 0; [HideInInspector] public FCGWaypointsContainer atualWayScript; [HideInInspector] public bool nodeSteerCarefully = false; //true if I'm turning to the side that has opposite traffic (Right hand and turning left) Or (Left hand and turning right) [HideInInspector] public bool nodeSteerCarefully2 = false; // For double line oneway [HideInInspector] public Transform myOldWay; [HideInInspector] public int myOldSideAtual = 0; [HideInInspector] public FCGWaypointsContainer myOldWayScript = null; private Vector3 _avanceNode = Vector3.zero; //private Position where an additional and momentary node can be added private float countTimeToSignal = 0; bool toSignal = false; private bool toSignalLeft = false; private bool toSignalRight = false; private Transform behind = null; //[HideInInspector] public Transform player; //[HideInInspector] public TrafficSystem tSystem; //[HideInInspector] public float distanceToSelfDestroy = 0; //0 = Do not autodestroy with player distance [System.Serializable] public class CarWheelsTransform { public Transform frontRight; public Transform frontLeft; public Transform backRight; public Transform backLeft; public Transform backRight2; public Transform backLeft2; } public CarSetting carSetting; [System.Serializable] public class CarSetting { public Transform carSteer; [Range(10000, 60000)] public float springs = 25000.0f; [Range(1000, 6000)] public float dampers = 1500.0f; [Range(60, 200)] public float carPower = 120f; [Range(5, 10)] public float brakePower = 8f; [Range(20, 30)] public float limitSpeed = 30.0f; [Range(30, 72)] public float maxSteerAngle = 40.0f; //Maximum wheel curvature angle [Range(-1, 1)] public float curveAdjustment = 0.0f; // make tighter or more open turns } private Vector3 shiftCentre = new Vector3(0.0f, -0.05f, 0.0f); private Transform GetTransformWheel(string wheelName) { GameObject[] wt; wt = GameObject.FindObjectsOfType(typeof(GameObject)).Select(g => g as GameObject).Where(g => g.name.Equals(wheelName) && g.transform.parent.root == transform).ToArray(); if (wt.Length > 0) return wt[0].transform; else return null; } public void Configure() { if (!wheelsTransforms.frontRight) wheelsTransforms.frontRight = GetTransformWheel("FR"); if (!wheelsTransforms.frontLeft) wheelsTransforms.frontLeft = GetTransformWheel("FL"); if (!wheelsTransforms.backRight) wheelsTransforms.backRight = GetTransformWheel("BR"); if (!wheelsTransforms.backLeft) wheelsTransforms.backLeft = GetTransformWheel("BL"); if (!wheelsTransforms.backRight2) wheelsTransforms.backRight2 = transform.Find("BR2"); if (!wheelsTransforms.backLeft2) wheelsTransforms.backLeft2 = transform.Find("BL2"); if (!transform.GetComponent()) transform.gameObject.AddComponent(); if (transform.gameObject.GetComponent().mass < 4000f) transform.gameObject.GetComponent().mass = 4000f; transform.gameObject.GetComponent().interpolation = RigidbodyInterpolation.Interpolate; if (!wheelsTransforms.frontLeft || !wheelsTransforms.frontRight || !wheelsTransforms.backRight || !wheelsTransforms.backLeft) { Debug.LogError("wheelsTransforms absent in inspector"); return; } float p = wheelsTransforms.frontRight.localPosition.z + 0.6f; float l = wheelsTransforms.frontRight.localPosition.x; // Transform testC = new GameObject("RayTest").transform; testC.SetParent(transform); testC.localPosition = new Vector3(0, 0f, wheelsTransforms.frontRight.localPosition.z + 4f); testC.LookAt(transform); testC.position += new Vector3(0, 0.8f, 0); if (Physics.Raycast(testC.position, testC.forward, out RaycastHit hit, 4)) { Debug.DrawRay(testC.position, testC.forward * 4, Color.red); p = ((wheelsTransforms.frontRight.localPosition.z + 4f) - hit.distance) - 0.15f; } else { Debug.LogError("Adicione um collider e então tente novamente"); } DestroyImmediate(testC.gameObject); if (!transform.Find("RayC1")) { mRayC1 = new GameObject("RayC1").transform; mRayC1.SetParent(transform); } else if (!mRayC1) mRayC1 = transform.Find("RayC1"); mRayC1.localRotation = Quaternion.identity; mRayC1.localPosition = new Vector3(-l, 0.8f, p); if (!transform.Find("RayC2")) { mRayC2 = new GameObject("RayC2").transform; mRayC2.SetParent(transform); } else if (!mRayC1) mRayC2 = transform.Find("RayC2"); mRayC2.localRotation = Quaternion.identity; mRayC2.localPosition = new Vector3(l, 0.8f, p); carSetting.maxSteerAngle = (int)Mathf.Clamp(Vector3.Distance(wheelsTransforms.frontRight.transform.position, wheelsTransforms.backRight.transform.position) * 12, 35, 72); wheel = new Transform[4]; wCollider = new WheelCollider[4]; GameObject center = new GameObject("Center"); Vector3[] centerPos = new Vector3[4]; Vector3 nCenter = new Vector3(0, 0, 0); wheel[0] = wheelsTransforms.frontRight; wheel[1] = wheelsTransforms.frontLeft; wheel[2] = wheelsTransforms.backRight; wheel[3] = wheelsTransforms.backLeft; for (int i = 0; i < 4; i++) { wCollider[i] = SetWheelComponent(i); // Define CenterOfMass center.transform.SetParent(wheel[i].transform); center.transform.localPosition = new Vector3(0, 0, 0); center.transform.SetParent(transform); centerPos[i] = center.transform.localPosition -= new Vector3(0, wCollider[i].radius, 0); nCenter += centerPos[i]; } shiftCentre = (nCenter / 4); DestroyImmediate(center); } private WheelCollider SetWheelComponent(int w) { WheelCollider result; Transform wheelCol = transform.Find(wheel[w].name + " - WheelCollider"); if (wheelCol) try { DestroyImmediate(wheelCol.gameObject); } catch { } if (wheelCol) return wheelCol.GetComponent(); wheelCol = new GameObject(wheel[w].name + " - WheelCollider").transform; wheelCol.transform.SetParent(transform); wheelCol.transform.position = wheel[w].position; wheelCol.transform.eulerAngles = transform.eulerAngles; WheelCollider col = (WheelCollider)wheelCol.gameObject.AddComponent(typeof(WheelCollider)); result = wheelCol.GetComponent(); JointSpring js = col.suspensionSpring; js.spring = carSetting.springs; js.damper = carSetting.dampers; col.suspensionSpring = js; col.suspensionDistance = 0.05f; col.radius = (wheel[w].GetComponent().sharedMesh.bounds.size.z * wheel[w].transform.localScale.z) * 0.5f * 0.92f; col.mass = 2000; return result; } void Start() { timeStoped = Time.time; float p = wheelsTransforms.frontRight.localPosition.z + 0.6f; if (!transform.Find("RayC1")) { mRayC1 = new GameObject("RayC1").transform; mRayC1.SetParent(transform); mRayC1.localRotation = Quaternion.identity; mRayC1.localPosition = new Vector3(-0.6f, 0.5f, p); } else if (!mRayC1) mRayC1 = transform.Find("RayC1"); if (!transform.Find("RayC2")) { mRayC2 = new GameObject("RayC2").transform; mRayC2.SetParent(transform); mRayC2.localRotation = Quaternion.identity; mRayC2.localPosition = new Vector3(0.6f, 0.5f, p); } else if (!mRayC1) mRayC2 = transform.Find("RayC2"); myReference = new GameObject("myReference").transform; myReference.SetParent(transform); myReference.localPosition = new Vector3(0, 0, wheelsTransforms.frontRight.localPosition.z * 0.6f); myReference.localRotation = Quaternion.identity; if(player && !FindObjectOfType()) Debug.LogError("The Traffic System.prefab not found in the Hierarchy"); if (atualWay) Init(); } public void Init() { atualWayScript = atualWay.GetComponent(); myRigidbody = transform.GetComponent(); myRigidbody.centerOfMass = shiftCentre; DefineNewPath(); if (currentNode == 0) currentNode = 1; distanceToNode = Vector3.Distance(atualWayScript.Node(sideAtual, currentNode), myReference.position + myReference.forward * (carSetting.curveAdjustment * 0.5f)); InvokeRepeating(nameof(MoveCar), 0.02f, 0.02f); status = StatusCar.transitingNormally; lightDirection = (LightLeft && LightRight); if (BreakLight) BreakLight.SetActive(false); if (LightLeft) LightLeft.SetActive(false); if (LightRight) LightRight.SetActive(false); } public void ActivateSelfDestructWhenAwayFromThePlayer() { if (tSystem && player) { if (distanceToSelfDestroy == 0) distanceToSelfDestroy = 200; InvokeRepeating(nameof(SelfDestructWhenAwayFromThePlayer), 5f, 5f); } } public float GetSpeed() { return speed; } public bool Get_avanceNode() { return (currentNode == 0 && nodeSteerCarefully && _avanceNode != Vector3.zero); } public Vector3 GetNodePosition() { return atualWayScript.Node(sideAtual, currentNode); } bool CheckBookAllPathOptions(FCGWaypointsContainer wayScript, int side) { int total; int wSide; FCGWaypointsContainer wScript; total = (side == 0) ? wayScript.nextWay0.Length : wayScript.nextWay1.Length; for (int i = 0; i < total; i++) { if (side == 0) { wScript = wayScript.nextWay0[i]; wSide = wayScript.nextWaySide0[i]; } else { wScript = wayScript.nextWay1[i]; wSide = wayScript.nextWaySide1[i]; } if (wScript) { if ((wScript.GetNodeZeroCar(wSide) != null && wScript.GetNodeZeroCar(wSide) != transform) && wScript.GetNodeZeroOldWay(wSide) != myOldWay && (!Get_avanceNode() || !wScript.GetNodeZeroCar(wSide).GetComponent().Get_avanceNode())) return false; } else { Debug.LogWarning("wScript Error"); } } return true; } bool BookAllPathOptions(FCGWaypointsContainer wayScript, int side, bool book = true) { int total; int wSide; FCGWaypointsContainer wScript; total = (side == 0) ? wayScript.nextWay0.Length : wayScript.nextWay1.Length; for (int i = 0; i < total; i++) { if (side == 0) { wScript = wayScript.nextWay0[i]; wSide = wayScript.nextWaySide0[i]; } else { wScript = wayScript.nextWay1[i]; wSide = wayScript.nextWaySide1[i]; } if (book) { bool force = wScript.GetNodeZeroCar(wSide) && wScript.GetNodeZeroCar(wSide).GetComponent().Get_avanceNode(); if (!wScript.SetNodeZero(wSide, wayScript.transform, transform, force)) return false; } else { wScript.UnSetNodeZero(wSide, transform); } } return true; } void MoveCar() { if (status == StatusCar.bloked) return; if (lightDirection) { countTimeToSignal++; if (countTimeToSignal > 16) { countTimeToSignal = 0; toSignal = !toSignal; if (toSignalLeft) LightLeft.SetActive(toSignal); else if (toSignalRight) LightRight.SetActive(toSignal); else { LightLeft.SetActive(false); LightRight.SetActive(false); } } } speed = myRigidbody.velocity.magnitude * 3.6f; VerificaPoints(); distanceToNode = Vector3.Distance(atualWayScript.Node(sideAtual, currentNode), myReference.position + myReference.forward * (carSetting.curveAdjustment * 0.5f)); if (_avanceNode != Vector3.zero) { //Debug.DrawLine(transform.position + Vector3.up * 2f, _avanceNode + Vector3.up * 2f, Color.cyan); relativeVector = transform.InverseTransformPoint(_avanceNode); if (Vector3.Distance(_avanceNode, myReference.position) < 4) _avanceNode = Vector3.zero; } else { //Debug.DrawLine(transform.position + Vector3.up * 0.2f, atualWayScript.Node(sideAtual, currentNode, (currentNode == 0 && nodeSteerCarefully) ? 3 : 0) + Vector3.up * 0.2f, Color.cyan); relativeVector = transform.InverseTransformPoint(atualWayScript.Node(sideAtual, currentNode, (currentNode == 0 && nodeSteerCarefully) ? 3 : 0)); } steer = ((relativeVector.x / relativeVector.magnitude) * carSetting.maxSteerAngle); bool b1 = true; bool b2; iRC++; if (iRC >= 4) { iRC = 0; //nodeSteerCarefully : true if I'm turning to the side that has opposite traffic (Right hand and turning left) Or (Left hand and turning right) if (currentNode == 0) { // Decide whether I should wait for another car to pass and then proceed if (behind == null && atualWayScript.BookNodeZero(this)) { // The way I was was not oneWay, and I'm turning to the side that has opposite traffic // Decide whether I should wait for another car to pass and then proceed if ((nodeSteerCarefully && !myOldWayScript.oneway) || (nodeSteerCarefully2)) { //Reserve the node next to mine in my previous lane, so as not to come by car in the opposite direction. if (!nodeSteerCarefully2) b1 = myOldWayScript.SetNodeZero((myOldSideAtual == 1) ? 0 : 1, myOldWay, transform); b2 = CheckBookAllPathOptions(myOldWayScript, myOldSideAtual) && BookAllPathOptions(myOldWayScript, myOldSideAtual, true); brake2 = (b1 && b2) ? 0 : 4000; } else brake2 = 0; } else brake2 = 4000; } else brake2 = 0; if (speed > 2) status = StatusCar.transitingNormally; if (brake2 <= 0 || behind) brake = FixedRaycasts(); else status = StatusCar.waitingForAnotherVehicleToPass; if (speed < 2 && (status != StatusCar.stoppedAtTrafficLights || status != StatusCar.waitingForAnotherVehicleToPass)) { if (Time.time > timeStoped + 50) { Destroy(transform.gameObject); return; } } else timeStoped = Time.time; } brake = (brake2 > brake) ? brake2 : brake; if (BreakLight) BreakLight.SetActive(brake > 200); float bk = 0; if (speed > carSetting.limitSpeed) // Keep the speed at the set limit bk = Mathf.Lerp(100, 1000, (speed - carSetting.limitSpeed) / 10); if (bk > brake) brake = bk; for (int k = 0; k < 4; k++) { if (brake == 0) wCollider[k].brakeTorque = 0; else { wCollider[k].motorTorque = 0; wCollider[k].brakeTorque = carSetting.brakePower * brake; } if (k < 2) { motorTorque = Mathf.Lerp(carSetting.carPower * 30, 0, speed / carSetting.limitSpeed); wCollider[k].motorTorque = motorTorque; wCollider[k].steerAngle = steer; } wCollider[k].GetWorldPose(out Vector3 _pos, out Quaternion _rot); wheel[k].position = _pos; wheel[k].rotation = _rot; } if (wheelsTransforms.backRight2) { wheelsTransforms.backRight2.rotation = wheelsTransforms.backRight.rotation; wheelsTransforms.backLeft2.rotation = wheelsTransforms.backRight.rotation; } //steeringwheel movement if (carSetting.carSteer) carSetting.carSteer.localEulerAngles = new Vector3(steerCurAngle.x, steerCurAngle.y, steerCurAngle.z - steer); //carSetting.carSteer.localEulerAngles = new Vector3(steerCurAngle.x, steerCurAngle.y, steerCurAngle.z + ((steer / 180) * -30.0f)); } private void VerificaPoints() { if (distanceToNode < 5) { if (currentNode < countWays - 1) { currentNode++; if (currentNode == 1) { atualWayScript.UnSetNodeZero(sideAtual, transform); // Release the node so that the cars that were waiting for me to pass can proceed status = StatusCar.transitingNormally; if (nodeSteerCarefully || nodeSteerCarefully2) { myOldWayScript.UnSetNodeZero((myOldSideAtual == 1) ? 0 : 1, transform); BookAllPathOptions(myOldWayScript, myOldSideAtual, false); //Release others nodes so that the cars that were waiting for me to pass can proceed } nodeSteerCarefully = false; nodeSteerCarefully2 = false; if (lightDirection) { toSignalRight = false; toSignalLeft = false; if (LightLeft) LightLeft.SetActive(false); if (LightRight) LightRight.SetActive(false); } } } else { int t = TestWay(); //True if the chosen path was the only option bool verify = (sideAtual == 0) ? atualWayScript.nextWay0.Length == 1 : atualWayScript.nextWay1.Length == 1; myOldWay = atualWay; myOldSideAtual = sideAtual; myOldWayScript = atualWayScript; if (sideAtual == 0 && (!atualWayScript.oneway || atualWayScript.doubleLine)) { sideAtual = atualWayScript.nextWaySide0[t]; atualWayScript = atualWayScript.nextWay0[t]; } else { sideAtual = atualWayScript.nextWaySide1[t]; atualWayScript = atualWayScript.nextWay1[t]; } atualWay = atualWayScript.transform; //The road I'm on has no exit, so interdict the previous road that had only this road as an option if (verify && atualWayScript.bloked) { myOldWayScript.bloked = true; brake2 = 6000; status = StatusCar.bloked; } DefineNewPath(); currentNode = 0; float a = GetAngulo(transform, atualWayScript.Node(sideAtual, 0)); //if (myOldWayScript.oneway) if (myOldWayScript.oneway && !myOldWayScript.doubleLine) { if (myOldWayScript.doubleLine) nodeSteerCarefully2 = (myOldSideAtual == 0 && a > 20 && a < 90) || (myOldSideAtual == 1 && a < 340 && a > 270); else nodeSteerCarefully = false; } else nodeSteerCarefully = (atualWayScript.rightHand == 0 && a < 340 && a > 270) || (atualWayScript.rightHand != 0 && a > 20 && a < 90); if (lightDirection) { toSignalLeft = (a < 340 && a > 270); toSignalRight = (a > 20 && a < 90); } if (nodeSteerCarefully) { _avanceNode = myOldWayScript.AvanceNode(myOldSideAtual, myOldWayScript.waypoints.Count - 1, 7); } } } } public Transform GetBehind() { return behind; } float FixedRaycasts() { RaycastHit hit; float wdist = 6; float wdist2 = (speed < 3) ? (wdist / 1.5f) : wdist; float rStop; mRayC1.localRotation = Quaternion.Euler(0, steer, 0); mRayC2.localRotation = mRayC1.localRotation; Debug.DrawRay((mRayC1.position + mRayC2.position) * 0.5f, mRayC1.forward * wdist2, Color.yellow); Debug.DrawRay(mRayC1.position, mRayC1.forward * wdist2, Color.yellow); Debug.DrawRay(mRayC2.position, mRayC2.forward * wdist2, Color.yellow); if (Physics.Raycast((mRayC1.position + mRayC2.position) * 0.5f, mRayC1.forward, out hit, wdist2)) { Debug.DrawRay((mRayC1.position + mRayC2.position) * 0.5f, mRayC1.forward * wdist2, Color.red); rStop = hit.distance; } else if (Physics.Raycast(mRayC1.position, mRayC1.forward, out hit, wdist2)) { Debug.DrawRay(mRayC1.position, mRayC1.forward * wdist2, Color.red); rStop = hit.distance; } else if (Physics.Raycast(mRayC2.position, mRayC2.forward, out hit, wdist2)) { Debug.DrawRay(mRayC2.position, mRayC2.forward * wdist2, Color.red); rStop = hit.distance; } else rStop = 0; behind = (rStop == 0) ? null : hit.transform; if (rStop > 0 && speed < 2) { if (status == StatusCar.stoppedAtTrafficLights || status == StatusCar.waitingForAnotherVehicleToPass || status == StatusCar.Undefined) { } else if (hit.transform.name == "Stop") status = StatusCar.stoppedAtTrafficLights; else if (hit.transform.GetComponent()) { StatusCar st = hit.transform.GetComponent().status; status = (st == StatusCar.stoppedAtTrafficLights || st == StatusCar.waitingForAnotherVehicleToPass) ? st : StatusCar.Undefined; } } if (rStop == 0) return 0; else return (rStop < 1 || speed < 0.5f) ? 20000 : (speed * 6) * ((wdist / rStop) * 6); } void DefineNewPath() { nodes = new Transform[atualWay.childCount]; int n = 0; foreach (Transform child in atualWay) nodes[n++] = child; countWays = nodes.Length; } int TestWay() { //Check if the path drawn for me is a good option (based on traffic) "VerifyTraffic" //Also check if the selected path has been blocked "CheckStoped" int total = 0; if (sideAtual == 0) total = atualWayScript.nextWay0.Length; else total = atualWayScript.nextWay1.Length; int t = Random.Range(0, total); // Sort one of the available paths if (total > 1) // If there are more path options to choose from { if (CheckStoped(t) || VerifyTraffic(t, 30) < 30 || VerifyNodeSteerCarefully2(t)) { //Test the paths to see which option is best float maior = 0; for (int i = 0; i < total; i++) { if (!CheckStoped(i)) // && !VerifyNodeSteerCarefully2(i)) { float vf = VerifyTraffic(i, 30); if (vf == 30) return i; else if (vf < 30) { if (vf > maior) { maior = vf; t = i; } } } } } } return t; } private Vector3 GetNodeNextWay(int way, int node = 0) { /* Returns the position of the specified node, from a chosen path that is among the available paths (vlinked to my current path) */ if (sideAtual == 0) return atualWayScript.nextWay0[way].Node(atualWayScript.nextWaySide0[way], node); else return atualWayScript.nextWay1[way].Node(atualWayScript.nextWaySide1[way], node); } private bool CheckStoped(int way) { //Checks if a path is blocked (due to no exit or other reason) if (sideAtual == 0) return atualWayScript.nextWay0[way].bloked; else return atualWayScript.nextWay1[way].bloked; } /* bool VerifyDoubleOneWayOption(int t) { //Vector3 node0 = GetNodeNextWay(t, 0); //nodeSteerCarefully2 = (myOldSideAtual == 0 && a > 20 && a < 90) || (myOldSideAtual == 1 && a < 340 && a > 270); return true; } */ bool VerifyNodeSteerCarefully2(int t) { if (atualWayScript.oneway && atualWayScript.doubleLine) { float a = GetAngulo(transform, GetNodeNextWay(t, 0)); return (sideAtual == 0 && a > 20 && a < 90) || (sideAtual == 1 && a < 340 && a > 270); } return false; } float VerifyTraffic(int t, float mts = 12) { //Checks if the specified path is a good choice, it may be congested RaycastHit hit2; Vector3 node0 = GetNodeNextWay(t, 0) + new Vector3(0, 0.5f, 0); Vector3 node1 = GetNodeNextWay(t, 1) + new Vector3(0, 0.5f, 0); if (Physics.Raycast(node0, node1 - node0, out hit2, mts)) if (hit2.transform.GetComponent()) { if (hit2.transform.GetComponent().GetSpeed() < 8) return hit2.distance; else return mts - 1; } return mts; } private void Pause(Vector3 position) { #if UNITY_EDITOR if (GameObject.Find("CubePause")) { GameObject.Find("CubePause").transform.position = position; UnityEditor.EditorApplication.isPaused = true; } #endif } private int countC = 0; void SelfDestructWhenAwayFromThePlayer() { if (speed < 2 && status != StatusCar.stoppedAtTrafficLights && (Time.time > timeStoped + 30) & InTheFieldOfVision(transform.position, player)) { tSystem.nVehicles--; Destroy(this.gameObject); } else if (Vector3.Distance(transform.position, player.position) < distanceToSelfDestroy || InTheFieldOfVision(transform.position, player)) countC = 0; else { countC++; if (countC >= 2) { tSystem.nVehicles--; Destroy(this.gameObject); } } } public void SelfDestructWhenAwayFromThePlayerInit() { if (tSystem && player) if (Vector3.Distance(transform.position, player.position) > distanceToSelfDestroy && !InTheFieldOfVision(transform.position, player)) { tSystem.nVehicles--; Destroy(this.gameObject); } else ActivateSelfDestructWhenAwayFromThePlayer(); } bool InTheFieldOfVision(Vector3 source, Transform target) { // the IACar wants to disappear without it being seen by the camera/player RaycastHit obsRay2; if (Physics.Linecast(source + Vector3.up * 1f, target.position + Vector3.up * 1f, out obsRay2)) //, ~(1 << LayerMask.NameToLayer("Lattice")))) { if (obsRay2.transform == target || obsRay2.transform.root == target) { //Debug.DrawLine(source, target.position, Color.red); return true; } else { //Debug.DrawLine(source, target.position, Color.green); return false; } } else { //Debug.DrawLine(source, target.position, Color.blue); return true; } } private float GetAngulo(Transform origem, Vector3 target) { float r; GameObject compass = new GameObject("Compass"); compass.transform.parent = origem; compass.transform.localPosition = new Vector3(0, 0, 0); compass.transform.LookAt(target); r = compass.transform.localEulerAngles.y; DestroyImmediate(compass); return r; } } }