Friday, 23 July 2010

cocos2d as an Application Framework - Part 4

cocos2dmug [Concrete/Interesting] So far I think the experiment to use cocos2d as an application framework has been successful. With little effort we have a very nice look and feel, excellent menu behaviour on an iPhone and a charming looking popup dialog.

Better than that, it seems relatively easy to mix UI framework into cocos2d – UI Views for example seem to behave well when added as nodes to a scene.

In this last part, I’m going to try something a little more challenging. What I want to build is a sexy About box. I ;want to mix animation, a scrolling text view and a background camera view using UIImagePickerController.

Containing cocos2d in a UIView

To show a camera surface as the background of our cocos2d scene, we are going to have to place the cocos2d as a subview of our window’s main view. We also need to make the cocos2d scene transparent. This is a little tricky but here’s how.

Look again at the selector applicationDidFinishLaunching: in the application delegate. The delegate manages the application window UIWindow *window, but there is no sign of the initialisation code for this window. That’s because the macro CC_DIRECTOR_INIT(); is doing all the work. The code behind this macro is:

window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

if( ! [CCDirector setDirectorType:kCCDirectorTypeDisplayLink] )
    [CCDirector setDirectorType:kCCDirectorTypeNSTimer];

CCDirector *__director = [CCDirector sharedDirector];
[__director setDeviceOrientation:kCCDeviceOrientationPortrait];
[__director setDisplayFPS:NO];
[__director setAnimationInterval:1.0/60];

EAGLView *__glView = [EAGLView viewWithFrame:[window bounds] pixelFormat:kEAGLColorFormatRGB565 depthFormat:0 preserveBackbuffer:NO];

[__director setOpenGLView:__glView];
[window addSubview:__glView];
window makeKeyAndVisible];

As you can see, an application window is allocated and initialized madeKeyAndVisible. Also a share CCDirector object is created and the OpenGL view is set to an EAGLView.

With a little modification we can inject a UIView between the window and the OpenGL view:

- (void) applicationDidFinishLaunching:(UIApplication*)application
{
	window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

	if(![CCDirector setDirectorType:kCCDirectorTypeDisplayLink])
		[CCDirector setDirectorType:kCCDirectorTypeNSTimer];

	CCDirector *director = [CCDirector sharedDirector];
	[director setDeviceOrientation:kCCDeviceOrientationPortrait];
	[director setDisplayFPS:YES];

	[director setAnimationInterval:1.0/60];

	EAGLView *glView = [EAGLView viewWithFrame:[[UIScreen mainScreen] bounds] pixelFormat:kEAGLColorFormatRGBA8 depthFormat:0 preserveBackbuffer:NO];
	[director setOpenGLView:glView];

	[glView setMultipleTouchEnabled:YES];
	glView.opaque = NO;
	glClearColor(0.0f,0.0f,0.0f,0.0f);
	glClear(GL_COLOR_BUFFER_BIT);

	overlay = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
	overlay.opaque = YES;
	overlay.backgroundColor = [UIColor blackColor];
	[overlay addSubview: glView];

	[window addSubview:overlay];
	[window makeKeyAndVisible];

	[CCTexture2D setDefaultAlphaPixelFormat: kTexture2DPixelFormat_RGBA8888];
	[director runWithScene: [LoaderScene scene]];
}

As you can see, I’m creating a UIVew called overlay and adding this to the window after making the OpenGL view a child of the overlay view. There are a couple of other tricks in this piece of code. By default the OpenGL view is created opaque. If this is the case, we won’t be able to see through the OpenGL view to the UIVIew layer below, so any camera surface rendered to this overlay will be obscured. To fix this we have to set the glView.opaque = NO, set a clear colour with zero alpha and clear the buffer before any rendering. Finally, we need to set the pixelFormat:kEAGLColorFormatRGBA8 when creating the EAGLView.

So now we have an UIView containing the a transparent background EAGLView.

Funky About Box

Finally, we are ready to put the about box together. I’m going to build three layers. I’m going to put three ‘cloud’ sprites onto the scene and set them animating. Next I will create a UIImagePickerController and attach this to the Overlay view, placing it below the EAGLView. Finally, I will create a UITextView and place this on top of the EAGLView:

