As a beginner Godot user, I am trying to create a system where I can assign X to Y (in my case, a hotel guests to rooms). The part I am struggling with is that system which manages what rooms are available and which are not. New guests are instantiated with an OptionButton, with a list of rooms to choose from: The rooms are in occupied and available groups, which should get updated _on_option_button_item_selected().
. After choosing a room, new guests arenāt offered the option to choose the occupied room, but old yet to be assigned guests are not updated.
I feel like this is not the correct way to approach the system design.
I would appreciate if more experienced users could suggest how to think about the problem, where to start from. I am happy to try design solutions from scratch, I would appreciate small hints and details as well. I am just trying to learn and being stuck on this problem for days has been frustrating.
If more details are needed, I am happy to provide them, just let me know. Thank you for your time.
Assigning X to Y is called mapping. A data structure thatās most suitable to maintain the mapping relationships is called hashmap aka associative array aka Dictionary.
You need a way for the āoldā guests to retrieve or be updated with the latest state of the rooms.
There are a number of ways you could approach this:
Whenever a room is occupied, send out a signal with the latest room states, then the guests on _ready() (or whenever) can connect to that signal. (think SignalBus).
Whenever a room is occupied, have whatever is managing the Guests call methods on each one to update the latest room state.
Iām not sure to have understood the issue. As I see it, based on what I took from your description, all rooms are members of one of either the āAvailableā group or the āOccupiedā group. Any room that has already been assigned a guest would be in the āOccupiedā group, all the others are āAvailableā. As and when a new guest requests a room, it would be chosen from the āAvailableā group, and that room would be removed from that group, and made a member of the āOccupiedā group instead. Whenever a guest leaves (āchecks outāā¦), the room would once again become a member of the āAvailableā group, instead of āOccupiedā. All existing guests have been affected to an āOccupiedā room at their arrival; what āupdateā is required, except to free their room when they leave..?
The only issue I see is to be sure that there are enough rooms in the āAvailableā group to accept a new guest, failing which a āNo Vacanciesā sign should light up..!
Have I missed something..?
Thank you all for the quick replies, I spent my afternoon learning about the new concepts you guys suggested, and now I have something that I feel like is close: but not quite there. I created a separate project and rewrote every part of this system from scratch, if someone finds time to look over this implementation using a dictionary and signals, I would greatly appreciate advice on it!
main.gd
extends Node2D
var available_rooms : int
# On ready, I set the starting room numbers
func _ready() -> void:
available_rooms = 4
populate_dict(available_rooms, false, 0, 0)
# I ask for amount of rooms, and if there is an occupancy change
func populate_dict( length : int, occupancy_change : bool,
room_number : int, guest_id : int):
# Reset the OptionsButton
$Guest/Control/OptionsButton.clear()
$Guest/Control/OptionsButton.add_item("Select a room")
$Guest/Control/OptionsButton.select(0)
# If not, just set all the rooms in the dictionary to x
if !occupancy_change:
for i in range(length):
Global.rooms_dict["Room"+str(i+1)] = "x"
$Guest/Control/OptionsButton.add_item("Room" + str(i+1))
# Else, set the entered room number to the guest's id
else:
for i in range(length):
if i != room_number - 1:
Global.rooms_dict["Room"+str(i+1)] = "x"
$Guest/Control/OptionsButton.add_item("Room" + str(i+1))
else:
Global.rooms_dict["Room"+str(i+1)] = guest_id
# Receive the signal emmited from OptionsButton
func _on_guest_new_selection(index: int) -> void:
populate_dict(available_rooms, true, index, $Guest.id)
guest.gd
extends Node2D
signal new_selection(index : int)
# Set an id for the guest
static var id : int = 0
# Forward the signal from OptionsButton to main
func _on_control_new_selection(index: int) -> void:
new_selection.emit(index)
control.gd
extends Control
signal new_selection(index : int)
# On item selected, send over the item's index
func _on_popup_item_selected(index: int) -> void:
new_selection.emit(index)
Scene tree:
main.tscn
main (Node 2D)
Ā» guest (Node 2D)
guest.tscn
guest (Node 2D)
Ā» Sprite 2D
Ā» Control
»» OptionsButton
I would appreciate criticism/advice/tips of any sort on any part of this. I just want to learn as much as I can with this project, so even unrelated topics interest me
My first advice would be to encapsulate when possible.
Your main script is currently making changes in a child that may or may not be there, and if you have multiple guests then only 1 will get updated.
Hereās a simple autoload script that can be called from your Guest (to be created by you) whenever the button is clicked within the Guest.
room_manager.gd
extends Node
signal room_status_updated(status: Dictionary[int, int])
const UNASSIGNED: int = -1
var max_rooms: int = 4
## {room_id: int, guest_id: int
var room_status: Dictionary[int, int] = {}
func _ready() -> void:
for i in range(1, max_rooms + 1):
# i being the room_id
# -1 to indicate it is not taken since I don't know how your guest_ids are created
room_status.set(i, UNASSIGNED)
func has_available_rooms() -> bool:
# Check the value in the room_status dictionary and if any single room is free, return true
for guest_id in room_status.values():
if guest_id == UNASSIGNED:
return true
return false
func assign_room(guest: Guest) -> bool:
if not has_available_rooms():
return false
var free_room_id := _get_free_room_id()
if free_room_id != UNASSIGNED:
room_status.set(free_room_id, guest.id)
room_status_updated.emit(room_status)
return true
return false
func _get_free_room_id() -> int:
for room_id in room_status:
if room_status.get(room_id) == UNASSIGNED:
return room_id
return UNASSIGNED
As you can see, it has 2 public methods that can be called but to be extra careful, assign_room calls the public method has_available_room too in case the caller did not first check if any rooms are available.
So the idea here is that your Guest script would call the global RoomManager.has_available_rooms() in _ready() to get the initial state, then you can disable or change the button state as needed, as well as connect to the room_status_updated signal, that way whenever it is emitted, your Guest can update itās state/button state to refect the current status of the rooms.
If there are rooms and you want to assign a guest to the room, then the Guest would call RoomManager.assign_room(self).
Note: My script lacks the removing of the guest from the room but you can figure that out yourself
Note 2: The Guest class should have an id variable defined on creation.