I have a class in which i am calling a method(with a SEL parameter) of another class like as follows
// class 1
+(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];
// returns a CClayer Object
id myClassLayer = [myClass objWithBackgroundSprite:objBackground withRect:CGRectMake(160,100, 300,120) atPoistion:pos_Top];
SEL callOnClick;
[myClassLayer AddButtonWithImage:ButtonBackground selector:callOnClick withDisabledImage:disabledBackground];
[scene addChild: myClassLayer];
// return the scene
return scene;
}
// class 2
-(void)AddButtonToHUDWithImage:(NSString *)imageName selector:(SEL)selector withDisabledImage:(NSString *)disbdImageName
{
CCMenuItem *menuItem1 = [CCMenuItemImage itemFromNormalImage:imageName selectedImage:imageName disabledImage:disbdImageName target:self selector:#selector(selector)];
CCMenu *menu = [CCMenu menuWithItems:menuItem1,nil];
[menu setPosition:ccp(160,100)];
[self addChild:menu];
}
-(void)selector
{
// not creating any object .. some other way if possible
}
but i would like to declare the selector method(callOnClick) in HelloWorld only(myClass being a Generic Class).
How can i call the selector in HelloWorld only??
If you need no instance, then you can use a class method and the target/object will be [SOMEType class] or [self class]:
+ (void)selector // << + not -
{
// not creating any object .. some other way if possible
}
Related
Whenever I want to transition to a certain scene, it takes a couple of seconds before the SKTransition even starts. Is it possible to have all scenes initialized before the game starts?
NewScene *newScene = [NewScene sceneWithSize:self.size];
SKTransition *reveal = [SKTransition moveInWithDirection:SKTransitionDirectionUp duration:0.5];
reveal.pausesIncomingScene = NO;
[self.view presentScene:newScene transition:reveal];
I've tried this with didMoveToView as well:
#implementation NewScene
-(id)initWithSize:(CGSize)size {
if(self = [super initWithSize:size]) {
// Load a bunch of stuff like this:
SKSpriteNode *menuButton = [SKSpriteNode spriteNodeWithImageNamed:#"mainMenu"];
menuButton.position = CGPointMake(self.frame.size.width/2,self.frame.size.height/4);
menuButton.name = #"menuButton";
[self addChild:menuButton];
[menuButton setScale:0.8];
}
}
How can I make sure that my Sprite Kit game runs smoothly?
EDIT:
It turns out the problem was that I kept putting the main thread to sleep to fade out music. I've made all my audio methods run in the background and it works fine now.
A good approach is to load all resources asyncronously before SKScene's initialization. Apple uses this approach in Adventure game:
NewScene.h:
typedef void (^AGAssetLoadCompletionHandler)(void);
#interface GameScene : SKScene<SKPhysicsContactDelegate, UIGestureRecognizerDelegate>
+ (void)loadSceneAssetsWithCompletionHandler:(AGAssetLoadCompletionHandler)handler;
#end
NewScene.m:
#implementation NewScene
-(id)initWithSize:(CGSize)size {
if(self = [super initWithSize:size]) {
// Load a bunch of stuff like this:
SKSpriteNode *menuButton = [SKSpriteNode spriteNodeWithTexture:[self menuButtonTexture];
menuButton.position = CGPointMake(self.frame.size.width/2,self.frame.size.height/4);
menuButton.name = #"menuButton";
[self addChild:menuButton];
[menuButton setScale:0.8];
}
}
#pragma mark - Shared Assets
+ (void)loadSceneAssetsWithCompletionHandler:(AGAssetLoadCompletionHandler)handler {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// Load the shared assets in the background.
[self loadSceneAssets];
if (!handler) {
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
// Call the completion handler back on the main queue.
handler();
});
});
}
+ (void)loadSceneAssets {
sBackgroundTexture = [SKTexture textureWithImageNamed:#"background"];
sMenuButtonTexture = [SKTexture textureWithImageNamed:#"mainMenu"];
// etc.
}
static SKTexture *sBackgroundTexture = nil;
- (SKTexture *)backgroundTexture {
return sBackgroundTexture;
}
static SKTexture *sMenuButtonTexture = nil;
- (SKTexture *)menuButtonTexture {
return sMenuButtonTexture;
}
#end
Then just present NewScene from your UIViewController:
if (!self.skView.scene) {
CGSize viewSize = self.view.bounds.size;
// Here you can present some loading scene or splash screen
[NewScene loadSceneAssetsWithCompletionHandler:^{
NewScene *scene = [[NewScene alloc] initWithSize:viewSize];
[self.skView presentScene:scene transition:[SKTransition crossFadeWithDuration:1.f]];
}];
}
I'm currently learning Cocos2D and I can't figure out how to access my sprite '_imgStudio' to make it universal so I can clean it up the image after my "removeStudio" timer finishes. I'd like to be able to move both the CCSprite draw functions into the spawnStudio function and to kill it once the timer finishes running.
However, I get an error saying 'Use of undeclared identifier '_imgStudio' so my removeStudio timer right now is pretty much useless.
Here's part of my helloWorldFile.
#implementation GameEngine
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
GameEngine *layer = [GameEngine node];
[scene addChild: layer];
return scene;
}
#pragma mark Main Initializer
//Initalizes GameSetup
-(id) init
{
if( (self=[super init]) ) {
NSLog(#"Game Setup Worked!");
CGSize winSize = [CCDirector sharedDirector].winSize;
CCSprite *_imgStudio = [CCSprite spriteWithFile:#"Studio~ipad.png"];
_imgStudio.opacity = 0;
_imgStudio.position = ccp(winSize.width/2, winSize.height/2);
[_imgStudio runAction:[CCFadeTo actionWithDuration:2.5f opacity:255]];
[self addChild:_imgStudio];
[self scheduleOnce: #selector(spawnStudio:) delay:10];
[self scheduleOnce: #selector(removeStudio:) delay:20];
}
return self;
}
-(void) spawnStudio: (ccTime) dt {
NSLog(#"TEST");
}
-(void) removeStudio: (ccTime) dt {
[_imgStudio removeFromParentAndCleanup:YES];
NSLog(#"ImageRemoved");
}
Thanks!
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];
}
}
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];
// ...
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