-(id) init
{
	
	if( (self=[super init] )) {
		
		self.isTouchEnabled  = YES;
		CGSize windowSize = [[CCDirector sharedDirector] winSize];
		
		CCSprite *cloud1 = [CCSprite spriteWithFile:@"cloud.png"];
		cloud1.position = ccp(-64, windowSize.height/2);
		[self addChild:cloud1 z:1];
		id move1 = [CCMoveBy actionWithDuration:20 position:ccp(windowSize.width+128,0)];
		[cloud1 runAction:[CCRepeatForever actionWithAction:[CCSequence actions: move1, [move1 reverse], nil]]];		
		
		CCSprite *cloud2 = [CCSprite spriteWithFile:@"cloud.png"];
		cloud2.position = ccp(80, (windowSize.height/2)+80);
		[self addChild:cloud2 z:2];
		id bounce2 = [CCMoveBy actionWithDuration:.45 position:ccp(0,8)];
		[cloud2 runAction:[CCRepeatForever actionWithAction:[CCSequence actions: bounce2, [bounce2 reverse], nil]]];		
		
		CCSprite *cloud3 = [CCSprite spriteWithFile:@"cloud.png"];
		cloud3.position = ccp(windowSize.width-80, (windowSize.height/2)-80);
		[self addChild:cloud3 z:3];
		id bounce3 = [CCMoveBy actionWithDuration:.55 position:ccp(0,8)];
		[cloud3 runAction:[CCRepeatForever actionWithAction:[CCSequence actions: bounce3, [bounce3 reverse], nil]]];		
				
		UIImagePickerController* picker=[[UIImagePickerController alloc] init];  
		picker.sourceType = UIImagePickerControllerSourceTypeCamera;
		picker.showsCameraControls = NO;
		picker.toolbarHidden = YES;
		picker.navigationBarHidden = YES;
		picker.wantsFullScreenLayout = YES;
		picker.cameraViewTransform = CGAffineTransformScale(picker.cameraViewTransform, 1, 1.4);
				
		KaleidophoneAppDelegate *delegate = (KaleidophoneAppDelegate *)[[UIApplication sharedApplication] delegate];
		[delegate.overlay insertSubview:picker.view belowSubview:[[CCDirector sharedDirector] openGLView]]; 
		
		UITextView *description = [[UITextView alloc] initWithFrame:CGRectMake(20,(windowSize.height/2)-100,windowSize.width-40,200)];
		description.backgroundColor = [UIColor clearColor];
		description.text = @"This is some text that is shown in the text field.\r\rThis text is very long spanning a number of lines.\r\rorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
		[description setEditable:NO]; 
		description.font = [UIFont fontWithName:@"Marker Felt" size:24.0f];
		description.textColor = [UIColor whiteColor];
		description.showsHorizontalScrollIndicator = NO;
		description.alwaysBounceVertical = YES;
		[delegate.overlay insertSubview:description aboveSubview:[[CCDirector sharedDirector] openGLView]]; 
		[description release];
		
	}
	return self;
}

The Results

Here are the screen shots for the funky About box:

cocos2d-about1 Ooh, a camera view of my TV with animated clouds and the About text.
Look, the clouds move. cocos2d-about2
cocos2d-about3 And the text scrolls

Conclusion

Ok, not perfect but an excellent start. Some very funky user interface components and at very little cost. Some things need more work, the EAGLView animation freezes when handling the touch events for the UITextView, but I'm sure this can be improved upon.

For anyone interested, I’ve published the source code for the demo application on code.google.com:

http://code.google.com/p/iphone-cocos2d-application-framework/

Have fun experimenting with cocos2d and UIKit.

Thursday, 22 July 2010

cocos2d as an Application Framework – Part 3

cocos2dmug[Concrete/Interesting] It’s all starting to come together. We have a application and a very interesting look and feel for the menu.

Now I want to really mix it up. I want to display something similar to that provided by UIAlertView, but the one from Apple just doesn’t fit the look and feel of the application under the cocos2d framework.

Custom Alert in UI Kit

Implementing a modal alert is relatively simple, I need create a XIB file with a single UIView:

cocos2d-alert1

My alert view has a title, message body and two buttons, all in a nice warm look and feel:

cocos2d-alert2

These tie back to the class definition as show in the code below:

