How to Program Dpad Joystick Touch Controls for iPhone Games

Screenshot of QuexlorLite showing the joystick aka D-pad
A screenshot of the iPhone game QuexlorLite showing it’s D-pad / joystick controls

A Walkthrough Tutorial for Objective C / iPhone SDK Beginners

So you want to learn how to program an up, down, left, right D-pad for your iPhone game, eh? All right. Let’s get started.

The Graphics

First thing to do is make the graphics. Use your favorite graphical editor (mine is Photoshop) and come up with something like this:

The two images we will use to build a joystick D-pad

This is a picture of the two elements of the joystick laid out next to each other. The first element is the D-pad background, which has arrows for up/north, right/east, down/south, and left/west. The second is the joystick’s button that moves with your thumb. If you are artistically challenged, then feel free to crop these elements from the image (I promise I won’t tell anybody).

Loading the Graphics

At this point, you’re going to need a working game engine. I highly recommend Cocos2D because it is easy to use and has plenty of support from it’s author (his name is Ricardo) and the Cocos2D community.

Once you have a game engine you are also going to need some basic game code to start with. If you are new to all this, you can download the source code to the iPhone game QuexlorLite and use it as a base for your own game.

Now that you have a game to work with, the first thing we need to do is add a few member variables to our Heads-Up Display (HUD) Layer:


// in Hud.h
@interface HudLayer : CCLayer
	{
		CCSprite* joypad,*joybtn,
		CGPoint touchPos;
		float joybtnDistSquared,joybtnAngle;
		BOOL isMovingJoybtn;
	}

Then we load the graphics:


-(id) init
{
	self = [super init];
	if(self != nil)
	{
		// set this so we can register with touch dispatcher
		isTouchEnabled = YES;
		// load our joystick background
		joypad = [[CCSprite spriteWithFile:@"joypad.png"] retain];
		joypad.position = ccp(70,70);
		joypad.opacity = 0;
		[self addChild:joypad z:1];
		// load joypad button
		joybtn = [[CCSprite spriteWithFile:@"joybtn.png"] retain];
		joybtn.position = ccp(70,70);
		joybtn.opacity = 0;
		[self addChild:joybtn z:2];
	}
	return self;
}

The graphics are loaded using Cocos2D’s handy spriteWithFile method. This method returns a CCSprite pointer that we retain (and release in the dealloc).

The joystick button is placed on top of the joystick background, ready for us to move it with our thumb.

The Professional Touch

We set the opacity of each joystick element to zero (effectively making it transparent) and then nicely fade it in and make it blink when the game starts using code like this:


[joypad runAction:[CCSequence actions:
	[CCDelayTime actionWithDuration:1.5f],
	[CCFadeTo actionWithDuration:1.5f opacity:192],
	[CCBlink actionWithDuration:0.66f blinks:3],
	nil]];

This launches a sequence of actions: 1) delay a second and a half, 2) fade in to 75% opacity over a second and a half, and 3) blink three times over two thirds of a second.

Responding to Touch Events

In order to move the joystick button, we need to respond to touch events. Here’s a little blast of code which does that:


-(BOOL) ccTouchBegan:(UITouch*)touch withEvent:(UIEvent*)event
{
	// started touching somewhere in the joystick pad?
	if( !isMovingJoybtn && [self isTouchingJoybtn:touch] )
	{
		touchPos = joypad.position;
		// initially move the joystick button to touch point
		[self moveJoybtn:touch];
		// we are now moving the joystick button
		isMovingJoybtn = YES;
	}
	// returning YES means we claim the touch
	// (always return YES because we want to claim
	// touching the whole screen when player dies)
	return YES;
}
-(void) ccTouchMoved:(UITouch*)touch withEvent:(UIEvent*)event
{
	// keep moving the joystick button
	if( isMovingJoybtn )
		[self moveJoybtn:touch];
}
-(void) ccTouchEnded:(UITouch*)touch withEvent:(UIEvent*)event
{
	// stop moving joystick
	[self stop];
}
-(void) ccTouchCancelled:(UITouch*)touch withEvent:(UIEvent*)event
{
	// stop moving joystick
	[self stop];
}

When we first touch the iPhone’s screen, we get the ccTouchBegan message. As long as we are still touching the screen, we continue to get the ccTouchMoved message. When we finally let up, we get ccTouchEnded. Pretty self-explanatory, eh?

