How To Make a Letter / Word Game with UIKit: Part 2/3
In this second part of the tutorial series, you’ll aim for developing a fully playable version of the game. When you’re finished, the user will be able to drag the tiles and drop them on the correct targets, where they will “stick” to the spot. By Marin Todorov.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How To Make a Letter / Word Game with UIKit: Part 2/3
45 mins
Creating a HUD
HUD’s up!
Your game could use some controls and readouts. You might ask, “Should I add these elements to the gameView?”
No. The gameView
is for all gameplay elements. You generally want to put elements like the score, time readouts and player controls onto their own view layer. This allows you to more easily do many types of things, like hide them when the game is paused, or maintain fixed sizes and locations for these controls while simultaneously zooming in on some area of the game board.
This separate layer is often called a heads-up-display, or HUD. It will be easier to test your HUD layer if you have something to display in it, so first you will make a label to display the game timer.
Create a new Objective-C class file in Anagrams/Classes/views named StopwatchView
, and make it a subclass of UILabel
. This will be a simple custom label that displays the remaining time in the format “[minutes]:[seconds]”.
Open up StopwatchView.h and add this single method to its interface:
-(void)setSeconds:(int)seconds;
Inside StopwatchView.m, add the implementation of setSeconds:
:
//helper method that implements time formatting
//to an int parameter (eg the seconds left)
-(void)setSeconds:(int)seconds
{
self.text = [NSString stringWithFormat:@" %02.f : %02i", round(seconds / 60), seconds % 60 ];
}
The above code isn’t fancy. It just sets the label’s text
property to the mm:ss format.
Inside the same file, find the comment in initWithFrame:
that reads “//Initialization code”. Just below that comment, add the following line of code:
self.backgroundColor = [UIColor clearColor];
This just makes the label’s background transparent. You will add more here later.
Now that you have a label to display, you need a HUD layer to hold it. Create a new file in Anagrams/Classes/views for an Objective-C class named HUDView
that subclasses UIView
.
In HUDView.h, add the following:
//at the top
#import "StopwatchView.h"
//inside the interface declaration
@property (strong, nonatomic) StopwatchView* stopwatch;
+(instancetype)viewWithRect:(CGRect)r;
For now, you’ll have a single property that holds a timer, as well as a custom convenience factory method that you’re about to implement.
Switch to HUDView.m and replace its contents with the following:
#import "HUDView.h"
#import "config.h"
@implementation HUDView
+(instancetype)viewWithRect:(CGRect)r
{
//create the hud layer
HUDView* hud = [[HUDView alloc] initWithFrame:r];
//the stopwatch
hud.stopwatch = [[StopwatchView alloc] initWithFrame: CGRectMake(kScreenWidth/2-150, 0, 300, 100)];
hud.stopwatch.seconds = 0;
[hud addSubview: hud.stopwatch];
return hud;
}
@end
The factory method creates a new HUDView
and initializes its stopwatch
property with a new StopwatchView
with 0 seconds remaining.
Now you have a reference to the timer view in the stopwatch
property and can go about implementing the logic behind it. But first, get that timer on the screen! You haven’t checked your progress in a while.
First add a HUDView
property to the game controller. Inside GameController.h, add:
//at the top
#import "HUDView.h"
//along the rest of the class properties
@property (weak, nonatomic) HUDView* hud;
Next create the HUD layer in your ViewController
– the same spot where you create the game layer. Switch to ViewController.m and at the top, import your new view class:
#import "HUDView.h"
Now inside viewDidLoad
, find the line self.controller.gameView = gameLayer;
and just below it, add the HUD to the window’s view and the game controller:
//add one layer for all hud and controls
HUDView* hudView = [HUDView viewWithRect:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
[self.view addSubview:hudView];
self.controller.hud = hudView;
You create a new HUD layer view as big as the screen and you add it to the view controller’s view. Then you also assign it to the game controller’s hud
property.
OK, build and run again and have a look at your new HUD layer!
Um, that stinks. Before you move on with the functionality, now is probably a good time to talk about….
The Art of Gamification
The fact you are using UIKit to create a game does not mean that you also have to use vanilla UIKit components. To make a game more “game-like”, you will want to use fonts, buttons and other controls that look like they belong in a game and not in a spreadsheet program.
For example, compare the two fonts below:
If you think the first font rendered above is more exciting, in a game context at least, perhaps you should hire a graphic designer. :] Long story short, choose an appropriate font for your game. You’re not likely to excite players with a game menu rendered in Arial or Verdana.
Note: Then why did you go for good old Verdana when you created the tile view? On tiles, it makes sense to have maximum readability. Players shouldn’t get confused about which letters they’re seeing.
Note: Then why did you go for good old Verdana when you created the tile view? On tiles, it makes sense to have maximum readability. Players shouldn’t get confused about which letters they’re seeing.
I’ve included a fun font for you in the project. To use it, first open up config.h and add these font definitions:
#define kFontHUD [UIFont fontWithName:@"comic andy" size:62.0]
#define kFontHUDBig [UIFont fontWithName:@"comic andy" size:120.0]
Some of you probably will ask, “Isn’t it faster to put the font definition in the code? Why should it be in a separate file?”
The answer is convenience. Imagine your graphic designer finds a much cooler font for your game. If you already have font assignments sprinkled all over the game code, replacing them will be a pain.
What’s more, abstracting the font size is a very good idea. That’s why you have two definitions – one for a big font and one for normal-sized font. This makes it a lot easier to change the font size in all HUDs throughout your game with a single line change.
Now import config.h at the top of StopwatchView.m:
#import "config.h"
In the same file, inside initWithFrame:
, add the following line of code just after where you set the background color:
self.font = kFontHUDBig;
This sets the label’s font to kFontHUDBig
, which you just defined in config.h.
Build and run again to behold your new, game-ready label!
Nice! However… if you try to drag the tiles around you will notice they don’t drag anymore…
Well… actually, that’s fine. It’s all because of how you normally have layers ordered in a game setup.
As illustrated in the schema below, you will always have the game controls, score, time, etc. on top, so that they are always visible. Under the controls you will have all the objects that move – heroes, word tiles, and so on. And usually at the very back you will have the background – whether static or parallax, it does not matter.
You have exactly the same setup so far, and since the HUD layer is on top of everything, it swallows all touches. Fear not! You can easily turn off the user’s interaction with the HUD layer, thus allowing the user to touch the tiles in the underlying game objects layer.
Disable touch handling in the HUDView
factory method. Switch to HUDView.m and in the viewWithRect:
method after HUDView* hud = [[HUDView alloc] initWithFrame:r];
, add the code to disable touches:
hud.userInteractionEnabled = NO;
Now it’s fixed forever!
Build and run the game again, and you’ll see that you can have your timer and drag tiles, too! Sweet victory!