#import <UIKit/UIKit.h>
#import "ColourfulButton.h"

@interface ModalAlert : UIViewController {
	IBOutlet UILabel *alertTitle;
	IBOutlet UILabel *alertMessage;
	IBOutlet ColourfulButton *alertCancel;
	IBOutlet ColourfulButton *alertOk;
	int nResult;  
}

@property (nonatomic, retain) UILabel *alertTitle;
@property (nonatomic, retain) UILabel *alertMessage;
@property (nonatomic, retain) ColourfulButton *alertCancel;
@property (nonatomic, retain) ColourfulButton *alertOk;
@property (nonatomic) int nResult;

- (IBAction)pressedOk;
- (IBAction)pressedCancel;

@end

int createModalAlert(NSString *title, NSString *msg, NSString *cancel, NSString *ok);  

Before I move on, let’s have a little look at this class definition. First, there is a global method called createModalAlert(). This is the entry point that will be called to show an alert. It takes a title string, a message string and two button strings.

The class is simply an extension to UIViewController, used to manage the UIView and tie the controls to class members.

This is all standard UIKit stuff.

To make things look a bit more exciting I done 5 things:

  • Use a common application font, Marker Felt. This looks good as an application font.
  • Used a colourful background for my view.
  • Used a UINavigationBar to provide a nice header for the view and a placeholder for the title
  • Used a sub-class for the buttons called ColourfulButton. This gives the buttons a better look and feel.
  • Added rounded corners to the bottom of the dialog

Integrating with cocos2d

Ideally, I want a single modal entry point that loads the dialog, handles any processing, cancels the dialog on pressing a button and returns the button id of the pressed button.

The entry point createModalAlert() does this for us:

int createModalAlert(NSString *title, NSString *msg, NSString *cancel, NSString *ok)  
{  
	ModalAlert *view = [[ModalAlert alloc] initWithNibName:@"ModalAlert" bundle:nil];
	CGSize offSize = [UIScreen mainScreen].bounds.size;   
	CGPoint offScreenCenter = CGPointMake(offSize.width / 2, offSize.height /2);   
	view.view.center = offScreenCenter;
	view.view.alpha = 0.0f;
	view.nResult = -1;
	view.view.layer.cornerRadius = 15;
	
	view.alertTitle.text = title;
	view.alertMessage.text = msg;
	
	[view.alertCancel setTitle:cancel forState:UIControlStateNormal];

	if (ok != nil)
		[view.alertOk setTitle:ok forState:UIControlStateNormal];
	else 
		[view.alertOk setHidden:YES];
	
	
	[[CCDirector sharedDirector] stopAnimation];
	
	[UIView beginAnimations:nil context:NULL];
	[UIView setAnimationDuration:0.5];
	view.view.alpha = 0.95f;
	[[[CCDirector sharedDirector] openGLView] addSubview:view.view];
	[UIView commitAnimations];
	
    	while ((!view.view.hidden) && (view.view.superview!=nil))  
    	{  
		[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate: [NSDate dateWithTimeIntervalSinceNow:0.1]];
    	}  
	
	int nResult = view.nResult;
    	[view release];  
	[[CCDirector sharedDirector] startAnimation];
    	return nResult;  
}  

The model method does a number of important things:

  • Create and position the UIView. I’m loading the view from ModaAlert.xib and locating the centre of the view in the centre of the scene.
  • Setup the text for the title, message and buttons. Note that if the function is passed nil for the second button, this button is hidden.
  • Tell cocos2d to stop all animation. This effectively pauses the application until the dialog has cleared.
  • Transition to show the view. The view is  created with its alpha set to zero.  I then set up a transition to fade in the view, add the view to the scene and commit the animation.
  • Run the modal loop. Because this is a modal dialog, we need to handle the message processing in this method. We use an NSLoop for this purpose and run until the view is hidden or removed.
  • Clean and return. Once the view has been removed, we exit the message loop, pick up the return result, start cocos2d animation and return the result.

The modal loop is controlled by the visibility of the view. To tie this into the button action and to set up the return values, we have the following implementations for the button events:

- (IBAction)pressedOk {
	nResult = 1;
	[self.view setHidden:YES];
}

- (IBAction)pressedCancel {
	nResult = 0;
	[self.view setHidden:YES];
}

