7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial
  1. Code
  2. Games

FlashPunk UI Components: Advanced Graphics, Extra Skins, and Polish

Scroll to top
Read Time: 51 mins

In this tutorial we'll finish what we started in the first part of this UI with FlashPunk mini-series. We'll learn how to customize the graphics of our components, and make a few adjustments to make our UI perfect.

Final Result Preview

Let's take a look at the final result we will be working towards:

Make sure you click everything to see how it responds!

Section 1: How to Draw

Step 1.1: Open Your Existing Project

If you don’t already have it, be sure to download the source code from part one. Open the project file in FlashDevelop (info here) and get ready to upgrade your UI!

Step 1.2: Drawing Stuff

The next step we need to do to be able to extensively customize the graphic side of our UI is learn how to draw the graphic stuff directly with code. At the momment we needed an image for each state of our UI (button normal, button hover, checkbox normal unselected, checkbox normal selected, etc.), so we needed a large ammount of Images. Now, let's say you want a different color for each button, or even a different shape for each one, and selected randomly... we can't afford to have millions of images: too work to make them and they consume too much memory.

But before starting to draw the components itself, we must first learn how to draw stuff using code in FlashPunk.

Step 1.3: Preparing a Drawing Test World

First of all, we need a new World to test the Drawing stuff. Create a new World class, called DrawWorld, and tell Main to go there when starting the game.


Step 1.4: Using the FlashPunk Drawing Utils

The FlashPunk Engine has a few utils which lets us Draw things to the screen or to a BitmapData.

These functions are: line, linePlus, rect, rectPlus, circle, circlePlus and curve (the other ones are used to draw other kinds of stuff). The 'plus' versions come with more options and give better results (using antialiasing) but are more CPU intensive.

Using them is easy; override the render method of your World or an Entity and call those functions, like this overriden render function for our DrawWorld, which draws some shapes:

Step 1.5: That's Slow!

The problem with that method is, it's really slow. We're drawing the same stuff over and over again, for no reason, to the screen. This would be OK if things were changing EVERY frame, but if they are not, it's a complete waste of resources.

What we're going to do instead is, create a bitmapData to store our drawings, then draw them there once or just every time they change. Then we just need to render that bitmapData to the screen using copyPixels, which is a much faster way of doing it... or we'll add a Stamp, which is a FlashPunk graphic that does exactly that: draw a bitmapData to the screen.

To make Draw do the drawing to a custom bitmapData instead of using the screen, we can use its setTarget function. Draw.resetTarget will make it draw future commands to the screen again.

Here's our DrawWorld code now. If you test it, the result should be exactly the same as before.

Step 1.6: Advanced Drawing

Okay. We know how to draw some circles, lines, squares, and so on to the screen and to a BitmapData now. Thing is, I want to make a good-looking button, not a lame button made of a simple square and a circle! That's why we need advanced drawing.

Advanced drawing is just some concept I made up to refer to using the AS3 Drawing API directly (you know, when you draw using the graphics of a Sprite, Shape, etc.). The process is, basically: First, create a Sprite so we can get a Graphics class. Then, we draw what we need to the Sprite graphics. Finally, we render the Sprite to a BitmapData. Done!

Using this process, we can draw advanced shapes and use advanced fills, like making some awesome-looking gradient buttons. Yay!

I'm not going to explain each individual method of the Draw API, as explaining it isn't the scope of this tutorial, but there are plenty of resources on the net if you don't know how it works.

The Drawing API is used on the Graphics class. But you can't create a Graphics class on-the-fly, and you wouldn't be able to "draw" it anywhere. Instead, we can create a Sprite and use its graphics property for drawing. Then, to use that Sprite as a FlashPunk graphic, we simply render it to a BitmapData.

Here's some example code, in which I draw a gradiented rectangle:

  • Lines 17-18: We create a Sprite to use its graphics property for drawing, and we store its graphics to a variable named g for less typing.
  • Lines 20-21: We create a gradient matrix, which is required to have a gradient fill. We provide it the size of our rectangle, and a rotation in radians (we convert 270 degrees to radians by multiplying by FP.RAD). As the rectangle will be drawn at (0,0), we set tx and ty properties to 0.
  • Lines 22-24: We draw the rounded rect with the gradient fill to the sprite graphics.
  • Lines 26-27: We create a BitmapData the size of the graphic, and render the sprite to it.
  • Line 29: We create a Stamp, providing our BitmapData which has the sprite rendered, and add it to the World at (100, 50).


Step 1.7: Filters!

We're now ready to draw gorgeous buttons... but we can step it up a bit and make them look even better! To do that, on top of the graphics itself, we can add filters to them. With Flash, we can add drop shadow filters, glow filters, bevel filters, and so on, easily.

To add filters, we simply need to populate the sprite's filter array with our filters - or if we want to use BitmapFilters, we use bd.applyFilter() after we've drawn the sprite.

Let's add an inner glow filter and a drop shadow filter to our rectangle, and also change the color of the screen, so we can preview it better. Code here:

If you preview the current code, you'll see the filters look somewhat... cropped.

Let's fix that!

Step 1.8: Quick Fix for the Filter Crop

First of all... why does it look cropped? Basically, the problem is our BitmapData is the size of the button, but the shadow is bigger than the button. So, when rendering the sprite to the bitmapdata, as the shadow doesn't fit the BitmapData, it gets cropped.

The easiest way to solve that is simply to enlarge the BitmapData. We'll also have to give the sprite some x and y offset, as the shadow is slightly on top and left of the button as well.

We also offset the stamp's x and y to the negative offset of the bitmap drawing. This way, the button coordinates (100, 50) originate from the rounded rectangle and not from the shadow, and it's in the same place as before.

Step 1.9: Endless Possibilities!

As you can see, combining the AS3 Drawing API and its filters can lead to impressive results. The possibilities are endless, if you know well how it works, so it might be worth reading a few things about the Drawing API and filters.

For example, here you have a pack of AS3 filter setups, with amazing results: Flash Effects Pack. And a cool static distortion filter: Static Distortion Effect using the DisplacementMapFilter.

There are thousands more of tutorials and effects using flash filters and the drawing API spread all over the web, which you could apply to your UI set. Even better: if you have the knowledge, you can create those amazing effects by yourself.

Section 2: Preparing Our UI

Step 2.1: Refactoring the UI Code

Let's implement all those drawing stuff to our UI. First of all, as having to write all the code needed to go from a Sprite to a BitmapData for each element we need to draw is a bit silly, we'll just create a helper function that will do that for us every time we need it. This way we don't repeat code over and over again.

We'll place this helper function in a base class all the UI elements will extend. Let's call it Component, place it in the ui folder, and make it extend Entity:

Now we need to change our ui classes to extend this instead of Entity. We'll only need to change Button and TextInput, as Checkbox extends Button so it will extend Component indirectly, and RadioButton extends Checkbox so the same happens.

Step 2.2: Helper Function

Taking as a base the code we made for drawing our cool gradient-y button, we'll build this helper function. Here's how stuff will work:

Component will have a protected sprite and g variables. This way, you can add filters to Sprite and draw stuff on graphics. They will be kept alive forever, so it's your job to clean them if you're going to draw multiple stuff on the same component, and destroy them completely when they aren't needed anymore.

Then, when calling this function, it will generate a BitmapData of the specified size and draw the sprite to it. Then it will return a Stamp containing that BitmapData, ready to use!

Even though there's already a graphic and sprite properties which can be cleant and used multiple times, if you really need to use a different sprite, the function will be able to get it through a parameter. By default, the parameters will point to the sprite member of the class.

Step 2.3: Removing Graphics From UI

We will take a different approach for skinning now. The base components (Button, Checkbox, etc.) will only hold the behaviour itself, without the graphics. Then we can extend them (to MenuButton, GameButton, MuteButton, etc.) to include the specific graphic behaviour.

So first of all, we must remove the graphic rendering of our components. We'll also make the player input the size of the components.

Step 2.3a: Removing Graphics From Button

For the button, first of all, we need to remove the graphic creation, and the variables for it. We'll also replace the label:Text property with a string property called text. And we'll require a width and height for setting the hitbox.

Then, we remove the renderGraphic function and place it in Component instead. We empty the changeState function, because it will be handled on the skinning classes. The render override will also be removed, because we don't have a label to render. So, after the update function, which we don't need to change, all we have is this:

We also could add a lastState variable, and set it on the changeState function, in case our skins need it. Remember, as lastState will be set in the changeState function, when overriding it we will place the new behaviour first and do the super call at the end.

Step 2.3b: Removing Graphics From RadioButton

For the checkbox, we'll need to remove the changeState override and all the graphic creation in the constructor. For the radio button, we'll just need to remove the graphic creation in the constructor. We'll also add the width and height parameters on both classes.

New Checkbox:

New RadioButton:

Step 2.3c: Removing Graphics From TextInput

For the text input, all we need to remove is the textGraphic property, and its creation. We'll also add an onFocus function so we can handle graphic changes for focus on the skin.

Step 2.4: Preparing to Test

Everything's prepared to begin building our skins! But first, we need to point to our TestWorld again. To do that, change the line in the Main class which points to the DrawWorld, and make it point to TestWorld.

If you test it now, you'll see a blank world. That's to be expected; we removed all the graphics from our components. Don't worry, though, we'll begin the skinning now!

Section 3: Skinning a Component

Step 3.1: Skinning the Button

Now we're going to go through, step by step, the whole process of skinning a component, taking as an example the button. We will see the most common techniques you will need when skinning your own components: drawing the graphics, adding some fancy animations, some cool sound effects, particle eye-candy, and even some pixel-perfect collision techniques and changing the mouse icon to a hand when hovering over the component.

This should basically prepare you to be able to skin any component you want with your own style and without any problem. We will then apply the knowledge we gained with the button to skin the checkbox and radio button, we'll learn how to skin a more complex and different button like the text input, and then we'll build an extra component and skin it.

Step 3.2: Normal Graphic

First of all we'll make a button show its normal graphic. We'll use the same cool graphic we used in the Draw World. So, basically, we copy what we used there and then call the drawStamp function to make the Sprite be transformed into a Stamp, and we'll set it to our button's graphic.

Before that, though, we need to actually have a button! Create a blue folder inside the src folder. This is where we'll place all our skinned components. We'll make them blue, as you can guess by the name. This is just for us to keep things organised. In your game, you'd probably want to put different folders with different skins in your ui folder, and call them something like menu, game, etc.

Then, make a BlueButton class which extends Button in the blue folder:

Now, we'll place the drawing code in the constructor:

To test it, we need to create the button in TestWorld. So, comment or remove all the components created there, and place a new BlueButton instead. Also, change the background color to a lighter one. Here's my TestWorld begin function:

If you test the project, you'll see the buttons are being drawn! However, they all are the same size, even though we specified the fat button to be very big. Let's give the button some cake.

Step 3.3: Button Graphic Size

First of all, I'd like to move the function which draws the button's graphic into a helper function of BlueButton. Keeps stuff cleaner.

All we did is move the button draw stuff from the constructor to a helper function. This helper function returns the Stamp, and asks for a width and a height. We set our graphic to the Stamp returned. Now we need to make it actually use the width and height provided.

All the changes we need to do are in the matrix gradient box, the round rect drawing and in the stamp creation. The stamp creation needs to have a bigger size, because of the filters. Here's the final code:

And here's the result! They don't do anything when you click them, but they're actual buttons!

Step 3.4: Glare and Border

Let's make our button a bit better by adding a border and a glare to it.

Adding a border is very easy. We could do two things: apply a line style to the button graphics before drawing the round rect, or use a filter. The former would make our button look weird, though, as the inner glow will also cover the border, so let's go for the filter approach.

Even though there's no specific BorderFilter in Flash, the effect can easily be achieved with a glow filter that has high strength and low blur. We'll add this filter between the glow filter and the shadow filter, like this:

The glare will be a little more complicated, but will introduce us to a new concept you will probably need for your own components: multiple graphics. As of now, the skin only consists of a single graphic. But what if we need to add more to it, like a glare?

We can take two approaches: using a Graphiclist, or using the renderGraphic function our components have. We'll use the renderGraphic function because our button graphic will change for the hover function, while the glare will remain the same. This way we don't have to bother updating the graphiclist.

To draw the glare, all we got to do is draw a semi-transparent big white ellipse, covering the button. Then, to avoid the glare covering everything in the world, we can mask the glare sprite using our button's graphic. Here's the code:

And the rendering:

Here's the end result. Beautiful, isn't it?

Step 3.5: Hover Graphic

To make the hover graphic, we'll use the same drawButton function but we'll make the button red-orangish. To do that, we'll need to ask for some color parameters on that function.

Now, our normal graphic needs the same colors!

To make the normal / hover switch, we'll store each graphic and make the correspondent switch in the changeState function. So first, let's make a variable for each graphic and populate it:

Now we switch to the correspondent graphic on the changeState function:

And here's the result! Finally, interactive buttons! (...which do nothing)

Step 3.6: Hover Animation Preparation

Let's say we want to add a tween for the hover graphic, instead of changing the graphic immediately on hover.

To be able to do that, we need to make a change first. As creating a new Stamp and a new BitmapData each frame would be a waste of resources, we'll adapt the drawButton function to draw to a given BitmapData instead. Then, we will simply use that BitmapData for a permanent Stamp in our button.

Now we create the Stamp which will hold it. First, we'll remove the current stamps we've got for the separate states, and use this one instead.

Time to tween!

Step 3.7: Tweening Button Colors

To tween the colors for the hover and normal states of our button, we will use the TweenLite library. How to use it is outside the scope of this tutorial, but there are plenty of resources on the net and here on Activetuts+.

(We could also use any other tweening library, or even FlashPunk's own tweening. But TweenLite is more extensive than FlashPunk Tweening, is the library which I know better and it's one of the best tweening libraries for AS3.)

So, go download TweenLite and add it to your code. As I use FlashDevelop, I got the SWC, placed it in the lib folder and right-clicked it to add it to my project library.

First of all, we'll create all the variables we need to tween on our button. In our case, it's just three colours, but it can be whatever you want! They need to be public, so TweenLite can access them.

We also need to activate a plugin in TweenLite so we can tween colors. Place this in Main:

All we need to do now is tween those properties in the changeState function:

We could do a lot of fancy stuff, like easing or using other TweenLite features, but we'll keep it simple for this example. Remember, you can use whatever you want for your skins.

As you can see, we also added an onUpdate parameter. That's so the graphic can be updated according to the tween values, and we actually see it. Here's the function:

And here's the result!

Step 3.8: Down State

For the down state, we'll simply quickly tween the button to black. You already know how to do this, just add another case with the tween parameters.

The only problem with this is, when going from down to another state, the transition is, in my opinion, too slow. Let's make it faster. As we want two different durations, the regular one and the "from down" one, we'll make an extra variable in that function. This variable will check the state we come from, and set the duration depending on that. Then, the NORMAL and HOVER transitions will take into account this variable.

Here's the function:

And here's the final result. Click our buttons!

Step 3.9: The Label

Our button has all the graphics, animations and behaviours. But it needs a very important thing, so the user knows the purpose of each button: a label.

We are already sending some text parameters to our button, so the only thing we need to do is create a label graphic with that text property. We could use FlashPunk's Text class with the renderGraphic function on the render override, but I would like to add some filters to our label, so we'll create the text field directly, and use a Stamp.

First of all, we'll prepare the Stamp, its creation and its render, and we'll use a function called renderLabel which will render that label into the stamp. We'll code the function later.

