Wiring a Lift in Godot with Instanced Buttons (No Prefab Spawning Required)

If your lift isn’t moving and you’re staring at “0 nearby interactables,” you’re not alone.
This guide shows a clean setup that uses already-instanced buttons in your scene, while keeping lift logic in a single script.

This approach avoids runtime spawning and instead links existing nodes by NodePath — perfect for level-authored layouts.


0) What Are the Lift Pieces Made Of?

Before wiring, it helps to know what each piece actually is:

  • Interactable: Base script (interactables/interactable.gd) that auto‑adds nodes to the interactable group so the player can detect and use them.
  • InteractableButton: Reusable button script (interactables/button.gd) that extends Interactable and handles interaction prompts + button signals.
  • LiftButton: Specific lift button script (interactables/lift_button.gd) that extends InteractableButton and calls methods on a LiftFloor.
  • LiftFloor: The moving platform script (interactables/lift_floor.gd) that contains movement logic and wires buttons.

Scene composition:

  • LiftFloor nodeCharacterBody3D with lift_floor.gd attached.
  • LiftButton sceneinteractables/lift_button.tscn whose root is Node3D with lift_button.gd attached plus an Area3D for interaction.
  • Start/End markersMarker3D nodes used by the lift to know where to move.

This means: the button is a scene, the lift floor is a scripted node, and the player looks for nodes in the interactable group.


1) Scene Layout (Lift Test Example)

In your scenes/lift_test.tscn, you should have:

  • LiftFloor (the moving platform)
  • LiftButton (main button; child of LiftFloor)
  • Start Call Button and End Call Button (in the scene root)
  • StartPoint and EndPoint markers

All buttons are instances of interactables/lift_button.tscn.


2) Lift Floor Script: Accept Existing Nodes

Use NodePath exports to point at existing button instances:

@export var lift_button_path: NodePath
@export var call_button_start_path: NodePath
@export var call_button_end_path: NodePath

Then, in _ready():

_lift_button = _get_button_from_path(lift_button_path, "LiftButton")
_call_button_start = _get_button_from_path(call_button_start_path, "CallButtonStart")
_call_button_end = _get_button_from_path(call_button_end_path, "CallButtonEnd")

_setup_button(_lift_button, "toggle", "Press F to use lift")
_setup_button(_call_button_start, "move_to_start", "Press F to call lift (start)")
_setup_button(_call_button_end, "move_to_end", "Press F to call lift (end)")

This lets you drag existing nodes into the inspector and wire the lift without spawning new scenes.


3) Ensure Buttons Are Properly Scripted

Your button scene (interactables/lift_button.tscn) must have lift_button.gd attached.
If the script is missing, the button shows up as plain Node3D and won’t be “interactable.”

Checklist:

  • Root node of lift_button.tscn uses lift_button.gd
  • lift_button.gd extends InteractableButton
  • InteractableButton extends Interactable
  • Interactable._ready() adds the node to the interactable group

4) Why “0 nearby interactables” Happens

The player prints:

Player checking 0 nearby interactables in 'interactable' group:

That means one of these is true:

  • The button script never ran (wrong script attached)
  • The button never got added to the interactable group
  • The node isn’t the correct type (LiftButton vs plain Node3D)

A simple fix is to ensure your setup code calls:

button.add_to_group("interactable")

5) Final Wiring in the Inspector

Select the LiftFloor node and assign:

  • lift_button_path → LiftButton (child)
  • call_button_start_path → ../Start Call Button
  • call_button_end_path → ../End Call Button
  • start_position → StartPoint
  • end_position → EndPoint

That’s it — no prefab spawning required.


6) Debugging Tips That Actually Help

Add a few debug prints to see what’s happening:

  • Lift logs:
    • assigned buttons
    • target changes
    • movement state
  • Button logs:
    • interaction blocked
    • method called
    • target lift object

This gives you instant visibility when something is “wired but not working.”


Wrap‑Up

Best practice here is simple:

  • Use NodePath for existing nodes
  • Use PackedScene only when you’re spawning
  • Always verify scripts are attached
  • Groups matter for player detection

If you want a cleaner, decoupled version, convert to signals.
If you want a prefab lift, keep the PackedScene path and spawn inside the lift.


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *