Updating my HUD class through a SceneManager class - objective-c

I'm doing an iPhone app (game) for University. I'm accessing the HUD class so I can update a label when progress is made through the game. Have I got a bad architecture to do this? Or how can I do it?
HUD Class
#implementation HUD
#synthesize statBar;
#synthesize levelText;
#synthesize label;
#synthesize level;
- (id) init {
if((self = [super init])) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
statBar = [CCSprite spriteWithFile:#"statbar.png"];
statBar.position = ccp(winSize.width/2, winSize.height-10);
levelText = [self createLevelText:10]; // testing purposes
levelText.position = ccp(((winSize.width)-(winSize.width)+20), winSize.height-10);
levelText.color = ccBLACK;
[self addChild:statBar];
[self addChild:levelText];
}
return self; // shouldnt reach this
}
- (CCLabelTTF *) createLevelText:(int)levelNo {
level = [NSString stringWithFormat:#"LVL: %d", levelNo];
label = [CCLabelTTF labelWithString:(NSString*) level fontName:#"CharlemagneStd-Bold.otf" fontSize:10];
//[label setString:(NSString *) level];
return label;
}
#end
ScreenManager Class (Relevant Code)
CCLayer *hudLayer;
int hudTag;
+(void) goPlay
{
hudLayer = [HUD node];
CCLayer *playLayer = [PlayLayer node];
hudTag = playLayer.tag;
[SceneManager goWithHud: playLayer: hudLayer: hudTag];
}
+ (CCScene *) goWithHud:(CCLayer *) playLayer:(CCLayer *) hudLayer:(int)hudTag
{
CCDirector *director = [CCDirector sharedDirector];
CCScene *newScene = [CCScene node];
[newScene addChild: playLayer];
[newScene addChild: hudLayer z:0 tag:hudTag];
if([director runningScene])
[director replaceScene:newScene];
else
[director runWithScene:newScene];
return newScene;
}
+(void)setScoreString:(int *)levelNo:(CCLayer *) hudLayer
{
NSString *string = [NSString stringWithFormat:#"LVL: %d", levelNo];
hudLayer.levelText = string;
}
-(void)updateScore
{
HUD *obj = (HUD *)[self getChildByTag:hudTag];
[obj setScoreString:#"100"];
}

Related

Trying to make SplashScene (Cocos2d) form the book of Pablo Ruiz, and it doesnt work

I add this scene to project and run it at ProjectRunDelegate
it fell when method cFadeAndShow starts
Can anybody tell me whats the problem?
im using xCode 3.2.6
and cocos2d 1.0.1
Or maybe someone already has working splash scene to show some company's logos on starts of game
Thanks
#import "SplashScene.h"
#implementation SplashScene
-(id) init {
if ( (self = [super init])) {
[self addChild:[SplashLayer node]];
}
return self;
}
-(void)dealloc{
[super dealloc];
}
#end
#implementation SplashLayer
-(id) init {
if ( (self = [super init])) {
self.isTouchEnabled = YES;
NSMutableArray * splashImages = [[NSMutableArray alloc] init];
for (int i =1; i<=2; i++) {
CCSprite *splashImage = [CCSprite spriteWithFile:[NSString stringWithFormat:#"splash%d.png",i]];
if (splashImage == nil) {
CCLOG(#"splashImage is nil");
}
[splashImage setPosition:ccp(240,160)];
[self addChild:splashImage];
if (i!=1)
[splashImage setOpacity:0];
[splashImages addObject:splashImage];
}
[self fadeAndShow:splashImages];
}
return self;
}
-(void) fadeAndShow:(NSMutableArray *) images{ // add the meehods
if ([images count]<=1) {
[images release];
[[CCDirector sharedDirector]replaceScene:[GameScene scene]];
}
else {
CCSprite *actual = (CCSprite *)[images objectAtIndex:0];
[images removeObjectAtIndex:0];
CCSprite * next = (CCSprite *)[images objectAtIndex:0];
[actual runAction:[CCSequence actions:[CCDelayTime actionWithDuration:2], [CCFadeOut actionWithDuration:1],
[CCCallFuncN actionWithTarget:self selector:#selector(remove:)],nil]];
[next runAction:[CCSequence actions:[CCDelayTime actionWithDuration:2], [CCFadeIn actionWithDuration:1],
[CCDelayTime actionWithDuration:2],
[CCCallFuncND actionWithTarget:self selector:#selector(cFadeAndShow:data:) data:images],nil]];
}
}
-(void) cFadeAndShow:(id)sender dara:(void*)data{
NSMutableArray * images = (NSMutableArray *) data;
[self fadeAndShow:images];
}
-(void)remove:(CCSprite *)s{
[s.parent removeChild:s cleanup:YES];
}
-(void)dealloc{
[super dealloc];
}
#end
Here's an answer:
[[CCDirector sharedDirector] replaceScene: [CCTransitionZoomFlipAngular
transitionWithDuration:2
scene:[GameScene node]
orientation:kOrientationLeftOver]];

CCLayer is null

I am trying to change the color of a CCLayerColor called bgColorLayer, however when I check to see if it is initialized it returns null. I have a color picker that calls the setBGColor: method. I know the colorpicker is calling the method and it is spitting out the correct colors. I am just at a loss as to why the bgColorLayer is null.
This is Cocos2D for Mac.
Any thoughts on why?
In my AppDelegeate method I have an IBOUTLET that is is tied to the NSColorWell
- (IBAction)colorwellBackground:(id)sender {
NSLog(#"Color Well: %#", [sender color]);
// Yes I know the sender color isn’t passing the correct value
AnimationViewerLayer * bkg = [AnimationViewerLayer alloc];
[bkg setBGColor:[sender color]];
}
AnimationViewerLayer.h
#interface AnimationViewerLayer : CCLayer
{
CCLayerColor * bgColorLayer;
}
+ (CCScene *) scene;
#end
AnimationViewLayer.m
#import "AnimationViewerLayer.h"
#implementation AnimationViewerLayer
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
AnimationViewerLayer *layer = [AnimationViewerLayer node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if( (self=[super init])) {
float red = 25.0 * 255;
bgColorLayer = [CCLayerColor layerWithColor:ccc4(57, 109, 58, 255)];
[self addChild:bgColorLayer z:1];
}
return self;
}
- (void) setBGColor: (ccColor3B) color{
NSLog(#"SET BG COLOR");
[bgColorLayer setColor:ccRED];
}
- (void) dealloc {
[super dealloc];
}
#end

Dealloc gives warnings

I am practicing making a simple app that switches scenes with a scene controller (state manager) class.
I created my scene:
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
GameMenu *layer = [GameMenu node];
[scene addChild: layer];
return scene;
}
-(id)init{
if ((self = [super init])){
self.isTouchEnabled = YES;
CGSize winSize = [[CCDirector sharedDirector] winSize];
gameMenuLabel = [CCLabelTTF labelWithString:#"This is the Main Menu. Click to Continue" fontName:#"Arial" fontSize:13];
gameMenuLabel.position = ccp(winSize.width/2, winSize.height/1.5);
[self addChild:gameMenuLabel];
}
return self;
}
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"ccTouchesBegan: called from MainMenu object");
[[StateManager sharedStateManager] runSceneWithID:kGamePlay];
}
-(void)dealloc{
[gameMenuLabel release];
gameMenuLabel = nil;
[super dealloc];
}
#end
But I keep getting this warning: https://dl.dropbox.com/u/1885149/Screen%20Shot%202012-10-06%20at%205.23.43%20PM.png (probably not much help, but figured I would link the screenshot.
I think it has something to do with the dealloc. If I comment out the dealloc in my scene, I do not get this warning. Any help would be greatly appreciated, thanks.
This is my statemanager's method for switching scenes:
-(void)runSceneWithID:(SceneTypes)sceneID {
SceneTypes oldScene = currentScene;
currentScene = sceneID;
id sceneToRun = nil;
switch (sceneID) {
case kSplashScene:
sceneToRun = [SplashScene node];
break;
case kGameMenu:
sceneToRun = [GameMenu node];
break;
case kGamePlay:
sceneToRun = [GamePlay node];
break;
case kGameOver:
sceneToRun = [GameOver node];
break;
default:
CCLOG(#"Unknown ID, cannot switch scenes");
return;
break;
}
if (sceneToRun == nil) {
// Revert back, since no new scene was found
currentScene = oldScene;
return;
}
if ([[CCDirector sharedDirector] runningScene] == nil) {
[[CCDirector sharedDirector] runWithScene:sceneToRun];
} else {
[[CCDirector sharedDirector] replaceScene:sceneToRun];
}
}
You should give a retain property to gameMenuLabel like this
#property (nonatomic, retain) CCLabelTTF* gameMenuLabel; //in .h file
And write this....
self.gameMenuLabel = [CCLabelTTF labelWithString:#"This is the Main Menu. Click to Continue" fontName:#"Arial" fontSize:13];
instead of this...
gameMenuLabel = [CCLabelTTF labelWithString:#"This is the Main Menu. Click to Continue" fontName:#"Arial" fontSize:13];
The problem is that you are giving an autoreleased object to gameMenuLabel and then releasing again that object in the dealloc section. Hence, the crash.

Strange Crash, No Debugger Clues

I am currently running this Block of code in my Level1.m file, this is the scene for the first level of my game.
#import "BankerL1.h"
#import "GameOverScene.h"
#import "BankerGameWin1.h"
// HelloWorldLayer implementation
#implementation BankerL1Layer
#synthesize label = _label;
#synthesize Banker = _Banker;
#synthesize WalkAction = _WalkAction;
#synthesize MoveAction = _MoveAction;
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
BankerL1Layer *layer = [BankerL1Layer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// 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])) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *background = [CCSprite spriteWithFile:#"Ninja Menu Background.png"];
background.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:background z:-1];
CCLabelTTF *Levelcounter = [CCLabelTTF labelWithString:#"Level 1" fontName:#"Marker Felt" fontSize:40];
Levelcounter.position = ccp(winSize.width * 0.80,winSize.height * 0.92);
[self addChild: Levelcounter];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: #"GreenorcSpriteSheet_default.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"GreenorcSpriteSheet_default.png"];
[self addChild:spriteSheet];
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <=6; ++i) {
[walkAnimFrames addObject: [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:#"Greenorc%d.png", i]]];
}
CCAnimation *walkAnim = [CCAnimation animationWithFrames:walkAnimFrames delay:0.1f];
self.Banker = [CCSprite spriteWithSpriteFrameName:#"Greenorc1.png"];
_Banker.position = ccp(winSize.width/2, (winSize.height/2)-190);
self.WalkAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]];
//[_Banker runAction:_WalkAction];
[spriteSheet addChild:_Banker];
self.isTouchEnabled = YES;
_targets = [[NSMutableArray alloc] init];
}
return self;
}
- (void) onEnter
{
// First, call super if you override this. ALWAYS.
[super onEnter];
[self schedule:#selector(gameLogic:) interval:1.5];
[self scheduleUpdate]; // use this instead of schedule: if it's for an update method.
}
//Implements the Callback function above
-(void)gameLogic:(ccTime)dt {
[self addTarget];
}
-(void)spriteMoveFinished:(id)sender {
CCSprite *sprite = (CCSprite *)sender;
[self removeChild:sprite cleanup:YES];
if (sprite.tag == 1) { // target
[_targets removeObject:sprite];
GameOverScene *gameOverScene = [GameOverScene node];
[gameOverScene.layer.label setString:#"You Lose :["];
[[CCDirector sharedDirector] replaceScene:gameOverScene];
} else if (sprite.tag == 2) { // projectile
[_targets removeObject:sprite];
}
}
//Adds the "targets" or in this case enemies, to the scene and spawns/moves them
-(void)addTarget {
CCSprite *target = [CCSprite spriteWithFile:#"seeker.png"
rect:CGRectMake(0, 0, 40, 40)];
target.tag = 1;
[_targets addObject:target];
// Determine where to spawn the target along the X axis
CGSize winSize = [[CCDirector sharedDirector] winSize];
int minX = target.contentSize.height/2;
int maxX = winSize.height - target.contentSize.height/2;
int rangeX = maxX - minX;
int actualX = (arc4random() % rangeX) + minX;//Randomizes the place it will spawn on X- Axis
// Create the target slightly off-screen along the top edge,
// and along a random position along the Y axis as calculated above
target.position = ccp(actualX, winSize.height + (target.contentSize.height/2));
[self addChild:target];
// Determine speed of the target
int minDuration = 2.0;
int maxDuration = 5.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;//Speed is randomized between 2 and 5
// Create the actions
id actionMove = [CCMoveTo actionWithDuration:actualDuration
position:ccp(actualX, -target.contentSize.height/2)];
id actionMoveDone = [CCCallFuncN actionWithTarget:self
selector:#selector(spriteMoveFinished:)];
[target runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
}
//WHEN THE THINGS COLLIDE, THEY DISSAPEAR
- (void)update:(ccTime)dt {
CGSize winSize = [[CCDirector sharedDirector] winSize];
NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];
for (CCSprite *target in _targets) {
CGRect targetRect = CGRectMake(
target.position.x - (target.contentSize.width/2),
target.position.y - (target.contentSize.height/2),
target.contentSize.width,
target.contentSize.height);
BOOL playerHit = FALSE;
for (CCSprite *player in _targets) {
CGRect playerRect = CGRectMake(
player.position.x - (player.contentSize.width/2),
player.position.y - (player.contentSize.height/2),
player.contentSize.width,
player.contentSize.height);
if (CGRectIntersectsRect(playerRect, targetRect)) {
//[targetsToDelete addObject:target];
playerHit = TRUE;
[targetsToDelete addObject:target];
break;
}
}
for (CCSprite *target in targetsToDelete) {
[_targets removeObject:target];
[self removeChild:target cleanup:YES];
_targetsDestroyed++;
[_label setString:[NSString stringWithFormat:#""]];
if (_targetsDestroyed > 30) {
GameWinScene *gameWinScene = [GameWinScene node];
_targetsDestroyed = 0;
[[CCDirector sharedDirector] replaceScene:gameWinScene];
} else{
NSString *killcounttext = [NSString stringWithFormat:#"Catches: %i", _targetsDestroyed];
self.label = [CCLabelTTF labelWithString:killcounttext fontName:#"Zapfino" fontSize:20];
_label.color = ccc3(225,225,225);
_label.position = ccp(winSize.width * 0.20,winSize.height * 0.92);
[self addChild:_label];
}
}
if (targetsToDelete.count > 0) {
[targetsToDelete addObject:target];
}
[targetsToDelete release];
}
for (CCSprite *target in targetsToDelete) {
[_targets removeObject:target];
[self removeChild:target cleanup:YES];
//[[SimpleAudioEngine sharedEngine] playEffect:#"ProjectileHit.wav"];
}
[targetsToDelete release];
}
-(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];
float bankerVelocity = 320.0/2.0;
CGPoint moveDifference = ccpSub(touchLocation, _Banker.position);
float distanceToMove = ccpLength(moveDifference);
float moveDuration = distanceToMove / bankerVelocity;
if (moveDifference.x < 0) {
_Banker.flipX = NO;
} else {
_Banker.flipX = YES;
}
[_Banker stopAction:_MoveAction];
if (!_Moving) {
[_Banker runAction:_WalkAction];
}
self.MoveAction = [CCSequence actions:
[CCMoveTo actionWithDuration:moveDuration position:touchLocation],
[CCCallFunc actionWithTarget:self selector:#selector(bearMoveEnded)],
nil];
[_Banker runAction:_MoveAction];
_Moving = TRUE;
}
-(void)bearMoveEnded {
[_Banker stopAction:_WalkAction];
_Moving = FALSE;
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
// in this particular example nothing needs to be released.
// cocos2d will automatically release all the children (Label)
self.Banker = nil;
self.WalkAction = nil;
// don't forget to call "super dealloc"
[super dealloc];
}
#end
The scene starts and everything works fine except as soon as a target is added (this is what I think is happeneing) the game freezes and crashes.
I don't know if the target being added is what is causing the crash, but it seems that whenever it is time for the target to come on, it crashes.
There is nothing in the debugger that says the game crashed, Xcode things the game is still running even though it is frozen. Please help :/ thanks
retain the _targets array in the init method like this: _targets = [[[NSMutableArray alloc] init] retain];

How to unload images in Cocos2d

I am working with cocos2d. At the first Default.png load as first splash, then splash1.png load as second splash. I see in Instruments, that memory don't free when I replace scene. How can I unload images from memory? Thanks!
#import "cocos2d.h"
#import "MainMenu.h"
#interface Splash : CCLayer {
NSMutableArray *m_pSplashes;
int m_nCurrentSplash;
CGSize m_szWinSize;
CCSequence *m_pSequence, *m_pSequenceDefault;
CCCallFunc *m_pCall;
CCSprite *m_pSplashDefault, *splash;
id m_pFadein, m_pDelay, m_pFadeout;
}
#property(nonatomic, retain) CCSequence *m_pSequence;
+(id) scene;
-(void) showNext: (id) sender;
#end
Implementation file
#import "Splash.h"
#implementation Splash
#synthesize m_pSequence;
+(id) scene {
CCScene *scene = [CCScene node];
Splash *layer = [Splash node];
[scene addChild: layer];
return scene;
}
-(id) init {
if( (self=[super init]) ) {
m_szWinSize = [[CCDirector sharedDirector] winSize];
m_pFadein = [CCFadeIn actionWithDuration:2];
m_pDelay = [CCDelayTime actionWithDuration:2];
m_pFadeout = [CCFadeOut actionWithDuration:2];
m_pCall = [CCCallFunc actionWithTarget:self selector:#selector(showNext:)];
m_nCurrentSplash = 0;
m_pSplashes = [[NSMutableArray alloc] init];
m_pSequenceDefault = [CCSequence actions:m_pFadeout, m_pCall, nil];
[m_pSplashes addObject:#"splash1.png"];
m_pSplashDefault = [[[CCSprite alloc] initWithFile:#"Default.png"] autorelease];
[m_pSplashDefault setRotation:-90];
[m_pSplashDefault setPosition:ccp(m_szWinSize.width/2, m_szWinSize.height/2)];
[self addChild:m_pSplashDefault];
[m_pSplashDefault runAction:m_pSequenceDefault];
[m_pFadein retain];
[m_pDelay retain];
[m_pFadeout retain];
[m_pCall retain];
}
return self;
}
-(void) showNext: (id) sender {
if ( m_nCurrentSplash >= [m_pSplashes count] )
{
CCScene *scene = [CCScene node];
id child = [MainMenu node];
[scene addChild:child];
[[CCDirector sharedDirector] replaceScene: [CCFadeTransition transitionWithDuration:1 scene:scene]];
[m_pCall release];
}
else
{
splash = [[[CCSprite alloc] initWithFile:[m_pSplashes objectAtIndex:m_nCurrentSplash]] autorelease];
[splash setPosition:ccp(m_szWinSize.width/2, m_szWinSize.height/2)];
splash.tag = 1;
[self addChild:splash];
m_nCurrentSplash ++;
m_pSequence = [CCSequence actions:m_pFadein, m_pDelay, m_pFadeout, m_pCall, nil];
[splash runAction:m_pSequence];
}
}
-(void) dealloc {
NSLog ( #"dealloc" );
[m_pSplashes release];
[m_pFadein release];
[m_pDelay release];
[m_pFadeout release];
[self removeAllChildrenWithCleanup:YES];
[super dealloc];
}
#end
Either you manually handle by using
[[CCTextureCache sharedTextureCache]removeTexture:(CCTexture2D *)tex]
or:
[[CCTextureCache sharedTextureCache] removeUnusedTextures];
if you are sure the texture is no longer being use.