Gavin Miller is a local Calgary iPhone app developer who will be gracing yycapps with a series of tutorials on app development. This is his third in a series of great articles, so enjoy.

While developing Puzzle Slidez: LOLCat Edition I picked up a few techniques for tile sliding on the iPhone. However I didn’t get there on my first shot. It took several algorithm implementations before I found the version that worked.

The first iteration was naive. Touch the tile with your finger to move it to the open space. The algorithm went like this:

- (void) TouchEnd {
  location = GetTouchLocation();

  SpriteTile *sprite = nil;
  if ((sprite = [self wasSpriteTouched:location]) != nil) {
    if ([self canSpriteOccupyOpenSquare:sprite]) {
      [self moveTileToOpenSquare:sprite duration:0.12];
    }
  }
}

The algorithm detects the location touched, determines if a tile is at that location, then it checks whether the touched tile can move into the empty space. If the tile can be moved, then it’s moved into the empty location.

The beauty of this algorithm is that it worked great in the simulator. The problem was that when using the iPhone, a person’s first instinct is to slide a tile, not touch it. As soon as we gave our game to a tester, we clearly saw that it was broken.

The second try at the algorithm went like this:


- (void) TouchBegan {
  location = GetTouchLocation();

  SpriteTile *sprite = nil;
  if ( (sprite = [self wasSpriteTouched:location]) != nil) {
    startTouchTile = sprite;
  }
}

- (void) TouchEnd {
  location = GetTouchLocation();

  SpriteTile *sprite = nil;
  if ( (sprite = [self wasSpriteTouched:location]) != nil) {
    [self performTileMovementSequence:sprite];
  } else if ([self wasOpenSquareTouched:location]) {
    [self performTileMovementSequence:startTouchTile];
  }
}

This algorithm detected whether the user was sliding a tile into the open position. It did this by obtaining two points: the start of a touch and the end of a touch. It then checked if the start touch was a tile, and if the end touch was the empty square. If both those conditions were met, the tile was moved.

Our first tester was able to play the game without issue, same with the second and third. Golden right? Wrong. Our fourth tester absolutely failed at being able to slide the tiles, their touches were too imprecise for the algorithm. Because the start point had to be a moveable tile, if the user was touched outside that tile it wouldn’t move. They got frustrated because they thought they were touching it. We watched our tester slide and slide and slide, but because they weren’t touching tile properly nothing would happen.

On to the third version of the algorithm:


- (void) TouchBegan {
  startTouch = GetTouchLocation();
}

- (void) TouchEnd {
  endTouch = GetTouchLocation();

  int touchDirection = [self getTouchDirectionFrom:startTouch
                                                to:endTouch];
  if (touchDirection == NO_TOUCH) {
    return;
  }

  SpriteTile *sprite = [self getSpriteToMoveInDirection:touchDirection];
  if (sprite != nil) {
    [self performTileMovementSequence:sprite];
  }
}

This algorithm works completely different from the other two. It assumes that if you’re sliding somewhere on the gaming surface, then you want to move a tile.

To do this we again obtain the first touch point, and the last touch point. It then takes these two locations and determines which direction the touch movement went – top to bottom, bottom to top, left to right, or right to left. Once the direction has been calculated, the algorithm checks whether a tile exists that can be moved in that direction and moves the tile if it can.

You’ll also notice a NO_TOUCH direction. Thresholds were added so that if a touch didn’t move far enough roughly 20 pixels we didn’t count it as a touch. This usually happens when someone simply taps a location on the screen. Because the point your touch begins, and ends at are slightly different, they look like a slide when in fact they aren’t.  NO_TOUCH also accounts for when a user slides from bottom-left diagnolly to the top-right. It doesn’t make sense to count that as a tile movement, so we don’t.

Taking this version back to our tester yielded much better results. They had no problem sliding the tiles around, and the frustration that had been there during our earlier tests completely disappeared.

Here’s a video of the 3 algorithms in action:

So what are the take aways from our algorithm iterations?

You need to test. Until your game makes it out into the real world you have no idea how users are going to interact with your product.

You need to test outside the simulator. A touch is not the same as a mouse click. It’s a difficult concept to get right, but it makes all the difference on the iPhone.