How To Make a Letter / Word Game with UIKit: Part 1/3

This 3-part tutorial series will guide you through the process of building a board game for the iPad, where you create words with letters. You’ll also learn about best practices for creating solid, modular iOS apps. And as a bonus, you’ll get a crash course in audio-visual effects with UIKit! By Marin Todorov.

Leave a rating/review
Save for later
Share
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

7) Slightly Rotate the Letters Randomly

Randomization is one of the keys to building a successful computer game. You want to randomize your game as much as possible. For example, no player enjoys enemies that all do the same thing every time the game runs.

In the case of the Anagrams game, you can randomize the placement of each tile so that they look more natural on the game board, as if a human put them down without trying too hard to align them properly:

In order to accomplish this randomization, add the following method to the interface in TileView.h:

-(void)randomize;

Inside TileView.m, add the following implementation of randomize:

-(void)randomize
{
    //1
    //set random rotation of the tile
    //anywhere between -0.2 and 0.3 radians
    float rotation = randomf(0,50) / (float)100 - 0.2;
    self.transform = CGAffineTransformMakeRotation( rotation );

    //2
    //move randomly upwards
    int yOffset = (arc4random() % 10) - 10;
    self.center = CGPointMake(self.center.x, self.center.y + yOffset);
}

This code does two things:

  1. It generates a random angle between -0.2 and 0.3 radians (using the helper function randomf defined in config.h). Then it calls CGAffineTransformMakeRotation to create a new transform for the tile view that will rotate it around its center by that random angle.
  2. It generates a random value between -10 and 0 and moves the tile up by that offset.

Note: You might want to replace all of these numbers with constants you define in config.h so you can fine-tune the tile appearance more easily.

Now you just need to call this method. Inside GameController.m, edit dealRandomAnagram by adding the following line of code just after the line that begins with tile.center = ...:

[tile randomize];

And that's all it takes! Hit run again to see the randomized tiles on the board:

Using what you've already achieved, you can also quickly add the targets to the game board. Let's do that before wrapping up this part of the tutorial.

8) Add the Targets

The target views are pretty similar to the tile views. They also subclass UIImageView and show a default image, and they also are assigned a letter. The difference is that they don't show a label with that letter and can't be dragged around. This means the code you need for the targets is similar to what you did before – but simpler!

Create a new class in Anagrams/Classes/views called TargetView and make it a subclass of UIImageView.

Open up the freshly created TargetView.h and inside the interface declaration add the following two properties and method:

@property (strong, nonatomic, readonly) NSString* letter;
@property (assign, nonatomic) BOOL isMatched;

-(instancetype)initWithLetter:(NSString*)letter andSideLength:(float)sideLength;

Yes, these are exactly the same properties and method name you used for the TileView! As you see, now you can move quickly. You already know what the above are for, so you can move straight to the implementation.

Switch to TargetView.m and delete the provided methods. Replace them with:

- (id)initWithFrame:(CGRect)frame
{
    NSAssert(NO, @"Use initWithLetter:andSideLength instead");
    return nil;
}

//create a new target, store what letter should it match to
-(instancetype)initWithLetter:(NSString*)letter andSideLength:(float)sideLength
{
    UIImage* img = [UIImage imageNamed:@"slot"];
    self = [super initWithImage: img];
    
    if (self != nil) {
        //initialization
        self.isMatched = NO;

        float scale = sideLength/img.size.width;
        self.frame = CGRectMake(0,0,img.size.width*scale, img.size.height*scale);
        
        _letter = letter;
    }
    return self;
}

Once again, this is the same code you started with in TileView.m. You resize the image according to the provided side length and assign the letter – that's all.

Now to display the targets on the screen. Open up GameController.m and add the following import:

#import "TargetView.h"

Then add the following code inside dealRandomAnagram, just before the comment that reads "//initialize tile list":

// initialize target list
_targets = [NSMutableArray arrayWithCapacity: ana2len];

// create targets
for (int i=0;i<ana2len;i++) {
    NSString* letter = [anagram2 substringWithRange:NSMakeRange(i, 1)];

    if (![letter isEqualToString:@" "]) {
        TargetView* target = [[TargetView alloc] initWithLetter:letter andSideLength:tileSide];
        target.center = CGPointMake(xOffset + i*(tileSide + kTileMargin), kScreenHeight/4);

        [self.gameView addSubview:target];
        [_targets addObject: target];
    }
}

This is almost the same code you used to deal the tiles on the board, except this time you grab the letters from the phrase stored in anagram2 and you don't randomize their position. You want the target views to look nice and neat, after all!

Why does the target initialization have to come before the tile initialization? Subviews are drawn in the order they are added to their parent view, so adding the target views first ensures that they will appear behind, or below, the tiles.

If you did want to add the target views after the tile views, there are other ways to get them behind the tiles, such as UIView's sendSubviewToBack: method. But adding them first is the most efficient solution.

Build and run again to see that your board is already close to being finished!

Waaaaaait a secoooond!!!

These two phrases don't match. Below you have three tiles followed by four tiles, while the targets at the top are four tiles following by three tiles!

Don't worry, you should actually expect this behavior. After all, the anagrams consist of two phrases which might each have different word counts. They just need to have an equal number of total characters (not including white spaces). So it's all good!

Where to Go from Here?

Click here to download the full source code for the project up to this point.

Congrats, you've achieved a lot today! Let's see what you've done so far:

  • You've created a model to load the level configuration.
  • You've connected the game controller, game view and model.
  • You have two custom views, one for tiles and one for targets.
  • You've finished the initial board setup.

You now have a sound foundation on which to build. Stay tuned for Part 2 of the series, where you'll begin interacting with the player and building up the gameplay.

In the meantime, if you have any questions or comments about what you've done so far, drop by the forums to contribute your two tiles' worth. :]

Contributors

Over 300 content creators. Join our team.