diff --git a/Mapify/Map/MapLifeCycle.cs b/Mapify/Map/MapLifeCycle.cs index ebe42eb..71bee18 100644 --- a/Mapify/Map/MapLifeCycle.cs +++ b/Mapify/Map/MapLifeCycle.cs @@ -144,7 +144,7 @@ public static IEnumerator LoadMap(BasicMapInfo basicMapInfo) LevelInfo levelInfo = SingletonBehaviour.Instance; levelInfo.terrainSize = mapInfo.terrainSize; levelInfo.waterLevel = mapInfo.waterLevel; - levelInfo.worldSize = mapInfo.worldSize; + levelInfo.worldSize = new Vector3(mapInfo.worldSize, levelInfo.worldSize.y, mapInfo.worldSize); levelInfo.worldOffset = Vector3.zero; levelInfo.defaultSpawnPosition = mapInfo.defaultSpawnPosition; levelInfo.defaultSpawnRotation = mapInfo.defaultSpawnRotation; diff --git a/Mapify/SceneInitializers/Terrain/DistantTerrainSetup.cs b/Mapify/SceneInitializers/Terrain/DistantTerrainSetup.cs index bb0e93a..6957601 100644 --- a/Mapify/SceneInitializers/Terrain/DistantTerrainSetup.cs +++ b/Mapify/SceneInitializers/Terrain/DistantTerrainSetup.cs @@ -15,7 +15,7 @@ public override void Run() DistantTerrain distantTerrain = distantTerrainObject.gameObject.AddComponent(); distantTerrain.trackingReference = SingletonBehaviour.Instance.playerTracker.GetTrackerTransform(); distantTerrain.singleTerrainSize = levelInfo.terrainSize; - distantTerrain.worldScale = levelInfo.worldSize; + distantTerrain.worldScale = levelInfo.worldSize.x; distantTerrain.step = 128; // No idea what this means but this is what it's set to in the game. } } diff --git a/MapifyEditor/Trackage/SnappedTrack.cs b/MapifyEditor/Trackage/SnappedTrack.cs new file mode 100644 index 0000000..8585e31 --- /dev/null +++ b/MapifyEditor/Trackage/SnappedTrack.cs @@ -0,0 +1,19 @@ +namespace Mapify.Editor +{ + public class SnappedTrack + { + public SnappedTrack(Track aTrack, BezierPoint aPoint) + { + track = aTrack; + point = aPoint; + } + private Track track; + private BezierPoint point; + + public void UnSnapped() + { + if (track == null){ return; } + track.UnSnapped(point); + } + } +} diff --git a/MapifyEditor/Trackage/Switch.cs b/MapifyEditor/Trackage/Switch.cs index 7dce3ff..b11e73f 100644 --- a/MapifyEditor/Trackage/Switch.cs +++ b/MapifyEditor/Trackage/Switch.cs @@ -9,6 +9,7 @@ namespace Mapify.Editor { + [ExecuteInEditMode] //this is necessary for snapping to work [RequireComponent(typeof(VanillaObject))] public class Switch : MonoBehaviour { @@ -23,65 +24,182 @@ public enum StandSide [Tooltip("Which way the switch should be flipped by default")] public StandSide defaultState; + private enum SwitchPoint + { + FIRST, //the point that is shared between the two tracks + THROUGH, + DIVERGING + } + +#if UNITY_EDITOR + private bool snapShouldUpdate = true; + + private Vector3 previousPositionSwitchFirstPoint; + private Vector3 previousPositionThroughTrackLastPoint; + private Vector3 previousPositionDivergingTrackLastPoint; + + + private SnappedTrack snappedTrackBeforeSwitch; + //the track connected to the through track + private SnappedTrack snappedTrackAfterThrough; + //the track connected to the diverging track + private SnappedTrack snappedTrackAfterDiverging; +#endif + public Track ThroughTrack => transform.Find("[track through]").GetComponent(); public Track DivergingTrack => transform.Find("[track diverging]").GetComponent(); public bool IsLeft => DivergingTrack.Curve.Last().localPosition.x < 0; +#if UNITY_EDITOR + + private void OnEnable() + { + snapShouldUpdate = true; + } + + private void OnDisable() + { + UnsnapConnectedTracks(); + } + + private void OnDestroy() + { + UnsnapConnectedTracks(); + } + private void OnDrawGizmos() { if (transform.DistToSceneCamera() >= Track.SNAP_UPDATE_RANGE_SQR) + { return; - Snap(); + } + + CheckSwitchMoved(); + + if (snapShouldUpdate) + { + Snap(); + snapShouldUpdate = false; + } + } + + private void CheckSwitchMoved() + { + var positionSwitchFirstPoint = transform.position; + var positionThroughTrackLastPoint = ThroughTrack.Curve.Last().position; + var positionDivergingTrackLastPoint = DivergingTrack.Curve.Last().position; + + if (positionSwitchFirstPoint != previousPositionSwitchFirstPoint || + positionThroughTrackLastPoint != previousPositionThroughTrackLastPoint || + positionDivergingTrackLastPoint != previousPositionDivergingTrackLastPoint) + { + snapShouldUpdate = true; + + previousPositionSwitchFirstPoint = positionSwitchFirstPoint; + previousPositionThroughTrackLastPoint = positionThroughTrackLastPoint; + previousPositionDivergingTrackLastPoint = positionDivergingTrackLastPoint; + } + } + + private void UnsnapConnectedTracks() + { + snappedTrackBeforeSwitch?.UnSnapped(); + snappedTrackAfterThrough?.UnSnapped(); + snappedTrackAfterDiverging?.UnSnapped(); } public void Snap() { -#if UNITY_EDITOR - BezierPoint[] bezierPoints = FindObjectsOfType(); - GameObject[] selectedObjects = Selection.gameObjects; - bool isSelected = selectedObjects.Contains(gameObject); - TrySnap(bezierPoints, isSelected, 0); - TrySnap(bezierPoints, isSelected, 1); - TrySnap(bezierPoints, isSelected, 2); -#endif + var bezierPoints = FindObjectsOfType(); + bool isSelected = Selection.gameObjects.Contains(gameObject); + + TrySnap(bezierPoints, isSelected, SwitchPoint.FIRST); + TrySnap(bezierPoints, isSelected, SwitchPoint.DIVERGING); + TrySnap(bezierPoints, isSelected, SwitchPoint.THROUGH); } - private void TrySnap(IEnumerable points, bool move, byte which) + private void TrySnap(IEnumerable points, bool move, SwitchPoint switchPoint) { - Transform reference; - switch (which) + var reference = switchPoint switch { - case 0: - reference = transform; - break; - case 1: - reference = DivergingTrack.Curve.Last().transform; - break; - case 2: - reference = ThroughTrack.Curve.Last().transform; - break; - default: - throw new ArgumentOutOfRangeException(nameof(which)); - } + SwitchPoint.FIRST => transform, + SwitchPoint.THROUGH => ThroughTrack.Curve.Last().transform, + SwitchPoint.DIVERGING => DivergingTrack.Curve.Last().transform, + _ => throw new ArgumentOutOfRangeException(nameof(switchPoint), switchPoint, null) + }; + + var position = reference.position; + var closestPosition = Vector3.zero; + var closestDistance = float.MaxValue; - Vector3 pos = reference.position; - Vector3 closestPos = Vector3.zero; - float closestDist = float.MaxValue; - foreach (BezierPoint otherBP in points) + foreach (BezierPoint otherSnapPoint in points) { - if (otherBP.Curve().GetComponentInParent() == this) continue; - Vector3 otherPos = otherBP.transform.position; - float dist = Mathf.Abs(Vector3.Distance(otherPos, pos)); - if (dist > Track.SNAP_RANGE || dist >= closestDist) continue; - if (otherBP.GetComponentInParent().IsSwitch) continue; - closestPos = otherPos; - closestDist = dist; + //don't connect to itself + if (otherSnapPoint.Curve().GetComponentInParent() == this) continue; + + Vector3 otherPosition = otherSnapPoint.transform.position; + float distance = Mathf.Abs(Vector3.Distance(otherPosition, position)); + + // too far away + if (distance > Track.SNAP_RANGE || distance >= closestDistance) continue; + + var otherTrack = otherSnapPoint.GetComponentInParent(); + + // don't snap a switch to another switch + if (otherTrack.IsSwitch) continue; + + closestPosition = otherPosition; + closestDistance = distance; + + otherTrack.Snapped(otherSnapPoint); + + //remember what track we snapped to + switch (switchPoint) + { + case SwitchPoint.FIRST: + snappedTrackBeforeSwitch = new SnappedTrack(otherTrack, otherSnapPoint); + break; + case SwitchPoint.THROUGH: + snappedTrackAfterThrough = new SnappedTrack(otherTrack, otherSnapPoint); + break; + case SwitchPoint.DIVERGING: + snappedTrackAfterDiverging = new SnappedTrack(otherTrack, otherSnapPoint); + break; + default: + throw new ArgumentOutOfRangeException(nameof(switchPoint), switchPoint, null); + } } - if (closestDist >= float.MaxValue) return; + // No snap target found + if (closestDistance >= float.MaxValue) + { + switch (switchPoint) + { + case SwitchPoint.FIRST: + snappedTrackBeforeSwitch?.UnSnapped(); + snappedTrackBeforeSwitch = null; + break; + case SwitchPoint.THROUGH: + snappedTrackAfterThrough?.UnSnapped(); + snappedTrackAfterThrough = null; + break; + case SwitchPoint.DIVERGING: + snappedTrackAfterDiverging?.UnSnapped(); + snappedTrackAfterDiverging = null; + break; + default: + throw new ArgumentOutOfRangeException(nameof(switchPoint), switchPoint, null); + } + + return; + } if (move) - transform.position = closestPos + (transform.position - reference.position); + { + transform.position = closestPosition + (transform.position - reference.position); + } } + +#endif } } diff --git a/MapifyEditor/Trackage/Track.cs b/MapifyEditor/Trackage/Track.cs index 7cf715d..87e46fe 100644 --- a/MapifyEditor/Trackage/Track.cs +++ b/MapifyEditor/Trackage/Track.cs @@ -6,6 +6,7 @@ namespace Mapify.Editor { + [ExecuteInEditMode] //this is necessary for snapping to work [RequireComponent(typeof(BezierCurve))] public class Track : MonoBehaviour { @@ -54,6 +55,17 @@ public class Track : MonoBehaviour public bool isOutSnapped { get; private set; } private BezierCurve _curve; +#if UNITY_EDITOR + private bool snapShouldUpdate = true; + private Vector3 previousPositionFirstPoint; + private Vector3 previousPositionLastPoint; + + //the track connected to the first point in our curve + private SnappedTrack snappedTrackBefore; + //the track connected to the last point in our curve + private SnappedTrack snappedTrackAfter; +#endif + public BezierCurve Curve { get { if (_curve != null) return _curve; @@ -80,6 +92,26 @@ private Switch ParentSwitch { : name : $"[Y]_[{stationId}]_[{yardId}-{trackId:D2}-{trackType.LetterId()}]"; +#if UNITY_EDITOR + + private void OnEnable() + { + snapShouldUpdate = true; + } + + private void OnDisable() + { + snappedTrackBefore?.UnSnapped(); + snappedTrackAfter?.UnSnapped(); + } + + private void OnDestroy() + { + snappedTrackBefore?.UnSnapped(); + snappedTrackAfter?.UnSnapped(); + } +#endif + private void OnValidate() { if (!isActiveAndEnabled || IsSwitch || IsTurntable) @@ -112,6 +144,7 @@ private void OnValidate() break; } } + #if UNITY_EDITOR private void OnDrawGizmos() { @@ -123,7 +156,22 @@ private void OnDrawGizmos() DrawDisconnectedIcon(Curve[0].position); if (!isOutSnapped) DrawDisconnectedIcon(Curve.Last().position); - Snap(); + + //first or last point moved? + if (Curve[0].position != previousPositionFirstPoint || + Curve.Last().position != previousPositionLastPoint) + { + snapShouldUpdate = true; + + previousPositionFirstPoint = Curve[0].position; + previousPositionLastPoint = Curve.Last().position; + } + + if (snapShouldUpdate) + { + Snap(); + snapShouldUpdate = false; + } } internal void Snap() @@ -175,48 +223,96 @@ private void DrawLoadingGauge() private void TrySnap(IEnumerable snapPoints, bool move, bool first) { - if (first) isInSnapped = false; - else isOutSnapped = false; - - BezierPoint point = first ? Curve[0] : Curve.Last(); - Vector3 pos = point.transform.position; - Vector3 closestPos = Vector3.zero; - float closestDist = float.MaxValue; + var mySnapPoint = first ? Curve[0] : Curve.Last(); + var pos = mySnapPoint.transform.position; + var closestPosition = Vector3.zero; + var closestDistance = float.MaxValue; - Collider[] colliders = new Collider[1]; + var colliders = new Collider[1]; // Turntables will search for track within 0.05m, so set it a little lower to be safe. if (!IsSwitch && Physics.OverlapSphereNonAlloc(pos, 0.04f, colliders) != 0) { - Collider collider = colliders[0]; - Track track = collider.GetComponent(); - if (collider is CapsuleCollider capsule && track != null && track.IsTurntable) + var foundCollider = colliders[0]; + var track = foundCollider.GetComponent(); + if (foundCollider is CapsuleCollider capsule && track != null && track.IsTurntable) { Vector3 center = capsule.transform.TransformPoint(capsule.center); - closestPos = pos + (Vector3.Distance(pos, center) - capsule.radius) * -(pos - center).normalized; - closestPos.y = center.y; - closestDist = Vector3.Distance(pos, closestPos); + closestPosition = pos + (Vector3.Distance(pos, center) - capsule.radius) * -(pos - center).normalized; + closestPosition.y = center.y; + closestDistance = Vector3.Distance(pos, closestPosition); + + // no need to remember snapped turntables because they don't have the "Disconnected" indicator + if (first) + { + snappedTrackBefore = null; + } + else + { + snappedTrackAfter = null; + } + } + } + + if (closestDistance >= float.MaxValue) + { + foreach (BezierPoint otherSnapPoint in snapPoints) + { + //don't snap to itself + if (otherSnapPoint.Curve() == mySnapPoint.Curve()) continue; + + Vector3 otherPosition = otherSnapPoint.transform.position; + float distance = Mathf.Abs(Vector3.Distance(otherPosition, pos)); + + // too far away + if (distance > SNAP_RANGE || distance >= closestDistance) continue; + + var otherTrack = otherSnapPoint.GetComponentInParent(); + + // don't snap a switch to another switch + if (IsSwitch && otherTrack.IsSwitch) continue; + + closestPosition = otherPosition; + closestDistance = distance; + + otherTrack.Snapped(otherSnapPoint); + + //remember what track we snapped to + if (first) + { + snappedTrackBefore = new SnappedTrack(otherTrack, otherSnapPoint); + } + else + { + snappedTrackAfter = new SnappedTrack(otherTrack, otherSnapPoint); + } } } - if (closestDist >= float.MaxValue) - foreach (BezierPoint otherBp in snapPoints) + // No snap target found + if (closestDistance >= float.MaxValue) + { + if (first) { - if (otherBp.Curve() == point.Curve()) continue; - Vector3 otherPos = otherBp.transform.position; - float dist = Mathf.Abs(Vector3.Distance(otherPos, pos)); - if (dist > SNAP_RANGE || dist >= closestDist) continue; - if (IsSwitch && otherBp.GetComponentInParent().IsSwitch) continue; - closestPos = otherPos; - closestDist = dist; + snappedTrackBefore?.UnSnapped(); + snappedTrackBefore = null; + + isInSnapped = false; } + else + { + snappedTrackAfter?.UnSnapped(); + snappedTrackAfter = null; - if (closestDist >= float.MaxValue) + isOutSnapped = false; + } return; + } if (first) isInSnapped = true; else isOutSnapped = true; - if (move) point.transform.position = closestPos; + if (move) mySnapPoint.transform.position = closestPosition; } + #endif internal void Snapped(BezierPoint point) { @@ -226,6 +322,14 @@ internal void Snapped(BezierPoint point) isOutSnapped = true; } + internal void UnSnapped(BezierPoint point) + { + if (point == Curve[0]) + isInSnapped = false; + if (point == Curve.Last()) + isOutSnapped = false; + } + public static Track Find(string stationId, char yardId, byte trackId, TrackType trackType) { return FindObjectsOfType().FirstOrDefault(t => t.stationId == stationId && t.yardId == yardId && t.trackId == trackId && t.trackType == trackType);