We create the label property which will hold our label Stamp:

The end of the constructor, where we call the drawLabel function after the drawGlare one:

The drawLabel function, which is empty at the moment:

And our render function, rendering the label right after the glare, so it's the top-most element of the button:

This process is basically what we'd do if we wanted to add additional elements to our button. Another strategy is to have a Graphiclist property instead of a Stamp, and add the custom graphics there. Then we can do the renderGraphic call with that Graphiclist.

The only thing left to do now is to populate the drawLabel function. This function will basically create a text field, set some format to it (font size: 20, custom font, white text, center alignment), set the text to it and apply a Glow Filter. Then it draws the label to a stamp, and centers the stamp vertically in our button.

We also need to embed the font. I used the bold version of the Comfortaa font face, which you can get for free here: Comfortaa at DaFont.com. After saving it in the fonts folder of our assets folder, we embed it from our Main class (the document class, the one which extends FlashPunk's Engine):

And here's the end result!

Step 3.10: Sound Effects

This one isn't recommended for all of your UI elements, as it might get quite annoying to the player, but it could work in some cases. I'm talking about sound effects. Basically, we're going to learn how to play a sound effect for specific case changes. To play the sound effects, we'll use FlashPunk's SFX class, which makes it really easy.

First of all, download the sfx. They are not that good, but they are OK for learning purposes. I made them using as3sfxr. Save them to the sfx folder of our assets folder, using right-click > "Save as..."

Then we need to embed them, in our Assets class.

In order to determine when to play those SFX, we'll use the changeState function. We can add them inside the state switch statement.

As you can see in the normal and hover states, we can also check the last (previous) state. This is useful if, for example, we want our OVER sound to just play when we're over the button. If that check wasn't there, every time we clicked the button it'd also sound.

Here's the result:

Step 3.11: More Effects!

The possibilites are endless. We could add extra animations, particle candy, and all sorts of things to make our UI more fancy. Unimaginable ammounts of crazy features. Unfortunately, it'd be too long to cover all of them, and at this point you already know how to do stuff with our UI buttons and make it work with the skin. So, now it wouldn't be a matter of "how to make x work with the buttons", but just simply "how to make x thing" (like how to make particles), and that's outside the scope of this tutorial.

Despite that, the example and the source include a variety of skins which introduce different techniques. You are free, and encouraged, to take a look at the commented source for each skin. This way you can learn more specific techniques. We'll talk more about the source at the end of the tutorial.

Step 3.12: Pixel-Perfect Detection

Even though I mentioned that I already explained enough effects and graphical techniques, there are still two behaviours you need to know. The first one is pixel-perfect detection.

That isn't really noticeable now, but let's make a test. Let's change the radius of our button. It'll look ugly, but it's just for testing purposes.

We changed the radius of our button from 20 to 100. Let's see how it looks, and more importantly, how our button behaves.

Hitbox collision.

Everything, appart from the obvious hideousness of our button, looks normal. There's one thing, though. Go place your mouse at the corners of our buttons. If you pay attention, you'll see the mouse is detected even if it's not over the button. That's because we're using hitboxes, so the graphic of the button isn't taken into account - just its bounding box. And, of course, the mouse is inside that bounding box.

A way to solve that is to use FlashPunk's Pixelmask. The pixelmask works like this for detecting collisions: first, it checks whether it's inside the bounding box, just like the hitbox we've been using. If it's not, okay, it's fine. But, if it is, then it checks with pixel-precision whether it's colliding with a graphic we provided. This way, we can make holes and rounded corners and all kinds of artefacts in our graphics, and it will only react to the cursor when it's actually over the button.

There's one thing, though. Imagine a button which only displays its border and the text, but is empty inside. We'd still want to detect the mouse when it's inside the button, even if it's on an "empty" part of it. Or, let's say, as it happens with our case, that we have outter effects in our button, like a shadow. We don't want to detect if the mouse is over those!

So, usually, a pixelmask is a different graphic than the button itself. In our case, the pixelmask would be just the rounded rectangle.

This will be easy to do. For the pixelmask, we'll draw a black rounded rect. Then, we draw it on a BitmapData, and finally set our button mask to a Pixelmask of that BitmapData. Like this:

Remember to call the drawMask method in the constructor of the button! This technique will work with all your skins, just remember to draw the basic shape there.

Here's how it looks:

Pixel perfect collision.

And here's the pixelmask but with our 20 pixel radius. It's barely noticeable, but the pixel-perfect collision is there!

Pixel perfect with normal radius

Step 3.13: Mouse Change

Another important thing to do is to change the mouse cursor. That's important feedback for the user. The ideal behavior is to have a normal arrow cursor by default, but then have a hand cursor when hovering over a button. This way, the user knows that element is clickable. That's almost always a recommended feedback (except for games like spot-the-difference, some kinds of graphic adventures, and so on).

To do that, we can use a FlashPunk property in the Input class: mouseCursor. It's a string, and you can change it as often as you want without any glitches occurring, as the property makes sure only one change is made to AS3 at the end of the frame.

To achieve the effect, we need to set the cursor to "normal" first, and then set it to "hand" when the button detects it's over it. Unfortunately, the only way we can do that is add a line to our World. If you don't feel like adding that line to every world you create, you can either (a) modify FlashPunk or (b) create a BaseWorld class which extends World, add that line and make every world you create extend BaseWorld.

This is what we've got to do, in our update, before the super.update:

Now this needs to go on Button update. I repeat, on Button update, not on the button skin, which is BlueButton.

Here's the result:

Step 3.14: That's It!

Finally. We finished our first skin, a button skin, with complete animation and other handy techniques! Now you're ready to skin all the buttons you want! But we must learn how to apply our knowledge to other components like checkboxes and radio buttons first...

Section 4: Checkboxes and Radio Buttons

Step 4.1: Skin the Checkbox

Before we introduce the new things we will have to consider for the checkbox, let's apply what we know about the button to the checkbox.

As I would have to explain everything again, and I don't want to repeat myself too much, here's our BlueCheckbox code, with comments when I think it's needed to explain something. Also, I didn't add the sound effects, as I find the ones I made too annoying:

Step 4.2: Determining the Check State

We need to determine whether a checkbox or a radio button is checked or unchecked, to make the skin go with that. For the checkbox, overriding the click method would do, but that's different with the radio button, as the property gets changed from the radio button group as well.

What we're going to do instead, is make the checked property a getter / setter, and call a changeCheck function when it gets changed.

First of all, make the variable protected and add an underscore. That's the common practice for getters and setters. Then, generate its getter and setter, like this:

Now, just call the new changeCheck function when checked gets set, and it's different from the original!

That's it. Get ready for the actual skin code!

Step 4.3: Checkbox's Check

To code the check states, we'll use a tick image. This tick image will be faded when clicking the checkbox, so it will display or hide with a fade in/out animation.

First of all, we need the check image. Download this one I made, and save it to the gfx folder of our assets folder. Then, embed it in the Assets class as CHECK.

Check Image

Now, we'll create the variable to store it. We'll make it an Image, this way we can modify its scale and alpha properties easily. Name the variable check, and make it protected.

Next, we create it in the constructor. To scale it, we'll get the ratio between the size of the check box (the square), using the height and the original width of the check image. This will make it as wide as the checkbox box, which will look nice as the image has a bit of blank space in the borders (basically because of the shadow). If it didn't, we would have to adjust the formula a bit, by adding a value to the size (in this case, the height) so there would be some kind of border. We also set the alpha according to the checked property given to the constructor.

The next thing we need to do is render the check on our render function. We'll check for the alpha property as well; this way we don't waste resources by rendering an image with alpha 0!

Finally, to determine when the button is checked and unchecked, we can use the changeCheck function we created on the previous step:

That's it for the checkbox! Check out how it looks:

Step 4.4: Radio Button

To do the radio button, we'll do the same as we do for the checkbox, but with a circular button and a circular check. The circular check will be drawn, and not an external imported image.

As we need to draw the check, but still modify its alpha, we'll need a method to convert a sprite to an Image, just like the stamp method we have. I also added a method to give a BitmapData, which will come in handy when you need animated stuff, and don't want to type it manually as we do in this tutorial.

Here's the code with that drawImage method in use:

And the result:

Section 5: Skinning TextInput

Step 5.1: Text Changed Callback

Now that we've skinned our Button, and its similar counter parts, the Checkbox and the RadioButton, it's time to skin a TextInput.

First of all, we need to add some callback function for when the text is changed; this way we can change the text easily. This goes in the text setter.

Step 5.2: The TextField

Time to make the skin itself. Create a new BlueTextInput under the blue package. There we will add all the skinning for our text input.

First of all, we need to create the TextField. We could've also added it to our TextInput base class, but maybe you'll want to create some skin that uses bitmap fonts, or something else, so I decided to leave that to each skin.

Now, let's fill the createTextfield function! We'll also need to make the text field drawable. We'll use a stamp for that, as usual, and will make it update as well.

We're offsetting the Stamp, so it will look right with the background:

The only thing left to do is fill the createTextfield function. We're making a simple textfield, with no effects. (We'll add fancy stuff later.)

