I’m learning Godot by making a top-down 2D game that’s very much like Pacman except with trains. Player is being chased by enemies (all CharacterBody2D) and everyone can board trains (Area2D following a Path2D) to get around the game area faster.
When a character boards a train, I want them to move in sync with the train (as in, actually stay on it instead of being left behind), but also to be able to move WITHIN the train (as in, go from the back to the front etc). This is easily achieved if I set the player and enemies to be children of the train. However, the characters will be boarding and leaving different trains frequently, so I’d have to keep reparenting them constantly. Correct me if I’m wrong but that doesn’t seem like a scalable solution to me.
So far I tried using the RemoteTransform2D node. When using global coordinates, that node manages to move the characters together with the train but it also makes them “stuck” and unable to move away from the RemoteTransform position at all while the train is moving. When using local coordinates, the RemoteTransform node doesn’t seem to do anything…
Is there another way to make a the characters have their position modified by the train node without having to reparent them as children of that specific train? I tried making a custom script by that keeps track of the global positions of the character and the train but it’s kind of cumbersome and doesn’t work as well as just reparenting. I feel like I’m missing something. If you know a simpler way to do it, I’d be really grateful!
Okay, I think I solved it using dynamically repositioned marker nodes - here is my somewhat hacky solution in case anyone stumbles on this thread while stuck on a similar problem.
const speed = 100
var direction = Vector2
var inside_train = false
@onready var marker = $"../TrainLine/TrainlineRoute/PathFollow2D/Train/PassengerPosition"
func board_train():
# when player boards train, Passenger Marker is placed at player position
inside_train = true
marker.global_position = global_position
martker.global_rotation = global_rotation
func _physics_process(delta):
# before moving, put player in the location of the passenger marker
if inside_train == true:
global_position = marker.global_position
# rotation needs updating or player will end up outside the train when train turns
global_rotation = marker.global_rotation
# move player as normal
velocity = direction * speed * delta
move_and_slide()
# after player moves, move the marker to the new player location
if inside_train == true:
marker.global_position = global_position
marker.global_rotation = global_rotation
Notes:
The code needs to be made neater (e.g. without a hardcoded get_node reference to the marker node from the player script).
Each passenger will need their own Passenger Marker node to allow for individual movement.
Each Passenger Marker node could be instantiated dynamically when a character boards a train.
There might be a smarter way to achieve it using a similar method with RemoteTransform nodes but I really can’t see it right now.