Archive

Posts Tagged ‘iphone’

Game Demo Tutorial #3: Collisions & Particle Systems

April 26th, 2009

In this entry I am going to cover using Chipmunk's collision pair function. This function is used to set up a collision test between two objects. If Chipmunk detects that two predefined objects have collided, the callback function that was passed to the collision pair function gets called. To show this we are going to extend the code from the last tutorial, adding a rock and a particle system.

The first thing we are going to do is add rock.png to our resources. Rock.png can be found in the source code for this entry. Next, we're going to add a method called makeSpaceRock to our GameLayer class within GameScene.m. Here is the code you need to add:

 
-(void) makeSpaceRockX: (float) x y:(float)y
{
	Sprite *rock = [[Sprite spriteWithFile:@"rock.png"] retain];
	rock.position = cpv(x,y);
	[self addChild: rock];
 
	cpVect verts[] = {
		cpv(-54,-43),
		cpv(-54, 43),
		cpv(54, 43),
		cpv(54,-43),
	};
 
	cpBody *rockBody = cpBodyNew(200.0f, INFINITY);
	rockBody->p = cpv(x, y);
	rockBody->v = cpv(0, 0);
 
	cpSpaceAddBody(space, rockBody);
 
	cpShape * rockShape = cpPolyShapeNew(rockBody, 4, verts, cpvzero);
	rockShape->e = 0.9f; rockShape->u = 0.9f;
	rockShape->data = rock;
	rockShape->collision_type = 0; //New!
	cpSpaceAddShape(space, rockShape);
 
	cpSpaceAddCollisionPairFunc(space, 0, 1, &bulletCollision, self); //new!
 
}
 

As you can see this method contains to lines of code we haven't seen before. We are setting a property called collision_type on rockShape and then calling cpSpaceAddCollisionPairFunc. collision_type is how we identify a particular object for the collision pair function. In order for everything to work properly you'll need to start numbering your collision_types from 0. rockShape will be numbered with a 0 and our bullets will be numbered with a 1. cpSpaceAddCollisionPairFunc takes the following arguments: the current simulation space, object A (as specified by collision_type), object B, C callback function to be called when a collision is detected, and then a data parameter. The last parameter is optional and could be left as null, but you can pass self in to get access to your GameLayer object during runtime.

Next we need to modify our method that creates bullets, makeBulletX. Here is the line you need to add:

 
laserShape->data = laser;
	laserShape->collision_type = 1; //this is new!
	cpSpaceAddShape(space, laserShape);
 

Now we need to see up our callback function, which we declared as bulletCollision in cpSpaceAddCollisionPairFunc. This C function will be located in GameScene.m, but outside of our classes, just like the function eachShape(void *ptr, void* unused). After the eachShape function add the following code:

 
static int bulletCollision(cpShape *a, cpShape *b, cpContact *contacts, int numContacts, cpFloat normal_coef, void *data)
{
	NSLog(@"Collision Detected");
	return 0;
}
 

Now we need to add a rock to the screen to test out our collision. In the init method of GameLayer add the following line:

 
[self makeSpaceRockX:200 y:200];
 

If you build and run the application you should now see a rock on screen. You should be able to shoot that rock with laser bullets and have the collision show up in the console. Hopefully everything worked for you. If not you can always grab the fully working source code at the end of this entry.

Next up we are going to flesh out our bullet collisions a little bit more. We want the rock to disappear when a bullet collides with it and we want an explosion to occur. First we want to add the following method to our GameLayer class:

 
-(void) createExplosionX: (float) x y: (float) y
{
	ParticleSystem *emitter = [ParticleExplosion node];
	emitter.position = cpv(x,y);
	[self addChild: emitter];
}
 

Now we want to go back to our collision callback function (bulletCollision) and modify its code to this:

 
GameLayer *game = (GameLayer*) data;
	[game createExplosionX:200 y:200];
	return 0;
 

Now if you run the application you should be able to shoot the rock and generate an explosion. This is great, but as you can see the explosion doesn't really look that great. It runs a little slow and the colors are wacky. To fix this we're going to create our own particle system. Right click on the Classes folder in X-Code and select Add->New File. Choose NSObject subclass and name it RockExplosion. Change RockExplosion.h to this:

 
#import "PointParticleSystem.h"
#import "QuadParticleSystem.h"
 