Our ccTouchBegan method is where most of the magic happens. We basically check to see if the touch point is within the boundaries of the joystick background using the isTouchingJoybtn method, and if so we store information on the touch and begin the joystick button’s movement.

The Pythagorean Theorem

A squared plus B squared equals C squared

Since the joystick background is a circle, we need some special code to determine whether our thumb is touching it. A rectangle test would be far too square. Thankfully, we can return to our roots and deploy a simple geometrical equation to help us. Anybody remember A squared plus B squared equals C squared?

In our case, A is the X distance from the thumb to the joystick center, B is the Y distance, and C is the diagonal distance (or radius).

The distanceFromJoypadSquared method simply calculates this radius. We then use it in the isTouchingJoybtn method to finally determine YES or NO whether the thumb is touching the joystick:


-(CGFloat) distanceFromJoypadSquared:(CGPoint)p
{
	// remember a squared + b squared = c squared?
	return ccpLengthSQ(ccpSub(p, joypad.position));
}
-(BOOL) isTouchingJoybtn:(UITouch*)touch
{
	// the joypad is a circle, so return yes if
	// distance from center is less than radius
	CGFloat c2 = [self distanceFromJoypadSquared:touchToPoint(touch)];
	return (c2 < kJoypadRadiusSquared);
}

Moving the Joystick Button

When we move the joystick button, we need to 1) make sure the joystick button does not move outside the boundaries of the joystick background, and 2) store the angle and distance of the joystick button so that we can use it to control our main character.


-(void) moveJoybtn:(UITouch*)touch
{
	// get previous touch point and determine offset
	CGPoint prev = (isMovingJoybtn ? touchToPreviousPoint(touch) : joybtn.position);
	CGPoint offset = ccpSub(touchToPoint(touch), prev);
	if( offset.x || offset.y )
	{
		// get new purported joybtn position and delta to joypad center
		touchPos = ccpAdd(touchPos, offset);
		CGPoint delta = ccpSub(touchPos, joypad.position);
		CGPoint newPos = touchPos;
		// get its angle and distance
		joybtnAngle = ccpToAngle(delta);
		joybtnDistSquared = [self distanceFromJoypadSquared:newPos];
		// clamp it inside the joypad
		if( joybtnDistSquared > kJoypadRadiusSquared )
		{
			newPos = ccpAdd(joypad.position,
				ccpMult(ccpForAngle(joybtnAngle), kJoypadRadius));
			joybtnDistSquared = kJoypadRadiusSquared;
		}
		// set it to the new position
		[joybtn setPosition:newPos];
	}
}
-(void) stop
{
	isMovingJoybtn = NO;
	joybtn.position = joypad.position;
}

The moveJoybtn method starts by calculating the previous touch position and the offset to the current touch position. It then adds the offset to the existing joystick button position to calculate the delta, or the desired new joystick button position. The angle of this delta is then saved for later and the joystick button is clamped within the boundaries of the joystick background.

Controlling the Main Character

We now have one particular member variable which will come in quite handy when we want to move the main character around the screen. It is called joybtnAngle. This angle can be used to smoothly move the character around the screen (like in the video below) or it can be "snapped" to one of the eight compass directions in order to give your game a more retro D-pad feel.

You can download the entire working source code to the game QuexlorLite to see this joystick code in action, complete with the snapping of the joystick angle to one of the eight compass directions.

Enjoy coding!

Comments

4 Responses to “How to Program Dpad Joystick Touch Controls for iPhone Games”

  1. Marin Todorov

    Hi Nat,

    first of all congrats on the blog – very useful stuff – already subscribed :)

    There’s one thing to share about the pad in Quexlor though – very often it happens that my thumb goes offscreen (from the bottom) and the pad positions is lost and somehow difficult to get moving again. (this is purely from perfectionist’s point of view)

    Any thoughts how could it be better in regard to that issue?

    congrats, best,
    Marin

    Reply
    • Nat

      Marin,
      Yes, I like your idea of moving the pad a little closer to the center of the screen. That will probably help a little. The issue is that when our thumbs go off the screen, the iPhone/iPad forgets about that touch event, even if our thumb is still touching the outer area of the phone (the part that is not “touchable”). It might be possible to remember the touch event better in the code. So, a little bit of perfecting and we could get it to be smoother.
      Thanks for feedback!
      Nat

  2. luckysing

    Hi Nat thanks for the joy pad tutorial.
    I wanted to ask is the source code for QuexlorLite available for free.
    Thanks again for the wonderful tutorials

    Reply
  3. Nat

    Hi luckysing. The full source code to QuexlorLite is available as part of purchasing the iPhone Game Kit. Thanks for your thanks, :)
    Nat

    Reply

