Resume game loop in cocos2d - cocos2d-iphone

I have a game with animation. In game scene, I use the method below to pause my game (it works perfectly, because the game is paused when the users taps on any point of the iOS device):
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch=[touches anyObject];
CGPoint locationOfTouch=[self convertTouchToNodeSpace: touch];
CGRect rectOfScreen=CGRectMake(0, 0, screenSize.width, screenSize.height);
if (CGRectContainsPoint(rectOfScreen, locationOfTouch))
{
[[CCDirector sharedDirector] replaceScene:[PauseScene scene]];
[self unschedule:#selector(spawnEnemies:)];
[self unschedule:#selector(checkCollisionOfEnemyWithBullet:)];
[self unschedule:#selector(update:)];
[self unschedule:#selector(isJoystickActivated:)];
[self unschedule:#selector(checkHasGameEnded:)];
[[CCDirector sharedDirector] pause];
}
}
To implement resume action, I'v created PauseLayer:CCLayer, where I've implemented the following method to resume the game:
-(void) continueGame:(id)sender
{
[[CCDirector sharedDirector] resume];
[[CCDirector sharedDirector] replaceScene:[GameSceneLayer scene]];
//[self resumeSchedulerAndActions];
}
Here is the code, how I envoke the method above:
CCMenuItemFont* continue_game=[CCMenuItemFont itemWithString:#"continue game" target:self selector:#selector(continueGame:)];
But, when I select continue game, the game start from the blank point: every game state, every game character will be new. How can I resume my game from the intial point where it was paused by user? Thank you!

You can use these two cocos2D function to pause and resume:
[self pauseSchedulerAndActions]; //pause
[self resumeSchedulerAndActions];//resume
Also maintain one bool variable, and check that whenever u need.
bool mISGamePaused;

Related

How to remove a target with delay time

I try to delete a target with delay time, code likes this
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [self convertTouchToNodeSpace: touch];
targetsToRemove = [[NSMutableArray array] init];
for (CCSprite *target in _targets) {// here _targets is NSMutableArray
if (CGRectContainsPoint(target.boundingBox, location)) {
[targetsToRemove addObject:target];
}
}
for (CCSprite *target in targetsToRemove) {
if (target.tag == 1) {
[target setTexture:[[CCTextureCache sharedTextureCache] addImage:#"1.png"]];
[_targets removeObject:target];
[self removeChild:target cleanup:YES];
}
else {
CCLOG(#"remove target immediately");
}
}
}
If the target.tag = 1, I want to delay 0.5 to show its images, and then remove it, I try to use scheduleOnce, but it crashs, so how can I do?
I'm not sure how to write this in Objective-C (I'm only familiar with Cocos2D-XNA which is C#), but see if this works:
Make a CCSequence, first action in the sequence is CCDelayTime with 0.5 as argument, and the second action in the sequence is CCRemoveSelf. Then just run this sequence on the target sprite.
Hope this is helpful to you. You may want to try https://gamedev.stackexchange.com/ for more help.
Try this way:
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
...
for (CCSprite *target in targetsToRemove) {
if (target.tag == 1) {
[target setTexture:[[CCTextureCache sharedTextureCache] addImage:#"1.png"]];
CCDelayTime *delay =[CCDelayTime actionWithDuration:3.0f];
CCCallFunc *removeTarget = [CCCallFunc actionWithTarget:self selector:#selector(removeSprites:data:)data:target];
[target runAction:[CCSequence actionWithActions:delay, removeTarget, nil]];
}
}
-(void)removeSprites:(id)sender data:(CCSPrite *)sprtToDelete
{
if(!_targets)
[_targets removeObject:sprtToDelete];
[sprtToDelete removeFromParentAndCleanUp:YES];
}
Here you are running two actions on each to be deleted sprite. So on first action you wait for 3 seconds and in second action you call a method with parameter as this sprite. And in that method you clean up your sprite.
Hope this will help. LEt me know if not.

Cocos2d restart current scene

I've got an end of level layer added to game, each level has its own scene. I want to be able to restart the current scene. Obviously the scene will change but the layer will remain the same. How is this done. I've tried-
CCScene *currentScene = [[CCDirector sharedDirector]runningScene];
[[CCDirector sharedDirector]replaceScene:currentScene];
Thanks
This does not work because you can't replace the same scene object with itself:
CCScene *currentScene = [[CCDirector sharedDirector]runningScene];
[[CCDirector sharedDirector]replaceScene:currentScene];
Instead you have to create a new instance of your scene, like so:
[[CCDirector sharedDirector] replaceScene:[YourSceneClass scene]];
If you don't know what the current scene class is, then this ought to work:
CCScene *currentScene = [CCDirector sharedDirector].runningScene;
CCScene *newScene = [[[currentScene class] alloc] init];
[[CCDirector sharedDirector] replaceScene:newScene];
Assuming you're using ARC as everyone should these days. Otherwise add an autorelease.
I ran into the same problem. I tried this
CCScene *currentScene = [CCDirector sharedDirector].runningScene;
CCScene *newScene = [[[currentScene class] alloc] init];
[[CCDirector sharedDirector] replaceScene:newScene];
and it gave me a blank screen.
The problem is this line
CCScene *newScene = [[[currentScene class] alloc] init];
[currentScene class] actually returns CCScene..
Hence
[CCScene alloc] init] gives us a blank screen.
The way how I got around this problem was by setting tag for each of my scene class.
For example:
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
scene.tag = 1;
// 'layer' is an autorelease object.
GameOneLayer * layer = [[[GameOneLayer alloc] init];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
Hope this helps.

cocos2d start / stop running Scene

I'm trying to load one scene. This runs fine the first time, but when I try to reload again appears a white square where the animation is placed.
This is the code to start and stop the scene. What I'm missing?
thanks.
-(void)runScene:(OTAnimationCC2d *)animation
{
scene = [CCScene node];
[scene addChild:animation];
if ([[[CCDirector sharedDirector] runningScene] isRunning])
{
[[CCDirector sharedDirector] replaceScene:scene];
}
else
{
[[CCDirector sharedDirector] runWithScene:scene];
}
}
-(void)stopScene
{
[[[CCDirector sharedDirector] runningScene] stopAllActions];
[[[CCDirector sharedDirector] runningScene] removeAllChildrenWithCleanup:YES];
[[CCDirector sharedDirector] pushScene:scene];
}
Why not just call [self runScene] at the end of stopScene rather than [[CCDirector sharedDirector] pushScene:scene]? It sounds like you want the scene to reload fresh, which your runScene already does when it calls replaceScene.
Either way you should be creating a new scene node and using replaceScene (which is being done in runScene and is why I recommend just calling that).

How do I detect multi-touch in cocos2d?

Edited Post
Ok I tried what rptwsthi said in another project just to test it......
-(id) init
{
if( (self=[super init])) {
self.isTouchEnabled = YES;
}
return self;
}
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray *touchArray=[touches allObjects];
if ([touchArray count] == 2) {
NSLog(#"touch 2");
}
else if([touchArray count]==1) {
NSLog(#"touch 1");
}
}
But only the "touch 1" NSLog pops ups when I press the screen with two fingers. Do I need to put what LearnCocos2D said in there somewhere too.
Old Post
I have a test app I'm making and in it I have 3 buttons in the hud, 2 are for moving left and right and the other is for shooting. This is what I currently have.....
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint loc = [touch locationInView:[touch view]];
loc = [[CCDirector sharedDirector] convertToGL:loc];
//Move Left
CGRect left = CGRectMake(leftButton.position.x-50/2, leftButton.position.y-50/2, 50, 50);
if (CGRectContainsPoint(left, loc)) {
[self schedule:#selector(moveLeft)];
}
//Move Right
CGRect right = CGRectMake(rightButton.position.x-50/2, rightButton.position.y-50/2, 50, 50);
if (CGRectContainsPoint(right, loc)) {
[self schedule:#selector(moveRight)];
}
//Shoot
CGRect shoot = CGRectMake(shootButton.position.x-50/2, shootButton.position.y-50/2, 50, 50);
if (CGRectContainsPoint(shoot, loc)) {
bullet = [CCSprite spriteWithFile:#"bullet.png"];
bullet.position = ccp(plane.position.x, plane.position.y+20);
[self addChild:bullet];
}
}
-(void) ccTouchesEnded:(UITouch *)touch withEvent:(UIEvent *)event {
[self unschedule:#selector(moveLeft)];
[self unschedule:#selector(moveRight)];
}
But I can only press one button at a time. I want to be able to hold the right or left button and also shoot with the shoot button. Can anyone fix my code or show me a basic example of multi-touch?
Also I'm new to iOS development and any help will be much appreciated. Thanks.
Have you enabled multiple touches on the cocos2d view?
[[CCDirector sharedDirector].openGLView setMultipleTouchEnabled:YES];
You Just use allObject instead of anyObject, and check it like:
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray *touchArray=[touches allObjects];
if ([touchArray count] == 2)
//DO ONE THING
else if([touchArray count]==1)
//DO ANOTHER THING
}

Cocos2D: SneakyJoystick + Touch Events, problem

im having some trouble using SneakyJoystick and ccTouchEnded stuff.
What is my goal, use the joystick to walk around and the touches to interact with the surrounding area.
I have two layers,ControlLayer (z:2) and GamePlayLayer (z:1)
Im Using TiledMap for my ground and map.
The Joystick by it self works fine, it is attached to the ControlLayer. I can walk, colide and stuff.
When i add the Touch events to the GamePlayLayer, the touch works, i can click on something on the "ground" and interact with it. BUT my joystick dosent work then, if i run using the touch the joystick just sit there not responsive.
Here is some of my code, if u guys need more, just ask.
Touch methods in the GameplayLayer
-(void) registerWithTouchDispatcher
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self
priority:0 swallowsTouches:YES];
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
return YES;
}
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchLocation = [touch locationInView: [touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
CGPoint tileCoord = [self tileCoordForPosition:touchLocation];
int tileGid = [meta tileGIDAt:tileCoord];
if (tileGid) {
NSDictionary *properties = [tileMap propertiesForGID:tileGid];
if (properties) {
NSString *collectable = [properties valueForKey:#"Collectable"];
if (collectable && [collectable compare:#"True"] == NSOrderedSame) {
[meta removeTileAt:tileCoord];
[foreground removeTileAt:tileCoord];
}
}
}
}
And how my scene is arranged:
#implementation SandBoxScene
-(id)init {
self = [super init];
if (self!=nil) {
//Control Layer
controlLayer = [GameControlLayer node];
[self addChild:controlLayer z:2 tag:2];
//GamePlayLayer
GameplayLayer *gameplayLayer = [GameplayLayer node];
[gameplayLayer connectControlsWithJoystick:[controlLayer leftJoyStick]
andJumpButton:[controlLayer jumpButton]
andAttackButton:[controlLayer attackButton]];
[self addChild:gameplayLayer z:1 tag:1];
}
return self;
}
#end
Thanks for the help!
The problem is that your code does not account for multiple touches. Using -(BOOL) ccTouchBegan:(UITouch *)touch.. or -(void) ccTouchEnded:(UITouch *)touch.. will only take one touch... instead you need to use ccTouchesEnded:.. your method should look something like this:
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
//get your touch from the set of UITouches
UITouch *myTouch = [touches anyObject];
//the rest below is the same from your method
CGPoint touchLocation = [myTouch locationInView: [myTouch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
CGPoint tileCoord = [self tileCoordForPosition:touchLocation];
int tileGid = [meta tileGIDAt:tileCoord];
if (tileGid) {
NSDictionary *properties = [tileMap propertiesForGID:tileGid];
if (properties) {
NSString *collectable = [properties valueForKey:#"Collectable"];
if (collectable && [collectable compare:#"True"] == NSOrderedSame) {
[meta removeTileAt:tileCoord];
[foreground removeTileAt:tileCoord];
}
}
}
}
You also need to add [glView setMultipleTouchEnabled:YES]; to your appDelegate. I am not entirely sure that the method above works. This question deals with implementing multitouch with cocos2d. Hope this helps
Sorry thats was not the solution, i do want to handle just one touch, the problem was in the priority, i was giving priority 0 to my gameplayLayer, and swalloing every time, so i didnt give chance to the controlayer that had priority 1 to get the touch and act upon my joystick.
The solution that i found was changing the priority from 0 to 2 then, the (controlLayer) joystick would act and pass the touch to the priority 2, that was my gameplayLayer
but thanks anyway :)