diff --git a/scenes/Main.tscn b/scenes/Main.tscn index c78681e..80a9bc9 100644 --- a/scenes/Main.tscn +++ b/scenes/Main.tscn @@ -7,6 +7,7 @@ [node name="Main" type="Node2D"] [node name="Train" parent="." instance=ExtResource( 1 )] +_speed = 5.0 _railwayPath = NodePath("../Railway") [node name="DirectionalLight" type="DirectionalLight" parent="."] diff --git a/scenes/Train.tscn b/scenes/Train.tscn index af13423..379b636 100644 --- a/scenes/Train.tscn +++ b/scenes/Train.tscn @@ -5,5 +5,6 @@ [node name="Train" type="Spatial"] script = ExtResource( 1 ) +_carPath = NodePath("Train Car") [node name="Train Car" parent="." instance=ExtResource( 2 )] diff --git a/scenes/TrainCar.tscn b/scenes/TrainCar.tscn index f11e3ec..be6303d 100644 --- a/scenes/TrainCar.tscn +++ b/scenes/TrainCar.tscn @@ -5,6 +5,7 @@ [node name="Train Car" type="Spatial"] script = ExtResource( 1 ) +Wheelbase = 5.0 _boxNode = NodePath("CSGBox") _bogiePaths = [ NodePath("Bogie"), NodePath("Bogie2") ] @@ -15,7 +16,7 @@ height = 1.0 depth = 8.0 [node name="Bogie" parent="." instance=ExtResource( 2 )] -transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -2 ) +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -2.5 ) [node name="Bogie2" parent="." instance=ExtResource( 2 )] -transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2 ) +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2.5 ) diff --git a/scripts/Train.cs b/scripts/Train.cs index 2451bb3..7806386 100644 --- a/scripts/Train.cs +++ b/scripts/Train.cs @@ -1,5 +1,6 @@ using Godot; using System; +using System.Collections.Generic; public class Train : Spatial { @@ -10,17 +11,48 @@ public class Train : Spatial private NodePath _railwayPath; private Railway _railway; - private readonly PathFollow _pathFollow = new PathFollow - { - RotationMode = PathFollow.RotationModeEnum.Oriented - }; private float _distance = 0; + [Export] + private NodePath _carPath; + private TrainCar _car; + + private Spatial[] _bogies; + private readonly Dictionary _bogiePathFollows = new Dictionary(); + + private ImmediateGeometry _imgui; + // Called when the node enters the scene tree for the first time. public override void _Ready() { - _railway = GetNode(_railwayPath) as Railway; - _railway.AddPathFollower(_pathFollow); + _imgui = new ImmediateGeometry(); + var m = new SpatialMaterial(); + m.VertexColorUseAsAlbedo = true; + m.FlagsUnshaded = true; + _imgui.MaterialOverride = m; + AddChild(_imgui); + + _railway = GetNode(_railwayPath); + _car = GetNode(_carPath); + + _bogies = new Spatial[_car.Bogies.Length]; + for (int i = 0; i < _bogies.Length; i++) + { + var b = _car.Bogies[i]; + _bogies[i] = b; + _bogiePathFollows[b] = new PathFollow + { + RotationMode = PathFollow.RotationModeEnum.Oriented + }; + _railway.AddPathFollower(_bogiePathFollows[b]); + + // detach the bogies from the car as we need to set the bogie + // positions in order to calculate the car position and it will + // get confusing if they're in a parent/child relationship, + // so make them all siblings + _car.RemoveChild(b); + this.AddChild(b); + } } // Called every frame. 'delta' is the elapsed time since the previous frame. @@ -28,6 +60,12 @@ public class Train : Spatial { var length = _railway.Curve.GetBakedLength(); + // first determine which is the front bogie. this is dependent + // on the direction of travel. + int travelDir = (int)(_distance / length) == 0 ? -1 : 1; + + DrawTravelDirectionIndicator(travelDir); + // keep track of total distance _distance += delta * _speed; // wrap at 2x total distance @@ -35,9 +73,40 @@ public class Train : Spatial var distance = PingPong(_distance, length); - _pathFollow.Offset = distance; - Translation = _pathFollow.Translation; - Rotation = _pathFollow.Rotation; + // get the position of the first bogie on the track + var b = _bogies[0]; + var pathFollow = _bogiePathFollows[b]; + + pathFollow.Offset = distance; + b.Translation = pathFollow.Translation; + b.Rotation = pathFollow.Rotation; + + // now we want to position the car over the first bogie + GD.Print(_car.Wheelbase); + _car.Translation = b.Translation; + _car.Rotation = b.Rotation; + + // TODO: this rotation quat needs to position the other + // bogie over the curve + _car.Translation += _car.Transform.basis + .RotationQuat() + .Xform(Vector3.Back) * _car.Wheelbase * 0.5f; + } + + private void DrawTravelDirectionIndicator(int travelDir) + { + _imgui.Clear(); + _imgui.Begin(Mesh.PrimitiveType.LineStrip); + _imgui.SetColor(new Color(1, 0, 0)); + var c = _car.Translation + Vector3.Up * 2; + _imgui.AddVertex(c); + var d = travelDir; + var l = 5; + var e = c + _car.Transform.basis + .RotationQuat() + .Xform(Vector3.Forward) * d * l; + _imgui.AddVertex(e); + _imgui.End(); } // poor mans branching ping pong diff --git a/scripts/TrainCar.cs b/scripts/TrainCar.cs index 8d88df1..c4aa0db 100644 --- a/scripts/TrainCar.cs +++ b/scripts/TrainCar.cs @@ -13,21 +13,37 @@ public class TrainCar : Spatial private NodePath[] _bogiePaths; [Export] - private float Wheelbase + public float Wheelbase { get => _wheelbase; set { _wheelbase = value; - if (Engine.EditorHint) - { - SetBogeyPositions(); - } + + // don't set the wheelbase except from the editor + if (!Engine.EditorHint) return; + + SetBogeyPositions(); } } private float _wheelbase; - private readonly Spatial[] _bogies = new Spatial[2]; + public Spatial[] Bogies + { + get + { + if (_bogies == null) + { + _bogies = new Spatial[2]; + for (int i = 0; i < _bogiePaths.Length; i++) + { + _bogies[i] = GetNode(_bogiePaths[i]); + } + } + return _bogies; + } + } + private Spatial[] _bogies = null; private CSGBox _box; private CSGBox Box @@ -42,6 +58,8 @@ public class TrainCar : Spatial } } + public Railway Railway { get; set; } + public override void _Ready() {