Game Development Community

dev|Pro Game Development Curriculum

Master Modules Part Four : The UI Base

by Simon Love · 04/26/2016 (11:31 pm) · 0 comments

Torque2D already contains a solid and extensive Graphical User Interface (GUI). This system, while robust, is also quite dated when compared to other modern alternatives (Qt, Flash, etc.). One way to solve this is to have a separate Scene and SceneWindow dedicated entirely to the User Interface.

In this scheme, UI elements would be SceneObject-based, allowing your GUI to use rotation, scaling, colorization, and physics. Combined with Peter Robinson's recent TextSprite technology...the possibilities are endless.

Take note that this module is does not depend on the other Master Modules.

You can grab it here

Initialization


- Scene

As usual, we will start by looking at our now famous /scripts/Init.cs file.
%Scene = new Scene();
UIBase_module.UIScene = %Scene;
A new Scene is created. The Scene's ObjectID is then stored as a variable to our module. This allows us to access it from anywhere in the game.

For example, adding a new object to this scene would be done by typing in
UIBase_module.UIScene.add(%mynewobject);

- SceneWindow

%SceneWindow = new SceneWindow(){
UseWindowInputEvents = true;
UseObjectInputEvents = true;
Profile = GuiSceneWindowProfile;
};
UIBase_module.UIWindow = %SceneWindow;
Following the same logic, we create our SceneWindow.

UseWindowInputEvents=true; means that our SceneWindow will capture all mouse Input events.
UseObjectInputEvents=true; means that all objects in our scene will be able to respond to touch/click events directly.

- Input Listener

Now that we have told the SceneWindow to accept Input Events, we create a new ScriptObject (named UI_IL) and set it as our SceneWindow's InputListener.
%IL = new ScriptObject(UI_IL);
%SceneWindow.addInputListener(%IL);
Having an Input Listener means that input events detected by the SceneWindow will be relegated to this object. Instead of handling mouse/touch input in methods declared on our SceneWindow(i.e. function SceneWindow::onTouchDown(%args)), we can do so directly on the InputListener.

We finish our initialization routine by assigning our new Scene to our SceneWindow.
%SceneWindow.setScene(%Scene);

Preparation

Once the Module is loaded, we are almost ready to go. One problem we have is that the GUI should, in theory, be placed in front of our game world. The following steps should then be performed after your Game's main SceneWindow has been placed onscreen.
UIBase_module.setGameSceneWindow(%YourSceneWindow);
   Canvas.pushDialog(UIBase_module.UIWindow);
The first line of code assigns your Game's SceneWindow as a variable to our UIBase_Module, allowing us to easily access it if need be.
The second line ensures that the GUI Scenewindow will be pushed on top of the Game's Scenewindow and thus be visible!

Handling Input

Since, as you've guessed it, our new UI SceneWindow will be in the way, it will intercept all mouse input. As a gift, I have implemented skeleton methods for most of the mouse input functions in scripts/InputListener.cs.

- Clicking/Dragging objects in the Gui SceneWindow

Traditional Buttons can still be used but this Module's goal is to be replace them with SceneObjects. By telling our GUI SceneWindow to UseObjectInputEvents, clicking and dragging those objects will call the corresponding input methods directly in these objects' namespace. This means that each one of your SceneObject-based Buttons will need to be assigned a Class or an object name and methods for its Input functions will need to be implemented through script.
function MyObject::onTouchDown(%this, %clicks, %pos, %touchcount)
{
...
}

- Sending Mouse clicks / Touch Events across Scenewindows

Since our Game's SceneWindow represents our game camera, its coordinates will not always correspond with those of the overlying GUI SceneWindow. Think about this, your GameCamera will probably move, zoom in and out and perhaps even shake or rotate!

In /scripts/UIFunctions.cs, you will find the following function
ConvertSceneWindowPoint(%point, %originalSW, %targetSW)
{
...
}
This handy function allows coordinate conversion between two SceneWindows. It converts the Scene coordinates of the given %point into Canvas coordinates and then converts the newly-obtained Canvas coordinates to the Scene coordinate of the target SceneWindow.

