Not accessing function in Objective-C - ios

I'm currently trying to access a function on another file.(another layer, to be more precise).
Both layers are on a scene.
Third layer is trying to get a function from first layer...
Here's how I'm doing this:
Here's my scene in scene.h
#import "firstLayer.h"
#import "secondLayer.h"
#import "thirdLayer.h"
#interface myScene : CCScene
{
// custom instance vars here...
}
#end
Here's how I cast my scene in scene.m
-(id)init {
self = [super init];
if(self != nil){
firstLayer *firstLayerz = [firstLayer node];
[firstLayerz setTag:111];
[self addChild:firstLayerz z:0];
secondLayer *secondLayerz = [secondLayer node];
[secondLayer setTag:112];
[self addChild:secondLayer z:2];
thirdLayer *thirdLayerz = [thirdLayer node];
[thirdLayerz setTag:113];
[self addChild:thirdLayerz z:4];
Here's how I cast the function in thirdLayer.m
#import "scene.h"
#implementation thirdLayer.m
-(id)init {
self = [super init];
if(self != nil){
firstLayer* firstLayerz = (firstLayer*)[self.parent getChildByTag:111];
[firstLayerz functionNeeded];
}
Here's functionNeeded in firstLayer.m (right below init(
-(void)functionNeeded {
NSLog(#"inside fnnction needed");
}
Of course the log ain't showing...
I do the proper cast in firstLayer.h
#interface firstLayer : CCLayer {
}
-(void)functionNeeded;
#end

In your firstLayer's init method write
self.tag = 111;
Now in your ThirdLayer where you want to call method of first layer write :
CCScene *current = [[CCDirector sharedDirector] runningScene];
if (current) {
id layer = [current getChildByTag:111];
if (layer) {
[layer functionNeeded];
}
}

Related

add two custom sprites into a scene,why do these sprites' methods will effect each other,anyone can find the mistake in my code? thanks

this is custom sprite class named BackGround
#import "BackGround.h"
// -----------------------------------------------------------------
id move02;
double roadX;
#implementation BackGround
+ (instancetype)initWithPicture: (NSString *) pic
{
return [[self alloc] init:pic];
}
-(id) init: (NSString *) pic
{
if(self = [super init])
{
CCSpriteFrameCache* spriteFrameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
CCSpriteFrame * bgSpriteFrame = [spriteFrameCache spriteFrameByName:pic];
self = [BackGround spriteWithSpriteFrame:bgSpriteFrame];
self.anchorPoint = ccp(0, 0);
roadX = -(self.contentSize.width-1)*2;
self.position = ccp((-roadX/2), 0);
id move01 = [CCActionMoveBy actionWithDuration:10.0f position:ccp(roadX,0.0)];
move02 = [CCActionRepeatForever actionWithAction:move01];
[self runAction:move02];
}
return self;
}
-(void)bgWhenRun
{
[self stopAllActions];
id move = [CCActionSpeed actionWithAction:move02 speed:2];
[self runAction:move];
}
-(void)bgWhenWalk
{
[self stopAllActions];
[self runAction:move02];
}
// -----------------------------------------------------------------
#end
this is scene class code
#import "_256Deathes.h"
#import "IntroScene.h"
#import "BackGround.h"
#import "cocos2d.h"
#import "Person.h"
// -----------------------------------------------------------------
Person * personA;
#implementation _256Deathes
{
}
- (instancetype)init
{
if ((self = [super init]))
{
NSAssert(self, #"Whoops");
self.userInteractionEnabled = YES;
CCSpriteFrameCache* spriteFrameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
[spriteFrameCache addSpriteFramesWithFile:#"256Deathes.plist"];
BackGround * bgSprite01 = [BackGround initWithPicture:#"earthA.png"];
bgSprite01.position = ccp(0, 0);
[self addChild:bgSprite01 z:0 name:#"bgSpriteA"];
BackGround * bgSprite02 = [BackGround initWithPicture:#"earthA.png"];
[self addChild:bgSprite02 z:1 name:#"bgSpriteB"];
}
return self;
}
- (void)onEnter
{
// always call super onEnter first
[super onEnter];
[self schedule:#selector(updateSprite) interval:0.02];
}
-(void)touchBegan:(CCTouch *)touch withEvent:(CCTouchEvent *)event
{
BackGround *spriteA = (BackGround *)[self getChildByName:#"bgSpriteA" recursively:NO];
BackGround *spriteB = (BackGround *)[self getChildByName:#"bgSpriteB" recursively:NO];
[spriteA bgWhenRun];
[spriteB bgWhenRun];
}
-(void)touchEnded:(CCTouch *)touch withEvent:(CCTouchEvent *)event
{
BackGround *sprite;
for(sprite in [self children])
{
if([sprite.name containsString:#"bgSprite"])
{
[sprite bgWhenWalk];
}
}
}
-(void) updateSprite
{
[self updateBackGround01];
}
-(void) updateBackGround01
{
BackGround *sprite;
for(sprite in [self children])
{
if([sprite.name containsString:#"bgSprite"])
{
double nextX = sprite.contentSize.width-3;
if(sprite.position.x <= (-nextX))
{
sprite.position = ccp(nextX, 0);
}
}
}
}
// -----------------------------------------------------------------
#end
when i touch begin or touch end, spriteA will stop moving, after i tried some times, i found [self stopAllActions] in methods named bgWhenRun and bgWhenWalk can make spriteA and spriteB effect each other.
anyone can find out the mistakes in the code then tell me?i have tried many times,now i really have no idea. thank you!
These two sprites effect each other because both are using same instance of variables id move02 and double roadX as being global ones. Declare them within scope of BackGround class i.e. as member variables of that class.

Why a use of undeclared identifier?

Why does my code say I'm using an undeclared identifier with 'hero' in shootAt in the line fourth from the end.
#import "GameplayLayer.h"
#import "Ship.h"
#import "MainCharacter.h"
#import "GameOverLayer.h"
int screenHeight;
int screenWidth;
#implementation GameplayLayer
-(id) init
{
if ((self = [super init]))
{
screenHeight = [[CCDirector sharedDirector] screenSize].height;
screenWidth = [[CCDirector sharedDirector] screenSize].width;
MainCharacter * hero = [[MainCharacter alloc] init];
[self addChild: hero];
hero.position = ccp(screenWidth/2, screenHeight/10);
Ship * ship1 = [[Ship alloc] init];
[self addChild: ship1];
numEnemies++;
ship1.position = ccp(screenWidth/2, screenHeight/2);
}
return self;
[self scheduleUpdate];
}
-(void) update: (ccTime) dt
{
KKInput * input = [KKInput sharedInput];
CGPoint touchPosition = [input locationOfAnyTouchInPhase:KKTouchPhaseBegan];
if (touchPosition.x != 0.0 || touchPosition.y != 0.0)
{
[hero shootAt: ccp(screenWidth/2, screenHeight)];
}
}
#end
Because hero is local variable defined in the constructor and hence not visible in other methods.
I think this is the problem of scope of variable, You declared
hero
in your
init Method
and trying to access this variable in
update Method (So hero is a local variable for init Method and undeclared for Update Method).
Update your code Like this, If you want a global Access of
hero object,
int screenHeight;
int screenWidth;
MainCharacter * hero;
And then initialize it in your init Method and access it in all other methods of same class.

Adding a subclass of CCSprite to a scene

I've recently decided to subclass my sprite, but I am a bit clueless on how to add them to a scene. At the moment, I have created my CCSprite subclass, using New File>Cocos2d>CCNode>Subclass of... CCSprite. Then, I have made my sprite in the Sprite.h file:
#interface Mos : CCSprite {
CCSprite *mos;
}
Once this is done, in the Sprite.m I code this:
#implementation Mos
-(id) init
{
if( (self=[super init])) {
mos = [CCSprite spriteWithFile:#"sprite_mos.png"];
}
return self;
}
What I want to know is how to then add this sprite into my game's scene.
Here is how to correctly subclass CCSprite as the documentation says:
#interface Mos : CCSprite {
// remove the line CCSprite *mos;
}
#implementation Mos
// You probably don't need to override this method if you will not add other code inside of it
-(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect
{
if( (self=[super initWithTexture:texture rect:rect]))
{
}
return self;
}
+ (id)sprite
{
return [Mos spriteWithFile:#"sprite_mos.png"];
}
#end
Then in your code, you can use Mos normally:
Mos *mos = [Mos sprite];
[scene addChild:mos];
The same way you add CCSprites and other classes.
Mos *newMos = [[Mos alloc] init];
// set coordinates and other properties
[scene addChild:newMos];
[newMos release];
Edit:
#interface Mos : CCSprite {
// some member variables go here
}
#implementation Mos
-(id)init
{
CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage:#"sprite_mos.png"];
if( texture ) {
CGRect rect = CGRectZero;
rect.size = texture.contentSize;
// set members to some values
return [self initWithTexture:texture rect:rect];
}
[self release];
return nil;
}
And then in your scene class
// ...
Mos *obj = [[Mos alloc] init];
// set position, etc
[scene addChild:obj];
[obj release];
// ...

Adding a Layer to a Scene does not work

I have been trying to get a layer into my scene. My scene is called "Survival". My layer is called "SSpriteLayer". The scene initializes, but the layer doesn't.
SURVIVAL.H:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "SSpriteLayer.h"
#interface Survival : CCLayer {}
#end
SURVIVAL.M:
#implementation Survival
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
Survival *layer = [Survival node];
SSpriteLayer *spriteLayer = [SSpriteLayer node];
// add layer as a child to scene
[scene addChild: layer];
[scene addChild: spriteLayer];
// return the scene
return scene;
}
-(id) init
{
if( (self=[super init]))
NSLog(#"SCENE HAS INIT");
return self;
}
#end
SSPRITELAYER.H:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface SSpriteLayer : CCLayer {
}
#end
SSPRITELAYER.M:
#import "SSpriteLayer.h"
#implementation SSpriteLayer
-(id) init
{
if( (self=[super init]))
NSLog(#"SPRITELAYER HAS INIT");
return self;
}
#end
What I do not understand is why my layer isn't initizializing, and why I am not getting the message "SPRITELAYER HAS INIT" in the debug area.
// add layer as a child to scene
[self addChild: layer];
[self addChild: SpriteLayer];
Change it And Try
Make sure, that you call
[Survival scene];
not
[Survival node];
and post code with calling your scene here

Cocos2d - Initial app layer displays incorrectly on app load, displays appropriately after reload

I'm using a GameManager singleton to handle some of the shared tasks required by my game. One of those tasks is loading individual game scenes. When the game starts up, whichever scene/layer combo I have displayed appears incorrectly; it looks like maybe the coordinates that items are positioned in relation to are wrong.
It doesn't matter which layer I choose–they all appear incorrectly. If you click on a button and load another scene/layer, then go back to the scene/layer in question, everything displays correctly. This only happens on retina display devices, so I think it might be related to the scaling I set for the different display types in the game manager. However, changing the scaling for Retina displays breaks things even more (the layers are too small).
Here's my AppDelegate.h
#import <UIKit/UIKit.h>
#class RootViewController;
#interface AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
RootViewController *viewController;
}
#property (nonatomic, retain) UIWindow *window;
#end
AppDelegat.m
#import "cocos2d.h"
#import "AppDelegate.h"
#import "GameConfig.h"
#import "RootViewController.h"
#import "GameplayScene.h"
#import "GameManager.h"
#implementation AppDelegate
#synthesize window;
- (void) removeStartupFlicker
{
#if GAME_AUTOROTATION == kGameAutorotationUIViewController
#endif
}
- (void) applicationDidFinishLaunching:(UIApplication*)application
{
// Init the window
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Try to use CADisplayLink director
// if it fails (SDK < 3.1) use the default director
if( ! [CCDirector setDirectorType:kCCDirectorTypeDisplayLink] )
[CCDirector setDirectorType:kCCDirectorTypeDefault];
CCDirector *director = [CCDirector sharedDirector];
// Init the View Controller
viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
viewController.wantsFullScreenLayout = YES;
EAGLView *glView = [EAGLView viewWithFrame:[window bounds]
pixelFormat:kEAGLColorFormatRGB565 // kEAGLColorFormatRGBA8
depthFormat:0 // GL_DEPTH_COMPONENT16_OES
];
// attach the openglView to the director
[director setOpenGLView:glView];
[director setDeviceOrientation:kCCDeviceOrientationPortrait];
[director setAnimationInterval:1.0/60];
[director setDisplayFPS:YES];
// make the OpenGLView a child of the view controller
[viewController setView:glView];
// make the View Controller a child of the main window
[window addSubview: viewController.view];
[window makeKeyAndVisible];
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
// Removes the startup flicker
[self removeStartupFlicker];
// Run the intro Scene
//[[CCDirector sharedDirector] runWithScene:[GameplayScene node]];
[[GameManager sharedGameManager] runSceneWithID:kMainMenuScene];
}
- (void)dealloc {
[[CCDirector sharedDirector] end];
[window release];
[super dealloc];
}
GameManager.h
#import <Foundation/Foundation.h>
#import "Constants.h"
#import "CommonProtocols.h"
#interface GameManager : NSObject {
BOOL isMusicON;
BOOL isSoundEffectsON;
BOOL hasPlayerDied;
BOOL newHighScore;
BOOL newBestTime;
BOOL isUiTextLeft;
int currentScore;
int highScore;
int lengthPlayed;
int bestTime;
int randomPurple;
int randomGreen;
int timeBonus;
int timeTillDeath;
int uiBackgroundHeight;
CharacterStates previousPurpleState;
CharacterStates previousGreenState;
SceneTypes currentScene;
}
#property (readwrite) BOOL isMusicON;
#property (readwrite) BOOL isSoundEffectsON;
#property (readwrite) BOOL hasPlayerDied;
#property (readwrite) BOOL newHighScore;
#property (readwrite) BOOL newBestTime;
#property (readwrite) BOOL isUiTextLeft;
#property (readwrite) int currentScore;
#property (readwrite) int highScore;
#property (readwrite) int lengthPlayed;
#property (readwrite) int bestTime;
#property (readwrite) int randomPurple;
#property (readwrite) int randomGreen;
#property (readwrite) int uiBackgroundHeight;
#property (readwrite) CharacterStates previousPurpleState;
#property (readwrite) CharacterStates previousGreenState;
#property (readwrite) int timeBonus;
#property (readwrite) int timeTillDeath;
+(GameManager*)sharedGameManager;
-(void)runSceneWithID:(SceneTypes)sceneID;
-(void)openSiteWithLinkType:(LinkTypes)linkTypeToOpen ;
#end
GameManager.m
#import "GameManager.h"
#import "GameplayScene.h"
#import "MainMenuScene.h"
#import "OptionsScene.h"
#import "CreditsScene.h"
#import "IntroScene.h"
#import "LevelCompleteScene.h"
#implementation GameManager
static GameManager* _sharedGameManager = nil;
#synthesize isMusicON;
#synthesize isSoundEffectsON;
#synthesize hasPlayerDied;
#synthesize newHighScore;
#synthesize newBestTime;
#synthesize isUiTextLeft;
#synthesize currentScore;
#synthesize highScore;
#synthesize lengthPlayed;
#synthesize bestTime;
#synthesize previousPurpleState;
#synthesize previousGreenState;
#synthesize randomPurple;
#synthesize randomGreen;
#synthesize timeBonus;
#synthesize timeTillDeath;
#synthesize uiBackgroundHeight;
+(GameManager*)sharedGameManager {
#synchronized([GameManager class])
{
if(!_sharedGameManager)
[[self alloc] init];
return _sharedGameManager;
}
return nil;
}
+(id)alloc {
#synchronized([GameManager class]){
NSAssert(_sharedGameManager == nil, #"Attempted to allocate a second instance of the Game Manager singleton");
_sharedGameManager = [super alloc];
return _sharedGameManager;
}
return nil;
}
-(id) init {
self = [super init];
if (self != nil) {
// Game manager initialized
CCLOG(#"Game manager singleton, init");
hasPlayerDied = NO;
// DECODING INFO FROM DEFAULTS
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [dirPaths objectAtIndex:0];
NSMutableData *gameData;
NSKeyedUnarchiver *decoder;
NSString *documentPath = [documentsDirectory stringByAppendingPathComponent:#"gameState.dat"];
gameData = [NSData dataWithContentsOfFile:documentPath];
if (gameData) {
decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:gameData];
highScore = [decoder decodeIntForKey:#"highScore"];
bestTime = [decoder decodeIntForKey:#"bestTime"];
isMusicON = [decoder decodeBoolForKey:#"isMusicON"];
isSoundEffectsON = [decoder decodeBoolForKey:#"isSoundEffectsON"];
isUiTextLeft = [decoder decodeBoolForKey:#"isUiTextLeft"];
//currentScore = [decoder decodeIntForKey:#"currentScore"];
[decoder release];
} else {
highScore = 0;
bestTime = 0;
isMusicON = TRUE;
isSoundEffectsON = TRUE;
isUiTextLeft = TRUE;
//currentScore = 0;
}
CCLOG(#"Music - %s", isMusicON ? "true" : "false");
CCLOG(#"Sound - %s", isSoundEffectsON ? "true" : "false");
//****************************
currentScore = 0;
timeBonus = 0;
timeTillDeath = 0;
uiBackgroundHeight = 0;
currentScene = kNoSceneUninitialized;
}
return self;
}
-(void)runSceneWithID:(SceneTypes)sceneID {
SceneTypes oldScene = currentScene;
currentScene = sceneID;
id sceneToRun = nil;
switch (sceneID) {
case kMainMenuScene:
sceneToRun = [MainMenuScene node];
break;
case kOptionsScene:
sceneToRun = [OptionsScene node];
break;
case kCreditsScene:
sceneToRun = [CreditsScene node];
break;
case kIntroScene:
sceneToRun = [IntroScene node];
break;
case kLevelCompleteScene:
sceneToRun = [LevelCompleteScene node];
break;
case kGameplayScene:
sceneToRun = [GameplayScene 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;
}
// Menu Scenes have a value of < 100
if (sceneID < 100) {
if ([[CCDirector sharedDirector] enableRetinaDisplay:YES]) {
// iPhone 4 Retina
[sceneToRun setScaleX:1.0f];
[sceneToRun setScaleY:1.0f];
CCLOG(#"GM:Scaling for iPhone 4 (retina)");
} else {
[sceneToRun setScaleX:1.0f];
[sceneToRun setScaleY:1.0f];
CCLOG(#"GM:Scaling for iPhone 3G(non-retina)");
}
}
if ([[CCDirector sharedDirector] runningScene] == nil) {
[[CCDirector sharedDirector] runWithScene:sceneToRun];
} else {
[[CCDirector sharedDirector] replaceScene:sceneToRun];
}
}
I ran into a similar problem once, but I can't seem to relate it directly to your code.
In short, the issue is that while I am building my layer/scene in the init method, the nodeToWorldTransformation (at least, possibly others as well) is not set. So, if you are trying to calculate the world coordinates (or possibly the size in world coordinates) of something, it does not work.
Now, in may case, I used that transform to calculate a scale factor at init time, and it was wrong. If I delayed the calculation to after the transformation was set, then everything was ok. The transformation becomes ready only after the layer you are creating has been added to its parent, but I am not exactly sure when it does. Finally, in my case I simply hardcoded the transformation, knowing all dimensions at init time.
It seems that your case could be analogous to this, but, as I said, I cannot relate this to your code.
You are calling node with the scene objects call [MainMenuScene scene];and try
and make this method with return type CCScene* and use to get return the scene and write
[[CCDirector sharedDirector]runWithScene:[obj runSceneWithID:1]];
Edit --
-(CCScene*)runSceneWithID:(SceneTypes)sceneID {
SceneTypes oldScene = currentScene;
currentScene = sceneID;
id sceneToRun = nil;
switch (sceneID) {
case kMainMenuScene:
sceneToRun = [MainMenuScene node];
break;
case kOptionsScene:
sceneToRun = [OptionsScene node];
break;
case kCreditsScene:
sceneToRun = [CreditsScene node];
break;
case kIntroScene:
sceneToRun = [IntroScene node];
break;
case kLevelCompleteScene:
sceneToRun = [LevelCompleteScene node];
break;
case kGameplayScene:
sceneToRun = [GameplayScene node];
break;
default:
CCLOG(#"Unknown ID, cannot switch scenes");
return nil;
break;
}
if (sceneToRun == nil) {
// Revert back, since no new scene was found
currentScene = oldScene;
}
return sceneToRun;
}

Resources