|
|
|
|
Reply From: |
Connor |
I took a page out of my old unreal engine games book and made a menu handler in my GameState singleton (autoload) that handles menus in a similar way to the same method used for handling scene switching in a singleton.
For anyone looking to do this it looks as follows:
you preload all of your menus into a dictionary:
#MENU_LEVEL.MAIN is index 1 not zero so keep that in mind if you change to an array
enum MENU_LEVEL {
NONE,
MAIN,
START,
JOIN,
OPTIONS
}
var menus = {
MENU_LEVEL.MAIN : preload("res://gui/MainMenuScreen.tscn").instance(),
MENU_LEVEL.START : preload("res://gui/StartGameScreen.tscn").instance(),
MENU_LEVEL.JOIN : preload("res://gui/JoinGameScreen.tscn").instance(),
MENU_LEVEL.OPTIONS : preload("res://gui/OptionsScreen.tscn").instance()
}
the enum is optional but it makes it nicer to call the switch menu function later. You could technically store all of the menus in an array or individually but that is lame.
after the menus dictionary you have this var: var current_menu : Node = null
which stores a reference to the currently open menu
in _ready() call this: load_menu(MENU_LEVEL.MAIN)
and here is the magic sauce:
func load_menu(menulevel):
call_deferred("_deferred_load_menu", menulevel)
func _deferred_load_menu(menulevel):
#replace the current menus instance with the new ones
current_menu = menus[menulevel]
var container = current_scene.find_node("menu", false, false)
if not container:
var menunode = Node.new()
menunode.set_name("menu")
current_scene.add_child(menunode)
container = menunode
#clear the current menu item/s
for location in container.get_children():
container.remove_child(location)
#add our selected menu
container.add_child(current_menu)
that deferred calls the load menu function which replaces current_menu with a reference to our already initialized menu of chosen index, and then gets our “menu” node in our scene (or adds it if it doesn’t exist yet), empties the menu node of all children, and adds our current_menu back again to it.
The benefits of this approach are:
- you only have to initialize your menu once and keep a copy of it
without deleting and reinitializing menus every time you switch
scenes
- switching menus is as simple as calling load_menu(MENU_LEVEL.OPTIONS) and it will handle removing the current
ui, replacing with the new one, keeping it organized in its own
container node, and all of that other stuff
- adding new menu items is as simple as providing the path to its scene and adding a new enum for it
- you can make a re-usable main menu back button that always calls load_menu(MENU_LEVEL.MAIN) ← i did
- it is very reliable and you can modify it to work in tandum with in game menus if you want as well.
Best of luck with this singleton menu controller pattern Let me know if anyone reads this, uses this, likes it, or notices some sort of error. Feedback is most welcome!
Enjoy!