1858 lines
56 KiB
C#
1858 lines
56 KiB
C#
#region "Imports"
|
|
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
using RoadArchitect.Splination;
|
|
using RoadArchitect.EdgeObjects;
|
|
#endregion
|
|
|
|
|
|
namespace RoadArchitect
|
|
{
|
|
public class SplineN : MonoBehaviour
|
|
{
|
|
#region "Vars"
|
|
/// <summary> Stores the position data </summary>
|
|
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;
|
|
/// <summary> Connected nodes array </summary>
|
|
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;
|
|
/// <summary> Is this node used by an intersection </summary>
|
|
public bool isIntersection = false;
|
|
/// <summary> Defines end of road, if special end or start it is the second node/second last node </summary>
|
|
public bool isEndPoint = false;
|
|
public int id = 0;
|
|
public int intersectionOtherNodeID = 0;
|
|
/// <summary> Contains previous and next node ids </summary>
|
|
public List<int> connectedID;
|
|
/// <summary> Contains previous and next node </summary>
|
|
public List<SplineN> 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<EdgeObjectMaker> EdgeObjects;
|
|
|
|
|
|
public void SetupEdgeObjects(bool _isCollecting = true)
|
|
{
|
|
if (EdgeObjects == null)
|
|
{
|
|
EdgeObjects = new List<EdgeObjectMaker>();
|
|
}
|
|
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<string> names = new List<string>(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<EdgeObjectMaker>();
|
|
}
|
|
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<int> InvalidList = new List<int>();
|
|
|
|
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<SplinatedMeshMaker> SplinatedObjects;
|
|
|
|
|
|
public void SetupSplinatedMeshes(bool _isCollecting = true)
|
|
{
|
|
if (SplinatedObjects == null)
|
|
{
|
|
SplinatedObjects = new List<SplinatedMeshMaker>();
|
|
}
|
|
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<SplinatedMeshMaker>();
|
|
}
|
|
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<SplinatedMeshMaker>();
|
|
}
|
|
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>();
|
|
}
|
|
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<string> names = new List<string>(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<SplinatedMeshMaker>();
|
|
}
|
|
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<int> InvalidList = new List<int>();
|
|
|
|
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<EdgeObjectMaker>();
|
|
}
|
|
}
|
|
|
|
|
|
#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<tTriList.Count;i+=2){
|
|
////// if(i < 210){ continue; }
|
|
////// if(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<Terrain>();
|
|
//// Vector3 HMVect = default(Vector3);
|
|
//// float tHeight = 0f;
|
|
//// for(int i=0;i<tHMList.Count;i++){
|
|
//// Gizmos.color = new Color(0f,1f,0f,1f);
|
|
//// Gizmos.DrawCube(tHMList[i] + new Vector3(0f,1f,0f),new Vector3(0.1f,2f,0.1f));
|
|
////
|
|
//// if(tTerrain){
|
|
//// tHeight = tTerrain.SampleHeight(tHMList[i]) + tTerrain.transform.position.y;
|
|
////
|
|
//// if(tHeight != tHMList[i].y){
|
|
//// HMVect = new Vector3(tHMList[i].x,tHeight,tHMList[i].z);
|
|
////
|
|
//// if(Mathf.Approximately(9.584141f,tHMList[i].y)){
|
|
//// int sdagsdgsd =1;
|
|
//// }
|
|
////
|
|
//// Gizmos.color = new Color(0f,0f,1f,1f);
|
|
//// Gizmos.DrawWireCube(HMVect + new Vector3(0f,1f,0f),new Vector3(0.15f,2f,0.15f));
|
|
//// }
|
|
//// }
|
|
//// }
|
|
// }
|
|
//
|
|
//// Vector3 P1 = new Vector3(480.7f,50f,144.8f);
|
|
//// Vector3 P2 = new Vector3(517.3f,60f,128.9f);
|
|
//// Vector3 P3 = new Vector3(518.8f,60f,132.7f);
|
|
//// Vector3 P4 = new Vector3(481.3f,50f,146.4f);
|
|
////
|
|
////
|
|
//// Gizmos.color = new Color(1f,0f,0f,1f);
|
|
//// Gizmos.DrawCube(P1,new Vector3(1f,1f,1f));
|
|
//// Gizmos.DrawCube(P2,new Vector3(1f,1f,1f));
|
|
//// Gizmos.DrawCube(P3,new Vector3(1f,1f,1f));
|
|
//// Gizmos.DrawCube(P4,new Vector3(1f,1f,1f));
|
|
////
|
|
//// tRect = new Construction3DRect(P1,P2,P3,P4);
|
|
////
|
|
//// Gizmos.color = new Color(0f,0f,1f,1f);
|
|
//// Gizmos.DrawCube(tRect.pMiddle,new Vector3(0.1f,0.1f,0.1f));
|
|
////
|
|
//// //This creates normalized line:
|
|
//// Gizmos.color = new Color(0f,1f,0f,1f);
|
|
//// Vector3 tVect2 = (tRect.normal.normalized*100f)+tRect.pMiddle;
|
|
//// Gizmos.DrawLine(tRect.pMiddle,tVect2);
|
|
////
|
|
//// //This creates emulated terrain point and straight up line:
|
|
//// Gizmos.color = new Color(0f,1f,1f,1f);
|
|
//// Vector3 F1 = new Vector3(500f,0f,138.5f);
|
|
//// Gizmos.DrawLine(F1,F1+ new Vector3(0f,100f,0f));
|
|
////
|
|
//// //This creates diagonal line of plane.
|
|
//// Gizmos.color = new Color(1f,0f,1f,1f);
|
|
//// Gizmos.DrawLine(P1,P3);
|
|
//// Gizmos.DrawLine(P2,P4);
|
|
////
|
|
//// //This creates intersection point:
|
|
//// Vector3 tPos = default(Vector3);
|
|
//// LinePlaneIntersection(out tPos,F1,Vector3.up,tRect.normal.normalized,tRect.pMiddle);
|
|
//// Gizmos.color = new Color(1f,1f,0f,1f);
|
|
//// Gizmos.DrawCube(tPos,new Vector3(0.3f,0.3f,0.3f));
|
|
// }
|
|
//
|
|
|
|
public List<Construction3DTri> tTriList;
|
|
public List<Vector3> 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<int>();
|
|
connectedNode = null;
|
|
connectedNode = new List<SplineN>();
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
|
/// <summary> Stores the cut materials. For use in UpdateCuts(). See UpdateCuts() in this code file for further description of this system. </summary>
|
|
public void StoreCuts()
|
|
{
|
|
//Buffers:
|
|
MeshRenderer MR = null;
|
|
MeshCollider MC = null;
|
|
|
|
//World cuts first:
|
|
if (roadCutWorld != null)
|
|
{
|
|
MR = roadCutWorld.GetComponent<MeshRenderer>();
|
|
MC = roadCutWorld.GetComponent<MeshCollider>();
|
|
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<MeshRenderer>();
|
|
MC = shoulderCutRWorld.GetComponent<MeshCollider>();
|
|
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<MeshRenderer>();
|
|
MC = shoulderCutLWorld.GetComponent<MeshCollider>();
|
|
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<MeshRenderer>();
|
|
if (MR != null)
|
|
{
|
|
roadCutMarkerMats = MR.sharedMaterials;
|
|
}
|
|
roadCutMarker = null;
|
|
}
|
|
if (shoulderCutRMarker != null)
|
|
{
|
|
MR = shoulderCutRMarker.GetComponent<MeshRenderer>();
|
|
if (MR != null)
|
|
{
|
|
shoulderCutRMarkerMats = MR.sharedMaterials;
|
|
}
|
|
shoulderCutRMarker = null;
|
|
}
|
|
if (shoulderCutLMarker != null)
|
|
{
|
|
MR = shoulderCutLMarker.GetComponent<MeshRenderer>();
|
|
if (MR != null)
|
|
{
|
|
shoulderCutLMarkerMats = MR.sharedMaterials;
|
|
}
|
|
shoulderCutLMarker = null;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public void UpdateCuts()
|
|
{
|
|
//Buffers:
|
|
MeshRenderer MR = null;
|
|
MeshCollider MC = null;
|
|
|
|
#region "Physic Materials"
|
|
//World:
|
|
if (roadCutPhysicMat != null && roadCutWorld)
|
|
{
|
|
MC = roadCutWorld.GetComponent<MeshCollider>();
|
|
if (MC != null)
|
|
{
|
|
MC.material = roadCutPhysicMat;
|
|
MC.material.name = MC.material.name.Replace(" (Instance)", "");
|
|
}
|
|
}
|
|
|
|
if (shoulderCutRPhysicMat != null && shoulderCutRWorld)
|
|
{
|
|
MC = shoulderCutRWorld.GetComponent<MeshCollider>();
|
|
if (MC != null)
|
|
{
|
|
MC.material = shoulderCutRPhysicMat;
|
|
MC.material.name = MC.material.name.Replace(" (Instance)", "");
|
|
}
|
|
}
|
|
|
|
if (shoulderCutLPhysicMat != null && shoulderCutLWorld)
|
|
{
|
|
MC = shoulderCutLWorld.GetComponent<MeshCollider>();
|
|
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<MeshRenderer>();
|
|
if (!MR)
|
|
{
|
|
roadCutWorld.AddComponent<MeshRenderer>();
|
|
}
|
|
if (MR != null)
|
|
{
|
|
MR.materials = roadCutWorldMats;
|
|
}
|
|
}
|
|
if (shoulderCutRWorldMats != null && shoulderCutRWorldMats.Length > 0 && shoulderCutRWorld)
|
|
{
|
|
MR = shoulderCutRWorld.GetComponent<MeshRenderer>();
|
|
if (!MR)
|
|
{
|
|
shoulderCutRWorld.AddComponent<MeshRenderer>();
|
|
}
|
|
if (MR != null)
|
|
{
|
|
MR.materials = shoulderCutRWorldMats;
|
|
}
|
|
}
|
|
if (shoulderCutLWorldMats != null && shoulderCutLWorldMats.Length > 0 && shoulderCutLWorld)
|
|
{
|
|
MR = shoulderCutLWorld.GetComponent<MeshRenderer>();
|
|
if (!MR)
|
|
{
|
|
shoulderCutLWorld.AddComponent<MeshRenderer>();
|
|
}
|
|
if (MR != null)
|
|
{
|
|
MR.materials = shoulderCutLWorldMats;
|
|
}
|
|
}
|
|
|
|
|
|
//Markers:
|
|
if (roadCutMarkerMats != null && roadCutMarkerMats.Length > 0 && roadCutMarker)
|
|
{
|
|
MR = roadCutMarker.GetComponent<MeshRenderer>();
|
|
if (!MR)
|
|
{
|
|
roadCutMarker.AddComponent<MeshRenderer>();
|
|
}
|
|
if (MR != null)
|
|
{
|
|
MR.materials = roadCutMarkerMats;
|
|
}
|
|
}
|
|
if (shoulderCutRMarkerMats != null && shoulderCutRMarkerMats.Length > 0 && shoulderCutRMarker)
|
|
{
|
|
MR = shoulderCutRMarker.GetComponent<MeshRenderer>();
|
|
if (!MR)
|
|
{
|
|
shoulderCutRMarker.AddComponent<MeshRenderer>();
|
|
}
|
|
if (MR != null)
|
|
{
|
|
MR.materials = shoulderCutRMarkerMats;
|
|
}
|
|
}
|
|
if (shoulderCutLMarkerMats != null && shoulderCutLMarkerMats.Length > 0 && shoulderCutLMarker)
|
|
{
|
|
MR = shoulderCutLMarker.GetComponent<MeshRenderer>();
|
|
if (!MR)
|
|
{
|
|
shoulderCutLMarker.AddComponent<MeshRenderer>();
|
|
}
|
|
if (MR != null)
|
|
{
|
|
MR.materials = shoulderCutLMarkerMats;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region "Destroy if empty"
|
|
if (roadCutMarker != null)
|
|
{
|
|
MR = roadCutMarker.GetComponent<MeshRenderer>();
|
|
if (MR == null || MR.sharedMaterial == null)
|
|
{
|
|
Object.DestroyImmediate(roadCutMarker);
|
|
}
|
|
}
|
|
if (shoulderCutRMarker != null)
|
|
{
|
|
MR = shoulderCutRMarker.GetComponent<MeshRenderer>();
|
|
if (MR == null || MR.sharedMaterial == null)
|
|
{
|
|
Object.DestroyImmediate(shoulderCutRMarker);
|
|
}
|
|
}
|
|
if (shoulderCutLMarker != null)
|
|
{
|
|
MR = shoulderCutLMarker.GetComponent<MeshRenderer>();
|
|
if (MR == null || MR.sharedMaterial == null)
|
|
{
|
|
Object.DestroyImmediate(shoulderCutLMarker);
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
|
|
/// <summary> Clears the cut materials </summary>
|
|
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"
|
|
/// <summary> Returns true if two of 3 pos Vectors to previous and next 2 nodes approx. match </summary>
|
|
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;
|
|
}
|
|
|
|
|
|
/// <summary> Returns <see langword="true"/> if exactly 2 values are approximately the same </summary>
|
|
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"
|
|
/// <summary> Returns false when isSpecialEndNode </summary>
|
|
public bool CanSplinate()
|
|
{
|
|
if (isSpecialEndNode)
|
|
{
|
|
// || bIsBridge_PreNode || bIsBridge_PostNode){
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary> Returns false when isIntersection or isSpecialEndNode </summary>
|
|
public bool IsLegitimate()
|
|
{
|
|
if (isIntersection || isSpecialEndNode)
|
|
{
|
|
// || bIsBridge_PreNode || bIsBridge_PostNode){
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary> Returns false when isSpecialEndNode </summary>
|
|
public bool IsLegitimateGrade()
|
|
{
|
|
if (isSpecialEndNode)
|
|
{
|
|
// || bIsBridge_PreNode || bIsBridge_PostNode){
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
|
|
/// <summary> Hide or unhide this node in hierarchy </summary>
|
|
public void ToggleHideFlags(bool _isHidden)
|
|
{
|
|
if (_isHidden)
|
|
{
|
|
this.hideFlags = HideFlags.HideInHierarchy;
|
|
transform.hideFlags = HideFlags.HideInHierarchy;
|
|
}
|
|
else
|
|
{
|
|
this.hideFlags = HideFlags.None;
|
|
transform.hideFlags = HideFlags.None;
|
|
}
|
|
}
|
|
}
|
|
} |