Add Action on CCLayer in cocos2d iOS - ios

I have a CCLayer class which i'm using for pause menu and inside that class i have menuitems . I've just added menu and it shows on screen but no animation in it. I want to add transition effect on layer as we can do it in scene. or add action as we do in sprite. I just want my pause menu to animate from up to down.
Here how i am adding my CClayer class.
menuLayer = [[PauseMenu alloc] initWithParent:self];
[self addChild:menuLayer z:99];
I have tried this code for action but it doesn't work
menuLayer = [[PauseMenu alloc] initWithParent:self];
[self addChild:menuLayer z:99];
id move=[CCMoveTo actionWithDuration:5.1 position:ccp(240,120)];
[menuLayer runAction:move];

Following your comment I'll recommend you not to use [[CCDirector sharedDirector] pause] as it does not really will pause your game logic (only actions and schedulers) but if you have some thread doing game logic (like moving objects or calculating some stuff) it will still keep running.
If you want to pause your game you should keep an internal state of your game. So for example in your update method you could do :
if (gameState == GAME_PAUSE)
return;
This way it will be easy for you to decide what continues to be done and what not until the game returns to play.

Related

How to create popup using sprite kit on iphone?

I am a beginner developing an iOS game using sprite kit. I would like to have 'pop-up' menu's that display objects (skspritenodes) such as daily rewards or settings/pause menu. The settings pop-up for example should be able to be accessed on the main home screen or during the game. Currently I have one view controller and the home scene and play scene are two different SKScenes. For reusability (and a clean project, as well as learning) I would like to have these pop-ups be their own class, including handling touches. Currently, I have a class for the settings pop-up that returns an SKNode, and this sknode contains several skspritenodes (the buttons/images that correspond to a settings pop up including enabling/disabling sound etc). However, I have to duplicate the touches code in both my home scene and my play scene to interact with this. (I currently have, in each skscene's touchesbegan method, "if nodeSettings !=nil", check the name of the skspritenode that corresponds to the touch-location, then call a method in the setting-pop-up class passing the name of the skspritenode clicked to handle interactions with the pop-up).
For my own knowledge and also to solve this problem, I would like to use a class that can handle the touch logic on its own (so in my play or home skscene, the only thing I do is create the pop-up. Any interaction, including dismissal, I would like to have handled in the class. No using the skscene's touches methods). I have found one 'solution' to this:
LTPopUpReward *test = [[LTPopUpReward alloc] init];
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:test];
CGFloat fltHeight = [UIScreen mainScreen].bounds.size.height;
CGFloat fltWidth = [UIScreen mainScreen].bounds.size.width;
popover.popoverContentSize = CGSizeMake(fltWidth/2, fltHeight/2); //your custom size.
CGRect rectPopUpReward = CGRectMake(500, 500, fltWidth/2, fltHeight/2);
[popover presentPopoverFromRect:rectPopUpReward inView:self.view permittedArrowDirections: UIPopoverArrowDirectionAny animated:YES];
and I like that you can dismiss the UIPopoverController by clicking outside of it, but this UIPopoverController only works on the iPad and doesn't work on the iPhone. I've seen this UIPopoverController for iphone not working? but was wondering if there is another way to solve my problem that Apple won't possibly disapprove of? For example, could I create a UIViewController, resize it and position it (i don't know how to do this) to simulate the pop-up?
Summarizing: my goal is to have a pop-up appear, but have all of its code (including touch) self contained within one class, and the objects on the pop-up are skspritenodes.
answering my own question: The solution I used to solve this problem is to use different SKViews. One SKView presents the main scene and another SKView presents the pop-up scene. You can adjust the size of the second SKView and even make its background transparent. Interacting with objects in this view will correctly call the touches methods in the class of the scene presented - That is this pop-up is dealt with when being created, and there is no other code dealing with it on the view-controller or main-scene's logic (all code, including creating objects and handling touch) are in the second skscene's code. The method below is called when I do "something" to call the 'pop-up'.
-(void)test4
{
skViewPopUp=nil;
scenePopUpReward=nil;
NSLog(#"test4 successfully fired");
CGFloat fltHeight = [UIScreen mainScreen].bounds.size.height;
CGFloat fltWidth = [UIScreen mainScreen].bounds.size.width;
CGRect rectPopUpReward = CGRectMake(0, 0, fltWidth/2, fltHeight/2);
skViewPopUp = [[SKView alloc] initWithFrame:rectPopUpReward];
[self.view addSubview:skViewPopUp];
skViewPopUp.allowsTransparency = YES;
scenePopUpReward = [[LTSceneStoreMain alloc] initWithSize:CGSizeMake(fltWidth/2, fltHeight/2)];
scenePopUpReward.backgroundColor = [UIColor clearColor];
[skViewPopUp presentScene:scenePopUpReward];
}

pause spritekit scene and show "paused" label

I want to show a "paused" SKLabelNode when someone clicks on the screen and therefore pauses the sprite kit game.
So I have in touchesBegan ->
[self.pausedLabel setHidden:!self.pausedLabel.hidden];
[self.scene.view setPaused:!self.scene.view.paused];
The Game is paused correctly but the SKLabelNode is not shown (scene not rendered before paused?!)
If I add a NSTimer for pausing the scene the label is shown, but then the game continues for that timer-time.
Does anyone have a better solution for this?
Thanks in advance
I would use SKAction for this. You can use +runBlock: to add the code related to hiding the label, and then use the -runAction method with the completion handler to pause the scene. The runBlock: method may return immediately, but this way, the screen manages to update before the scene is paused.
SKAction *action = [SKAction runBlock:^{
[self.pausedLabel setHidden:!self.pausedLabel.hidden];
}];
[self.pausedLabel runAction:action completion:^{
[self.scene.view setPaused:!self.scene.paused];
}];
Just use a state ivar to determine if the scene should update its content or not.
When you click the button set this state to PAUSE and in your scene frame update loop test the state.
if (_state != PAUSE) {// Use enum for the state var
// Update scene objects
}
when your button is clicked:
Add pause label to scene
Set state to PAUSE
The benefits of this approach is that it allows you to decide exactly what will happen on pause (opposing to pausing the whole scene). You can animate a cool background while in pause or do anything you'd like as this is totally in your control

How to run the same block of code - Cocos2d

I am using cocos2d and have 2 AI sprites called TheEvilOne and TheEvilTwo. These 2 sprites call the same bloc of code from the same class sending the sprite as a parameter. However the game gets buggy as I run this code as only one of the sprites preforms the actions and my code stops working. My question is is it possible to call the same bloc of code for multiple sprites simultaneously or is there something wrong with my code. Below is an example of what I am running on my program.
-(void)LoadingEvilActions:(id)sender { //This is Getting Constantly Called
if(loaded == NO) {
theEvilOne = [CCSprite spriteWithFile:#"Evil_Alt_Idle_00.png"]; //These sprites have been declared in my .h file
[self addChild:theEvilOne z:200];
theEvilTwo = [CCSprite spriteWithFile:#"Evil_Alt_Idle_00.png"];
[self addChild:theEvilTwo z:200];
loaded = YES;
}
[self CheckCollision:theEvilOne];
[self setCenterofScreen:theEvilOne];
[self StayonScreen:theEvilOne];
[self AiCharacter:theEvilOne];
[self CheckCollision:theEvilTwo];
[self setCenterofScreen:theEvilTwo];
[self StayonScreen:theEvilTwo];
[self AiCharacter:theEvilTwo];
}
-(void)AiCharacter:(id)sender {
CCSprite *EvilCharacter = (CCSprite *)sender;
if (aiactionrunning == NO){
.... Do More Stuff // For E.G.
id jump_Up = [CCJumpBy actionWithDuration:0.6f position:ccp(randomjump, EvilCharacter.contentSize.height)
height:25 jumps:1];
id jump_Down = [CCJumpBy actionWithDuration:0.42f position:ccp(randomjump,-EvilCharacter.contentSize.height)
height:25 jumps:1];
id seq = [CCSequence actions:jump_Up,jump_Down, [CCCallFuncN actionWithTarget:self selector:#selector(stopAiAction:)], nil];
[EvilCharacter stopAllActions];
[EvilCharacter runAction:seq];
aiactionrunning = YES;
}
}
-(void)stopAiAction:(id)sender {
aiactionrunning = NO;
}
EDIT
I'm running random number generators within my AI Character method and many actions.
The Game already works with just 1 enemy sprite and I decided to try and implement a way to create many.
EDIT 2
I just added the part of the method that stops the sprites being constantly, I was trying to simplify all the code that was irrelevant to my question and forgot to add that part.
I changed the way I am calling my methods like suggested by LearnCocos2d not solving my problem but making it much simpler. I am also not using ARC
One of my sprites is the only one preforming the majority of actions however in some instances the other sprite may preform an actions aswell, but is mainly preformed one sprite. I think my main question is can I call the same method using different sprites passing the sprite as a parameter.
EDIT 3
I have figured out that my problem is there is a Boolean value flag that is enclosing my AiCharacter method, where when one sprite runs through the method it stops the other sprite running the method. Is there some way I can implement an array of records or such so each sprite have their own Boolean flags.
With making this 'array' is it possible to change the Boolean for TheEvilOne and TheEvilTwo using the temp sprite EvilCharacter without doing both separately.
If I understand your question correct you are trying to take one action and run it on more than one character at a time, like:
id move = [CCMoveTo actionWithDuration:0.5f position:ccp(0,0)];
[theEvilOne runAction:move];
[theEvilTwo runAction:move];
That wouldn't work because Evil 1 will not have anything performed on it since it was moved to running on Evil 2. When an action is running it is running on one target. Instead you would:
id move = [CCMoveTo actionWithDuration:0.5f position:ccp(0,0)];
[theEvilOne runAction:move];
[theEvilTwo runAction:[move copy]];
Assuming you are using arc. If not then you'd want to release the copy of course. When it comes to your particular example, why are you trying actions to call methods. Why not just call the method? It seems pointless as LearnCocos2D has pointed out.
Another potential problem you have is that you are constantly creating more and more sprites each time the method is called. Is that on purpose or are there only suppose to be one Evil 1 and one Evil 2? If so then you shouldn't be constantly creating more sprites.
Edit:
Remove your bool. Do something like this instead:
CCSprite *EvilCharacter = (CCSprite *)sender;
if ([EvilCharacter numberOfRunningActions] == 0){
...
}

CocosBuilder Animations not running

I'm creating a simple animation with CocosBuilder that just moves a CCLayerColor from top right to bottom left and for some reason the animations will not perform. I have the timeline set to auto play and over a duration of 2 seconds. I have a class that splits up all layers and then adds those layers to a CCScrollLayer. I'm just wondering if the problem is when i remove the layers from the scene and add then to the CCScrollLayer that the animations are removed and in turn not performed.
CCScene* scene = [CCBReader sceneWithNodeGraphFromFile:#"Untitled.ccbi"];
self.scrollLayer = [[CCScrollLayer alloc] init];
CCLayer* child = [[scene children] objectAtIndex:0];
for (CCNode* layer in [child children]) {
[layer removeFromParent];
[self.scrollLayer addChild:layer];
[layer resumeSchedulerAndActions];
}
[self.scrollLayer updatePages];
self.scrollLayer.delegate = self;
[self addChild:self.scrollLayer];
I can see the CCLayerColor object added to the screen but its just not animating.
i've added some custom code to the CCScrollLayer to deal with the situation but i'm just confused as to why the animations are not performing. any help would be great!
EDIT: Maybe a better question would be in CocosBuilder are the actions on the timeline directly linked to the object performing the action or somehow linked through the scene to that object?
Perhaps you forgot to add the scrollLayer as child?
[self addChild:self.scrollLayer];
In the sample code the node created from a ccbi is not referenced either. Maybe you aren't actually using it?

Motion Tween effect ( like flash ) on iphone, maybe using cocos 2d?

I thought doing a simple animation would be easy but is is taking hours and Im not getting even close to have the expected effect...
I need to simulate a simple Flash Motion Tween like for iphone/ipad using xcode
this is the desired effect: http://www.swfcabin.com/open/1340330187
I already tried setup a timer adding X position and it doens't get the same effect, my cooworkers suggested me cocos 2d to do this using actions and sprites, which might would be fine although I wouldn't like to third party frameworks, but if there is a way to do the same with cocos I would definitively use it.
Does anybody have any suggestions, I feel like it might be simpler than I thought
thanks all
If there is no troubles to you, that you will have to do it insinge OpenGL view, it is really very simple. To show some info, you need CCLabel class. To change it's position, you need CCMoveTo/CCMoveBy action, to change opacity, you need CCFadeTo/CCFadeIn/CCFadeOut actions, to make delay you need CCDelayTime. To make it all work together you need CCSpawn and CCSequence.
CCSpawn will run several actions at the same time(for example fade in and move from right to the center), CCSequence will run several actions one by one (sequence to fade in + move to center, delay for same time, sequence to fade out + move from center to the left). Then you should only schedule method, that will create labels and run actions on them. In code it will be something like
lets define full animation time
#define ANIMATION_TIME 4.f
schedule method in any place you want to start animation
[self schedule:#selector(runNextMessage) interval:ANIMATION_TIME];
it will call runNextMessage method every ANIMATION_TIME seconds
- (void) runNextMesage
{
NSString* message = //get next message
CCLabelTTF* label = [CCLabelTTF labelWithString:message
dimensions:desiredDimensionsOfTheLabel
alignment:UITextAlignmentLeft
lineBreakMode:UILineBreakModeWordWrap
fontName:#"Arial"
fontSize:20.f];
CGSize winSize = [[CCDirector sharedDirector] winSize];
// place the label out the right border
[label setPosition: ccp(winSize.width + label.contentSize.width, winSize.height / 2)];
// adding it to the screen
[self addChild:label];
ccTime spawnTime = ANIMATION_TIME / 3;
// create actions to run
id appearSpawn = [CCAction actionOne:[CCMoveTo actionWithDuration:spawnTime]
two:[CCFadeIn actionWithDuration:spawnTime]];
// create show action and disappear action
// create result sequence
id sequence = [CCSequence actions: appearSpawn, showAction, disappearAction, nil];
[label runAction: sequence];
}

Resources