Not a tutorial but an example of a JRPG-like menu system using modal dialogs.
Note: The whole project is about the menu/dialog system. The game-like presentation is just a façade because I had fun doing it and also used it to experiment with some other things.
Source code: https://github.com/Toxe/godot-modal-dialogs
Playable web version: https://toxe.itch.io/godot-modal-dialogs
Controls
- Use keyboard, mouse or controller.
- Press Enter/Space, 1-9 or Cross/A on controller to select a menu option.
- Press Escape or Circle/B on controller to close a menu.
Select "Flee" to quit the program.
Credits
- Cornelia Sans font by EliDirkx98: https://fontstruct.com/fontstructions/show/1914648
Creating menus
Building a menu with actions and sub-menus is pretty simple. Just pass a Callable to menu.add_action()
that performs the action or pass a Callable to menu.add_menu()
that builds the sub-menu.
func build_item_menu(menu: Menu) -> void:
menu.add_action("Potion", func() -> void: show_notification("Using Potion."))
menu.add_action("Ether", func() -> void: show_notification("Using Ether."))
menu.add_menu("Phoenix Down", build_item_phoenix_down_menu)
func build_item_phoenix_down_menu(menu: Menu) -> void:
for character_name in characters:
menu.add_action(character_name, func() -> void: show_notification("Using Phoenix Down on %s." % character_name))
You can see the main scene that creates all the menus and handles all the actions here:
https://github.com/Toxe/godot-modal-dialogs/blob/master/T05_ModalDialogs/main.gd
Controls vs. Windows, Viewports and Popups
Initially I thought to use Popups. Either a PopupPanel or a basic Popup. After all I wanted to make dialogs and that's kind of what they are supposed to do, right? But for the life of me I could not get it to work the way I wanted. I also tried to use just Windows (a Popup is just a Window subclass) but I ran into the same issues.
- The Windows don't scale automatically. In the project settings I set the main window stretch mode to "canvas_items" and everything scales nicely when you maximize or resize the program window or embed it in a web page. But the Windows and Panels don't scale. I assume they are rendered to a texture and then that texture gets scaled which can look quite ugly. I did not find any option to easily fix this although I am sure that you can deal with this manually but I didn't want to do that. (This scaling issue also happens when using a built-in dialog like a Godot FileDialog.)
- The positioning of the Windows was a bit tricky but I got it to work eventually.
- When trying to make the dialog/menu Windows exclusive to disable all input outside of the menu this also disables the ability to press Alt-F4 or click the OS window close button in the corner of the window. And this behavior would just be unacceptable.
- When using PopupPanels I had issues with the shadow behind the menu and the transparent background. The size of the Popup was wrong and there were artifacts in the corners.
So in the end I just used Controls and it was simple and intuitive to do and everything works the way I wanted it to. You could of course fix all these issues but it's just not worth the hassle and these are just simple menu dialogs after all so there is really no real benefit of using Windows/Viewports.
Don't get me wrong, Viewports are fantastic! But in this case using the Viewport subclasses just added more problems than it was worth. Controls on the other hand are simple.