#region "Imports" using UnityEngine; using System.Collections.Generic; using RoadArchitect.Splination; using RoadArchitect.EdgeObjects; #endregion namespace RoadArchitect { public class SplineN : MonoBehaviour { #region "Vars" /// Stores the position data public Vector3 pos; public Quaternion rot; public Vector3 tangent; public Vector2 easeIO; public float dist = 0f; public float time = 0f; public float nextTime = 1f; public Vector3 nextTan = default(Vector3); public float oldTime = 0f; public float tempSegmentTime = 0f; public bool isSpecialEndNode = false; public SplineN specialNodeCounterpart = null; public SplineN specialNodeCounterpartMaster = null; /// Connected nodes array public SplineN[] originalConnectionNodes = null; public bool isSpecialEndNodeIsStart = false; public bool isSpecialEndNodeIsEnd = false; public bool isSpecialIntersection = false; public bool isSpecialRoadConnPrimary = false; public bool isRoadCut = false; public float minSplination = 0f; public float maxSplination = 1f; public int idOnSpline = -1; public SplineC spline; //Unique ID public string uID; public SplineN intersectionOtherNode; public string gradeToNext; public string gradeToPrev; public float gradeToNextValue; public float gradeToPrevValue; public float initialRoadHeight = -1f; //Navigation: public bool isNeverIntersect = false; /// Is this node used by an intersection public bool isIntersection = false; /// Defines end of road, if special end or start it is the second node/second last node public bool isEndPoint = false; public int id = 0; public int intersectionOtherNodeID = 0; /// Contains previous and next node ids public List connectedID; /// Contains previous and next node public List connectedNode; public bool isIgnore = false; #region "Tunnels" public bool isTunnel = false; public bool isTunnelStart = false; public bool isTunnelEnd = false; public bool isTunnelMatched = false; public SplineN tunnelCounterpartNode = null; #endregion //Bridges: public bool isBridge = false; public bool isBridgeStart = false; public bool isBridgeEnd = false; public bool isBridgeMatched = false; public SplineN bridgeCounterpartNode = null; public RoadIntersection intersection = null; public iConstructionMaker intersectionConstruction; #endregion #region "Edge Objects" public List EdgeObjects; public void SetupEdgeObjects(bool _isCollecting = true) { if (EdgeObjects == null) { EdgeObjects = new List(); } int eCount = EdgeObjects.Count; EdgeObjectMaker EOM = null; for (int index = 0; index < eCount; index++) { EOM = EdgeObjects[index]; EOM.node = this; EOM.Setup(_isCollecting); } } public EdgeObjectMaker AddEdgeObject() { EdgeObjectMaker EOM = new EdgeObjectMaker(); EOM.node = this; EOM.SetDefaultTimes(isEndPoint, time, nextTime, idOnSpline, spline.distance); EOM.startPos = spline.GetSplineValue(EOM.startTime); EOM.endPos = spline.GetSplineValue(EOM.endTime); EdgeObjects.Add(EOM); return EOM; } public void CheckRenameEdgeObject(EdgeObjectMaker _eom) { // We have _eom already in EdgeObjects List names = new List(EdgeObjects.Count - 1); for (int i = 0; i < EdgeObjects.Count; i++) { if (ReferenceEquals(_eom, EdgeObjects[i])) { continue; } names.Add(EdgeObjects[i].objectName); } bool isNotUnique = true; string name = _eom.objectName; int counter = 1; while (isNotUnique) { if (names.Contains(_eom.objectName)) { _eom.objectName = name + counter.ToString(); counter++; continue; } break; } } public void EdgeObjectQuickAdd(string _name) { EdgeObjectMaker EOM = AddEdgeObject(); EOM.LoadFromLibrary(_name, true); EOM.SetDefaultTimes(isEndPoint, time, nextTime, idOnSpline, spline.distance); EOM.node = this; EOM.Setup(); } public void RemoveEdgeObject(int _index = -1, bool _isSkippingUpdate = false) { if (EdgeObjects == null) { return; } if (EdgeObjects.Count == 0) { return; } if (_index < 0) { if (EdgeObjects.Count > 0) { EdgeObjects[EdgeObjects.Count - 1].ClearEOM(); EdgeObjects.RemoveAt(EdgeObjects.Count - 1); } } else { if (EdgeObjects.Count > _index) { EdgeObjects[_index].ClearEOM(); EdgeObjects.RemoveAt(_index); } } if (!_isSkippingUpdate) { SetupEdgeObjects(); } } public void RemoveAllEdgeObjects(bool _isSkippingUpdate = false) { if (EdgeObjects == null) { return; } while (EdgeObjects.Count > 0) { RemoveEdgeObject(-1, _isSkippingUpdate); } } public void CopyEdgeObject(int _index) { EdgeObjectMaker EOM = EdgeObjects[_index].Copy(); EdgeObjects.Add(EOM); CheckRenameEdgeObject(EOM); SetupEdgeObjects(); } public void EdgeObjectLoadFromLibrary(int _i, string _name) { if (EdgeObjects == null) { EdgeObjects = new List(); } int eCount = EdgeObjects.Count; if (_i > -1 && _i < eCount) { EdgeObjectMaker EOM = EdgeObjects[_i]; EOM.LoadFromLibrary(_name); EOM.SetDefaultTimes(isEndPoint, time, nextTime, idOnSpline, spline.distance); EOM.node = this; EOM.Setup(); } } public void DetectInvalidEdgeObjects() { int mCount = EdgeObjects.Count; List InvalidList = new List(); for (int index = 0; index < mCount; index++) { if (EdgeObjects[index].edgeObject == null) { InvalidList.Add(index); } } for (int index = (InvalidList.Count - 1); index >= 0; index--) { RemoveEdgeObject(InvalidList[index], true); } SetupEdgeObjects(); } #endregion #region "Extruded objects" public List SplinatedObjects; public void SetupSplinatedMeshes(bool _isCollecting = true) { if (SplinatedObjects == null) { SplinatedObjects = new List(); } int eCount = SplinatedObjects.Count; SplinatedMeshMaker SMM = null; for (int index = 0; index < eCount; index++) { SMM = SplinatedObjects[index]; SMM.Setup(true, _isCollecting); } } public int SplinatedMeshGetIndex(ref string _uID) { if (SplinatedObjects == null) { SplinatedObjects = new List(); } int eCount = SplinatedObjects.Count; SplinatedMeshMaker SMM = null; for (int index = 0; index < eCount; index++) { SMM = SplinatedObjects[index]; if (string.CompareOrdinal(SMM.uID, _uID) == 0) { return index; } } return -1; } public void SetupSplinatedMesh(int _i, bool _isGettingStrings = false) { if (SplinatedObjects == null) { SplinatedObjects = new List(); } int eCount = SplinatedObjects.Count; if (_i > -1 && _i < eCount) { SplinatedMeshMaker SMM = SplinatedObjects[_i]; SMM.Setup(_isGettingStrings); } } public SplinatedMeshMaker AddSplinatedObject() { if (SplinatedObjects == null) { SplinatedObjects = new List(); } SplinatedMeshMaker SMM = new SplinatedMeshMaker(); SMM.Init(spline, this, transform); SplinatedObjects.Add(SMM); SMM.SetDefaultTimes(isEndPoint, time, nextTime, idOnSpline, spline.distance); SMM.StartPos = spline.GetSplineValue(SMM.StartTime); SMM.EndPos = spline.GetSplineValue(SMM.EndTime); return SMM; } public void CheckRenameSplinatedObject(SplinatedMeshMaker _smm) { // We have _smm already in SplinatedObjects List names = new List(SplinatedObjects.Count - 1); for(int i = 0; i < SplinatedObjects.Count; i++) { if (ReferenceEquals(_smm, SplinatedObjects[i])) { continue; } names.Add(SplinatedObjects[i].objectName); } bool isNotUnique = true; string name = _smm.objectName; int counter = 1; while(isNotUnique) { if (names.Contains(_smm.objectName)) { _smm.objectName = name + counter.ToString(); counter++; continue; } break; } } public void SplinatedObjectQuickAdd(string _name) { SplinatedMeshMaker SMM = AddSplinatedObject(); SMM.LoadFromLibrary(_name, true); SMM.SetDefaultTimes(isEndPoint, time, nextTime, idOnSpline, spline.distance); SMM.Setup(true); } public void SplinatedObjectLoadFromLibrary(int _i, string _name) { if (SplinatedObjects == null) { SplinatedObjects = new List(); } int eCount = SplinatedObjects.Count; if (_i > -1 && _i < eCount) { SplinatedMeshMaker SMM = SplinatedObjects[_i]; SMM.SetDefaultTimes(isEndPoint, time, nextTime, idOnSpline, spline.distance); SMM.LoadFromLibrary(_name); SMM.Setup(true); } } public void CopySplinatedObject(ref SplinatedMeshMaker _SMM) { SplinatedMeshMaker SMM = _SMM.Copy(); SplinatedObjects.Add(SMM); CheckRenameSplinatedObject(SMM); SetupSplinatedMeshes(); } public void RemoveSplinatedObject(int _index = -1, bool _isSkippingUpdate = false) { if (SplinatedObjects == null) { return; } if (SplinatedObjects.Count == 0) { return; } SplinatedMeshMaker SMM = null; if (_index < 0) { if (SplinatedObjects.Count > 0) { SMM = SplinatedObjects[SplinatedObjects.Count - 1]; SMM.Kill(); SplinatedObjects.RemoveAt(SplinatedObjects.Count - 1); SMM = null; } } else { if (SplinatedObjects.Count > _index) { SMM = SplinatedObjects[_index]; SMM.Kill(); SplinatedObjects.RemoveAt(_index); SMM = null; } } if (!_isSkippingUpdate) { SetupSplinatedMeshes(); } } public void RemoveAllSplinatedObjects(bool _isSkippingUpdate = false) { if (SplinatedObjects == null) { return; } while (SplinatedObjects.Count > 0) { RemoveSplinatedObject(-1, _isSkippingUpdate); } } public void DetectInvalidSplinatedObjects() { int mCount = SplinatedObjects.Count; List InvalidList = new List(); for (int index = 0; index < mCount; index++) { if (SplinatedObjects[index].Output == null) { InvalidList.Add(index); } } for (int index = (InvalidList.Count - 1); index >= 0; index--) { RemoveSplinatedObject(InvalidList[index], true); } SetupSplinatedMeshes(); } #endregion public void LoadWizardObjectsFromLibrary(string _fileName, bool _isDefault, bool _isBridge) { if (_isBridge) { RemoveAllSplinatedObjects(true); RemoveAllEdgeObjects(true); } RoadUtility.LoadNodeObjects(_fileName, this, _isDefault, _isBridge); } public void Setup(Vector3 _pos, Quaternion _rot, Vector2 _io, float _time, string _name) { pos = _pos; rot = _rot; easeIO = _io; time = _time; name = _name; if (EdgeObjects == null) { EdgeObjects = new List(); } } #region "Gizmos" // private void TerrainDebugging(){ // Construction3DTri tTri = null; // Vector3 tHeightVec = new Vector3(0f,10f,0f); // if(tTriList != null){ // // //// bool bOddToggle = false; //// for(int i=0;i 230){ break; } //// if(i < 1330){ continue; } //// if(i > 1510 || i > (tTriList.Count-10)){ break; } //// tTri = tTriList[i]; //// //// if(bOddToggle){ //// Gizmos.color = new Color(0f,1f,1f,1f); //// }else{ //// Gizmos.color = new Color(1f,1f,0f,1f); //// } //// //// Gizmos.DrawLine(tTri.P1,tTri.P2); //// Gizmos.DrawLine(tTri.P1,tTri.P3); //// Gizmos.DrawLine(tTri.P2,tTri.P3); ////// Gizmos.color = new Color(0f,1f,0f,1f); ////// Gizmos.DrawLine(tTri.pMiddle,(tTri.normal*100f)+tTri.pMiddle); //// //// //// //// if(bOddToggle){ //// Gizmos.color = new Color(0f,1f,1f,1f); //// }else{ //// Gizmos.color = new Color(1f,1f,0f,1f); //// } //// //// Gizmos.DrawLine(tTri.P1+tHeightVec,tTri.P2+tHeightVec); //// Gizmos.DrawLine(tTri.P1+tHeightVec,tTri.P3+tHeightVec); //// Gizmos.DrawLine(tTri.P3+tHeightVec,tTri.P2+tHeightVec); //// Gizmos.color = new Color(0f,1f,0f,1f); //// Gizmos.DrawLine(tTri.pMiddle+tHeightVec,(tTri.normal*100f)+tTri.pMiddle+tHeightVec); //// ////// //// //// tTri = tTriList[i+1]; //// if(bOddToggle){ //// Gizmos.color = new Color(0f,1f,1f,1f); //// }else{ //// Gizmos.color = new Color(1f,1f,0f,1f); //// } //// //// Gizmos.DrawLine(tTri.P1,tTri.P2); //// Gizmos.DrawLine(tTri.P1,tTri.P3); //// Gizmos.DrawLine(tTri.P2,tTri.P3); //// //// if(bOddToggle){ //// Gizmos.color = new Color(0f,1f,1f,1f); //// }else{ //// Gizmos.color = new Color(1f,1f,0f,1f); //// } //// //// Gizmos.DrawLine(tTri.P1+tHeightVec,tTri.P2+tHeightVec); //// Gizmos.DrawLine(tTri.P1+tHeightVec,tTri.P3+tHeightVec); //// Gizmos.DrawLine(tTri.P3+tHeightVec,tTri.P2+tHeightVec); //// Gizmos.color = new Color(0f,1f,0f,1f); //// Gizmos.DrawLine(tTri.pMiddle+tHeightVec,(tTri.normal*100f)+tTri.pMiddle+tHeightVec); //// //// //// //// bOddToggle = !bOddToggle; ////// Gizmos.DrawCube(tRectList[i].pMiddle,new Vector3(1f,0.5f,1f)); //// } // // //// Gizmos.color = new Color(0f,1f,0f,1f); //// Terrain tTerrain = GameObject.Find("Terrain").GetComponent(); //// Vector3 HMVect = default(Vector3); //// float tHeight = 0f; //// for(int i=0;i tTriList; public List tHMList; private void OnDrawGizmos() { DrawGizmos(false); } private void OnDrawGizmosSelected() { DrawGizmos(true); } private void DrawGizmos(bool _isSelected) { if (!spline.road.isGizmosEnabled == true) { return; } if (isIgnore) { return; } if (isIntersection) { return; } if (isSpecialEndNode) { return; } if (isSpecialEndNodeIsEnd || isSpecialEndNodeIsStart) { return; } if (_isSelected) { Gizmos.color = spline.road.selectedColor; Gizmos.DrawCube(transform.position + new Vector3(0f, 6.25f, 0f), new Vector3(3.5f, 12.5f, 3.5f)); return; } // Not Selected if (isSpecialRoadConnPrimary) { Gizmos.color = spline.road.Color_NodeConnColor; Gizmos.DrawCube(transform.position + new Vector3(0f, 7.5f, 0f), new Vector3(5f, 15f, 5f)); } else { Gizmos.color = spline.road.defaultNodeColor; Gizmos.DrawCube(transform.position + new Vector3(0f, 6f, 0f), new Vector3(2f, 11f, 2f)); } } #endregion #region "Grade" public void SetGradePercent(int _nodeCount) { Vector3 P1 = default(Vector3); Vector3 P2 = default(Vector3); float dist; float grade; bool isNone = false; if (_nodeCount < 2) { gradeToPrev = "NA"; gradeToNext = "NA"; gradeToNextValue = 0f; gradeToPrevValue = 0f; } if (!isEndPoint && !isSpecialEndNode && _nodeCount > 1 && ((idOnSpline + 1) < spline.nodes.Count)) { P1 = pos; P2 = spline.nodes[idOnSpline + 1].pos; if (isNone) { grade = 0f; } else { dist = Vector2.Distance(new Vector2(P1.x, P1.z), new Vector2(P2.x, P2.z)); grade = ((P2.y - P1.y) / dist) * 100; } gradeToNextValue = grade; gradeToNext = grade.ToString("0.##\\%"); } else { gradeToNext = "NA"; gradeToNextValue = 0f; } if (idOnSpline > 0 && !isSpecialEndNode && _nodeCount > 1 && ((idOnSpline - 1) >= 0)) { P1 = pos; P2 = spline.nodes[idOnSpline - 1].pos; if (isNone) { grade = 0f; } else { dist = Vector2.Distance(new Vector2(P1.x, P1.z), new Vector2(P2.x, P2.z)); grade = ((P2.y - P1.y) / dist) * 100; } gradeToPrevValue = grade; gradeToPrev = grade.ToString("0.##\\%"); } else { gradeToPrev = "NA"; gradeToPrevValue = 0f; } } public Vector3 FilterMaxGradeHeight(Vector3 _pos, out float _minY, out float _maxY) { Vector3 tVect = _pos; tVect.y = pos.y; float CurrentDistance = Vector2.Distance(new Vector2(pos.x, pos.z), new Vector2(_pos.x, _pos.z)); // float CurrentDistance2 = Vector3.Distance(pos,tVect); // float CurrentYDiff = tPos.y - pos.y; // float CurrentGrade = CurrentYDiff/CurrentDistance; //Get max/min grade height position for this currrent tDist distance: _maxY = (spline.road.maxGrade * CurrentDistance) + pos.y; _minY = pos.y - (spline.road.maxGrade * CurrentDistance); //(tPos.y-pos.y)/CurrentDistance // float DifferenceFromMax = -1; if (_pos.y > _maxY) { // DifferenceFromMax = tPos.y - MaximumY; _pos.y = _maxY; } if (_pos.y < _minY) { // DifferenceFromMax = MinimumY - tPos.y; _pos.y = _minY; } return _pos; } public void EnsureGradeValidity(int _iStart = -1, bool _isAddToEnd = false) { if (spline == null) { return; } SplineN PrevNode = null; SplineN NextNode = null; if (_isAddToEnd && spline.GetNodeCount() > 0) { PrevNode = spline.nodes[spline.GetNodeCount() - 1]; } else { if (_iStart == -1) { PrevNode = spline.GetPrevLegitimateNode(idOnSpline); } else { PrevNode = spline.GetPrevLegitimateNode(_iStart); } } if (PrevNode == null) { return; } Vector3 tVect = transform.position; float tMinY1 = 0f; float tMinY2 = 0f; float tMaxY1 = 0f; float tMaxY2 = 0f; if (PrevNode != null) { PrevNode.FilterMaxGradeHeight(tVect, out tMinY1, out tMaxY1); } if (NextNode != null) { NextNode.FilterMaxGradeHeight(tVect, out tMinY2, out tMaxY2); } bool bPrevNodeGood = false; bool bNextNodeGood = false; if (tVect.y > tMinY1 && tVect.y < tMaxY1) { bPrevNodeGood = true; } if (tVect.y > tMinY2 && tVect.y < tMaxY2) { bNextNodeGood = true; } if (!bPrevNodeGood && !bNextNodeGood && PrevNode != null && NextNode != null) { float tMaxY3 = Mathf.Min(tMaxY1, tMaxY2); float tMinY3 = Mathf.Max(tMinY1, tMinY2); if (tVect.y < tMinY3) { tVect.y = tMinY3; } else if (tVect.y > tMaxY3) { tVect.y = tMaxY3; } } else { if (!bPrevNodeGood && PrevNode != null) { if (tVect.y < tMinY1) { tVect.y = tMinY1; } else if (tVect.y > tMaxY1) { tVect.y = tMaxY1; } } else if (!bNextNodeGood && NextNode != null) { if (tVect.y < tMinY2) { tVect.y = tMinY2; } else if (tVect.y > tMaxY2) { tVect.y = tMaxY2; } } } transform.position = tVect; } #endregion #region "Util" public void ResetNavigationData() { connectedID = null; connectedID = new List(); connectedNode = null; connectedNode = new List(); } public void BreakConnection() { SplineN tNode2 = specialNodeCounterpart; if (isSpecialEndNodeIsStart) { spline.isSpecialStartControlNode = false; spline.isSpecialEndNodeIsStartDelay = false; } else if (isSpecialEndNodeIsEnd) { spline.isSpecialEndControlNode = false; spline.isSpecialEndNodeIsEndDelay = false; } if (tNode2.isSpecialEndNodeIsStart) { tNode2.spline.isSpecialStartControlNode = false; tNode2.spline.isSpecialEndNodeIsStartDelay = false; } else if (tNode2.isSpecialEndNodeIsEnd) { tNode2.spline.isSpecialEndControlNode = false; tNode2.spline.isSpecialEndNodeIsEndDelay = false; } specialNodeCounterpart = null; isSpecialEndNode = false; isSpecialEndNodeIsEnd = false; isSpecialEndNodeIsStart = false; isSpecialRoadConnPrimary = false; tNode2.specialNodeCounterpart = null; tNode2.isSpecialEndNode = false; tNode2.isSpecialEndNodeIsEnd = false; tNode2.isSpecialEndNodeIsStart = false; tNode2.isSpecialRoadConnPrimary = false; tNode2.specialNodeCounterpartMaster.isSpecialRoadConnPrimary = false; specialNodeCounterpartMaster.isSpecialRoadConnPrimary = false; try { Object.DestroyImmediate(tNode2.transform.gameObject); Object.DestroyImmediate(transform.gameObject); } catch (MissingReferenceException) { } } public void SetupSplinationLimits() { //Disallowed nodes: if (!CanSplinate()) { minSplination = time; maxSplination = time; return; } //Figure out min splination: SplineN node = null; minSplination = time; for (int index = idOnSpline; index >= 0; index--) { node = spline.nodes[index]; if (node.CanSplinate()) { minSplination = node.time; } else { break; } } //Figure out max splination: maxSplination = time; int nodeCount = spline.GetNodeCount(); for (int index = idOnSpline; index < nodeCount; index++) { node = spline.nodes[index]; if (node.CanSplinate()) { maxSplination = node.time; } else { break; } } } #endregion #region "Cut materials storage and setting" public GameObject roadCutWorld = null; public GameObject shoulderCutRWorld = null; public GameObject shoulderCutLWorld = null; public GameObject roadCutMarker = null; public GameObject shoulderCutRMarker = null; public GameObject shoulderCutLMarker = null; private Material[] roadCutWorldMats; private Material[] shoulderCutRWorldMats; private Material[] shoulderCutLWorldMats; private Material[] roadCutMarkerMats; private Material[] shoulderCutRMarkerMats; private Material[] shoulderCutLMarkerMats; private PhysicMaterial roadCutPhysicMat; private PhysicMaterial shoulderCutRPhysicMat; private PhysicMaterial shoulderCutLPhysicMat; /// Stores the cut materials. For use in UpdateCuts(). See UpdateCuts() in this code file for further description of this system. public void StoreCuts() { //Buffers: MeshRenderer MR = null; MeshCollider MC = null; //World cuts first: if (roadCutWorld != null) { MR = roadCutWorld.GetComponent(); MC = roadCutWorld.GetComponent(); if (MR != null) { roadCutWorldMats = MR.sharedMaterials; } if (MC != null) { roadCutPhysicMat = MC.material; roadCutPhysicMat.name = roadCutPhysicMat.name.Replace(" (Instance)", ""); } //Nullify reference only roadCutWorld = null; } if (shoulderCutRWorld != null) { MR = shoulderCutRWorld.GetComponent(); MC = shoulderCutRWorld.GetComponent(); if (MR != null) { shoulderCutRWorldMats = MR.sharedMaterials; } if (MC != null) { shoulderCutRPhysicMat = MC.material; shoulderCutRPhysicMat.name = shoulderCutRPhysicMat.name.Replace(" (Instance)", ""); } shoulderCutRWorld = null; } if (shoulderCutLWorld != null) { MR = shoulderCutLWorld.GetComponent(); MC = shoulderCutLWorld.GetComponent(); if (MR != null) { shoulderCutLWorldMats = MR.sharedMaterials; } if (MC != null) { shoulderCutLPhysicMat = MC.material; shoulderCutLPhysicMat.name = shoulderCutLPhysicMat.name.Replace(" (Instance)", ""); } shoulderCutLWorld = null; } //Markers: if (roadCutMarker != null) { MR = roadCutMarker.GetComponent(); if (MR != null) { roadCutMarkerMats = MR.sharedMaterials; } roadCutMarker = null; } if (shoulderCutRMarker != null) { MR = shoulderCutRMarker.GetComponent(); if (MR != null) { shoulderCutRMarkerMats = MR.sharedMaterials; } shoulderCutRMarker = null; } if (shoulderCutLMarker != null) { MR = shoulderCutLMarker.GetComponent(); if (MR != null) { shoulderCutLMarkerMats = MR.sharedMaterials; } shoulderCutLMarker = null; } } /// /// Updates the cut materials. Called upon creation of the cuts to set the newly cut materials to previously set materials. /// For instance, if the user set a material on a road cut, and then regenerated the road, this function will apply the mats that the user applied. /// public void UpdateCuts() { //Buffers: MeshRenderer MR = null; MeshCollider MC = null; #region "Physic Materials" //World: if (roadCutPhysicMat != null && roadCutWorld) { MC = roadCutWorld.GetComponent(); if (MC != null) { MC.material = roadCutPhysicMat; MC.material.name = MC.material.name.Replace(" (Instance)", ""); } } if (shoulderCutRPhysicMat != null && shoulderCutRWorld) { MC = shoulderCutRWorld.GetComponent(); if (MC != null) { MC.material = shoulderCutRPhysicMat; MC.material.name = MC.material.name.Replace(" (Instance)", ""); } } if (shoulderCutLPhysicMat != null && shoulderCutLWorld) { MC = shoulderCutLWorld.GetComponent(); if (MC != null) { MC.material = shoulderCutLPhysicMat; MC.material.name = MC.material.name.Replace(" (Instance)", ""); } } #endregion #region "Get or Add MeshRenderer" if (roadCutWorldMats != null && roadCutWorldMats.Length > 0 && roadCutWorld) { MR = roadCutWorld.GetComponent(); if (!MR) { roadCutWorld.AddComponent(); } if (MR != null) { MR.materials = roadCutWorldMats; } } if (shoulderCutRWorldMats != null && shoulderCutRWorldMats.Length > 0 && shoulderCutRWorld) { MR = shoulderCutRWorld.GetComponent(); if (!MR) { shoulderCutRWorld.AddComponent(); } if (MR != null) { MR.materials = shoulderCutRWorldMats; } } if (shoulderCutLWorldMats != null && shoulderCutLWorldMats.Length > 0 && shoulderCutLWorld) { MR = shoulderCutLWorld.GetComponent(); if (!MR) { shoulderCutLWorld.AddComponent(); } if (MR != null) { MR.materials = shoulderCutLWorldMats; } } //Markers: if (roadCutMarkerMats != null && roadCutMarkerMats.Length > 0 && roadCutMarker) { MR = roadCutMarker.GetComponent(); if (!MR) { roadCutMarker.AddComponent(); } if (MR != null) { MR.materials = roadCutMarkerMats; } } if (shoulderCutRMarkerMats != null && shoulderCutRMarkerMats.Length > 0 && shoulderCutRMarker) { MR = shoulderCutRMarker.GetComponent(); if (!MR) { shoulderCutRMarker.AddComponent(); } if (MR != null) { MR.materials = shoulderCutRMarkerMats; } } if (shoulderCutLMarkerMats != null && shoulderCutLMarkerMats.Length > 0 && shoulderCutLMarker) { MR = shoulderCutLMarker.GetComponent(); if (!MR) { shoulderCutLMarker.AddComponent(); } if (MR != null) { MR.materials = shoulderCutLMarkerMats; } } #endregion #region "Destroy if empty" if (roadCutMarker != null) { MR = roadCutMarker.GetComponent(); if (MR == null || MR.sharedMaterial == null) { Object.DestroyImmediate(roadCutMarker); } } if (shoulderCutRMarker != null) { MR = shoulderCutRMarker.GetComponent(); if (MR == null || MR.sharedMaterial == null) { Object.DestroyImmediate(shoulderCutRMarker); } } if (shoulderCutLMarker != null) { MR = shoulderCutLMarker.GetComponent(); if (MR == null || MR.sharedMaterial == null) { Object.DestroyImmediate(shoulderCutLMarker); } } #endregion } /// Clears the cut materials public void ClearCuts() { roadCutWorldMats = null; shoulderCutRWorldMats = null; shoulderCutLWorldMats = null; roadCutMarkerMats = null; shoulderCutRMarkerMats = null; shoulderCutLMarkerMats = null; roadCutPhysicMat = null; shoulderCutRPhysicMat = null; shoulderCutLPhysicMat = null; } #endregion #region "Bridges" public void BridgeToggleStart() { //If switching to end, find associated bridge if (isBridgeStart) { BridgeStart(); } else { BridgeDestroy(); } } public void BridgeToggleEnd() { //If switching to end, find associated bridge if (isBridgeEnd) { int nodeCount = spline.GetNodeCount(); SplineN node = null; for (int i = 1; i < (nodeCount - 1); i++) { node = spline.nodes[i]; if (node.isBridgeStart && !node.isBridgeMatched) { node.BridgeToggleStart(); if (node.isBridgeMatched && node.bridgeCounterpartNode == this) { return; } } } } else { BridgeDestroy(); } } private void BridgeStart() { //Cycle through nodes until you find another end or another start (in this case, no creation, encountered another bridge): int EndID = idOnSpline + 1; int nodeCount = spline.GetNodeCount(); if (isEndPoint) { //Attempted to make end point node a bridge node: isBridgeStart = false; return; } if (EndID >= nodeCount) { //Attempted to make last node a bridge node: isBridgeStart = false; return; } else if (idOnSpline == 0) { //Attempted to make first node a bridge node: isBridgeStart = false; return; } isBridgeMatched = false; bridgeCounterpartNode = null; int StartI = idOnSpline + 1; SplineN tNode = null; for (int i = StartI; i < nodeCount; i++) { tNode = spline.nodes[i]; if (tNode.isIntersection) { //Encountered intersection. End search. return; } if (tNode.isBridgeStart) { //Encountered another bridge. Return: return; } if (tNode.isIgnore) { continue; } if (tNode.isBridgeEnd) { isBridgeMatched = true; tNode.isBridgeMatched = true; bridgeCounterpartNode = tNode; tNode.bridgeCounterpartNode = this; spline.TriggerSetup(); return; } } } private void BridgeDestroy() { if (bridgeCounterpartNode != null) { bridgeCounterpartNode.BridgeResetValues(); } BridgeResetValues(); spline.TriggerSetup(); } public void BridgeResetValues() { isBridge = false; isBridgeStart = false; isBridgeEnd = false; isBridgeMatched = false; bridgeCounterpartNode = null; } public bool CanBridgeStart() { if (isBridgeStart) { return true; } if (isBridgeEnd) { return false; } if (isEndPoint) { return false; } int mCount = spline.GetNodeCount(); if (idOnSpline > 0) { if (spline.nodes[idOnSpline - 1].isBridgeStart) { return false; } } if (idOnSpline < (mCount - 1)) { if (spline.nodes[idOnSpline + 1].isBridgeStart) { return false; } if (spline.isSpecialEndControlNode) { if ((mCount - 3 > 0) && idOnSpline == mCount - 3) { return false; } } else { if ((mCount - 2 > 0) && idOnSpline == mCount - 2) { return false; } } } if (spline.IsInBridge(time)) { return false; } return true; } public bool CanBridgeEnd() { if (isBridgeEnd) { return true; } if (isBridgeStart) { return false; } if (isEndPoint) { return false; } int mCount = spline.GetNodeCount(); if (idOnSpline < (mCount - 1)) { if (spline.isSpecialStartControlNode) { if (idOnSpline == 2) { return false; } } else { if (idOnSpline == 1) { return false; } } } for (int i = idOnSpline; i >= 0; i--) { if (spline.nodes[i].isBridgeStart) { if (!spline.nodes[i].isBridgeMatched) { return true; } else { return false; } } } return false; } #endregion #region "Tunnels" public void TunnelToggleStart() { //If switching to end, find associated Tunnel if (isTunnelStart) { TunnelStart(); } else { TunnelDestroy(); } } public void TunnelToggleEnd() { //If switching to end, find associated Tunnel if (isTunnelEnd) { int nodeCount = spline.GetNodeCount(); SplineN node = null; for (int index = 1; index < (nodeCount - 1); index++) { node = spline.nodes[index]; if (node.isTunnelStart && !node.isTunnelMatched) { node.TunnelToggleStart(); if (node.isTunnelMatched && node.tunnelCounterpartNode == this) { return; } } } } else { TunnelDestroy(); } } private void TunnelStart() { //Cycle through nodes until you find another end or another start (in this case, no creation, encountered another Tunnel): int EndID = idOnSpline + 1; int mCount = spline.GetNodeCount(); if (isEndPoint) { //Attempted to make end point node a Tunnel node: isTunnelStart = false; return; } if (EndID >= mCount) { //Attempted to make last node a Tunnel node: isTunnelStart = false; return; } else if (idOnSpline == 0) { //Attempted to make first node a Tunnel node: isTunnelStart = false; return; } isTunnelMatched = false; tunnelCounterpartNode = null; int StartI = idOnSpline + 1; SplineN node = null; for (int i = StartI; i < mCount; i++) { node = spline.nodes[i]; if (node.isIntersection) { //Encountered intersection. End search. return; } if (node.isTunnelStart) { //Encountered another Tunnel. Return: return; } if (node.isIgnore) { continue; } if (node.isTunnelEnd) { isTunnelMatched = true; node.isTunnelMatched = true; tunnelCounterpartNode = node; node.tunnelCounterpartNode = this; spline.TriggerSetup(); return; } } } private void TunnelDestroy() { if (tunnelCounterpartNode != null) { tunnelCounterpartNode.TunnelResetValues(); } TunnelResetValues(); spline.TriggerSetup(); } public void TunnelResetValues() { isTunnel = false; isTunnelStart = false; isTunnelEnd = false; isTunnelMatched = false; tunnelCounterpartNode = null; } public bool CanTunnelStart() { if (isTunnelStart) { return true; } if (isTunnelEnd) { return false; } if (isEndPoint) { return false; } int mCount = spline.GetNodeCount(); if (idOnSpline > 0) { if (spline.nodes[idOnSpline - 1].isTunnelStart) { return false; } } if (idOnSpline < (mCount - 1)) { if (spline.nodes[idOnSpline + 1].isTunnelStart) { return false; } if (spline.isSpecialEndControlNode) { if ((mCount - 3 > 0) && idOnSpline == mCount - 3) { return false; } } else { if ((mCount - 2 > 0) && idOnSpline == mCount - 2) { return false; } } } if (spline.IsInTunnel(time)) { return false; } return true; } public bool CanTunnelEnd() { if (isTunnelEnd) { return true; } if (isTunnelStart) { return false; } if (isEndPoint) { return false; } int nodeCount = spline.GetNodeCount(); if (idOnSpline < (nodeCount - 1)) { if (spline.isSpecialStartControlNode) { if (idOnSpline == 2) { return false; } } else { if (idOnSpline == 1) { return false; } } } for (int i = idOnSpline; i >= 0; i--) { if (spline.nodes[i].isTunnelStart) { if (!spline.nodes[i].isTunnelMatched) { return true; } else { return false; } } } return false; } #endregion #region "Is straight line to next node" /// Returns true if two of 3 pos Vectors to previous and next 2 nodes approx. match public bool IsStraight() { int id1 = idOnSpline - 1; int id2 = idOnSpline + 1; int id3 = idOnSpline + 2; int nodeCount = spline.GetNodeCount(); if (id1 > -1 && id1 < nodeCount) { if (!IsApproxTwoThirds(ref pos, spline.nodes[id1].pos)) { return false; } } if (id2 > -1 && id2 < nodeCount) { if (!IsApproxTwoThirds(ref pos, spline.nodes[id2].pos)) { return false; } } if (id3 > -1 && id3 < nodeCount) { if (!IsApproxTwoThirds(ref pos, spline.nodes[id3].pos)) { return false; } } return true; } /// Returns if exactly 2 values are approximately the same private static bool IsApproxTwoThirds(ref Vector3 _v1, Vector3 _v2) { int cCount = 0; if (RootUtils.IsApproximately(_v1.x, _v2.x, 0.02f)) { cCount += 1; } if (RootUtils.IsApproximately(_v1.y, _v2.y, 0.02f)) { cCount += 1; } if (RootUtils.IsApproximately(_v1.z, _v2.z, 0.02f)) { cCount += 1; } if (cCount == 2) { return true; } else { return false; } } #endregion #region "Non-editor util" /// Returns false when isSpecialEndNode public bool CanSplinate() { if (isSpecialEndNode) { // || bIsBridge_PreNode || bIsBridge_PostNode){ return false; } else { return true; } } /// Returns false when isIntersection or isSpecialEndNode public bool IsLegitimate() { if (isIntersection || isSpecialEndNode) { // || bIsBridge_PreNode || bIsBridge_PostNode){ return false; } else { return true; } } /// Returns false when isSpecialEndNode public bool IsLegitimateGrade() { if (isSpecialEndNode) { // || bIsBridge_PreNode || bIsBridge_PostNode){ return false; } else { return true; } } #endregion /// Hide or unhide this node in hierarchy public void ToggleHideFlags(bool _isHidden) { if (_isHidden) { this.hideFlags = HideFlags.HideInHierarchy; transform.hideFlags = HideFlags.HideInHierarchy; } else { this.hideFlags = HideFlags.None; transform.hideFlags = HideFlags.None; } } } }