User Interfaces
by @Pattentrick
Welcome to the exciting and wonderful world of UI elements! Impact++ offers a variety of simple UI elements right out of the box. There are ready to use elements for buttons, displaying text, meters, overlays and much more. In this guide we will take a closer look at the idea behind UI elements in Impact++ and how you can use them for your game.
The Basics
First of all, please keep in mind that the UI elements of Impact++ should be used for simple user interfaces. If you need something big and complicated, you should consider to use the good old DOM instead. Using the DOM is a lot cheaper regarding to performance. And complex user interfaces are also easier to implement with classic DOM elements.
But for simple user interfaces Impact++ provides us with very cool UI elements. All UI elements inherit from the UIElement
base class, which is located by default under plusplus/ui/ui-element.js
inside the project folder. You will also find every other UI element under plusplus/ui/
.
The UIElement
class itself again is an entity which extends the EntityExtended
class. Because of that, UI elements behave very similar to your ordinary Impact++ entities. For example, you can define an animation sheet, or a size, like you would for every other normal entity. However, there are a few things that are specific to UI elements.
UI elements are frozen: true
by default. An entity with frozen: true
will skip updating, which is good for performance, and UI elements usually don't need to be updated. Also, all UI elements are on an own layer called ui
, so they won't interfere with your other entities. And they are fixed to the screen too, so you don't have to worry about reposition them manually, if you move your camera around. But you can disable this behaviour if you set fixed: false
on your UI element if you like.
Additionally UI elements won't be destroyed if you change levels and they ignore game pauses. If you want to change this behaviour, take a look at the CLEAR_ON_LOAD_UI_LAYER
and IGNORE_PAUSE_UI_LAYER
property in the Impact++ config file located under plusplus/core/config.js
. But make sure that your overwrite these properties in your own config-user.js
and not in the config.js
.
Also keep in mind that like all other EntityExtended
entities, UI elements are static by default. If you change the performance
to dynamic
the UI element will be automatically removed from the UI layer and will be added to the entities layer.
Positioning
If you spawn a new UI element, it will appear in the top left corner of your game. This is the default behaviour, but you can reposition it or even set a margin if needed. Let's take at look at some examples.
You can spawn a new UI element like this:
var ui = ig.game.spawnEntity(ig.UIElement, 0, 0);
Let's add a margin of 2% for a little more space:
var ui = ig.game.spawnEntity(ig.UIElement, 0, 0, {
margin: {
x: 0.02,
y: 0.02
}
});
Note that margins on UI elements are actually pseudo margins. That means that they don't really keep other entities away, they are used to offset the element based on the pivot.
Of course you could also set a new position based on percentages in values from 0 to 1, but make sure that posAsPct
is set to true
if you use the posPct
property:
var ui = ig.game.spawnEntity(ig.UIElement, 0, 0, {
posPct: {
x: 0.5,
y: 0.5
}
});
Additionally you can set posAsPct
to false
and set the pos
as normal:
var ui = ig.game.spawnEntity(ig.UIElement, 0, 0, {
posAsPct: false,
pos: {
x: 30,
y: 10
}
});
There is also the moveTo
method which moves an UI element to another entity or position, which might come in handy in some situations of your game.
By the way, you don't have to define all of the properties of your UI element in the spawnEntity
method, as seen in the examples above. For a better code organization you can also make a new class, which extends the UIElement
class, and just spawn an entity with it.
Interactive UI Elements
Now that we understand the basics about UI elements, and how we can move them around, we should examine interactive UI elements. Impact++ has a base class for interactive UI elements called UIInteractive
which offers some cool stuff for your game.
When a UIInteractive
entity is touched or clicked it, will automatically call its activateComplete
or its deactivateComplete
method. Look at the code of this custom UIInteractive
entity for example:
ig.UICustomElement = ig.global.UICustomElement = ig.UIInteractive.extend({
// size, animation sheet and other stuff goes here ...
// override the activate method to do something special when button interacted with
activateComplete: function ( entity ) {
// call parent activate
this.parent();
// do some activation behavior
},
// and since interactive elements are toggled by default
// you can also do something when deactivated
deactivateComplete: function ( entity ) {
this.parent();
// do some deactivation behavior
}
});
As you can see, you could easily add your own game mechanics to the activateComplete
or deactivateComplete
method after this.parent()
is called. By default an UIInteractive
element will toggle between the activateComplete
and deactivateComplete
methods.
In some cases you don't want this behaviour. You may just want that the activateComplete
method gets called every time your element is interacted with, without any toggle at all. In that case you can set the alwaysToggleActivate
property of your UI element to true
.
Setting alwaysToggleActivate: true
will result in always calling the activateComplete
method if you click or touch the element, no matter how often you click or touch it.
Another useful feature is, that you can also hook into the activated or deactivated signals of the UIInteractive
element, as you can see in the example below:
var ui = ig.game.spawnEntity(ig.UIInteractive, 0, 0);
ui.onActivated.add( player.pickUpItem, player );
ui.onDeactivated.add( player.dropItem, player );
The first parameter of the add method is the callback method you want to call, and the second one is the context of the callback. So in the example above the player will pick up, or drop, an item when the corresponding UI element is clicked or touched.
Like that you can even use abilities:
var ui = ig.game.spawnEntity(ig.UIInteractive, 0, 0);
ui.onActivated.add( myPlayer.specialAbility.activate, myPlayer.specialAbility );
As you may have guessed, the UIInteractive
element is highly useful for buttons. Impact++ provides us with a ready to use button class called UIButton
, which is based on the UIInteractive
element.
The UIButton
class disables toggling between the activateComplete
and deactivateComplete
methods by default, so that only the activate method gets called. On top of that the UIButton
class helps with some basic animation handling.
Text for User Interfaces
Impact++ provides us with a class called UIText
, which is highly useful for displaying text in your game world. A good example of use for the UIText
class, would be displaying the player score in your game, or the amount of collected coins.
Let's take a closer look at this code example :
var _c = ig.CONFIG;
var score = ig.game.spawnEntity(ig.UIText, 0, 0, {
font: new ig.Font( _c.PATH_TO_MEDIA + 'font_04b03_white_16.png' ),
text: 'Score: 9000'
});
Please note that you need to define a font for your UIText
entity. If you don't it will use the font mentioned in ig.CONFIG.FONT.MAIN_NAME
of your config file. The value of the text
property gets displayed in the game. You can of course easily change the value of the text property later on to update it:
score.text = 'Score: 9001';
With the maxWidth
and maxHeight
properties you can define the maximum width or height of the text area. If you have multiple lines, you can set the text alignment via the textAlign
property. Possible values for textAlign
are ig.Font.ALIGN.CENTER
, ig.Font.ALIGN.LEFT
and ig.Font.ALIGN.RIGHT
.
More UI Elements
We looked at the basics of UI elements, at interactive UI elements and at UI elements for text. But you know what? There are a lot more in Impact++! Taken as a whole, Impact++ offers 13 UI related classes that are really awesome and can help you with your current game!
There are toggle classes like UITogglePause
or UIToggleVolume
, which are useful for toggling the game pause or the volume of the game music. The UIMeter
class displays horizontally or vertically meters that are perfect for health bars. UITracker
is an UI element for tracking the closest entity of a type or name in a level. And with the UIOverlay
you can add all sorts of overlays to your game.
Have a closer look at the plusplus/ui/
folder of your Impact++ project, or take a look at the docs under http://collinhover.github.io/impactplusplus/ig.html, to get an overview of all the UI classes.