That’s it – nothing more is required to present a modal view under cocos2d. As a test, I’m calling the dialog from the onQuit: selector:

-(void)onQuit: (id) sender
{
	if (createModalAlert( @"Quit", @"Are you sure you want to exit?", @"No", @"Yes")==1)	//Exit
		exit(0);
}

The results look great:

cocos2d-alert3Transitions

Here we are using a UIKit animation to show the dialog. cocos2d supports a number of transition for Sprites, layers and scenes. Transitions include rotates, slides, fades, jumps, zooms and flips.

A nice technique is to have a splash screen that transitions into the menu. This is very simple. All you need to do is create a scene with a single layer and sprite on that layer. The sprite is set to cover the entire screen:

#import "LoaderScene.h"
#import "MenuScene.h"

@implementation LoaderScene

+(id) scene
{
	CCScene *scene = [CCScene node];
	LoaderScene *layer = [LoaderScene node];
	[scene addChild: layer];
	return scene;
}

-(id) init
{
	
	if( (self=[super init] )) {
		
		CCSprite *sprite = [CCSprite spriteWithFile:@"Default.png"];
		CGSize size = [[CCDirector sharedDirector] winSize];
		sprite.position = ccp(size.width/2,size.height/2);
		[self addChild: sprite z:0];
		[self schedule: @selector(done:) interval:2.5];
	}
	return self;
}

-(void)done:(ccTime)dt
{
	[self unschedule:@selector(done:)];
	[[CCDirector sharedDirector] replaceScene:[CCFlipAngularTransition transitionWithDuration:0.5f scene:[MenuLayer scene]]];
}

- (void) dealloc
{
	[super dealloc];
}

@end

By making this scene the first scene in your application, the scene is loaded, centred and added to the layer and made visible.

Notice also that after creating and positioning the splash screen sprite, a timer is created. This is done using cocos2d scheduling. It is advisable to use this mechanism rather than NSTimer because cocos2d scheduling is cocos2d aware.

When the timer fires, I simply stop the timer and change the scene using the replaceScene: selector. This selector allows us to specify a transition to use. I’ve used a CCFlipAngularTransition. Have fun!

In Part 4

In the next part we will look at a scene that support a UIImagePickerController view.

Wednesday, 21 July 2010

cocos2d as an Application Framework – Part 2

cocos2dmug[Concrete/Interesting] In the previous blog I looked at cocos2d and showed how a simple menu could be created with very little effort.

The menu is quite funky but not that exciting. cocos2d supports Sprites, so let’s build a menu with animated sprites, something like the Cover Flow you find in iTunes.

Cover Flow Menu

For a more exciting look and feel for the menu, I’m going to do a couple of things. First, I’m going to change the visual behaviour of the menu items – give them a sprite as well as text. Second, I’m going to modify the visual and input behaviour of the menu (the container for the menu items) to animate the menu items.

For the menu items, I have to first create a class that inherits from CCMenuItem:

#import <foundation/foundation.h>
#import "cocos2d.h"

@interface MenuItemComplete : CCMenuItem <CCRGBAProtocol> {
	CCLabel *title;
	CCNode<CCRGBAProtocol> *sprite;
	CCNode<CCRGBAProtocol> *spriteDisabled;
	float originalScale_;	
}

@property (nonatomic,readwrite,retain) CCNode<CCRGBAProtocol> *sprite;
@property (nonatomic,readwrite,retain) CCNode<CCRGBAProtocol> *spriteDisabled;
@property (nonatomic,readwrite,retain) CCLabel *title;

-(id) initFromImage:(NSString*)image title:(CCLabel *)title target:(id)target selector:(SEL)selector;
-(void) activate;
-(void) selected;
-(void) unselected;

@end

You can see that our class inherits from CCMenuItem and implements a couple of sprites and a label. One sprite for an enabled menu item, the other for a disabled menu item.

I’ve also declared an initializing selector called initFromImage:. In the implementation the important stuff is happening in this method and in the drawing method:

-(id) initFromImage:(NSString *)image title:(CCLabel *)t target:(id)target selector:(SEL)selector
{
	if( (self=[super initWithTarget:target selector:selector]) ) {
		
		originalScale_ = 1;
		
		self.sprite = [CCSprite spriteWithFile:image];
		self.spriteDisabled = [CCSprite spriteWithFile:image];
		[self.spriteDisabled setOpacity:80];
		[self setContentSize: [self.sprite contentSize]];
		
		self.title = t;
		self.title.position = ccp(self.contentSize.width/2 , -10);
		[self addChild: title z:100];
	}
	return self;	
}

-(void) draw
{
	if(isEnabled_)
		[sprite draw];				
	else
		[spriteDisabled draw];
}

In the init method we create the two sprites from and image past to the selector. The disabled sprite is just a copy of the normal sprite but I’ve set the opacity to 80%. Similarly, I’ve created a label from the text passed to the selector.

I’m using a variable called originalSize – this will be used later when controlling the sprite animation. Finally I’m positioning the label in this node.

Drawing is very simple, all that we do is draw the normal or disabled sprite according the the menu item’s enabled state.

We have to implement a few more selectors to support menu item behaviour, specifically, activate:, selected: and unselected:

-(void) activate {
	if(isEnabled_) {
		[self stopAllActions];
        
		self.scale = originalScale_;
        
		[super activate];
	}
}

-(void) selected
{
	if(isEnabled_) {	
		[super selected];
		[self stopActionByTag:kZoomActionTag];
		originalScale_ = self.scale;
		CCAction *zoomAction = [CCScaleTo actionWithDuration:0.1f scale:originalScale_ * 1.2f];
		zoomAction.tag = kZoomActionTag;
		[self runAction:zoomAction];
	}
}

-(void) unselected
{
	if(isEnabled_) {
		[super unselected];
		[self stopActionByTag:kZoomActionTag];
		CCAction *zoomAction = [CCScaleTo actionWithDuration:0.1f scale:originalScale_];
		zoomAction.tag = kZoomActionTag;
		[self runAction:zoomAction];
	}
}

These selectors support the visual behaviour of the menu item. When the menu item is activated, all I need to do is stop all animations, restore the active sprite to its original size and bubble up the event. When a menu item is selected I want the sprite to grow and shrink, so I stop the current animation, create a new animation action, a zoom, and set that going. Finally, unselected restores the default animation action. For a better visual effect, I've also decided to arrange the menu items horizontally through a call to the selector alignItemsHorizontally:

We can use the new class in our menu scene in place of the current menu items. We need to add a few images for our menu items and off we go:

-(id) init
{

	if( (self=[super init] )) {
		MenuItemComplete *mnuKaleidoscope = [[MenuItemComplete alloc] initFromImage:@"mnuKaleidoscope.png" title:[CCLabel labelWithString:@"Kaleidoscope" fontName:@"marker felt" fontSize:24] target: self selector: @selector(onKaleidoscope:)];
		MenuItemComplete *mnuAbout = [[MenuItemComplete alloc] initFromImage:@"mnuAbout.png" title:[CCLabel labelWithString:@"About" fontName:@"marker felt" fontSize:24] target: self selector: @selector(onAbout:)];
		MenuItemComplete *mnuQuit = [[MenuItemComplete alloc] initFromImage:@"mnuQuit.png" title:[CCLabel labelWithString:@"Quit" fontName:@"marker felt" fontSize:24] target: self selector: @selector(onQuit:)];
		CCMenu *menu = [CCMenu menuWithItems:mnuKaleidoscope, mnuAbout, mnuQuit, nil];
		[menu alignItemsHorizontally];
		[self addChild:menu];
		
		CCLabel * l = [CCLabel labelWithString:@"Main Menu" fontName:@"marker felt" fontSize:28];
		l.position = ccp(160,420);
		[self addChild:l];
		
	}
	return self;
}

The results look pretty good, the menu items behave well when selected, but no menu animation yet:

cocos2d-menu2Now I need to add behaviour to the menu. I want the menu to respond to left and right swipes, these will drag the sprites. I want the menu to wrap to give a cylindrical effect. To complete the effect, the icons should shrink and dim as they move away from the centre.

First I need to create a new class that inherits from CCMenu. At this point I’m going to cheat. João Caxaria has created a very good one that responds to touches and accelerometer. You can read more about it from:

http://www.cocos2d-iphone.org/forum/topic/139

You can find the source for the looping menu from the following link:

