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.

Leave a rating/review
Save for later
Share

Welcome back to our 3-part tutorial series that shows you how to make a letter / word game with UIKit – in this case, a game of anagrams!

If you successfully followed through the first part of this series, you should now have your game board showing up onscreen. So far, you’ve learned how to kick-start your UIKit game, how to plan your controllers and how to connect your views, and have also started implementing the game elements.

Now you’ll take on the gameplay itself and grant the user some special powers, like dragging the tiles around and dropping them onto the targets at the top of the screen. A heads-up-display with a timer and score ticker will keep the player’s ego in check.

Time to grab your UIKit and get back to work!

Getting Started: Your Epic Goal

When you run the completed project from Part 1 of this tutorial, you should see something like this:

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. When all tiles have been placed on the correct targets, the player will win that puzzle.

There will also be a timer – the player will have a limited amount of time to finish each puzzle – and a score display that will increase and decrease in real time, according to the player’s actions.

You’ll achieve these epic goals by taking on these smaller steps:

  • Make the tiles draggable.
  • Make the tiles notify the game controller when they are dropped somewhere.
  • Implement handling of tile drops in the game controller.
  • Check if the player has won after each successful tile placement.
  • Create a separate view layer to contain elements like score readouts and menus. It’s usually best to keep these arranged in their own view, rather than including them in the same view as the actual gameplay elements.
  • Add a level timer and a player score. This is a game, after all!

All right! You’ve been debriefed. Now back to the code!

Drag Those Tiles

You might already be familiar with how to handle touch events with UIKit. If you are, there’s nothing different about handling touches in a UIKit game. You just need to implement the touch delegate methods in TileView. Before your tiles can receive touch events, however, you need to enable them.

Inside TileView.m, add the following line to initWithLetter:andSideLength:, just after the line that reads _letter = letter;:

    // enable user interaction
    self.userInteractionEnabled = YES;

This instructs iOS to send this object events when a touch occurs within the object’s bounds. By default, this is set to NO for a UIImageView (which this class derives from), so you have to set it to YES manually.

Next, you need to add the dragging code. To accomplish this, you are going to take the following strategy:

  • When the user touches down on a tile, figure out the offset within the tile of where their finger lies.
  • When the user drags, you’ll set the center of the tile to the new position of their finger – except you’ll shift the tile by the offset you computer earlier to account where within the tile the user’s finger is.

Let’s try this out. Still in TileView.m, change the @implementation line to look like this:

@implementation TileView
{
    int _xOffset, _yOffset;
}

You’ll use _xOffset and _yOffset to keep track of the distance between the center of the tile and the initial placement of the user’s finger when the touch began.

To actually drag the tiles, add the following touch handling methods to TileView.m, just above the @end:

#pragma mark - dragging the tile
//1 
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    CGPoint pt = [[touches anyObject] locationInView:self.superview];
    _xOffset = pt.x - self.center.x;
    _yOffset = pt.y - self.center.y;
}

//2
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    CGPoint pt = [[touches anyObject] locationInView:self.superview];
    self.center = CGPointMake(pt.x - _xOffset, pt.y - _yOffset);
}

//3
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self touchesMoved:touches withEvent:event];
}

Here’s what’s going on in the above code, step-by-step:

  1. When a touch is detected, you fetch its location within the tile’s superview (that is, the view that contains the tile). You calculate and store the distance from the touch to the tile’s center.
  2. When the player moves their finger, you move the tile to that location, but you adjust the location by the offsets you stored in _xOffset and _yOffset. This keeps the tile from centering itself under the player’s finger as soon as they start moving it – you want it to feel like the user’s dragging a particular point within the tile.
  3. When the player lifts their finger, you make one last call to touchesMoved:withEvent: to make sure the tile’s position is set to the touch’s final location. You could have just typed the same code here as in touchesMoved:withEvent:, but it’s better to avoid repeating code where possible to make maintenance easier.

All right! Build and run the project and have fun playing around with the game tiles.

Cool – you’re already one step closer to your goal.

Hey, Game Controller! A Tile Is Dropping!

In order to make the game controller accept notifications from tiles when they are dropped somewhere on the board, you’ll make the game controller a delegate to all tiles. The tiles will then invoke a method on their delegate when the player drops them. Therefore, get ready to get some experience with the delegation pattern!

Switch to TileView.h and, just below the #import statement at the top, add a forward declaration for the TileView class:

@class TileView;

You always need to do this when you declare the class’s delegate protocol in the interface file. You need to pre-define the class so you can use the class name in the protocol, and afterwards you can create the class interface.

Now go on with declaring a protocol with a single method:

@protocol TileDragDelegateProtocol <NSObject>
-(void)tileView:(TileView*)tileView didDragToPoint:(CGPoint)pt;
@end

TileDragDelegateProtocol requires one method – the one that handles a finished drag and drop operation.

Now scroll down a bit and inside the interface, add a property to store the delegate:

@property (weak, nonatomic) id<TileDragDelegateProtocol> dragDelegate;

All right! That should be enough declarations – time to add the code. Switch to TileView.m and at the end of touchesEnded:withEvent: add:

if (self.dragDelegate) {
    [self.dragDelegate tileView:self didDragToPoint:self.center];
}

Totally easy, right? You check whether the dragDelegate property is set, and if so, you just call the delegate’s tileView:didDragPoint: method, passing it self and self.center.

Now you need to make GameController conform to your new protocol and actually do something with this information.

Contributors

Over 300 content creators. Join our team.