Ok so I'm still on my learning journey and am trying to add a new scene to the end of a game. Currently after a level ends, there is a Next button to take you to the next level. On the final stage, the next button originally didn't do anything and just had a 'return' function. I'm trying to make it so that if the current stage is the last level, the next button (nextAction) will load up the next scene "EndLayer". Here is what I have but it is not working:
- (void) nextAction {
if (g_SoundFlag) {
[sd_button play];
}
_clickedButtonIndex = 1;
NSInteger currentStage = [AppSettings getCurrentStage];
if (currentStage >= 24) {
//return;
NSString *r = #"CCTransitionFade";
Class transion = NSClassFromString(r);
[[CCDirector sharedDirector] replaceScene:[transion transitionWithDuration:0.3 scene:[EndLayer scene]]];
}
[[CCTextureCache sharedTextureCache] removeUnusedTextures];
[AppSettings setCurrentStage: currentStage+1];
[[CCDirector sharedDirector] replaceScene:[Game scene]];
}
Related
I need some help sending the player's score when they lost over to another scene but can't figure out how.
This is the code I have right now:
if(CGRectIntersectsRect(playerOne.boundingbox, object.boundingbox))
{
[self gameOver];
};
-(void)gameOver
{
[[CCDirector sharedDirector] replaceScene:[GameOver scene] withTransition:[CCTransistion transitionFadeWithDuration:1]
}
So basicly when these two's bounding box collide, the game is over and send you over to the gameOver scene.
How can I send over the score over to the Game Over scene too?
Thanks!
Add a property into the GameOver class named score. Then, before you replace the scene, set the score property to whatever the score is.
Example (note: this is untested so some types might be wrong as I've never used Cocos2d):
-(void)gameOver {
NSInteger score = /* get the score here */;
GameOver *scene = [GameOver scene];
[scene setScore:score];
[[CCDirector sharedDirector] replaceScene:scene withTransition:[CCTransistion transitionFadeWithDuration:1]];
}
Now, you can just fetch the score in the GameOver scene like so:
-(void)someMethod {
NSInteger score = [self score];
NSLog("Score: %d",score);
}
Hi Im making a cocos2d game that has a sprite flying and falling, Im trying to have a first tap touch event for example when the user touches the screen for the first time it'll start the game animation and start the physics engine. Whats happening is that when the user starts the game the sprite falls down right away, can anyone give me a hand with this?
right now Im using something like this but Im not sure how to get the physics engine to wait until the user touches the screen for the first time.
CCSprite *_pixie
CCNode *_start;
BOOL *_firstTap;
CCPhysicsNode *_physicsNode;
-(void)didLoadFromCCB{
_physicsNode.collisionDelegate = self;
_firstTap = True;
}
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
if(_firstTap == TRUE){
_start.visible = FALSE;
_firstTap = False;
}
//flying sounds & so on
if (!_gameOver) {
[[OALSimpleAudio sharedInstance] playEffect:MAGIC volume:0.4 pitch:1 pan:0 loop:NO];
[_pixie.physicsBody applyImpulse:ccp(0, 420.f)];
[_pixie.physicsBody applyAngularImpulse:11000.f];
_sinceTouch = 0.f;
}
}
- (void)update:(CCTime)delta {
if(_firstTap == FALSE){
float yVelocity = clampf(_pixie.physicsBody.velocity.y, -1 * MAXFLOAT, 200.f);
if ((_sinceTouch > .5f)) {
[_pixie.physicsBody applyAngularImpulse:-40000.f*delta];
}
}
}
Change
BOOL *_firstTap;
to
BOOL _firstTap; //No asterisk
And also make sure that you set _firsttap = YES in viewDidLoad functions
- (void)viewDidLoad
{
[super viewDidLoad];
_firstTap = YES;
}
Looks to me like the first touch Boolean value may not be defined until after the update code is called. You are also mixing BOOL values with bool values.
Objective-C : BOOL vs bool
I have a sprite-kit game where I need to be checking often to see if the player has lost
- (void)update:(NSTimeInterval)currentTime
{
for (SKSpriteNode *sprite in self.alienArray ) {
if (sprite.position.y < 10) {
LostScene *lostScene = [[LostScene alloc] initWithSize: CGSizeMake(CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds))];
NSLog(#"about to present");
[self.view presentScene:lostScene transition:[SKTransition fadeWithDuration:0.5]];
}
}
}
but when this method gets called (which I know is happening), no scene presents. What am I doing wrong? I believe it has something to do with the transition, because when I take it out, it works fine
You should add a property of the existing scene like: BOOL playerHasLost and edit your update method:
- (void)update:(NSTimeInterval)currentTime
{
if(!playerHasLost)
{
for (SKSpriteNode *sprite in self.alienArray )
{
if (sprite.position.y < 10)
{
playerHasLost = YES;
LostScene *lostScene = [[LostScene alloc] initWithSize: CGSizeMake(CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds))];
NSLog(#"about to present");
[self.view presentScene:lostScene transition:[SKTransition fadeWithDuration:0.5]];
break;//to get out of for loop
}
}
}
}
So this way as soon as the sprite get to position that you treat as lost position it will set the variable to YES, present the scene and it will not do it again.
The reason is simply that the update method gets called every frame, with a running transition the scene will be presented anew every frame and thus it appears as if nithing is happening. You should see the NSLog spamming the log console.
I'm having an odd, irritating issue.
For example, in my main menu screen, I have a button that says "Instructions."
Once I click that, in the instructions layer, there is a button that takes you back to the main menu.
However, for some reason, the button action is not exclusive to the sprite image. If i click 3 inches away from the 'backtomenu' button, it still takes me back to the main menu.
So, my question is, how can I make a button be clicked only if you click the actual image?
(this is how I create a button)
- (id) init
{
if((self = [super init]))
{
[self instructions];
}
return self;
}
- (void) instructions
{
bgI = [CCSprite spriteWithFile:#"testbackground11.png"];
[bgI setPosition:ccp(160,240)];
ccTexParams params = {GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT};
[bgI.texture setTexParameters:¶ms];
[self addChild:bgI z:0];
returnToMenu = [CCMenuItemImage itemFromNormalImage:#"berry2.png"
selectedImage:#"berry2_selected.png"
target : self
selector: #selector (ifReturnToMenu:)];
CCMenu *myReturnMenu = [CCMenu menuWithItems:returnToMenu, nil];
[myReturnMenu alignItemsVertically];
[self addChild: myReturnMenu];
}
- (void) ifReturnToMenu: (CCMenuItem *) menuItem
{
if(menuItem == returnToMenu)
[[CCDirector sharedDirector] replaceScene:
[CCTransitionFade transitionWithDuration:0.5f scene: [MainMenu scene]]];
}
I am not sure how 'isReturnToMenu' is fired, but you can try this
- (void) ifReturnToMenu: (CCMenuItem *) menuItem{
if(menuitem == returnToMenu){
[[CCDirector sharedDirector] replaceScene:
[CCTransitionFade transitionWithDuration:0.5f scene: [MainMenu scene]]];
}
}
If it doesnt work, you'll need to post the code that fires it so we can help you more
Situation:
I'm getting some mysterious crashing shortly after a CCCallFunc. In short, we have a button. The button has a tag to identify it later. When the button is pressed, we run some actions to animate it, and when the animation is done, we CCCallFunc another method to transition to another scene. We crash shortly after the CCCallFunc. Source and errors below.
Point Of Crash (in cocos2d source):
// From CCActionInstant.m of cocos2d
-(void) execute
{
/*** EXC_BAD_ACCESS on line 287 of CCActionInstant.m ***/
[targetCallback_ performSelector:selector_];
}
#end
Snapshot of Thread 1:
My Code:
Below is some source taken from MenuLayer.m (a simple menu to display a button).
// from MenuLayer.m
// …
#implementation MenuLayer
-(id) init{
if((self=[super init])) {
/****** Create The Play Button (As a CCMenu) ********/
CCSprite *playSprite = [CCSprite spriteWithFile:#"playbutton.png"];
CCMenuItemSprite *playItem = [CCMenuItemSprite itemFromNormalSprite:playSprite selectedSprite:nil target:self selector:#selector(animateButton:)];
playItem.tag = 3001;
playItem.position = ccp(160.0f, 240.0f);
CCMenu *menu = [CCMenu menuWithItems:playItem, nil];
menu.position = ccp(0.0f, 0.0f);
[self addChild:menu z:0];
}
}
// ...
- (void)animateButton:(id)sender{
/*** Run an animation on the button and then call a function ***/
id a1 = [CCScaleTo actionWithDuration:0.05 scale:1.25];
id a2 = [CCScaleTo actionWithDuration:0.05 scale:1.0];
id aDone = [CCCallFunc actionWithTarget:self selector:#selector(animationDone:)];
[sender runAction:[CCSequence actions:a1,a2,aDone, nil]];
}
- (void)animationDone:(id)sender{
/*** Identify button by tag ***/
/*** Call appropriate method based on tag ***/
if([(CCNode*)sender tag] == 3001){
/*** crashes around here (see CCActionInstant.m) ***/
[self goGame:sender];
}
}
-(void)goGame:(id)sender{
/*** Switch to another scene ***/
CCScene *newScene = [CCScene node];
[newScene addChild:[StageSelectLayer node]];
if ([[CCDirector sharedDirector] runningScene]) {
[[CCDirector sharedDirector] replaceScene:newScene]];
}else {
[[CCDirector sharedDirector] runWithScene:newScene];
}
}
Use CCCallFuncN instead of CCCallFun.
CCCallFuncN passes the Node as parameter, the problem with CCCallFun is that you are loosing reference of the node.
I test your code with CCCallFuncN and works ok.
Just a hunch. Besides checking for memory leaks, try to schedule a selector with a 0 second interval instead of directly sending the goGame message. I have a suspicion that director's replaceScene causes a cleanup of the scene and all objects associated with it. That in turn could leave the CCCallFunc action in an undefined state. Although normally it works fine - which is to say that this is just another indication about something sketchy, memory- respectively object-lifetime-management-wise.
Btw, if you support iOS 4 as a minimum, use CCCallBlock instead of CCCallFunc. That's safer and cleaner.