using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using Pools; using Roads; using UnityEditor; using UnityEngine; using Valve.VR.InteractionSystem; namespace Routes { public enum TriggerState { Inside, Outside, } public enum RoadDirection { West, North, East, South, None } public class RoadDirectionHelper { public static RoadDirection OppositeOf(RoadDirection direction) { switch (direction) { case RoadDirection.West: return RoadDirection.East; case RoadDirection.North: return RoadDirection.South; case RoadDirection.East: return RoadDirection.West; case RoadDirection.South: return RoadDirection.North; case RoadDirection.None: return RoadDirection.None; default: throw new ArgumentOutOfRangeException(nameof(direction), direction, null); } } } public enum TurnDirection { Right, Left, Straight } public abstract class Turn : MonoBehaviour, IRoad { public RoadDirection comingFrom; public RoadDirection goingTo; [CanBeNull] private Pool arrowPool; private bool arrowPoolAvailable; private TurnDirection turnDirection; private List usedArrows = new List(); private Collider trigger; private static readonly RoadDirection[] allDirections = {RoadDirection.West, RoadDirection.North, RoadDirection.East, RoadDirection.South}; public Action OnTriggerExitBicycle { get; set; } public TriggerState BikeTriggerState { get; private set; } = TriggerState.Outside; public float SlopeDeg { get; private set; } public float MinY { get; private set; } private void Awake() { arrowPool = FindObjectsOfType().FirstOrDefault(o => o.CompareTag("ArrowPool")); arrowPoolAvailable = arrowPool != null; trigger = GetComponent(); if (!arrowPoolAvailable) Debug.LogWarning("Arrow Pool not found"); } private void Start() { SlopeDeg = transform.localRotation.eulerAngles.z; MinY = GetComponent().bounds.center.y; UpdateArrows(); } [CanBeNull] protected abstract Transform RoadDirectionToTransform(RoadDirection position); private bool AddArrows(RoadDirection position, GameObject arrows) { //Debug.Log($"---{gameObject.name}--- adding arrows at {position}"); var t = RoadDirectionToTransform(position); if (t == null) return false; //Debug.Log($" Transform for position => {t.gameObject.name}"); SetRotation(arrows, position); arrows.transform.position = t.position; return true; } private void SetRotation(GameObject arrows, RoadDirection position) { var t = arrows.transform; //by default, the arrows show to east switch (position) { case RoadDirection.West: { if (turnDirection == TurnDirection.Left || turnDirection == TurnDirection.Straight && goingTo == RoadDirection.South) { t.rotation = Quaternion.Euler(0, 90, 0); //arrows.transform.Rotate(Vector3.up, 90); } else if (turnDirection == TurnDirection.Right || turnDirection == TurnDirection.Straight && goingTo == RoadDirection.North) { t.rotation = Quaternion.Euler(0, 270, 0); //arrows.transform.Rotate(Vector3.up, 90); } break; } case RoadDirection.North: if (turnDirection == TurnDirection.Left || turnDirection == TurnDirection.Straight && goingTo == RoadDirection.West) { t.rotation = Quaternion.Euler(0, 180, 0); //arrows.transform.Rotate(Vector3.up, 180); } break; case RoadDirection.East: if (turnDirection == TurnDirection.Right || turnDirection == TurnDirection.Straight && goingTo == RoadDirection.South) { t.rotation = Quaternion.Euler(0, 90, 0); //arrows.transform.Rotate(Vector3.up, 90); } else if (turnDirection == TurnDirection.Left || turnDirection == TurnDirection.Straight && goingTo == RoadDirection.North) { t.rotation = Quaternion.Euler(0, 270, 0); //arrows.transform.Rotate(Vector3.up, -90); } break; case RoadDirection.South: if (turnDirection == TurnDirection.Right || turnDirection == TurnDirection.Straight && goingTo == RoadDirection.West) { t.rotation = Quaternion.Euler(0, 180, 0); //arrows.transform.Rotate(Vector3.up, 180); } break; case RoadDirection.None: throw new ArgumentException("RoadDirection.None not allowed for adding arrows"); default: throw new ArgumentOutOfRangeException(nameof(position), position, null); } } public void UpdateArrows() { if (!arrowPoolAvailable) return; if (comingFrom == RoadDirection.None || goingTo == RoadDirection.None) { usedArrows.ForEach(o => { // ReSharper disable once PossibleNullReferenceException arrowPool.ReturnToPool(o); }); usedArrows.Clear(); return; } turnDirection = TurnDirectionMapper.GetTurnDirection(comingFrom, goingTo); var usedArrowIndex = 0; foreach (var position in allDirections.Where(i => i != comingFrom && i != goingTo)) { GameObject arrows; if (usedArrowIndex < usedArrows.Count) { arrows = usedArrows[usedArrowIndex]; } else { // ReSharper disable once PossibleNullReferenceException arrows = arrowPool.GetItem(); usedArrows.Add(arrows); } var used = AddArrows(position, arrows); if (!used) { // ReSharper disable once PossibleNullReferenceException arrowPool.ReturnToPool(arrows); usedArrows.Remove(arrows); continue; } usedArrowIndex++; } trigger.enabled = true; } private void OnTriggerExit(Collider other) { if (other.CompareTag("bike") && OnTriggerExitBicycle != null) { OnTriggerExitBicycle(); trigger.enabled = false; BikeTriggerState = TriggerState.Outside; } } private void OnTriggerEnter(Collider other) { if (other.CompareTag("bike")) { BikeTriggerState = TriggerState.Inside; } } } }