Cyclone's New Menu
The time finally came to revamp the main menu for Cyclone. Doing menu work for me is really hard to get into but once I'm knee deep into it, it's all I want to do. I decided now is the time to work on a semi-final menu system due to the following.
- I just finished Steam Input and the menu wasn't compatible.
- The white text on a bright background was hard to make out.
- I only had a "New Game" option. There was no way to jump to a map you wanted to play without the console enabled.
The first step was to figure out how to integrate the GUI with Steam input. The Leadwerks GUI system is from my experience is an unfinished predecessor of the same GUI calls of the Ultra App Kit. The input was really for a mouse and keyboard but I didn't want to bother learning imgui or another API. One thing that made it really complex is that Leadwerks uses Lua scripts for the GUI draw and event queue commands,
In the end, I just did a Steam Input binding to control the mouse with the touchpad or a joystick and told the OS to simulate the left mouse being pressed when the action is called. I don't know if this will get me any approval badges, but now you can control the menu with just the controller. The extra parameters don't seem to do anything but I kept them in. Regardless, it works. We don't have to call any "Legacy Keys" for the bindings!
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CycloneMenu::OnUpdate() { if (!Hidden()) { if (Input::ActionHit(ACTION_MENUSELECT)) { EventQueue::Emit(Event::MouseDown, Window::GetCurrent(), Key::LButton, Window::GetCurrent()->GetMousePosition().x, Window::GetCurrent()->GetMousePosition().y); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CycloneMenu::ProcessEvent(const Leadwerks::Event iEvent) { ... else if (iEvent.id == Event::MouseDown) { // A hacky way of doing this. #ifdef _WIN32 INPUT Inputs[3] = { 0 }; Inputs[0].type = INPUT_MOUSE; Inputs[0].mi.dx = Window::GetCurrent()->GetMousePosition().x; // desired X coordinate Inputs[0].mi.dy = Window::GetCurrent()->GetMousePosition().y; // desired Y coordinate //Inputs[0].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; Inputs[1].type = INPUT_MOUSE; Inputs[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; Inputs[2].type = INPUT_MOUSE; Inputs[2].mi.dwFlags = MOUSEEVENTF_LEFTUP; SendInput(3, Inputs, sizeof(INPUT)); #endif ... } }
Now, controlling the mouse with a joystick isn't the best approach. I also had to make my buttons much bigger so it was harder to miss the bounds of the button when using the controller. I also kept all my UI elements in the center of the screen.
Next was the options menu. I used choice boxes on everything to make it less Mouse centric,
Finally came the new "Play" menu which I wanted to revamp from just a simple button that would load the "start" map. Right now, I'm forecasting only to ship with 10 maps but what about any new maps later on? Would I just add it onto the 10? What if I want to make a set of maps that focus on a theme or a new element? Would that break the progression? What about when custom maps are loaded? People would be going to the "Custom Maps" box more than the "New Game" button by then. It's not like it's a story or anything to justify those maps being held at a different standard than other maps.
I decided to take a similar approach to the campaigns in Left 4 Dead. The chapters shipped with the game are loaded into the menu first. Then the application looks for anything under the addon's folder and loads those in. Each chapter can have a collection of maps that are easily selected by the user.
{ "name": "Cyclone 101", "author": "Reep Softworks", "maps": { "Level 0": { "filepath": "Maps/lvl0.map", "imagepath": "Materials/GUI/background_lvl0_artpass1.tex" }, "Level 1": { "filepath": "Maps/lvl1.map" }, "Level 2": { "filepath": "Maps/lvl2.map" } } }
Custom maps work the same way no special treatment. This all works with a json script and the application can locate the script in the zip package. Also, if no image is defined for a map, a "NO IMAGE" texture substitutes in. Just click start, and off you go!
{ "name": "MyCoolAddon", "author": "reepblue", "maps": { "The Cool Addon Map": { "filepath": "Maps/addontest.map", "imagepath": "Materials/GUI/loadingscreen.tex" } } }
One thing I'm not sure about is splitting my 10 maps in 3 chapters. I did this after feedback of the list being so empty with just one entry. Hopefully I'll have time to make new maps. Being that now I'm free to work on small collections instead of one long track should be motivating. A goal of arranging the maps like this is so I can justify the game based on the amount of content over "how long" it is.
It should be really easy to integrate Steam Workshop with this but I'm not going worry about it now, Tonight I'm happy I can play Cyclone with my Steam Controller without reaching for the mouse and keyboard!
- 1
2 Comments
Recommended Comments