A Game Idea Machine
Did you ever get stuck when trying to come up with new game ideas? Try out my little tool I put together:
It generates new game ideas by randomly choosing from genre, visual style and other parameters. You can also preselect each parameter, e.g. if you just want to make 8bit 2D games.
Feel free to use it, share it or do whatever you like with it!
Using a physical Joystick in a Cocos2D (for Mac) Game (Part 2)
In the previous post I explained how to intercept joystick events in a Cocos2D for Mac project using DDHidLib. Now we will use this foundation to control a space ship.
Adding a Space Ship
Download the zip file containing the image of a space ship and a bullet to shoot here. Extract the zip and add both files to the Resources group in your Xcode project.
Now add a new class derived from CCNode and name it “Ship”. Open Ship.m. Add an init method:
{
self = [super init];
if (self)
{
// add ship sprite
CCSprite *ship = [CCSprite spriteWithFile:@"ship.png"];
[self addChild:ship];
}
return self;
}
Open HelloWorldLayer.m. Remove the code which adds the “Hello World” label in the init-method. We don’t need that any more. Now add the following code at the end of init:
self.ship = [[[Ship alloc] init] autorelease];
self.ship.position = ccp(30.0, winSize.height / 2.0f);
[self addChild:self.ship];
Build an run the project. You should now see the space ship on the screen.
Moving the Ship
We will implement ship movement using booleans to control the directions. Open Ship.h and modify it so that it looks like this:
#import "cocos2d.h"
@interface Ship : CCNode
{
BOOL moveUp;
BOOL moveDown;
BOOL moveLeft;
BOOL moveRight;
}
@property (nonatomic, assign) BOOL moveUp;
@property (nonatomic, assign) BOOL moveDown;
@property (nonatomic, assign) BOOL moveLeft;
@property (nonatomic, assign) BOOL moveRight;
@end
In Ship.m add the @synthesize directives:
@synthesize moveDown;
@synthesize moveLeft;
@synthesize moveRight;
The actual movement will be handled in a Cocos2D standard update method:
{
#define VELOCITY 150
CGPoint position = self.position;
if(self.moveUp)
position.y += VELOCITY * dt;
if(self.moveDown)
position.y -= VELOCITY * dt;
if(self.moveRight)
position.x += VELOCITY * dt;
if(self.moveLeft)
position.x -= VELOCITY * dt;
self.position = position;
}
VELOCITY is the amount of pixels per second the ship should move. The ship’s position is updated depending on which direction is currently active.
Register the ship object to be included in Cocos2D’s update calls by adding
to the init method. To clean up, also add a dealloc with the according unscheduleUpdate:
{
[self unscheduleUpdate];
[super dealloc];
}
Open HelloWorldLayer.m and scroll down to the DDHidLib delegate methods. The ship can be controlled either with an analog stick or a d-pad, so we will implement movement behavior in the according delegate methods.
Analog:
- (void)ddhidJoystick:(DDHidJoystick *)joystick
stick:(unsigned)stick
xChanged:(int)value
{
// this method gets called when an analog stick is moved on the x axis.
if(value < -THRESHOLD)
self.ship.moveLeft = YES;
else if(value > THRESHOLD)
self.ship.moveRight = YES;
else
{
self.ship.moveLeft = NO;
self.ship.moveRight = NO;
}
}
- (void)ddhidJoystick:(DDHidJoystick *)joystick
stick:(unsigned)stick
yChanged:(int)value
{
// this method gets called when an analog stick is moved on the y axis.
if(value < -THRESHOLD)
self.ship.moveUp = YES;
else if(value > THRESHOLD)
self.ship.moveDown = YES;
else
{
self.ship.moveUp = NO;
self.ship.moveDown = NO;
}
}
d-pad:
stick:(unsigned)stick
povNumber:(unsigned)povNumber
valueChanged:(int)value
{
// This method gets called when d-pad buttons are pressed. The value is direction in degrees * 100
// reset movement
self.ship.moveUp = NO;
self.ship.moveDown = NO;
self.ship.moveLeft = NO;
self.ship.moveRight = NO;
switch (value)
{
case -1:
// no movement
break;
case 0:
self.ship.moveUp = YES;
break;
case 4500:
self.ship.moveUp = YES;
self.ship.moveRight = YES;
break;
case 9000:
self.ship.moveRight = YES;
break;
case 13500:
self.ship.moveRight = YES;
self.ship.moveDown = YES;
break;
case 18000:
self.ship.moveDown = YES;
break;
case 22500:
self.ship.moveDown = YES;
self.ship.moveLeft = YES;
break;
case 27000:
self.ship.moveLeft = YES;
break;
case 31500:
self.ship.moveLeft = YES;
self.ship.moveUp = YES;
break;
default:
break;
}
}
Build and run. You should now be able to move the ship around using an analog stick or a d-pad.
Shooting
Open HelloWorldLayer.h and add a member variable:
The BOOL flag will determine if new bullets should be fired or not.
Open HelloWorldLayer.m and in the init method register the object to receive update: calls:
Unregister in dealloc:
Add a new method that shoots a bullet:
{
CGSize winSize = [CCDirector sharedDirector].winSize;
CCSprite *bullet = [CCSprite spriteWithFile:@"bullet.png"];
bullet.position = ccpAdd(self.ship.position, ccp(bullet.contentSize.width / 2.0f, 0));
[self addChild:bullet];
[bullet runAction:[CCSequence actions:
[CCMoveBy actionWithDuration:1.0 position:ccp(winSize.width, 0)],
[CCCallFuncN actionWithTarget:self selector:@selector(removeBullet:)],
nil]];
}
A new sprite is instantiated and added to the layer. A CCMoveBy action is used to animate the bullet until it is out of view. Then the removeBullet: method is called:
{
[node stopAllActions];
[self removeChild:node cleanup:YES];
}
This method stops all active actions and removes the bullet from the layer.
Add the upadte: method which simply shoots bullets if the shoot flag is YES:
{
if(shoot)
[self shootBullet];
}
To set the values for the shoot flags we implement two DDHidLib delegate methods which handle button presses:
{
// this method would be a good place to start shooting bullets
shoot = YES;
}
- (void)ddhidJoystick:(DDHidJoystick *)joystick buttonUp:(unsigned)buttonNumber
{
// this method would be a good place to stop shooting bullets
shoot = NO;
}
Build and run. Now you can move your ship AND shoot bullets!
You can download the complete Xcode project here: JoystickTest_Final.zip
Using a physical Joystick in a Cocos2D (for Mac) Game (Part 1)
Quite a while ago I started playing around with Cocos2D for Mac and so far I love it. As a first test project I am making a retro style side-scrolling space shoot-em’-up.
While processing keyboard input is quite easy, the only thing I was really missing is built-in support for joysticks and gamepads. I could not find anything related to this topic on the official Cocos2D forums. You only get plenty of articles describing how to implement a soft-gamepad on the iPhone or iPad. I guess this is because the Mac port of Cocos2D is quite new.
After doing some research I found out that a joystick is a HID (Human Interface Device) and there is a crude, low level C API on the Mac to interface HIDs called IOHIDLib. Then I found out about Dave Dribin’s excellent DDHidLib library, an Objective-C wrapper around IOHIDLib. You can download it here: DDHidLib. In the first part of the tutorial I’ll show you how to integrate it in your Cocos2D project (I assume you use Xcode 4).
Building the Framework
- Download and extract the source code of DDHidLib from the above link.
- Open the DDHidLib Xcode project.
- Select the DDHidLib scheme.
- Edit the scheme so it uses the Release build configuration.
- Build the framework. If you run into problems here make sure the Base SDK is set to “Latest Mac OS X” in the target’s build settings.
- Locate the framework in Finder for later use.
Demo Project
Now I’ll take you through the process of integrating DDHidLib into a Cocos2D project.
Create a new project in Xcode using the template called “cocos2d_macosx” and name it “JoystickTest”. Build and run. This should just display a Hello World label. Now to the fun part.
Adding the Framework
- Drag DDHidLib.framework into the Frameworks group of your demo project and make sure “Copy items” is checked. The framework will now be linked to the target.
- Go to you project settings, select the JoystickTest target.
- Select the “Build Phases” tab and add a new “Copy Files” phase.
- Select destination “Frameworks” and also rename the phase to “Frameworks”.
- Drag DDHidLib.framework from the project navigator into the build phase.
- Build and run the project to see if everything works.
Intercepting Joystick Events
- Open HelloWorldLayer.h and add a member variable:
-
Open HelloWorldLayer.m and add these pieces:
#import <DDHidLib/DDHidLib.h>
At the end of the init method add
// allJoysticks returns an array of all connected joysticks
joysticks = [[DDHidJoystick allJoysticks] retain];
// we want to be the delegate of the joysticks
[joysticks makeObjectsPerformSelector:@selector(setDelegate:) withObject:self];
// start listening to all joystick events
[joysticks makeObjectsPerformSelector:@selector(startListening) withObject:nil]; -
Now we can receive delegate methods which are called when the user interacts with the joystick.
Add the following code at the end of the file. Use these delegate methods to set states or trigger actions in your game logic. The methods are pretty self explanatory.#pragma mark - Joystick stuff
- (void)ddhidJoystick:(DDHidJoystick *)joystick buttonDown:(unsigned)buttonNumber
{
// this method would be a good place to start shooting bullets
NSLog(@"button down: %d", buttonNumber);
}
- (void)ddhidJoystick:(DDHidJoystick *)joystick buttonUp:(unsigned)buttonNumber
{
// this method would be a good place to stop shooting bullets
NSLog(@"button up: %d", buttonNumber);
}
#define THRESHOLD 2<<13 // this threshold defines the dead zone of analog sticks
- (void)ddhidJoystick:(DDHidJoystick *)joystick
stick:(unsigned)stick
xChanged:(int)value
{
// this method gets called when an analog stick is moved on the x axis.
if(value < -THRESHOLD)
NSLog(@"stick left");
else if(value > THRESHOLD)
NSLog(@"stick right");
else
NSLog(@"x axis neutral zone");
}
- (void)ddhidJoystick:(DDHidJoystick *)joystick
stick:(unsigned)stick
yChanged:(int)value
{
// this method gets called when an analog stick is moved on the y axis.
if(value < -THRESHOLD)
NSLog(@"stick up");
else if(value > THRESHOLD)
NSLog(@"stick down");
else
NSLog(@"y axis neutral zone");
}
- (void)ddhidJoystick:(DDHidJoystick *)joystick
stick:(unsigned)stick
otherAxis:(unsigned)otherAxis
valueChanged:(int)value
{
NSLog(@"otherAxis: %u value: %d", otherAxis, value);
}
- (void)ddhidJoystick:(DDHidJoystick *)joystick
stick:(unsigned)stick
povNumber:(unsigned)povNumber
valueChanged:(int)value
{
// This method gets called when d-pad buttons are pressed. The value is direction in degrees * 100
switch (value)
{
case -1:
text = @"d-pad none";
break;
case 0:
text = @"d-pad N";
break;
case 4500:
text = @"d-pad NE";
break;
case 9000:
text = @"d-pad E";
break;
case 13500:
text = @"d-pad SE";
break;
case 18000:
text = @"d-pad S";
break;
case 22500:
text = @"d-pad SW";
break;
case 27000:
text = @"d-pad W";
break;
case 31500:
text = @"d-pad NW";
break;
default:
break;
}
} - Connect a joystick or pad to your Mac and try it out!
You can download the finished Xcode project here: JoystickTest.zip
