How to move background images infinitely in iOS coco2d - ios

I have to move background images in iOS Coco2d but I am having a few difficulties. I have tried some solutions provided on some websites but have not been successful in getting them to work properly. Below is the code I am currently working on:-
The background moves smoothly the first time but it is not working properly after that:-
Code in init function :-
bg1 = [CCSprite spriteWithFile: #"bg1.png"];
bg1.anchorPoint = CGPointZero;
[self addChild:bg1 z:-2];
bg2 = [CCSprite spriteWithFile: #"bg1.png"];
[self addChild:bg2 z:-3];
bg2.anchorPoint = CGPointMake(480, 0);
// schedule a repeating callback on every frame
[self schedule:#selector(nextFrame:) interval:.4f];
- (void) nextFrame:(ccTime)dt {
id actionMove = [CCMoveTo actionWithDuration:.4 position:ccp(bg1.position.x - 100 * dt, bg1.position.y)]; //winSize.height/2)];
id actionMove1 = [CCMoveTo actionWithDuration:.4 position:ccp(bg2.position.x - 100 * dt, bg2.position.y)]; //winSize.height/2)];
id actionMoveDone = [CCCallFuncN actionWithTarget:self selector:#selector(spriteMoveFinished:)];
[bg1 runAction:[CCSequence actions:actionMove,actionMoveDone, nil]];
[bg2 runAction:[CCSequence actions:actionMove1,actionMoveDone, nil]];
}
-(void)spriteMoveFinished:(id)sender {
CCSprite *sprite = (CCSprite *)sender;
if(sprite == bg1) {
if (bg1.position.x < -480) {
[self removeChild:bg1 cleanup:NO];
bg1.position = ccp( 480 , bg1.position.y );
[self addChild:bg1 z:-2];
}
}
else if(sprite == bg2)
if (bg2.position.x < -480) {
[self removeChild:bg2 cleanup:NO];
bg2.position = ccp( bg1.position.x+ 480 , bg1.position.y );
[self addChild:bg2 z:-3];
}
}
}

Try this, make sure you flip background 2.
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define MM_BG_SPEED_DUR       ( IS_IPAD ? (6.0f) : (2.0f) )
-(void)onEnter
{
[super onEnter];
[self initBackground];
[self schedule: #selector(tick:)];
}
-(void)initBackground
{
NSString *tex = #"BG/Background.png";//[self getThemeBG];
mBG1 = [CCSprite spriteWithFile:tex];
mBG1.position = ccp(s.width*0.5f,s.height*0.5f);
[self addChild:mBG1 z:LAYER_BACKGROUND];
mBG2 = [CCSprite spriteWithFile:tex];
mBG2.position = ccp(s.width+s.width*0.5f,s.height*0.5f);
mBG2.flipX = true;
[self addChild:mBG2 z:LAYER_BACKGROUND];
}
-(void)scrollBackground:(ccTime)dt
{
CGSize s = [[CCDirector sharedDirector] winSize];
CGPoint pos1 = mBG1.position;
CGPoint pos2 = mBG2.position;
pos1.x -= MM_BG_SPEED_DUR;
pos2.x -= MM_BG_SPEED_DUR;
if(pos1.x <=-(s.width*0.5f) )
{
pos1.x = pos2.x + s.width;
}
if(pos2.x <=-(s.width*0.5f) )
{
pos2.x = pos1.x + s.width;
}
mBG1.position = pos1;
mBG2.position = pos2;
}
-(void)tick:(ccTime)dt
{
[self scrollBackground:dt];
}

I think this way is a little simpler. You initialize the backgrounds in initand move them in update.
In the init method:
// position backgrounds
CCSprite *bg1 = [CCSprite spriteWithSpriteFrame:spriteFrame];
CCSprite *bg2 = [CCSprite spriteWithSpriteFrame:spriteFrame];
CCSprite *bg3 = [CCSprite spriteWithSpriteFrame:spriteFrame];
bg1.anchorPoint = ccp(0, 0);
bg1.position = ccp(0, 0);
bg2.anchorPoint = ccp(0, 0);
bg2.position = ccp(bg1.contentSize.width-1, 0);
bg3.anchorPoint = ccp(0, 0);
bg3.position = ccp(2*bg1.contentSize.width-1, 0);
_backgrounds = #[bg1, bg2, bg3];
[self addChild:bg1 z:INT_MIN];
[self addChild:bg2 z:INT_MIN];
[self addChild:bg3 z:INT_MIN];
In the update method:
// endless scrolling for backgrounds
for (CCSprite *bg in _backgrounds) {
bg.position = ccp(bg.position.x - 50 * delta, bg.position.y);
if (bg.position.x < -1 * (bg.contentSize.width)) {
bg.position = ccp(bg.position.x + (bg.contentSize.width*2)-2, 0);
}
}
Note: the code is for Cocos2d 3.0

Related

What will be the best approach implementing infinite/repeating scrolling world in SpriteKit?

While moving the character it must stay inside a rectangle centred on the screen and all other game objects must scroll.
But as you get to the edge of the world it must repeat.
The characters can move in any direction.
You have to divide the world in 3 sections. Section 1 and 3 must be identical. If you reach the end of the world (Section 3) you can switch back to section 1.
http://www.youtube.com/watch?v=-FX-tFks5pg
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
_background = [SKSpriteNode spriteNodeWithImageNamed:#"background"];
_background.anchorPoint = CGPointMake(0, 0);
_background.name = #"background";
_background.position = CGPointMake(0, 0);
[self addChild:_background];
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
if (_lastUpdateTime) {
_deltaTime = currentTime - _lastUpdateTime;
} else {
_deltaTime = 0;
}
_lastUpdateTime = currentTime;
if (_deltaTime > 1) {
_deltaTime = 1.0 / 60.0;
}
[self enumerateChildNodesWithName:#"background" usingBlock:^(SKNode *node, BOOL *stop) {
node.position = CGPointMake(node.position.x - backgroundMoveSpeed * _deltaTime, node.position.y);
if (node.position.x < - (node.frame.size.width + 100)) {
[node removeFromParent];
}
}];
if (_background.position.x < -bound) {
//bound = 500
SKSpriteNode *temp = [SKSpriteNode spriteNodeWithImageNamed:#"background"];
temp.anchorPoint = CGPointMake(0, 0);
temp.name = #"background";
temp.position = CGPointMake(_background.position.x + _background.frame.size.width, 0);
[self addChild:temp];
_background = temp;
}
the background image's size is 2048x640, so you should change the bound according to your background image's size.

Delegate not working between HudLayer and GameLayer

I have created a HudLayer class which defines a protocol for when button presses happen.
-(id) init
{
if( (self=[super initWithColor:ccc4(255, 255, 0, 128)])) {
self.position=ccp(0,0);
self.contentSize=CGSizeMake(480, 40);
scoreLabel=[CCLabelTTF labelWithString:#"0" fontName:#"Marker Felt" fontSize:24];
scoreLabel.position=ccp(62,20);
scoreLabel.anchorPoint=ccp(0,0.5);
[self addChild:scoreLabel];
CCLabelTTF *textLabel=[CCLabelTTF labelWithString:#"Score:" fontName:#"Marker Felt" fontSize:24];
textLabel.position=ccp(5,20);
textLabel.anchorPoint=ccp(0,0.5);
[self addChild:textLabel];
CCMenuItemImage * item = [CCMenuItemImage itemWithNormalImage:#"fire.png" selectedImage:#"fire.png" target:self selector:#selector(projectileButtonTapped:)];
CCMenu *menu = [CCMenu menuWithItems:item, nil];
menu.position = ccp(150, 20);
[self addChild:menu];
}
return self;
}
- (void)projectileButtonTapped:(id)sender
{
NSLog(#"projectileButtonTapped HudLayer");
[self.delegate respondsToSelector:#selector(projectileButtonTapped:)];
}
Then in my HelloWorldLayer class I implement the protocol and set myself as the delegate.
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
//add another layer to the scene
// HudLayer *anotherLayer = [HudLayer node];
// anotherLayer.delegate = self;
// [scene addChild: anotherLayer];
// layer.hud=anotherLayer;
// return the scene
return scene;
}
-(id) init
{
if( (self=[super init]) ) {
_tileMap = [CCTMXTiledMap tiledMapWithTMXFile:#"GridWars#medium.tmx"];
_background = [_tileMap layerNamed:#"Background"];
_foreground = [_tileMap layerNamed:#"Foreground"];
_meta = [_tileMap layerNamed:#"Meta"];
_meta.visible = NO;
CCTMXObjectGroup *objectGroup = [_tileMap objectGroupNamed:#"Objects"];
NSAssert(objectGroup != nil, #"tile map has no objects object layer");
NSDictionary *spawnPoint = [objectGroup objectNamed:#"SpawnPoint"];
int x = [spawnPoint[#"x"] integerValue];
int y = [spawnPoint[#"y"] integerValue];
_wizardHero = [[WizardHero alloc]init];
_redEnemy = [[RedEnemy alloc]init];
_wizardHero.position = ccp(x,y);
[self addChild:_wizardHero];
[self setViewPointCenter:_wizardHero.position];
[self addChild:_tileMap z:-1];
self.touchEnabled = YES;
self.enemies = [[NSMutableArray alloc] init];
self.projectiles = [[NSMutableArray alloc] init];
[self schedule:#selector(testCollisions:)];
for (spawnPoint in [objectGroup objects]) {
if ([[spawnPoint valueForKey:#"Enemy"] intValue] == 1){
x = [[spawnPoint valueForKey:#"x"] intValue];
y = [[spawnPoint valueForKey:#"y"] intValue];
[self addEnemyAtX:x y:y];
}
}
_hud = [HudLayer node];
_hud.delegate = self;
[self addChild:_hud];
}
return self;
}
- (void)projectileButtonTapped:(id)sender
{
// Find where the touch is
// CGPoint touchLocation = [touch locationInView: [touch view]];
// touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
// touchLocation = [self convertToNodeSpace:touchLocation];
if (self.wizardHero.selectedTargets.count > 0) {
// Create a projectile and put it at the player's location
CCSprite *projectile = [CCSprite spriteWithFile:#"Projectile.png"];
projectile.position = _wizardHero.position;
[self addChild:projectile];
// Determine where we wish to shoot the projectile to
int realX;
// Are we shooting to the left or right?
CGPoint diff = ccpSub(self.redEnemy.position, self.wizardHero.position);
if (diff.x > 0)
{
realX = (_tileMap.mapSize.width * _tileMap.tileSize.width) +
(projectile.contentSize.width/2);
} else {
realX = -(_tileMap.mapSize.width * _tileMap.tileSize.width) -
(projectile.contentSize.width/2);
}
float ratio = (float) diff.y / (float) diff.x;
int realY = ((realX - projectile.position.x) * ratio) + projectile.position.y;
CGPoint realDest = ccp(realX, realY);
// Determine the length of how far we're shooting
int offRealX = realX - projectile.position.x;
int offRealY = realY - projectile.position.y;
float length = sqrtf((offRealX*offRealX) + (offRealY*offRealY));
float velocity = 480/1; // 480pixels/1sec
float realMoveDuration = length/velocity;
// Move projectile to actual endpoint
id actionMoveDone = [CCCallFuncN actionWithTarget:self
selector:#selector(projectileMoveFinished:)];
[projectile runAction:
[CCSequence actionOne:
[CCMoveTo actionWithDuration: realMoveDuration
position: realDest]
two: actionMoveDone]];
[self.projectiles addObject:projectile];
}
}
The problem is that only the projectileButtonTapped: in the HudLayer is called (ie. the delegate's method never gets called).
P.S.
To save space I left out both .h files. But I assure you they are correct, with the #protocol used in HudLayer and that same protocol name put in <> within the HelloWorldLayer.
I think :
- (void)projectileButtonTapped:(id)sender
{
NSLog(#"projectileButtonTapped HudLayer");
if ([self.delegate respondsToSelector:#selector(projectileButtonTapped:)]) {
[self.delegate performSelector:#selector(projectileButtonTapped:) withObject:sender];
}
}

how to run actions on multiple sprites at the same time

I'm new to cocos2d. I'm writing my first app. But I have a problem I can't solve it. The problem is that when I move multiple sprites, the others are OK except the last one. I want my sprites will run actions at the same time. But I don't know how to fix it. Any ideas or advice about promoting my code. Thanks.
Here's my code.
-(void) setHeadFace:(Face *)headFace moveFrom:(CGPoint)startPosition moveTo:(CGPoint)endPosition`
{
CCMoveTo *moveOut = [CCMoveTo actionWithDuration:0.2f position:startPosition];
CCScaleTo *scaleTo = [CCScaleTo actionWithDuration:0.2f scale:0.0f];
CCSpawn *moveFrom = [CCSpawn actions:moveOut,scaleTo,nil];
CCMoveTo *moveTo = [CCMoveTo actionWithDuration:0.0f position:endPosition];
CCSequence *headAction = [CCSequence actions:moveFrom,moveTo,nil];
[headFace.faceSprite runAction:headAction];
}
-(void) setMidlFace:(Face *)curtFace moveTo:(CGPoint)movePosition nextFace:(Face *)nextFace
{
CCMoveTo *moveTo = [CCMoveTo actionWithDuration:0.2f position:movePosition];
CCSequence *moveAction = [CCSequence actions:moveTo,nil];
[curtFace.faceSprite runAction:moveAction];
nextFace.faceSprite = curtFace.faceSprite;
nextFace.faceType = curtFace.faceType;
[nextFace.faceSprite setPosition:movePosition];
}
-(void) setTailFace:(Face *)tailFace moveTo:(CGPoint)movePosition
byGuardSprite:(CCSprite *)guardSprite`
{
CCDelayTime *delay = [CCDelayTime actionWithDuration:0.2f];
CCMoveTo *moveIn = [CCMoveTo actionWithDuration:0.2f position:movePosition];
CCScaleTo *scaleTo = [CCScaleTo actionWithDuration:0.2f scale:1.0f];
CCSpawn *moveTo = [CCSpawn actions:moveIn,scaleTo,nil];
CCCallBlock *touchBlock =[CCCallBlock actionWithBlock:^{
tailFace.faceSprite = guardSprite;
tailFace.faceType = guardSprite.tag;
tailFace.faceSprite.tag = -1;
isTouch = YES;
}];
CCSequence *tailAction=[CCSequence actions:delay,moveTo,touchBlock,nil];
[guardSprite runAction:tailAction];
}
-(void) moveFaces:(Face *)face direction:(int)direction`
{
CCSprite *guardSprite = nil;
CGPoint movePosition;
CGPoint curtPosition;
CGPoint startPosition;
CGPoint endPosition;
int x = face.cdX;
int y = face.cdY;
CGFloat width = faceGrid[x][0].position.x;
CGFloat height = faceGrid[0][y].position.y;
switch (direction) {
case MOVE_DOWN:
CCLOG(#"move down:direction %d", direction);
movePosition = CGPointMake(width,faceGrid[x][0].position.y);
//move the first face out of the grid
startPosition = CGPointMake(width,faceGrid[x][0].position.y-GRID_OFFSET.y/2);
endPosition = CGPointMake(width,faceGrid[x][GRID_HEIGHT-1].position.y+GRID_OFFSET.y/2);
[self setHeadFace:faceGrid[x][0] moveFrom:startPosition moveTo:endPosition];
guardSprite = faceGrid[x][0].faceSprite;
guardSprite.tag = faceGrid[x][0].faceType;
for (int j=1; j<GRID_HEIGHT; j++)
{
curtPosition=CGPointMake(width,faceGrid[x][j].position.y);
//move the middle face to the next face
[self setMidlFace:faceGrid[x][j] moveTo:movePosition nextFace:faceGrid[x][j-1]];
movePosition = curtPosition;
}
//use the guard face to set the last face's move action
[self setTailFace:faceGrid[x][GRID_HEIGHT-1] moveTo:movePosition byGuardSprite:guardSprite];
break;
......
}
I used tick function for same purpose.
-(void)onEnter
{
[super onEnter];
self.isTouchEnabled = true;
[self schedule: #selector(tick:)];
}
-(void) tick: (ccTime) dt
{
CGPoint pos = head.position ;
head.position = ccp(pos.x+gameSpeed, pos.y);
pos = tail.position ;
tail.position = ccp(pos.x+gameSpeed, pos.y);
}

Cocos2d EXC_BAD_ACCESS

I am new to cocos2d and suddenly got this EXC_BAD_ACCESS,
I made a new winning menu and i got the error
I think the error is because i called a released object, but i dont release anything?
My Debug Console had no error, which is strange
here is my Level_1.m
//
// Level_1.m
// iPadGame
//
// Created by My Name on 1/25/12.
// Copyright 2012 __MyCompanyName__. All rights reserved.
//
#import "Level_1.h"
#import "HelloWorldLayer.h"
CCSprite *player;
CCSprite *enemy;
CCSprite *enemy2;
CCSprite *enemy3;
CCSprite *star;
CCSprite *star2;
CCSprite *star3;
CCSprite *bg;
CCSprite *toolBar;
CCLabelTTF *youWin;
bool movePlayer;
#implementation Level_1
#synthesize score;
+(CCScene *) scene {
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
Level_1 *layer = [Level_1 node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
-(void) setUpWinMenu {
[CCMenuItemFont setFontName:#"Marker Felt"];
[CCMenuItemFont setFontSize:75];
CCMenuItem *MainMenu = [CCMenuItemFont itemFromString:#"Main Menu" target:self selector:#selector(gotoMainMenu)];
CCMenu *WinMenu = [CCMenu menuWithItems:MainMenu, nil];
[self addChild:WinMenu];
MainMenu.position = ccp(400,500);
}
// 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]))
{
self.isTouchEnabled = YES;
scoreNumber = 10;
bg = [CCSprite spriteWithFile:#"metal_background.jpeg"];
bg.position = ccp(512,384);
[self addChild:bg];
toolBar = [CCSprite spriteWithFile:#"ToolBar.png"];
toolBar.position = ccp(512,-30);
[self addChild:toolBar];
score = [CCLabelAtlas labelWithString:#"0123456789" charMapFile:#"ScoreFinal.png" itemWidth:50 itemHeight:75 startCharMap:'.'];
[self addChild:score];
score.position = ccp (-100,15);
CCLabelTTF *scoreLabel = [CCLabelTTF labelWithString:#"Score:" fontName:#"Marker Felt" fontSize:45];
scoreLabel.position = ccp(score.position.x + 275,score.position.y + 40);
scoreLabel.color = ccc3(0, 0, 0);
[self addChild:scoreLabel];
star = [CCSprite spriteWithFile:#"Star.png"];
star.position = ccp(400,600);
[self addChild:star];
star2 = [CCSprite spriteWithFile:#"Star.png"];
star2.position = ccp(600,600);
star3 = [CCSprite spriteWithFile:#"Star.png"];
star3.position = ccp(200,600);
player = [CCSprite spriteWithFile:#"ball.png"];
player.position = ccp(500,300);
[self addChild:player];
enemy = [CCSprite spriteWithFile:#"SpaceShip.png"];
enemy.position = ccp(150,600);
[self addChild:enemy];
enemy2 = [CCSprite spriteWithFile:#"SpaceShip.png"];
enemy2.position = ccp(250,600);
[self addChild:enemy2];
enemy3 = [CCSprite spriteWithFile:#"SpaceShip.png"];
enemy3.position = ccp(350,600);
[self addChild:enemy3];
[self schedule:#selector(enemyMove) interval:0.01];
[self schedule:#selector(collisionDetection) interval:0.01];
[self schedule:#selector(getStar) interval:0.01];
NSString *string = [NSString stringWithFormat:#"Score: %i", (int)scoreNumber];
[score setString:string];
x = 15;
x2 = 15;
x3 = 15;
y = 15;
Bx = 10;
By = 10;
movePlayer = FALSE;
CCRepeatForever *repeat = [CCRepeatForever actionWithAction: [CCRotateBy actionWithDuration:2 angle:360]];
[star runAction:repeat];
star.visible = 1;
}
return self;
}
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView: [myTouch view]];
location = [[CCDirector sharedDirector]convertToGL:location];
CGRect playerRect = CGRectMake(player.position.x - (player.contentSize.width/2),
player.position.y - (player.contentSize.height/2),
player.contentSize.width,
player.contentSize.height);
CGRect Tlocation = CGRectMake(location.x, location.y, 10, 10);
NSLog(#"Touch Began");
if (CGRectIntersectsRect (Tlocation, playerRect)) {
player.position = location;
movePlayer = TRUE;
}
}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *myTouch = [touches anyObject];
CGPoint point = [myTouch locationInView:[myTouch view]];
point = [[CCDirector sharedDirector] convertToGL:point];
if (movePlayer == TRUE) {
player.position = point;
if (player.position.y < 110) {
player.position = ccp(player.position.x, 111);
}
}
}
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"Touch ended");
movePlayer = FALSE;
}
-(void) enemyMove {
enemy.position = ccp(enemy.position.x + x, enemy.position.y);
enemy2.position = ccp(enemy2.position.x - x2, enemy2.position.y);
enemy3.position = ccp(enemy3.position.x + x3, enemy3.position.y);
if (enemy.position.x > 1024 || enemy.position.x < 0) {
x = -x;
}
if (enemy2.position.x > 1024 || enemy2.position.x < 0) {
x2 = -x2;
}
if (enemy3.position.x > 1024 || enemy3.position.x < 0) {
x3 = -x3;
}
if (enemy.position.y > 768 || enemy.position.y < 120) {
y = -y;
}
}
-(void) collisionDetection {
if (CGRectIntersectsRect(player.boundingBox, enemy.boundingBox)) {
[self schedule:#selector(collisionAlert)];
}
if (CGRectIntersectsRect(player.boundingBox, enemy2.boundingBox)) {
[self schedule:#selector(collisionAlert)];
}
if (CGRectIntersectsRect(player.boundingBox, enemy3.boundingBox)) {
[self schedule:#selector(collisionAlert)];
}
}
-(void) getStar {
if (CGRectIntersectsRect(player.boundingBox, star.boundingBox)) {
NSLog(#"Got Star!");
scoreNumber += 100;
NSString *string = [NSString stringWithFormat:#"Score: %i", (int)scoreNumber];
[score setString:string];
[self addChild:star2];
if (star.visible == 1) {
}
}
if (CGRectIntersectsRect(player.boundingBox, star2.boundingBox)) {
NSLog(#"Got Star!");
scoreNumber += 100;
NSString *string = [NSString stringWithFormat:#"Score: %i", (int)scoreNumber];
[score setString:string];
[self addChild:star3];
}
if (CGRectIntersectsRect(player.boundingBox, star3.boundingBox)) {
youWin = [CCLabelTTF labelWithString:#"You Win" fontName:#"Marker Felt" fontSize:75];
youWin.position = ccp(500,400);
[self addChild:youWin];
[self setUpWinMenu];
NSLog(#"Got Star!");
scoreNumber += 100;
NSString *string = [NSString stringWithFormat:#"Score: %i", (int)scoreNumber];
[score setString:string];
player.position = ccp(player.position.x - 10, player.position.y - 20);
[self unschedule:#selector(enemyMove)];
[self unschedule:#selector(collisionAlert)];
[self unschedule:#selector(getStar)];
}
return;
}
-(void) collisionAlert {
player.position = ccp(player.position.x - 10, player.position.y - 20);
[self unschedule:#selector(enemyMove)];
UIAlertView* dialog = [[UIAlertView alloc] init];
[dialog setDelegate:self];
[dialog setTitle:#"Fail"];
[dialog setMessage:#"You are a Failure!"];
[dialog addButtonWithTitle:#"Goto Main Menu"];
[dialog addButtonWithTitle:#"Retry!"];
[dialog addButtonWithTitle:#"Dont push this button"];
[dialog show];
[dialog release];
[self unschedule:#selector(collisionAlert)];
}
-(void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex {
if(buttonIndex == 0) {
[[CCDirector sharedDirector] replaceScene:[CCTransitionFlipAngular transitionWithDuration:1 scene:[HelloWorldLayer node]]];
}
if (buttonIndex == 1) {
[[CCDirector sharedDirector] replaceScene:[Level_1 node]];
}
if (buttonIndex == 2) {
[self schedule:#selector(noting)];
}
}
-(void) gotoMainMenu {
[[CCDirector sharedDirector] replaceScene:[CCTransitionJumpZoom transitionWithDuration:1 scene:[HelloWorldLayer node]]];
}
#end
im not finished completely but there maybe a few empty methods but im sure thats not whats causing the problem
All this objects:
CCSprite *player;
CCSprite *enemy;
CCSprite *enemy2;
CCSprite *enemy3;
CCSprite *star;
CCSprite *star2;
CCSprite *star3;
CCSprite *bg;
CCSprite *toolBar;
are being allocated with autorelease methods, such as CCSprite spriteWithFile: and then, when you access these objects in other methods, like you do at ccTouchesBegan: withEvent: they are already deallocated, and you get the EXC_BAD_ACCESS
One thing you can do to fix it, is to call the spriteWithFile: method followed by a retain call, like
toolBar = [[CCSprite spriteWithFile:#"ToolBar.png"] retain];
But don't forget to release the retained objects on your Level_1's class dealloc (which I didn't see implemented in your class)
-(void) dealloc {
[toolBar release];
[super dealloc]
}
Even if you don't see anything on the console, if you run the app under the debugger, you should be able to inspect the call stack at the moment of the crash.
This will tell you clearly if you are accessing some already deallocated object, or possibly trying to send a message.

Cocos2D - Adding holes and different heights between buildings

I'm trying to build something similar to Canabalt, adding holes and different heights between buildings (modules). You can see a screenshot of how the game is looking right now at: http://twitpic.com/4kb5jd
Here is the code I'm currently using:
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init] )) {
moduleSize = 160;
screenSize = [[CCDirector sharedDirector] winSize];
CCSpriteFrameCache* frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
[frameCache addSpriteFramesWithFile:#"ModulesScene1.plist"];
CCTexture2D* gameArtTexture = [[CCTextureCache sharedTextureCache] addImage:#"ModulesScene1.png"];
// Create the background spritebatch
spriteBatch = [CCSpriteBatchNode batchNodeWithTexture:gameArtTexture];
[self addChild:spriteBatch];
numStripes = 1;
/* BEGIN MODULES */
NSString* frameName = [NSString stringWithFormat:#"Module0-hd.png"];
CCSprite* sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(0, screenSize.height / 2);
[spriteBatch addChild:sprite z:0 tag:0];
frameName = [NSString stringWithFormat:#"Module0-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake((moduleSize - 1.1f), screenSize.height / 2);
[spriteBatch addChild:sprite z:1 tag:1];
frameName = [NSString stringWithFormat:#"Module1-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake((moduleSize * 2) - 1.1f, screenSize.height / 2);
[spriteBatch addChild:sprite z:2 tag:2];
frameName = [NSString stringWithFormat:#"Module2-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(((moduleSize * 3) - 1.1f), screenSize.height / 2);
[spriteBatch addChild:sprite z:3 tag:3];
frameName = [NSString stringWithFormat:#"Module0-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(((moduleSize * 4) - 1.1f), screenSize.height / 2);
[spriteBatch addChild:sprite z:4 tag:4];
frameName = [NSString stringWithFormat:#"Module1-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(((moduleSize * 5) - 1.1f), screenSize.height / 2);
[spriteBatch addChild:sprite z:5 tag:5];
/* END MODULES */
// Get current scrollSpped
scrollSpeed = [[GameManager sharedGameManager] scrollSpeed];
speedFactors = [[CCArray alloc] initWithCapacity:numStripes];
[speedFactors addObject:[NSNumber numberWithFloat:2.5f]];
NSAssert([speedFactors count] == numStripes, #"speedFactors count does not match numStripes!");
[self scheduleUpdate];
}
return self;
}
-(void) update:(ccTime)delta
{
CCSprite* sprite;
scrollSpeed = [[GameManager sharedGameManager] scrollSpeed];
CCARRAY_FOREACH([spriteBatch children], sprite)
{
NSNumber* factor = [speedFactors objectAtIndex:0];
CGPoint pos = sprite.position;
pos.x -= scrollSpeed * [factor floatValue];
if (pos.x < -screenSize.width)
{
pos.x += ((screenSize.width * 2) - 2);
int x = (arc4random() % 3);
int xHole = (arc4random() % 10);
NSString *randomName = nil;
CCSpriteFrame *randomFrame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:randomName];
[sprite setDisplayFrame:randomFrame];
}
sprite.position = pos;
}
}
to add holes between the buildings you could add a simple rand() function like that in the init method:
...
sprite.position = CGPointMake(((moduleSize * 3) - 1.1f + (rand()%40)), screenSize.height / 2);
...
this will add a random gap (max 40 points)

Resources