@interface RockExplosion : PointParticleSystem
{
}
@end
 

As you can see we are going to be extending Cocos2D's PointParticleSystem class.

In the implementation file add the following code:

 
#import "RockExplosion.h"
#import "TextureMgr.h"
#import "Director.h"
 
@implementation RockExplosion
-(id) init
{
	return [self initWithTotalParticles:2];
}
 
-(id) initWithTotalParticles:(int)p
{
	if( !(self=[super initWithTotalParticles:p]) )
		return nil;
 
	// duration
	duration = 0.1f;
 
	// gravity
	gravity.x = 10;
	gravity.y = 10;
 
	// angle
	angle = 90;
	angleVar = 360;
 
	// speed of particles
	speed = 200;
	speedVar = 40;
 
	// radial
	radialAccel = 0;
	radialAccelVar = 0;
 
	// tagential
	tangentialAccel = 0;
	tangentialAccelVar = 0;
 
	// emitter position
	position.x = 160;
	position.y = 240;
	posVar.x = 0;
	posVar.y = 0;
 
	// life of particles
	life = 10.0f;
	lifeVar = 2;
 
	// size, in pixels
	startSize = 40.0f;
	startSizeVar = 20.0f;
 
	// emits per second
	emissionRate = totalParticles/duration;
 
	// color of particles
	startColor.r = 0.99f;
	startColor.g = 0.99f;
	startColor.b = 0.99f;
	startColor.a = 1.0f;
	startColorVar.r = 0.0f;
	startColorVar.g = 0.0f;
	startColorVar.b = 0.0f;
	startColorVar.a = 0.0f;
	endColor.r = 0.0f;
	endColor.g = 0.0f;
	endColor.b = 0.0f;
	endColor.a = 1.0f;
	endColorVar.r = 0.0f;
	endColorVar.g = 0.0f;
	endColorVar.b = 0.0f;
	endColorVar.a = 0.0f;
 
	self.texture = [[TextureMgr sharedTextureMgr] addImage: @"rock.png"];
 
	// additive
	blendAdditive = NO;
 
	return self;
}
 
@end
 

Now we need to go back and modify our createExplosion method in GameLayer. The ParticleSystem should now be created from RockExplosion instead of ParticleExplosion. The line of code should be:

 
ParticleSystem *emitter = [RockExplosion node];
 

Also, you will need to go into GameScene.h and add #import RockExplosion.h.

Great! Now we have a nice little explosion when the lasers hit our rock. Let's go back and actually get rid of the space rock when a laser hits it. In GameScene.m, change the code inside the bulletCollision function to this:

 
	GameLayer *game = (GameLayer*) data;
	a->body->p = cpv(800,800);
	b->body->p = cpv(800,800);
	[game createExplosionX:200 y:200];
	return 0;
 

This code will move the space rock and bullet that hit it off screen, leaving only the exploding rock chunks. Compile and run your code, looks cool, huh?

SOURCE CODE: Game Demo Tutorial Entry 3 Source Code

rjett Game Demo Tutorial Series , , ,

Objective-C and Chipmunk’s cpSpaceAddCollisionPairFunc

April 19th, 2009

I've been writing some really inefficient code in the past couple of hours. Mostly because I didn't know how to call methods on my Objective-C object from a C callback function. If you are using Chipmunk with Cocos2d you might come across the need to have some code respond to certain collisions, say a main character in a game and a pit of spikes. Here is the simple solution:

When you call Chipmunk's collision pair function in your Objective-C object you need to utilize that last parameter:

 
cpSpaceAddCollisionPairFunc(space, 0, 2, &damage, self);
 

In the above line &damage would reference a static C function outside of your Obj-C class and have a signature like this:

 
static int damage(cpShape *a, cpShape *b, cpContact *contacts,
int numContacts, cpFloat normal_coef, void *data)
 

In this C function you would then need to cast the pointer to self back to its object type. For example, the object where I called cpSpaceAddCollisionPairFunc was called GameLayer, thus my callback looks like this:

 
static int damage(cpShape *a, cpShape *b, cpContact *contacts,
int numContacts, cpFloat normal_coef, void *data)
{
	 GameLayer *game = (GameLayer *)data;
    //Calls damageTaken function on Obj-C GameLayer object:
       [game damageTaken];
	return 0;
}
 