http://dl.dropbox.com/u/3314174/loopingmenu.zip

With that now added to the project, all I need to do now is change my scene to use a looping menu as the menu item container. The results are very impressive:

cocos2d-menu3 cocos2d-menu4 cocos2d-menu5 cocos2d-menu6 cocos2d-menu7 cocos2d-menu8

Note: I did need to make a few more changes because LoopingMenu was designed for landscape, but after some simple tweaks, it all works well in portrait.

In Part 3

In the next part I will start to delve into the world of cocos2d / UI Kit hybrids. I will be implementing a modal dialog that uses standard UI Kit elements like UIViewController and a XIB resource file.

Tuesday, 20 July 2010

cocos2d as an Application Framework – Part 1

cocos2dmug [Concrete/Interesting] cocos2d is a multi-platform games engine written in C/C++. It has been ported to a number of environments including the iPhone under Objective-C.

Like all developers, I dream of creating the most popular game ever. I’m probably a little too late because Pac Man day’s have come and gone. However, I believe the foundation of a games engine has application outside of the realm of games.

In this first part I will be discussing the use of the cocos2d games engine as an application framework. In later articles I will expand on this to show how we can mix elements of cocos2d and the iPhone UI Framework.

Basic Elements of a Games Engine

Take a look at Adobe Air and even Microsoft Silverlight. Under these frameworks applications are better thought of as scenes, with layers and objects (nodes on the scene). These objects may be animation or sprites (for instance a ‘Busy’ animation) or they may be user interface elements like labels, button or menus. Layers are groups of nodes that exist on the same Z-index or plane. This could be backgrounds, foregrounds, even popup dialogs or input boxes. And scenes are the world or landscape upon which everything is displayed, like the application window:

 cocos2d-layers

cocos2d-kittyani cocos2d, like Adobe Air, has a time dimension. That is to say, object can be tested, modified, added or deleted to the scene over a timeline. Certain time functions are static in nature, such as a sprite animation or a transition from scene to scene. Some are less obvious such as the scaling and translations associated with a Carousel Menu.

Finally, cocos2d and other similar platforms allow you to tie up device events to objects. For example, using the accelerometer on the iPhone to control the direction and speed of a sprite, or making a button respond to touch input.

For a deeper introduction to cocos2d look at the documentation on their website: http://www.cocos2d-iphone.org/wiki/doku.php/

An Application Framework

So where am I going with all this. Well before I write the best game ever for the iPhone, I thought I’d release a cocos2d application. And I want to use cocos2d as an application framework, to take care of all my user interface management rather than a traditional games framework.

I also want to mix this with standard UI Framework elements. What I hope to get is a very innovative user interface with very little work. 

What I will be covering in this article is:

  • cocos2d application framework
  • New Look Menus and Dialogs
  • Integrating UI into the scene
  • Responding to device events

Starting the Application

Cocos2D installs a number of templates into Xcode – this makes it easy to start your application. I’m using the standard ‘cocos2d Application’:

cocos2d-template

Running the wizard creates a simple ‘Hello World’ application which will server well as our staring point.

For the purposes of this article, I’m going to create a simple Kaleidoscope application based on a brilliant piece of code by Nori Nomura: http://github.com/norio-nomura

His implementation uses UIImagePickerController, Quartz and OpenGL, so this will test our ability to integrate UI framework into cocos2d and use cocos2d as an application framework.

Adding a Menu

Before I create a menu, let’s look at the structure of the application I’ve just created. There are two classes of interest. The application delegate and the HelloWorldScene.

In the application delegate, take a look at the applicationDidFinishLaunching: selector:

