How do I make something stay open when clicked on

Godot Version

4.4

Question

I am trying to make a cabinet door that opens when clicked and when clicked again closes
Below is the code I thought would work but it only stays open as long as I am holding the mouse button

func _on_closed_cabinet_right_input_event(viewport, event, shape_idx):
	if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
		$"LivingRoomwalls/open cbinet right".visible = true
		$LivingRoomwalls/Door.visible = false

func _on_open_cabinet_right_input_event(viewport, event, shape_idx):
	if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
		$"LivingRoomwalls/open cbinet right".visible = false
		$LivingRoomwalls/Door.visible = true

I am not sure what those two func are connected to, but my guess is that since they both play with the same event input that the second is playing the moment you release the first.

I would consolidate those into one func().

In that func just check

if event:
     if $LivingRoomWalls/Doors.visible:
          #set doors visible = false
          #set other visible = true
     else:
          #set visibility of those above to the opposite value.

Have you used print statements to do any debugging?

Hi! Basic or maybe beginner coder here!

Maybe you should make a variable that counts how many times you pressed that?
When it’s 1 then the cabinet is open,
then when the variable is 2 then the cabinet closes,

then when you tap again it goes back to 1 (it’s back to the open state) So maybe like this?

var Times_Clicked: int = 0

func _on_closed_cabinet_right_input_event(viewport, event, shape_idx):
	if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
        if Times_Clicked == 2:
            Times_Clicked = 1
        Times_Clicked += 1

func process(delta: float) -> void:
    if Times_Clicked == 1:
		$"LivingRoomwalls/open cbinet right".visible = true
		$LivingRoomwalls/Door.visible = false
    elif Times_Clicked == 2:
		$"LivingRoomwalls/open cbinet right".visible = false
		$LivingRoomwalls/Door.visible = true

Sorry if this doesn’t work! Afterall.. i did say i was a beginner or basic coder! If this did work then wowzie!

(Warning do not be super confident in my code!)

1 Like

One change i’d recommend to your suggestion. Instead of a random int val, use a basic statemachine setup.

enum {CLOSED, OPENED}

var door_state: = CLOSED

Then in your input just check.

if door_state == CLOSED:
     door_state = OPENED
else:
     door_state = CLOSED

Then in physics just change your two if statements.

if door_state == CLOSED:
#change visibility
else:
#change visibility

Though you could simplify this further if you wanted and optimize more, but this should work.

1 Like

Wow! I didn’t think of that because i usually use enums for enemies or players, not items. Great job:DD

Yep, you could simplify.

enum {IDLE, CHANGED}

var state = IDLE

Then,

if Input:
state = CHANGED

Then in physics,

if state == CHANGED:
#visible of one = !visible of self
#visible of other = !visible of self
state = IDLE
1 Like

@Joee_Yeager Based on your code, I recommend something like this. NOTE: your logic seems to be backwards, but since the variable names weren’t clear, I copied your logic best I could.

@onready var open_cabinet_right = $"LivingRoomwalls/open cbinet right"
@onready var door = $LivingRoomwalls/Door

var is_cabinet_open = false

func _on_cabinet_right_input_event(viewport, event, shape_idx):
	if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
		if is_cabinet_open:
			open_cabinet_right.visible = false
			door.visible = true
			is_cabinet_open = false
		else:
			open_cabinet_right.visible = true
			door.visible = false
			is_cabinet_open = true

@isabelle_alejar @regnarok I just used a boolean here. It’s clearer in my opinion, processes faster than an int, and makes the logic a little easier. You can achieve the same clarity that the enum gives in code with the name of the boolean variable.

If you want to get fancy, you could also do something like this with a boolean. I don’t recommend it because the code is confusing to read, but in more complex code something like this will run faster because there’s no if statement at all.

@onready var open_cabinet_right = $"LivingRoomwalls/open cbinet right"
@onready var door = $LivingRoomwalls/Door

var is_cabinet_open = false

func _on_cabinet_right_input_event(viewport, event, shape_idx):
	if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
		open_cabinet_right.visible = !is_cabinet_open
		door.visible = is_cabinet_open
		is_cabinet_open = !is_cabinet_open
2 Likes

Yeah @dragonforge-dev , adding the boolean var would give clarity, it is pretty much a refined version of my suggestion keeping to his code logic just adding that extra var for the clarity, and making his node ref var as well. All in all a pretty little piece of code.

Yeah, the enum post was a response to @isabelle_alejar suggestion, I figured it wasn’t a wrong way to handle it, and the logic being used was the same as a enum with state control.

2 Likes

There are definitely multiple ways to handle it that are valid. I just replied because I know @isabelle_alejar is trying to learn and I wanted to give yet another way. :slight_smile:

2 Likes