- Warning -
This double conversion is, obviously, quite costly in terms of performance. Use sparingly.

For instance, if you want to see if an object from your Game's Scenewindow has been clicked, you would take the %pos parameter from our InputListener's onTouchDown method and execute the following steps.
function UI_IL::onTouchDown(%this, %clicks, %pos, %touchcount)
{
//First, find what Scene is set to our Game's SceneWindow
%targetScene = UiBase_Module.GameSceneWindow.getScene();

//Convert the click's coordinates
%newpos = ConvertSceneWindowPoint(%pos, UIBase_Module.UIWindow, UIBase_Module.GameSceneWindow);

//Perform picking
%clickobjects = %targetScene.pickPoint(%newpos);
...
}

- GUI Followers

What if you wanted your Player character to have his Life Bar hover around his head and follow him around the screen?

The Life Bar object would exists in the GUI Scene and would host a Behavior updating on every tick.
function GUIFollow_BEH::onUpdate(%this)
{
   //Position in the GAME SceneWindow
   %o_pos = %mytargetobject.getPosition();
   %t_pos = ConvertSceneWindowPoint(%o_pos, UIBase_module.GameSceneWindow, UIBase_module.UIWindow);
   %this.owner.moveTo(%t_pos,45,true,true,0.05);
}
This code converts the position of our target object from the Game's SceneWindow to the GUI SceneWindow (the reverse of what we did in the previous example). Our LifeBar Object (the owner of the Behavior) would then be sent to that position.

Even if you zoom in or out, the GUI element will track the position accordingly.
The best example I have in mind is in Civilization 5; zoom in or out and the City Info Label remains the same size for readability.

As yet ANOTHER gift, I have placed this behavior in UIBase/behaviors/ for immediate use.

I could go on and on about test-case scenarios but the truth is that what you need to get started is all here. Create objects, load them with cool behaviors and make the UI of your dreams; it's that simple.

Conclusion

As you can see, this module will act as the basis of a solution to your Scene-based GUI needs.

I have tried to keep these blog posts straightforward and to the point as much as possible. I am aware that it's a lot to process in a single sitting and the lack of examples might hurt the immediate appeal of the Master Modules.

I had initially planned on doing this over the course of three weeks, creating detailed demos, video descriptions and basically authoring my own Sandbox equivalent. Would it really have helped? Would it have brought more developers to use these modules? The answer is no.

I would like to reiterate that these modules are intended to be as general-purpose as possible so that they can be built upon. They can be used immediately and will provide you with brand new possibilities and easy tools to expand your prototypes and games right now!!!. If anything, it might give you guys ideas for your own projects and systems in this engine or the next.

Know that I am, like you, but one person, passionate about this game engine. Nobody has forced me to do this; I do it out of love for the community and the engine. I want to share my expertise and experience with all hopeful game developers.

I see game development as martial arts (okay okay, I'll have to credit Chris DeLeon for this). Seriously though, his words are very important; listen.



Torque2D is not the state-of-the-art, cutting-edge, ultra-violent competitive martial art; it is but a step on your journey as a game developer. I know zero developers who have used just one game engine or programming language throughout their life; life is about learning and growing.

Learning two or more game engines forces you to compare approaches to game development; you can't help but grow from the experience.

Torque2D needs you. Play with it, file issues, contact Peter Robinson to know how you can help, start discussions on these forums regarding things that annoy you about the way T2D handles things. There is no one but us to take Torque2D where we want it to go.

What's next?

I have buckled down and pushed these modules and blog posts out in under 4 days and am immensely satisfied with the results. I think that my stupid face should be burnt into your minds by now as I have flooded the blog section in the last few days.

I plan on starting a video series soon merging my love of retro games with Torque2D in an (hopefully) entertaining way. As always, giving free stuff to the community will be at the core of the concept.

How do you plan on helping Torque2D? Think about it; even the smallest actions count!

About the author

I am here to help. I've worked at every imaginable position in game development, having entered the field originally as an audio guy.