- (void) applicationDidFinishLaunching:(UIApplication*)application
{
	// CC_DIRECTOR_INIT()
	//
	// 1. Initializes an EAGLView with 0-bit depth format, and RGB565 render buffer
	// 2. EAGLView multiple touches: disabled
	// 3. creates a UIWindow, and assign it to the "window" var (it must already be declared)
	// 4. Parents EAGLView to the newly created window
	// 5. Creates Display Link Director
	// 5a. If it fails, it will use an NSTimer director
	// 6. It will try to run at 60 FPS
	// 7. Display FPS: NO
	// 8. Device orientation: Portrait
	// 9. Connects the director to the EAGLView
	//
	CC_DIRECTOR_INIT();
	
	// Obtain the shared director in order to...
	CCDirector *director = [CCDirector sharedDirector];
		
	// Turn on display FPS
	[director setDisplayFPS:YES];
	
	// Turn on multiple touches
	EAGLView *view = [director openGLView];
	[view setMultipleTouchEnabled:YES];
	
	// Default texture format for PNG/BMP/TIFF/JPEG/GIF images
	// It can be RGBA8888, RGBA4444, RGB5_A1, RGB565
	// You can change anytime.
	[CCTexture2D setDefaultAlphaPixelFormat: kTexture2DPixelFormat_RGBA8888];
		
	[[CCDirector sharedDirector] runWithScene: [HelloWorld scene]];
}

This is where the framework is initialized and starts the business of showing the first scene. In this case, the scene called ‘Hello World’.

The ‘Hello World’ scene is implemented in the HelloWorldScene class. The important function to look at is the init: selector:

// on "init" you need to initialize your instance
-(id) init
{
	// always call "super" init
	// Apple recommends to re-assign "self" with the "super" return value
	if( (self=[super init] )) {
		
		// create and initialize a Label
		CCLabel* label = [CCLabel labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:64];

		// ask director the the window size
		CGSize size = [[CCDirector sharedDirector] winSize];
	
		// position the label on the center of the screen
		label.position =  ccp( size.width /2 , size.height/2 );
		
		// add the label as a child to this Layer
		[self addChild: label];
	}
	return self;
}

Pretty simple stuff. All it’s doing is setting up and positioning a label and adding this to the scene. Of course, under the hood the framework is doing the clever stuff of rendering the scene and the layers and nodes.

cocos2d supports some primitive node types like layers and labels as well as buttons and menus. I’m going to modify the HelloWorldScene to manage a menu node with menu items. I do this by creating a menu in the init: selector:

-(id) init
{
	// always call "super" init
	// Apple recommends to re-assign "self" with the "super" return value
	if( (self=[super init] )) {
		CCMenuItemFont *mnuKaleidoscope = [CCMenuItemFont itemFromString: @"Kaleidoscope" target:self selector:@selector(onKaleidoscope:)];
		CCMenuItemFont *mnuAbout = [CCMenuItemFont itemFromString: @"About" target:self selector:@selector(onAbout:)];
		CCMenuItemFont *mnuQuit = [CCMenuItemFont itemFromString: @"Quit" target:self selector:@selector(onQuit:)];
		CCMenu *menu = [CCMenu menuWithItems:mnuKaleidoscope, mnuAbout, mnuQuit, nil];
		[menu alignItemsVertically];
		[self addChild:menu];
		
		CCLabel * l = [CCLabel labelWithString:@"Main Menu" fontName:@"marker felt" fontSize:24];
		l.position = ccp(160,400);
		[self addChild:l];
		
	}
	return self;
}

Ok, not a bad start. The result is a main screen menu with three menu items, displayed vertically. The menu items have some funky behaviour and there is a label ‘Main Menu’ at the top.

cocos2d-menu1

Few things to note, we have a scene with a single layer. On the layer we are adding a label and menu. The label is being positioned relative to the centre of the label. All nodes have origins (their centre) and by default this is in the centre of the bounding rectangle for the node. For the menu, we are adding three menu items, each with an appropriate selector. One final note at this point, when you run the application you will see a number at the bottom left of the screen. This shows the screens per second rendering of the engine. This is useful in debug but you will want to remove this for production. Setting setDisplayFPS:NO in applicationDidFinishLaunching will do this for you.

In Part 2…

I will look at extending the menu for a more funky look and feel as well as looking at dialogs and popup windows.

Tuesday, 6 July 2010

Space and Time

Spacetime-diagram-illustrating-the-causal-relationships-with-1 [Abstract/ Sharing]  Here is a short poem about Space and Time. Someone said the present is brief and precious and we can never get back moment that are lost. I disagree

This poem offers an alternative view, talking about events in space/time with the present flowing through this landscape. I also make reference to the c-boundary confining all space and time.

Hope you enjoy:


Events frozen into the fabric of Space and Time,
The Present rushing past at the Speed of Light.

The Past and Future everywhere, less the edge of the Universe
Where possibility and history remains void.

newrule