Here's two, non-really-visible, editable text fields. The first is single line, the second multiline.

Step 5.3: Fancy Background

We need to see the text a bit better! That's why we are going to code the background now.

As I would like to add some animation later to the background, to give visual feedback on a TextField control, we'll use the same technique we used for the buttons to draw it.

First add this to the constructor:

Then we need to make the drawBg function.

Create the color properties as well, as we will tween them later:

Don't forget the render function. In this case, render the bgStamp before the super, so we render it below the text.

Here's the result. We can definitely see our text fields, now!

Step 5.4: Focus Animation

I'd be cool to show some feedback to the user, so it's easy to distinguish the selected text field.

We can override the onFocus function for that. Inside it, we'll just need to tween the colors we are using in the drawBg method. Easy!

Don't forget the updateGraphic function:

That's it. Check it out here!

Step 5.5: Text Cursor

It would be nice to see some kind of marker at the end of the text. This is pretty easy to do. First, we need to build a Stamp with a white rectangle.

Then we need to render it:

We'll make it visible only when the TextField is focused.

Finally, we need to move it every time we change the text.

Here's the moveCursor function. First it gets the width and height of the last line. For the height, it also multiplies it by the number of lines, so we position it at the last one. Finally, we set the cursor coordinates to those. In this particular case, we offset the x by 10 and the y by 8. (These offsets are likely to vary with font, size, etc. and the best way to determine them is by testing manually. Feel free to adapt them!)

Here we have our text fields with cursors:

Step 5.6: Mouse Cursor

You can change the mouse cursor to a text cursor easily, with just one line of code, as we already implemented what we needed in our world. You just need
to add this to the update of your TextInput class:

Here's how it looks. Hover over the text inputs and your cursor will change!

Section 6: Conclusion

That was it for this tutorial. We learned how to skin our components with different techniques, we added animations and other fancy stuff like sound effects. Remember there's infinite things you can add to your UI to make it more pretty.

The most important thing, though, is that the UI is customized for each game. It needs to fit each game, its gameplay, the mood... if it doesn't, there's no point on making a custom UI! Also remember not to add too many effects, just add the needed ones - don't go overboard.

As there are a lot of techniques you'll only need for specific things you want to do for each UI, I can't explain all of them in a tutorial. But I can show you some more. If you have a look at our demo, you will see there are some different skins, each requiring its own technique. I'd recommend you download the source, and investigate how each of them is made. I've commented the necessary bits!

Good luck. Thanks for reading, and hope you make an awesome UI for your FlashPunk game. Leave here a comment with your game if you make one!

Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.