I have a game whereby the button for pause is supposed to be on the top right hand corner, however on iPhone 5 it is 3/4 way up the top, so I tried to manually set it but I cannot get it to work, this works, however on the iPhone 3 & 4 it does not show (so it's obviously ignoring some part of the IF statement)
CCMenuItemSprite* item1 = [CCMenuItemSprite itemWithNormalSprite:[CCSprite spriteWithFile:[[MainInfo shareInstance] getImageName:#"pause1.png"]]
selectedSprite:[CCSprite spriteWithFile:[[MainInfo shareInstance] getImageName:#"pause2.png"]]
target:self
selector:#selector(soundOff)];
CCMenu *menu = [CCMenu menuWithItems:item1, nil];
if ( ![[MainInfo shareInstance] isIPad] )
menu.position = ccp(290, 450); //450 iPhone3/4
// else
if (IS_IPHONE_5) {
// do something specific for iPhone 5
menu.position = ccp(290, 530); //450 iPhone3/4
}else
menu.position = ccp(696, 960);
[_bottomFrame addChild:menu z:30 tag:1234];
[self updateBoard];
}
At the top of the .m file I have the following;
#define IS_IPHONE_5 ([UIScreen mainScreen].bounds.size.height == 568.0)
Could anyone please help with a correct way to write the code above?
Many thanks
Chris
Your ELSE statment is not enclosed in brackets furthoremore:
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
if (screenSize.height > 480.0f) {
/*Do iPhone 5 stuff here.*/
} else {
/*Do iPhone Classic stuff here.*/
}
Related
I am making a 14 year old kid making a game in cocos2d. I am pretty new to cocos2d. I want to display the same coin sprite next to each other to make a pattern.
So I added this in my main gameplay layer:
- (void)coinPatterns {
menu = [CCMenu menuWithItems:[Coins class], [Coins class], self, nil];
[menu alignItemsHorizontally];
[self addChild:menu];
}
And this is how I am initializing menu:
[[GameMechanics sharedGameMechanics] setSpawnRate:50 forMonsterType:menu];
This is what is in my coins class:
- (id)initWithMonsterPicture
{
self = [super initWithFile:#"coin.png"];
if (self)
{
CGRect screenRect = [[CCDirector sharedDirector] screenRect];
CGSize spriteSize = [self contentSize];
posX = screenRect.size.width + spriteSize.width * 0.5f;
posY = 150;
self.initialHitPoints = 1;
self.animationFrames = [NSMutableArray array];
[self scheduleUpdate];
inAppCurrencyDisplayNode.score = [Store availableAmountInAppCurrency];
}
coinValue = 3;
return self;
}
- (void)spawn
{
self.position = CGPointMake(posX, posY);
self.visible = YES;
}
- (void)gotCollected {
self.visible = FALSE;
self.position = ccp(-MAX_INT, 0);
[Store addInAppCurrency:coinValue];
}
I keep getting a Incompatible pointer types sending 'class' to parameter of type 'CCMenuItem'. Can someone please tell me how I should change the code so that this works?
Thanks!
menuWithItems: takes an array of CCMenuItem objects, you are sending a class itself. I don't know what the class Coin does, but if the purpose is to show an image and then do something when it's tapped I suggest you to do this:
CCMenuItem *myCoin1 = [CCMenuItemImage
itemFromNormalImage:#"coin.png" selectedImage:#"coinSelected.png"
target:self selector:#selector(coin1WasTapped:)];
CCMenuItem *myCoin2 ...
menu = [CCMenu menuWithItems: myCoin1, myCoin2, myCoin3, ..., nil];
You should create a method coin1WasTapped: that will be called when the coin was tapped, you can "collect" the coins here. Maybe remove them from the menu or an animation.
If you are going to create many coins I suggest you to use a for loop to create them all in an array. This way it will be easier to manipulate later.
This tutorial is really good, it can help you to understand better what you need to do and how to do it.
Good luck!
Here's an interesting dilemma. I have two CCMenus being loaded on a page, each with two CCMenuItemImages as buttons. All four buttons call the same function, which decides what to do using a switch statement that goes off the caller's tag value.
The four buttons are start, tutorial, options, and credits. I have them split into two menus so that I can horizontally and vertically align them in a faux grid. This layer is the main menu layer, so it is the first thing to load after the game starts.
The problem is that when the game first loads, pressing any button will call the "options" button. Not just the function, pressing any button on the menu activates the options button's selected state. If I press "start," for instance, the start button's selected state (a glow around the image) doesn't work–the options button glows instead.
Once I get into the options menu, and then back out of it, the main menu works as expected, with each button activating its requisite function.
I should note that I've also run a clean, and removed the app from both the simulator and my iPhone and rebuilt it.
Here's my .h:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "Constants.h"
#import "GameManager.h"
#interface MainMenuLayer : CCLayer {
CCMenu *mainMenuTop;
CCMenu *mainMenuBottom;
}
#end
And this is my .m:
#import "MainMenuLayer.h"
// Private methods
#interface MainMenuLayer()
- (void)displayMainMenu;
#end
#implementation MainMenuLayer
- (void)playScene:(CCMenuItemFont*) itemPassedIn {
if ([itemPassedIn tag] == 1) {
CCLOG(#"Tag 1 found, Scene 1");
[[GameManager sharedGameManager] runSceneWithID:kGameplayScene];
} else if ([itemPassedIn tag] == 2) {
CCLOG(#"Tag was: %d", [itemPassedIn tag]);
CCLOG(#"Placeholder for next chapters");
} else if ([itemPassedIn tag] == 3) {
CCLOG(#"Tag 3, Options");
[[GameManager sharedGameManager] runSceneWithID:kOptionsScene];
} else if ([itemPassedIn tag] == 4) {
CCLOG(#"Tag 4, Credits");
[[GameManager sharedGameManager] runSceneWithID:kCreditsScene];
}
}
- (void)displayMainMenu {
CGSize winSize = [CCDirector sharedDirector].winSize;
// Main Menu Top Layer Buttons
CCMenuItemImage *playGameButton = [CCMenuItemImage itemFromNormalImage:#"button-start-up.png" selectedImage:#"button-start-down.png" disabledImage:nil target:self selector:#selector(playScene:)];
[playGameButton setTag:1];
CCMenuItemImage *tutorialButton = [CCMenuItemImage itemFromNormalImage:#"button-tutorial-up.png" selectedImage:#"button-tutorial-down.png" disabledImage:nil target:self selector:#selector(playScene:)];
[tutorialButton setTag:2];
// Main Menu Bottom Layer Buttons
CCMenuItemImage *optionsButton = [CCMenuItemImage itemFromNormalImage:#"button-options-up.png" selectedImage:#"button-options-down.png" disabledImage:nil target:self selector:#selector(playScene:)];
[optionsButton setTag:3];
CCMenuItemImage *creditsButton = [CCMenuItemImage itemFromNormalImage:#"button-credits-up.png" selectedImage:#"button-credits-down.png" disabledImage:nil target:self selector:#selector(playScene:)];
[creditsButton setTag:4];
mainMenuTop = [CCMenu menuWithItems:playGameButton,tutorialButton,nil];
mainMenuBottom = [CCMenu menuWithItems:optionsButton,creditsButton,nil];
[mainMenuTop alignItemsHorizontallyWithPadding: 10.0f];
[mainMenuTop setPosition: ccp(winSize.width/2, -500)];
[mainMenuBottom alignItemsHorizontallyWithPadding:10.0f];
[mainMenuBottom setPosition:ccp(winSize.width/2, -600)];
id moveActionTop = [CCMoveTo actionWithDuration:0.5f position:ccp(winSize.width/2, 150)];
id moveEffectTop = [CCEaseIn actionWithAction:moveActionTop rate:1.0f];
[mainMenuTop runAction:moveEffectTop];
[self addChild:mainMenuTop z:2 tag:kMainMenuTagValue];
id moveActionBottom = [CCMoveTo actionWithDuration:0.5f position:ccp(winSize.width/2, 75)];
id moveEffectBottom = [CCEaseIn actionWithAction:moveActionBottom rate:1.0f];
[mainMenuBottom runAction:moveEffectBottom];
[self addChild:mainMenuBottom z:3 tag:kMainMenuBottomTagValue];
}
-(id)init {
self = [super init];
if (self != nil) {
[self displayMainMenu];
}
return self;
}
#end
I ended up just positioning things manually. I tried to use the method linked by LearnCocos2D, but I couldn't determine how to make it work properly; the items didn't end up in a proper grid.
I have SneakyJoystick up and running but I want to move my sprite tile by tile in a certain frequency ... I am pretty new to iphone programming and cocos2d so I don't exactly know how the whole SneakyJoystick thingy works.
I got the code from a book and again: I just want my Sprite to move like in the game Pokèmon tile by tile...
-(void)initJoystickAndButtons {
CGSize screenSize = [CCDirector sharedDirector].winSize;
CGRect joystickBaseDimensions =
CGRectMake(0, 0, 128.0f, 128.0f);
CGRect jumpButtonDimensions =
CGRectMake(0, 0, 64.0f, 64.0f);
CGRect attackButtonDimensions =
CGRectMake(0, 0, 64.0f, 64.0f);
CGPoint joystickBasePosition;
CGPoint jumpButtonPosition;
CGPoint attackButtonPosition;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// The device is an iPad running iPhone 3.2 or later.
CCLOG(#"Positioning Joystick and Buttons for iPad");
joystickBasePosition = ccp(screenSize.width*0.0625f,screenSize.height*0.052f);
jumpButtonPosition = ccp(screenSize.width*0.946f,screenSize.height*0.052f);
attackButtonPosition = ccp(screenSize.width*0.947f,screenSize.height*0.169f);
} else {
// The device is an iPhone or iPod touch.
CCLOG(#"Positioning Joystick and Buttons for iPhone");
joystickBasePosition = ccp(screenSize.width*0.07f,
screenSize.height*0.11f);
jumpButtonPosition = ccp(screenSize.width*0.93f,
screenSize.height*0.11f);
attackButtonPosition = ccp(screenSize.width*0.93f,
screenSize.height*0.35f);
}
SneakyJoystickSkinnedBase *joystickBase = [[[SneakyJoystickSkinnedBase alloc] init] autorelease];
joystickBase.position = joystickBasePosition;
joystickBase.backgroundSprite =[CCSprite spriteWithFile:#"dpadDown.png"];
joystickBase.thumbSprite =[CCSprite spriteWithFile:#"joystickDown.png"];
joystickBase.joystick = [[SneakyJoystick alloc]initWithRect:joystickBaseDimensions];
leftJoystick = [joystickBase.joystick retain];
leftJoystick.isDPad = YES;
[self addChild:joystickBase];
SneakyButtonSkinnedBase *jumpButtonBase =[[[SneakyButtonSkinnedBase alloc] init] autorelease];
jumpButtonBase.position = jumpButtonPosition;
jumpButtonBase.defaultSprite =[CCSprite spriteWithFile:#"jumpUp.png"];
jumpButtonBase.activatedSprite =[CCSprite spriteWithFile:#"jumpDown.png"];
jumpButtonBase.pressSprite = [CCSprite spriteWithFile:#"jumpDown.png"];
jumpButtonBase.button = [[SneakyButton alloc]initWithRect:jumpButtonDimensions];
jumpButton = [jumpButtonBase.button retain];
jumpButton.isToggleable = NO;
[self addChild:jumpButtonBase];
SneakyButtonSkinnedBase *attackButtonBase =[[[SneakyButtonSkinnedBase alloc] init] autorelease];
attackButtonBase.position = attackButtonPosition;
attackButtonBase.defaultSprite = [CCSprite spriteWithFile:#"handUp.png"];
attackButtonBase.activatedSprite = [CCSprite spriteWithFile:#"handDown.png"];
attackButtonBase.pressSprite = [CCSprite spriteWithFile:#"handDown.png"];
attackButtonBase.button = [[SneakyButton alloc]initWithRect:attackButtonDimensions];
attackButton = [attackButtonBase.button retain];
attackButton.isToggleable = NO;
[self addChild:attackButtonBase];
> }
> -(void)applyJoystick:(SneakyJoystick *)aJoystick toNode:(CCNode *)tempNode forTimeDelta:(float)deltaTime{
> CGPoint scaledVelocity = ccpMult(aJoystick.velocity, 44.0f); // 1
> CGPoint newPosition = ccp(tempNode.position.x + scaledVelocity.x * deltaTime,tempNode.position.y + scaledVelocity.y * deltaTime);
> [tempNode setPosition:newPosition];
> if (jumpButton.active == YES) {
> CCLOG(#"Jump button is pressed.");
> if (attackButton.active == YES) {
> CCLOG(#"Attack button is pressed.");
> } }
> }
>
> # pragma mark -
> # pragma mark Update Method
> -(void) update:(ccTime)deltaTime {
> [self applyJoystick:leftJoystick toNode:dude
> forTimeDelta:deltaTime];
> }
I did something similar for my game. There are many steps and cannot go much into detail.
First you need to know when is the joystick being used.
Second you need to interpet the direction of the joystick. For a game like Pokemon, you only need to check for up/down/right/left directions. It is possible to access the degrees of the joystick. Simply interpret the degrees like "if degrees are between -45 to 45, it means the joystick is mainly facing right" etc.
Third you will have to unlink the joystick from your player object. That tutorial, somewhere, makes you link both of them so that the joystick will automatically move the player. You have to undo that.
Fourth make up a schedule somewhere in your scene. The schedule will interpret the joystick direction (if it is being used), and will run a CCMoveBy action on the player. If the joystick directs to the right and the map's tile size is 32, then the CCMoveBy movement parameter would be (32,0). Remember to not run a nother action if the player is already running one.
There are many details and so much to polish. You better try to ask each thing individually instead of everything in one shot.
EDIT: The given answer works on the device, but beware it fails on the simulator.
When my iPad starts up, I show a loading label, centered in the middle of the screen. I set its autoresizingMask so it recenters on orientation change.
As the app starts up, the label's text changes, so I want to recenter the label based on its new length. However, the following piece of code doesn't center the label correctly:
- (void) setLabelText:(NSString*)text {
CGSize maximumLabelSize = CGSizeMake(500,20);
CGSize expectedLabelSize = [text sizeWithFont:loadingLabel.font
constrainedToSize:maximumLabelSize
lineBreakMode:loadingLabel.lineBreakMode];
loadingLabel.frame = CGRectMake(self.view.frame.size.width/2-expectedLabelSize.width/2,
loadingLabel.frame.origin.y,
expectedLabelSize.width,
loadingLabel.frame.size.height);
loadingLabel.text = text;
}
I also considered checking [[UIDevice currentDevice]orientation], and if the iPad is in landscape mode, then I'd use self.view.frame.size.height to set the xOrigin of the label.
However, if the device is face up or face down, (and not landscape or portrait) then this method fails. I also have a lastOrientation variable in my appDelegate, which remembers if the app is in landscape or portrait, even when face up or face down, based on the device's last known orientation. However, at start-up, this variable isn't necessarily set.
Is there some simple solution I am missing here, so I can resize and center my label?
EDIT: I tried checking UIStatusBarOrientation based on the advice posted, but it doesn't work:
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft
|| [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight) {
NSLog(#"landscape");
width = self.view.frame.size.height;
} else {
NSLog(#"portrait");
}
This always logs portrait, at least on start-up, on the simulator.
Check [[UIApplication sharedApplication] statusBarOrientation]
I found a trick to solve the FaceUp orientation issue!!!
Delay the orientation check till AFTER the app has started running, then set variables, view sizes, etc.!!!
//CODE
- (void)viewDidLoad {
[super viewDidLoad];
//DELAY
[NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(delayedCheck)
userInfo:nil
repeats:NO];
}
-(void)delayedCheck{
//DETERMINE ORIENTATION
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait ){
FACING = #"PU";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown ){
FACING = #"PD";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft ){
FACING = #"LL";
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight ){
FACING = #"LR";
}
//DETERMINE ORIENTATION
//START
[self setStuff];
//START
}
-(void)setStuff{
if( FACING == #"PU" ){
//logic for Portrait
}
else
if( FACING == #"PD" ){
//logic for PortraitUpsideDown
}
else{
if( FACING == #"LL"){
//logic for LandscapeLeft
}
else
if( FACING == #"LR" ){
//logic for LandscapeRight
}
}
//CODE
You can addSubviews, position elements, etc. in the 'setStuff' function ... anything that would initially depend on the orientation!!!
:D
-Chris Allinson
I'm creating an universal application and my CCMenu appears just fine on both iPhone, iPhone 4 and iPad. However the buttons do nothing when touched on the iPad.
I have no specific iPad code other than modifying the contentScaling property so that the iPad uses the same images as the iPhone 4. This means that the same images work on iPhone 4 but not on the iPad.
I am using cocos2d 0.99.rc0 and the iOS 4.1 SDK. I don't even know where to start troubleshooting this.
The only oddity i noticed recently is that the iPad seems to draw the menu scene once, then quickly redraws it for some reason, moving everything one pixel or something. My menu class is very simple and has no "refreshing" code or anything that is supposed to move. This doesnt happen on either low or high res iPhones.
Here is my code, sloppy but yet very simple.
MainMenu.m:
CCMenuItemImage * playItem = [self makeMenuButtonWithSprite:#"Play.png" withSelector:#selector(play:)];
CCMenuItemImage * resumeItem = [self makeMenuButtonWithSprite:#"Resume.png" withSelector:#selector(resume:)];
CCMenuItemImage * optionsItem = [self makeMenuButtonWithSprite:#"Options.png" withSelector:#selector(options:)];
CCMenuItemImage * helpItem = [self makeMenuButtonWithSprite:#"Help.png" withSelector:#selector(help:)];
CCMenu *myMenu;
// Check if there is a valid savegame by comparing versions.
if ([[uD stringForKey:#"CFBundleVersion"] isEqualToString:[[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleVersion"]] ) {
myMenu = [CCMenu menuWithItems:playItem, resumeItem, optionsItem, helpItem, nil];
} else {
myMenu = [CCMenu menuWithItems:playItem, optionsItem, helpItem, nil];
}
// Arrange the menu items vertically
[myMenu alignItemsVerticallyWithPadding:0.0f];
myMenu.position = ccp(dB.wWidth/2,dB.wHeight/2);
// add the menu to your scene
[self addChild:myMenu z:100];
And the CCMenuItemImage factory:
- (CCMenuItemImage *)makeMenuButtonWithSprite:(NSString *)spriteFileName withSelector:(SEL)selector {
CCSprite *spriteForButton = [CCSprite spriteWithFile:spriteFileName];
spriteForButton.anchorPoint = ccp(0.5f,0.5f);
CCMenuItemImage * buttonImage =[CCMenuItemImage itemFromNormalImage:#"button.png"
selectedImage: #"button.png"
target:self
selector:selector];
[buttonImage addChild:spriteForButton z:100];
spriteForButton.position = ccp([buttonImage boundingBox].size.width/2,([buttonImage boundingBox].size.height/2)-5);
return buttonImage;
}
I don't think that any known bug exists for this issue. Not sure how to debug this without seeing any code, but, if it helps, here's some code of mine that successfully adds a menu using cocos2d 0.99.5, on iOS 4.0, 4.1 and 4.2 (no difference when I upgraded):
-(void) initBottomMenu {
CCMenuItem *aboutButton = [self gameButtonWithName:#"about" selector:#selector(onAbout:)];
CCMenuItem *settingsButton = [self gameButtonWithName:#"settings" selector:#selector(onSettings:)];
CCMenuItem *tutButton = [self gameButtonWithName:#"tutorial" selector:#selector(onTutorial:)];
CCMenu *menu = [CCMenu menuWithItems:aboutButton, settingsButton, tutButton, nil];
menu.position = ccp(xPos, yPos);
[menu alignItemsHorizontallyWithPadding:45.0];
[self addChild:menu];
}
The gameButtonWithName:selector: method looks like this:
-(CCMenuItem *) gameButtonWithName:(NSString *)name selector:(SEL)s {
NSString *iPadSuffix = #"IPad";
NSString *normal = [[NSString alloc] initWithFormat:#"%#Btn%#.png", name, iPadSuffix, nil] ;
NSString *selected = [[NSString alloc] initWithFormat:#"%#Btn%#.png", name, iPadSuffix, nil];
CCMenuItem *retButton = [CCMenuItemImage itemFromNormalImage:normal
selectedImage:selected
disabledImage:selected
target:self
selector:s];
[selected release];
[normal release];
return retButton;
}
sort of sloppy, but it works out well for adding a menu to my main scene.
Problem found. This was related to my custom hack to make the iPad load retina graphics. The problem was in my appDelegate where i set the contentScaleFactor which made ccDirector scale and UIScreen scale mismatch.
Problem boiled down to graphics being big but cocos2d thinking that coordinates are low res.