Leave a Reply


four − = 3

Subscribe via email

Subscribe in a reader


iPhone Game Creation for Beginners

A hands-on introduction to all the tools you need to develop an iPhone game. It includes source code to a simple board game built with Cocos2d and a comprehensive book that will teach you Xcode, Objective C and the Cocos2d framework. Plus, you get documentation, support and a ton of artwork to start your own creation.
More info…


Action-RPG Engine Code & Tutorial

Create your own action, RPG, adventure or RTS game with this starter kit. Learn how to manage tilemaps, characters, AI and more. This Starter Kit includes a flexible RPG engine built on Cocos2d, along with a sample RPG project that will teach you everything you need to know. Also included is a helpful ebook tutorial and a gigantic royalty-free art package!
More info…

Featured Posts

Cocos2d 2.0, iOS 6 & iPhone 5 Updates - 9/24/12

Making Cross-Platform iPhone & Android Games – Don’t Get Left Behind! (Part 3) - 7/11/12

5 Cocos2D iPhone Game Source Code Kits to Revolutionize Your Game Development - 4/5/12

How to Make Games With the iPhone Game Kit 5.0 - 2/19/12

Learn to Make iPhone Games with the iPhone Game Kit 4.0 - 12/10/11

The Cocos2D Family of Game Engines, Their Platforms & Languages - 11/2/11

Game Design Lessons: Introducing Flow - 9/23/11

What is Cocos2D and Why is it One of the Best iPhone Game Engines? - 6/3/11

Community RPG Developer’s Diary, Part One - 1/20/11

CCZSprite and HudLevelSprite, Two Cocos2D Extensions You Need to Know About - 8/10/10

How to Program Dpad Joystick Touch Controls for iPhone Games - 6/7/10

Other Posts

Awesome Heroes Arena! - 3/13/13

Making Cross-Platform iPhone & Android Games – Don’t Get Left Behind! (Part 2) - 5/26/12

An Awesome Review of our RPG Engine from a Customer - 4/26/12

Making Cross-Platform iPhone & Android Games – Don’t Get Left Behind! - 4/16/12

ShakeMidi: A Wireless MIDI Controller That You Can Shake - 12/1/11

Download Monster Checkers Updated Source Code Soon - 7/29/11

iPhone Game Kit Discussed on the Cocos2D Podcast - 7/8/11

New iPhone Game Kit 3.4 Update - 4/28/11

Quexlor LoF Hits the App Store - 4/8/11

The iPhone Game Kit Community Project – A Newcomer’s Perspective - 3/29/11

AI: What Cocos2D Cannot Do - 2/9/11

Cocos2D Community Game, Developer’s Diary, Part Two - 1/28/11

3.2 Kit is Out, Cocos2D 0.99.5 Compatible - 1/13/11

3.1 Kit is Out! Let’s Start the Community RPG - 12/9/10

Develop the Game Kit’s Community RPG and be a part of gaming history! - 11/23/10

iPhone Game Kit 3.0 Released - 10/14/10

New Game Added to the iPhone Game Kit! - 9/21/10

New Tiled Map Editor 0.5.1 Works Like a Charm! - 9/10/10

Four Interesting Things We Are Working To Improve The iPhone Game Kit - 8/25/10

iOS4 Compatible iPhone or iPad Game Source Code - 8/2/10

Making High Resolution Graphics For iPad and iPhone4 Games - 7/16/10

Game Source Code & Tutorials



iPhone Game Creation for Beginners

A hands-on introduction to all the tools you need to develop an iPhone game. It includes source code to a simple board game built with Cocos2d and a comprehensive book that will teach you Xcode, Objective C and the Cocos2d framework. Plus, you get documentation, support and a ton of artwork to start your own creation.
More Info...


Action-RPG Engine Code & Tutorial

Create your own action, RPG, adventure or RTS game with this starter kit. Learn how to manage tilemaps, characters, AI and more. This Starter Kit includes a flexible RPG engine built on Cocos2d, along with a sample RPG project that will teach you everything you need to know. Also included is a helpful ebook tutorial and a gigantic royalty-free art package!
More Info...