Dieses Dokuwiki verwendet ein von Anymorphic Webdesign erstelltes Thema.
Table of Contents

In this lesson, you'll learn how Cocos2d helps you divide your game into “scenes,” and how to transition from scene to scene. Because that turns out to be so easy, we'll also cover CCMenu and related classes, which make it equally easy to build menu scenes.

This lesson assumes you've already gone through Lesson 1. Install & Test and Lesson 2. Your First Game.

Scenes

A “scene” in Cocos2d is just a special sort of node that acts as the ultimate parent for all other nodes that are visible. You can use this however you like, but typical usage is probably to make one scene for the “real” playable part of your game, and then use other scenes for the title page, high scores list, options, and so on. A scene is represented by the CCScene class.

A scene is “running” if it is the scene that is visible, has actions that are progressing, and so on. Only one scene can be running at a time. However, it's possible to push another scene on top of the current one, pausing the current one and running the new one; then later pop that new one and resume running the first. Or, you can have one scene entirely replace another (which is usually preferable, since it uses less memory).

This pushing/popping or replacing of scenes is done by the director (CCDirector). You've already seen this if you've poked around much in the project template. Look in the application delegate (e.g., in Lesson1AppDelegate.m or whatever it's called in your project). At the bottom of the applicationDidFinishLaunching method, you'll find a line like this:

	[[CCDirector sharedDirector] runWithScene: [HelloWorld scene]];

This tells the director to start running the given scene (HelloWorld).

To replace the running scene with another – for example, when the user taps the “Play” button on the menu screen, or when the game is over and you want to go back to the main menu – simply call replaceScene on the director:

	[[CCDirector sharedDirector] replaceScene: [SomeOtherScene scene]];

This terminates the current scenes, and starts the next one. You could later restart the first (or any other) by calling replaceScene again.

If you wanted to just pause the current scene instead, use pushScene instead of replaceScene; then you would call popScene later to terminate the new one, and resume the old. But use this sparingly, since memory on the iPhone is limited, and all scenes on the stack stay in memory.

There are other handy things the Director can do, such as pause/resume the current scene in place; see the CCDirector reference for the details.

(more content coming soon!)

Fancy Transitions

Fancy transitions between scenes is supported too with CC*Transition.

[[CCDirector sharedDirector] replaceScene:
	 [CCTransitionFade transitionWithDuration:0.5f scene:[SomeOtherScene scene]]];

Some of the common transitions are:

  • CCTransitionFade
  • CCTransitionFlipAngular
  • CCTransitionShrinkGrow
  • CCTransitionMoveInB
  • CCTransitionMoveInT
  • CCTransitionMoveInL
  • CCTransitionMoveInR
  • CCTransitionFadeTR
  • CCTransitionFadeUp
  • CCTransitionFlipX
  • CCTransitionFlipY
  • CCTransitionPageTurn
  • CCTransitionCrossFade

Check API docs for more transition types.

Menus

Menus provide one way for users to interact with your game using a familiar GUI concept, “buttons”. People will often use Menus to tell the Director to change the scene, but they can also be used as a convenient and flexible way to provide controls for your game.

To create a menu, simply create an instance of Menu

    CCMenu * myMenu = [CCMenu menuWithItems:nil];

This creates an empty menu that has no menu items (buttons). To make the menu useful, you will need to add “Menu Items” to it.

There are several types of MenuItem to choose from:

There are subtle differences between the individual types of menu item, but essentially, they all allow you to specify a target and a selector to be called when the button is touched.

One of the simplest menu items to create is CCMenuItemImage which uses a specified image as the 'hit area' for the menu item.

    CCMenuItemImage *menuItem1 = [CCMenuItemImage itemWithNormalImage:@"myFirstButton.png"
                selectedImage: @"myFirstButton_selected.png"
                target:self
                selector:@selector(doSomething:)];
  • itemWithNormalImage is the image you want to use for the menu item
  • selectedImage specifies the image to use when the button is pressed
  • target specifies which object should respond to the menu item being pressed. In this case, “self” probably refers to the scene in which the menu was created.
  • selector is the targets method that should be called.

Note: There is a difference between @selector(doSomething) and @selector(doSomething:) (note the extra colon). With the colon, the menuItem will be passed to the method. This is useful if you want to pass additional data to the method being called. For example, you could use the menu item 'tag' to decide how to proceed. You may even choose to subclass the MenuItemType to store additional information which can be accessed in the doSomething: method.

Once you have created your menu items, you can add them to the menu in the same way you would add “things” to any other CCNode

[myMenu addChild:menuItem1];

Alternatively, you could create several menu items at once and add them to the menu at creation by changing the menuWithItems constructor to look like this… (In this example, remember to “nil terminate” the constructor)

CCMenu *myMenu = [CCMenu menuWithItems:menuItem1, menuItem2, menuItem3, nil];

CCMenu also provides some convenience methods to layout your menu, such as “alignItemsVertically” and “alignItemsInRows” which can be used like this

   [myMenu alignItemsVertically];

Putting it all together, creating a menu might look a little something like this

// Create some menu items
CCMenuItemImage * menuItem1 = [CCMenuItemImage itemWithNormalImage:@"myfirstbutton.png"
                selectedImage: @"myfirstbutton_selected.png"
                target:self
                selector:@selector(doSomethingOne:)];
 
CCMenuItemImage * menuItem2 = [CCMenuItemImage itemWithNormalImage:@"mysecondbutton.png"
                 selectedImage: @"mysecondbutton_selected.png"
                 target:self
                 selector:@selector(doSomethingTwo:)];
 
 
CCMenuItemImage * menuItem3 = [CCMenuItemImage itemWithNormalImage:@"mythirdbutton.png"
                  selectedImage: @"mythirdbutton_selected.png"
                  target:self
                  selector:@selector(doSomethingThree:)]; 
 
 
// Create a menu and add your menu items to it
CCMenu * myMenu = [CCMenu menuWithItems:menuItem1, menuItem2, menuItem3, nil];
 
// Arrange the menu items vertically
[myMenu alignItemsVertically];
 
// add the menu to your scene
[self addChild:myMenu];

Here are 6 images that you can use to test this out.

myfirstbutton.png myFirstButton_selected.png mySecondButton.png mySecondButton_selected.png myThirdButton.png myThirdButton_selected.png

In order to get these images to work you will to download them and place them in the root directory of your project then add them to your resources in your Xcode file. (when you download them make sure to rename them to include the upper and lower case differentiation since the iPhone file system *is* case sensitive).

You will notice that each menu defined above had a separate call back method, so you will need to add these

- (void) doSomethingOne: (CCMenuItem  *) menuItem 
{
	NSLog(@"The first menu was called");
}
- (void) doSomethingTwo: (CCMenuItem  *) menuItem 
{
	NSLog(@"The second menu was called");
}
- (void) doSomethingThree: (CCMenuItem  *) menuItem 
{
	NSLog(@"The third menu was called");
}

To find out more about menus and how to use them, please read through the CCMenu documentation

After finishing the first three lessons you should have something that looks somewhat like this. Notice that the set up of the menus has been separated out.

//
//  HelloWorldLayer.m
//  Lesson1
//
 
 
// Import the interfaces
#import "HelloWorldScene.h"
#import "CCTouchDispatcher.h"
 
 
CCSprite *seeker1;
CCSprite *cocosGuy;
 
// HelloWorld implementation
@implementation HelloWorld
 
+(id) scene
{
	// 'scene' is an autorelease object.
	CCScene *scene = [CCScene node];
 
	// 'layer' is an autorelease object.
	HelloWorld *layer = [HelloWorld node];
 
	// add layer as a child to scene
	[scene addChild: layer];
 
	// return the scene
	return scene;
}
// set up the Menus
-(void) setUpMenus
{
 
	// Create some menu items
	CCMenuItemImage * menuItem1 = [CCMenuItemImage itemWithNormalImage:@"myfirstbutton.png"
						            selectedImage: @"myfirstbutton_selected.png"
						                   target:self
						                 selector:@selector(doSomethingOne:)];
 
	CCMenuItemImage * menuItem2 = [CCMenuItemImage itemWithNormalImage:@"mysecondbutton.png"
						            selectedImage: @"mysecondbutton_selected.png"
						                   target:self
						                 selector:@selector(doSomethingTwo:)];
 
 
	CCMenuItemImage * menuItem3 = [CCMenuItemImage itemWithNormalImage:@"mythirdbutton.png"
						            selectedImage: @"mythirdbutton_selected.png"
						                   target:self
						                 selector:@selector(doSomethingThree:)]; 
 
 
	// Create a menu and add your menu items to it
	CCMenu * myMenu = [CCMenu menuWithItems:menuItem1, menuItem2, menuItem3, nil];
 
	// Arrange the menu items vertically
	[myMenu alignItemsVertically];
 
	// add the menu to your scene
	[self addChild:myMenu];
}
// 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 our seeker sprite, and add it to this layer
        seeker1 = [CCSprite spriteWithFile: @"seeker.png"];
        seeker1.position = ccp( 50, 100 );
        [self addChild:seeker1];
 
        // do the same for our cocos2d guy, reusing the app icon as its image
        cocosGuy = [CCSprite spriteWithFile: @"Icon.png"];
        cocosGuy.position = ccp( 200, 300 );
        [self addChild:cocosGuy];
 
	// schedule a repeating callback on every frame
        [self schedule:@selector(nextFrame:)];
	[self setUpMenus];
 
		// register to receive targeted touch events
        [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self
			                                 priority:0
		                                  swallowsTouches:YES];
	}
	return self;
}
 
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
	// in case you have something to dealloc, do it in this method
	// in this particular example nothing needs to be released.
	// cocos2d will automatically release all the children (Label)
 
	// don't forget to call "super dealloc"
	[super dealloc];
}
- (void) nextFrame:(ccTime)dt {
    seeker1.position = ccp( seeker1.position.x + 100*dt, seeker1.position.y );
    if (seeker1.position.x > 480+32) {
        seeker1.position = ccp( -32, seeker1.position.y );
    }
}
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
	return YES;
	}
- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
	CGPoint location = [touch locationInView: [touch view]];
	CGPoint convertedLocation = [[CCDirector sharedDirector] convertToGL:location];
 
	[cocosGuy stopAllActions];
	[cocosGuy runAction: [CCMoveTo actionWithDuration:1 position:convertedLocation]];    
	}
 
- (void) doSomethingOne: (CCMenuItem  *) menuItem 
{
	NSLog(@"The first menu was called");
}
- (void) doSomethingTwo: (CCMenuItem  *) menuItem 
{
	NSLog(@"The second menu was called");
}
- (void) doSomethingThree: (CCMenuItem  *) menuItem 
{
	NSLog(@"The third menu was called");
}
 
 
@end

Menu items can also use a block instead of a selector:

	// Create some menu items
		CCMenuItemLabel *mi1 = [CCMenuItemLabel 
                                        itemWithLabel:someLabel 
                                        block:^(id sender) { 
                                            [theDirector pushScene:[SceneGame node];
                                          }
                                       ]; 

You can find a good introduction to Objective-C blocks here. Blocks help eliminate having to create these sorts of one-off methods for simple menu items.

prog_guide/lesson_3._menus_and_scenes.txt · Last modified: 2012/12/21 23:16 by harkathmaker
Trace: lesson_3._menus_and_scenes
Dieses Dokuwiki verwendet ein von Anymorphic Webdesign erstelltes Thema.
CC Attribution-Noncommercial-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0