Now that I've figured out this little trick I need to go back and get rid of a little of ugly global variables and schedulers. :P

rjett Uncategorized , , , , ,

Stanford iPhone Course

April 4th, 2009

This quarter Stanford will be delivering video recordings of lectures from their iPhone course on iTunes. This course is taught by Apple employees. The first lecture is out now, but mostly covers first day class administration stuff. I am looking forward to hopefully finding some value in future lectures. You can check it out here.

rjett Uncategorized , , ,

Removing the status bar from an iPhone application

March 28th, 2009

To remove the status bar from your application simply add the following line of code to your project:

 
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
 

You can also edit your plist file and add a key for UIStatusBarHidden and set its value to true.

rjett Uncategorized , , ,

Cocos2D for iPhone: Sprites

March 26th, 2009

Setting Cocos2D to portrait mode

Before we get started let's switch to portrait mode.

In XCode, locate your delegate class implementation. If you followed the Monocle Studios example given in the previous post the file you are looking for is named "SimpleGameAppDelegate.m".

Under the applicationDidFinishLaunching function you should find a line of code that looks something like this:

[[Director sharedDirector] setLandscape: YES];

To force your application to be in portrait mode you simple change the YES to a NO:

[[Director sharedDirector] setLandscape: NO];

You could also just delete or comment out the line. That also seems to serve the same function.

Loading Sprites

Cocos2D makes it ridiculously easy to load a sprite. First you want to right click on the Resources folder in your navigation pane in XCode. Then you want to click Add -> Existing files. Locate the .png file you want to load in as your sprite and click ok. In the next window you want to check "Copy items into destination group's folder (if needed)." Then, click "Add".

In a game layer you can easily load the sprite you just added to your project with one line of code:

 Sprite * ninja = [Sprite spriteWithFile:@"ninjaSprite.png"];

If you want to position the sprite you can do so easily by using the following line:

[ninja setPosition:cpv(50, 50)];

To have Cocos display this sprite you have to add it. To do this you would use the following line:

[self addChild: ninja];

In case you missed it elsewhere, cpv creates a Chipmunk vector. Chipmunk vectors are used by Cocos to specify x and y coordinates of objects (e.g. cpv(xCoordinateHere, yCoordinateHere).

Moving a Sprite by using a timer

Once your sprite has been loaded you can easily move it by using a timer. Cocoa has its own timers, but the authors of Cocos2d for iPhone consider using their scheduler to be the best practice for timer based behaviors. To use the Cocos2d scheduler you simply need to specify a function to call. For example:

 
[self schedule: @selector(moveStuff:)];
 

In the above example, moveStuff is the name of the method that the scheduler will call. You can also add an interval when you schedule a function to be called. For example:

 
[self schedule: @selector(moveStuff:) interval: 0.5]; // half second interval
 

In my experience, scheduling a function to be called without specifying an interval tells Cocos2D to call this function as often as possible without affecting performance. The function that the scheduler will call needs to conform to the interface that Cocos2D expects. Here is an example of a moveStuff function:

 
-(void) moveStuff: (ccTime) dt
{
        t += dt; //t is a global float that I initially set to 0.0f
        ninja.position = cpv(10*sin(dt), 380); //moves the sprite back
        //(let's assume we have pointer to ninja in the header file for this class).
        //and forth on the x-axis
}
 

rjett Uncategorized , ,

Cocos2D: An Introduction

March 22nd, 2009

What?

Cocos2D is a framework for creating 2D games in Python. Cocos2D has been ported from Python to Objective-C for use on the iPhone. Cocos2D has a lot of great functionality that a developer can adopt for a mobile game including sprite management, basic menus, 2D physics (via Chipmunk), particle system, parallax scrolling, and more.

Understanding Cocos2D

Cocos2D is based around the concepts of scenes. A scene could be a menu, game level, options, menu, credits screen, etc. Cocos also has something called layers. Layers in Cocos2D are means of organizing your code within your scene.

Getting started

To get started with Cocos2D for iPhone I would highly recommend this tutorial from Monocle Studios. It will get you set up with a nice clean ready to go Cocos2D template. All the examples that I will be giving later in this blog assume that you already have a working Cocos2D template.

rjett Uncategorized , ,