Godot Version
4.3
Problem(s)
Hello! I’m trying to code a simple escape room, I’m entirely new to Godot. I’m in that beginner phase where you simply follow tutorials along, and I figured watching one for escape rooms/point and click would be a good way to be introduced to the genre and eventually deal with it myself.
The only tutorial I found was Robin Lamb’s and the problem began when I finished the second video. It’s dedicated to drag-and-drop inventory features. The person doesn’t explain the code very well so I just copied it word by word and it’s… half-working.
The last part of the video is about using an item that you collected on something that is in the room in order to solve puzzles and that type of stuff. In the video it works fine, in my code it doesn’t at all. (I have a small suspicion the video skipped a few vital parts but I don’t want to accuse someone I don’t know of messing up…)
In my code I used a watering can as the item and a flower as the thing that needs to be interacted with. The flower is supposed to bloom when the watering can’s Area2D enters the flower’s Area2D and the item is released. It does nothing. If you look up the video, you’ll see that it seemingly works.
Here is the entire main script which is where this interaction is being handled. I annotated it a little and the flower interaction is at the very bottom.
extends Node2D
var hand_cursor = preload("res://question.png")
var detail_selected = false
var slot1_filled = false
var slot2_filled = false
var slot3_filled = false
var wateringcan_used = false
#Cursor things
func change_cursor_hand():
if !detail_selected:
Input.set_custom_mouse_cursor(hand_cursor)
func change_cursor_default():
if !detail_selected:
Input.set_custom_mouse_cursor(null)
func change_cursor_hand_detail():
Input.set_custom_mouse_cursor(hand_cursor)
func change_cursor_default_detail():
Input.set_custom_mouse_cursor(null)
# Inventory things
func fill_slot(slot):
match slot:
1: slot1_filled = true
2: slot2_filled = true
3: slot3_filled = true
func empty_slot(slot):
match slot:
1: slot1_filled = false
2: slot2_filled = false
3: slot3_filled = false
func choose_slot(item):
var chosen_slot = 1
if !slot1_filled:
chosen_slot = $inventory/Container/slot1.global_position
slot1_filled = true
item.drop_location_id = 1
elif !slot2_filled:
chosen_slot = $inventory/Container/slot2.global_position
slot1_filled = true
item.drop_location_id = 2
elif !slot3_filled:
chosen_slot = $inventory/Container/slot3.global_position
slot1_filled = true
item.drop_location_id = 3
return chosen_slot
func set_drop_location(item):
var drop_location
match item.drop_location_id:
0: drop_location = item.global_position
1: drop_location = $inventory/Container/slot1.global_position
2: drop_location = $inventory/Container/slot2.global_position
3: drop_location = $inventory/Container/slot3.global_position
return drop_location
func _on_slot_1_area_area_entered(area: Area2D) -> void:
if area.is_in_group("item") and !slot1_filled:
empty_slot(area.get_parent().drop_location_id)
area.get_parent().drop_location_id = 1
fill_slot(area.get_parent().drop_location_id)
func _on_slot_2_area_area_entered(area: Area2D) -> void:
if area.is_in_group("item") and !slot2_filled:
empty_slot(area.get_parent().drop_location_id)
area.get_parent().drop_location_id = 2
fill_slot(area.get_parent().drop_location_id)
func _on_slot_3_area_area_entered(area: Area2D) -> void:
if area.is_in_group("item") and !slot3_filled:
empty_slot(area.get_parent().drop_location_id)
area.get_parent().drop_location_id = 3
fill_slot(area.get_parent().drop_location_id)
#Item interactions by clicking (not the problem, I think)
func _on_door_area_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
if !detail_selected and event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
$door_closed.visible = false
$door_open.visible = true
func _on_door_area_2_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
if !detail_selected and event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
$door_closed.visible = true
$door_open.visible = false
func _on_chicken_area_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
if !detail_selected and event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
$dialogue_box.visible = true
detail_selected = true
change_cursor_hand_detail()
func _on_area_2d_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
$dialogue_box.visible = false
detail_selected = false
change_cursor_default_detail()
#The watering can thing that isnt working
func _on_area_2d_area_entered(area):
if area.is_in_group("item"):
if area.get_parent().item_id == 1:
$flower.visible = false
$flowerBloom.visible = true
wateringcan_used = true
empty_slot(area.get_parent().drop_location_id)
area.get_parent().queue_free()
Input.set_custom_mouse_cursor(hand_cursor)
And here is the object script, attached to the watering can.
extends Sprite2D
var dragging = false
var drag_cursor = preload("res://Catpaw holding Mouse icon.png")
var hand_cursor = preload("res://question.png")
var picked_up = false
var drop_location_id = 0
var drop_location
var dropped = false
var timer_off = true
@export var item_id = 1
func _physics_process(delta: float) -> void:
if dragging:
global_position = lerp(global_position, get_global_mouse_position(), 30 * delta)
dropped = false
Input.set_custom_mouse_cursor(drag_cursor)
else:
if picked_up:
if !dropped:
drop_location = get_parent().set_drop_location(self)
if timer_off:
$Timer.start()
timer_off = false
global_position = lerp(global_position, drop_location, 20 * delta)
func _on_area_2d_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
if !picked_up and !dragging:
global_position = get_parent().choose_slot(self)
z_index = 10
picked_up = true
else:
if event.pressed:
dragging = true
else:
dragging = false
Input.set_custom_mouse_cursor(hand_cursor)
func _on_timer_timeout():
dropped = true
timer_off = true
There are also some other smaller things that don’t work but this is the main problem so far since puzzle solving is a key part of escape rooms. Also, I wasn’t sure if this should be placed under Physics since I’m dealing with areas and not bodies.
Both the watering can and the flower have the same structure. They are both Sprite2Ds, with an Area2D and a rectangle CollisionShape2D inside them. The watering can has a Timer which should cause the item to drop…? The person doesn’t explain it very well… Only the root node and the watering can have scripts of their own.
Note: the “wateringcan_used” variable is my own version of a “card_used” var the video uses, since their object is a card. The person doesn’t explain the variable at all. I simply included it to make the code identical.
Any more information will be happily provided. Any help appreciated. I also have a feeling this entire code probably has a much easier way to be made, and advice on that would be appreciated as well.
Have a good day =)
EDIT: Solution
The problem was because of the groups system – I placed the Sprite2D node in the “item” group instead of Area2D, so it wasn’t recognizing the area as an item. Make sure to put the Area in the group and not the Sprite.
Cya!