Godot Version
v4.7.beta2.official [777579205]
Question
I've started a Project for a Game Jam, for end of this month. The idea is to place Wooden Train tracks on a board, like a jigsaw puzzle. Once a circuit is created, a loco would appear and run around the circuit. That's the idea, but I'm quite some way away from there..!
It's 3D, but for moving the track elements, the view is 'Top Down'. For the moment, only two straight tracks and one curve are on the board. These can be moved, by selecting with the mouse, Left click to place it. If the tongue is over a hole, this locks the piece (turns Red...). To free a piece, Right click. Whilst not locked, Right click rotates the piece 90°. A Right click on a locked piece frees it (turns Green...).
All fine for now, so where's the problem..? Hmm... It's a bit 'clunky'; if the mouse pointer moves too fast, the piece gets lost.
The main issue is the way that the pieces need, for now, individual scripts, and there should be a lot more pieces to come..! Soooooo...
Before going too far, could I have some advice as to how better structure it all. I can do what it takes, as long as itās within the grasp of a slow-witted old duffer (yes, thatās meā¦), and does not imply use of elaborate plugins, artificial intelligence or uncouth language..! Iāve attached a link to a āzipā file on my Google Drive, containing all of the Project (without the ā.godotā folder, naturally). Itās quite small, and, I hope, fairly easy to follow, but needs suggestions for improvement. The ābiggyā is the addressing of the piece, and its label, in the code, for each piece. Thatās not good, for extending to lots of pieces; how to do better, please..?
Thanks in advance for any advice and/or suggestions; meanwhileā¦
Have a great day.
Google Drive : Wood_Trai.zipā¦
You probably donāt need individual scripts for each piece. Just write a single script that all pieces will share, with exported variables.
Make each different track piece a standalone scene, so you can modify the exported variables in the Inspector.
Yes, thanks for that; Iāve been trying to get that to work, but thereās a snag, it seems. The code which reacts to the signal has to address the specific Object, which I canāt seem to decouple, or address from outside the Object. Hereās the code in questionā¦
func _process(_delta):
if lv_dragging == true:
if get_mouse_world_position() != null:
lv_offset = get_mouse_world_position()
var lv_x = lv_offset.x
var lv_z = lv_offset.z
$stra_01_54.global_position = Vector3(lv_x,0.0,lv_z)
func _on_static_body_3d_input_event(_camera, event, _event_position, _normal, _shape_idx):
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.is_pressed():
print("Dragging")
if lv_dragging == false:
if lv_lock == false:
lv_dragging = true
else:
print("Over")
lv_dragging = false
if lv_conn_flag == true:
lv_lock = true
print("Locked")
$stra_01_54/Label3D.modulate = Color(1.0,0.0,0.0,1)
if event.button_index == MOUSE_BUTTON_RIGHT and event.is_pressed():
if lv_lock == true:
lv_lock = false
lv_conn_flag = false
print("Unlocked")
$stra_01_54/Label3D.modulate = Color(0.0,1.0,0.0,1)
else:
print("Rotate")
lv_dragging = false
if lv_conn_flag == true:
lv_lock = true
$stra_01_54.rotate_y(deg_to_rad(int(90)))
,
...and here's the Layout tree and overall Editor view...
Itās the MeshInstance3d thatās being addressed, for Mouse position detection, Rotation, and changing the Label3D colour. If I could address this outside of the script, I think that a common script would work, but how to address this MeshInstance3D..?
If Iām understanding correctly what youāre trying to do, you can store the MeshInstance3D in the script:
-
Declare a variable to store the MeshInstance3D in the script, e.g. āvar mesh_node: MeshInstance3Dā.
-
In _ready(), assign the MeshInstance3D to mesh_node.
It looks like your MeshInstance3D nodes have a different name for each piece, but theyāre the only direct child of the root node. So this should work:
for child in self.get_children():
mesh_node = child
If you add more direct children to any pieceās root node later, the above wonāt work anymore. In that case, you may want to add a condition to check that the child is a MeshInstance3D:
for child in self.get_children():
if child is MeshInstance3D:
mesh_node = child
Of course, that wonāt work either if the additional children are also MeshInstance3D.
Another option is to make mesh_node an exported variable, and assign the MeshInstance3D manually in the Inspector:
@export var mesh_node: MeshInstance3D
You should be able to drag the MeshInstance3D from the node tree to the mesh_node field in the Inspector. If each track piece variant is a standalone scene, thatās doable. Itās just more manual work.
Hope that helps!
Edit: forgot to add - after that, any external code just needs address mesh_node on the track piece. For example:
$āLayout/track_pieceā.mesh_node ā That finds the MeshInstance3D.
Yes, these are the suggestions I was hoping for. Iāll have to break open another tube of aspirin and try to incorporate these (foreign, to meā¦) notions, but itās on the right track. The actual structure of the track pieces shouldnāt change much, now (it took me long enough to get this structure to work..!), but there will be other, identical and different, pieces to add to the board. It would make sense to have most of the code common, and not specific to each piece. That would work, but would be a real āpigās earā of code. Dinner first, then Iāll try out these methods. Thanks again. 
Youāre welcome! The wooden railway brought back some nice childhood memories 
I also wrote code for train tracks a year ago, so Iāve been there!
Thanks to the help offered above ^^, I was able to render the code āanonymousā, common to all of the pieces. Using the same principles, I could also have colour-coding on the pieces, to indicate their state, or condition (waiting, moving or lockedā¦). I have enough pieces on the virtual āboardā to complete a closed circuit for the first time..! I added some background music, just because, and need to tidy up a little, before deciding how to turn it into something a bit less āclunkyā. Progress has been made, then, but there is more progress to come before signing it off.
Iām very pleased with the advice given; many thanks. 
Youāre welcome, Iām glad I could be of help! Train systems have a reputation for being hard to do, but I also learned a lot from making one.
Iād love to see the final result if you post it somewhere later when itās finished!
I finished the Project (but are they ever really finished..?) with a lot less going on than originally imagined, but the short delay for the Game Jam meant that I consider it a miracle that anything at all got done..! I sent it off to the Jam; thereās a copy of the Windows āexeā file on my Google drive, for anyone to download, if interested. Be aware that itās extremely modest, of course; unlikely to overtake Tetris in the game charts..! At the very last minute, I even added a screen overlay with the mouse and keyboard controls. Hereās the link to it ā¦
Wood_Rail.exe on my Google Drive ā¦
Itās not much, but at least I got ānot muchā done..! Miracle, I tellāee; miracle..!
Peace.
Edit : I see that thereās now an Itch.io link to download it..! Hereā¦