Ran across this while working with CCMenuItemImage. It seems like I have to set the SelectedImage and the NormalImage to different CCSprites, otherwise it crashes my application. (I plan on using unique assets later on for both states) CCMenuItemImage *ItemButton; is defined / initialized.
The following does not work:
CCSprite *updatedSprite = [CCSprite spriteWithFile:#"1_button.png"];
[ItemButton setNormalImage:updatedSprite];
[ItemButton setSelectedImage:updatedSprite];
The following does work:
CCSprite *updatedSpriteNormal = [CCSprite spriteWithFile:#"1_button.png"];
[ItemButton setNormalImage:updatedSpriteNormal];
CCSprite *updatedSpriteSelected = [CCSprite spriteWithFile:#"1_button.png"];
[ItemButton setSelectedImage:updatedSpriteSelected];
Curious to know why that would happen, I've done some digging but couldn't find anything definitive. Any insight would be great.
When you setSelectedImage, the sprite is added as a child to the ItemButton, thus it has a parent. You must create a second instance of CCSprite to setNormalImage, because the node hierarchy of cocos2d will always prevent adding as a child an object that already has a parent.
Related
I am wanting to use the same sprite multiple times in Cocos2d 3.0
at the moment when i do this i get the following error
"reason: 'child already added to another node. It can't be added again'"
i have looked at other responses to similar questions here on stacker overflow and they state that spriteBatchNode is required. However this has depreciated in version 3.0.
Make local instances of the sprites *( i have used nodes here as i get an error when trying to add them to the array (Incompatible pointer types assigning to 'CCSprite *' from 'CCNode '))
CCNode *_sprite1;
CCNode *_sprite2;
CCNode *_sprite3;
CCNode *_sprite4;
I currently Have an array where sprites(CCNodes)are added
_array1 = #[_sprite1,_sprite2,_sprite3,_sprite4];
_array2 = #[_sprite1,_sprite2,_sprite3,_sprite4];
I would then make a call to spawn the sprites
-(void)spawnSprites1
{
int randomNumber = [self generateRandomNumberBetweenMin:0 Max:_array1.count-1];
CCSprite *sprite = [_array1 objectAtIndex:randomNumber];
sprite.position = ccp(_size.width +100 , _size.height *0.26);
sprite.zOrder = DrawingOrderPlayer;
[_physicsNode addChild:sprite];
CCLOG(#"content size = %f",_size.height);
}
-(void)spawnSprites2
{
int randomNumber = [self generateRandomNumberBetweenMin:0 Max:_array2.count-1];
CCSprite *sprite = [_array2 objectAtIndex:randomNumber];
sprite.position = ccp(_size.width +100 , _size.height *0.26);
sprite.zOrder = DrawingOrderPlayer;
[_physicsNode addChild:sprite];
CCLOG(#"content size = %f",_size.height);
}
if the same sprite is drawn from either i receive the above crash log.
Does anybody know how to resolve this issue in Cocos2d v3.0
Thanks
Each new sprite needs to be a new CCSprite instance. Since cocos2d doesn't implement NSCopying yet, the easiest way is to initialize new sprites using one template instance's texture, like so:
CCSprite* newSprite = [CCSprite spriteWithTexture:templateSprite.texture];
Then assign any property from the templateSprite to newSprite if the copy should have the same value(s).
Problem resolved, rather the pulling sprites out of an array randomly, it was just as easy to randomly pull them using a switch statement.
I'm having trouble getting my sprite batch node to work and it's partly because I don't understand the concept complete. The SpriteFrameCache is shared, which makes it easy to access, but the SpriteBatchNode isn't so I don't know the best way to access it from another class.
I have my sprite batch node set up as an instance variable in my main GameplayLayer.m:
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"MyTexture.plist"];
spriteBatchNode = [CCSpriteBatchNode batchNodeWithFile:#"MyTexture.png"];
But then I have a Monster class with animations set up inside the class but the sprites are in the texture that was created in my GameplayLayer class:
CCAnimation *walkAnim = [CCAnimation animation];
[walkAnim addSpriteFrame:[spriteFrameCache spriteFrameByName:#"monster-sprite-walk0.png"]];
//some other code
self.monsterWalkAnimation = [CCRepeatForever actionWithAction:walkAnimationAction];
Which doesn't work, I'm guessing because it has no idea where the texture is. What is the best way to access that sprite batch node, or am I setting this up all wrong?
i have this function :
-(void)blink:(CCSprite *)sprite
{
CCSprite *blinker=[sprite copy]; // i have add that to prevent sprite from change.
it gets a sprite and do animation on it, but sprite is keep changing all time cause its a pointer, so my function keep get a different sprites -WHICH I DONT WANT.
i was trying to copy it to another ccsprite, but its crashes.
whats wrong here ?
is that because i havnt release it ?
thanks alot
Can you post the code where call the blink method?
Maybe you can try this:
-(void) blink:(CCSprite*)sprite {
[sprite retain];
// Do some stuff with the sprite here
[sprite release];
}
However, functions should be called with thread-safe parameters so they don't get deallocated during the functions execution.
I'm probably over-thinking this, but I've been stuck on it a while, so I figured I'd reach out for some advice/help.
I'm using GameKitHelper (http://www.learn-cocos2d.com/tag/gamekithelper/), thus far, it's been pretty helpful. So, I have the helper initialized on in my "MainMenu" with the protocol implemented, etc:
#interface MainMenu : CCLayer <GameKitHelperProtocol> {
...
GameKitHelper *gkHelper;
}
In the main menu code, I have this:
gkHelper = [GameKitHelper sharedGameKitHelper];
gkHelper.delegate = self;
[gkHelper authenticateLocalPlayer];
Seems pretty strait forward. In fact, it works, exactly as I expect it to. I have the methods it's looking to be in place there (even though most don't have code associated with them (yet?)). My issue is when I actually want to start my game. So, I'm using the onMatchFound() to start the game, which basically works:
-(void) onMatchFound:(GKMatch*)match
{
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.2f scene: [[MultiplayerLoading initWithData:Multiplayer withMultiplayerType:gameTypeToPlay andInitiator:false] scene]]];
}
My issue is when I'm attempting to play the game, the receive delete method fires in the MainMenu NOT the game class, so things aren't being calculated properly.
Is there a way to pass the control to the game layer from the main menu when the onMatchFound fires?
Hopefully this gives enough info, let me know if not.
Thanks everyone!
There's two ways you can make this work. One way is to have a global Singleton class as the GameKitHelper delegate. You can then relay messages via this Singleton class.
Or simply assign the new scene as the GameKitHelper delegate:
-(void) onMatchFound:(GKMatch*)match
{
CCScene* newScene = [MyNewScene scene];
[GameKitHelper sharedGameKitHelper].delegate = newScene;
[[CCDirector sharedDirector] replaceScene:newScene];
}
Also, there seems to be something wrong with how you create the new scene:
[[MultiplayerLoading initWithData:Multiplayer
withMultiplayerType:gameTypeToPlay
andInitiator:false] scene];
It appears you are first calling the init method, then the class method scene which allocates the instance (see the scene implementation). It looks to me like it should rather be:
[[[MultiplayerLoading alloc] initWithData:Multiplayer
withMultiplayerType:gameTypeToPlay
andInitiator:false] autorelease];
Btw, the Cocoa Coding Guidelines recommend not to "link" method parameters with the "and" keyword and using "with" more than once is also quite odd. Cleaned up it should rather be:
[[[MultiplayerLoading alloc] initWithData:Multiplayer
multiplayerType:gameTypeToPlay
initiator:false] autorelease];
Excuse me for being picky. :)
Could this be because your MainMenu is set as the delegate in your GameKitHelper? I'd try setting the delegate to the game inside onMatchFound. Give that a try.
How does one release a texture atlas using cocos2d?
I have the following code
NSString *blue= = #"Blue.plist";
CCSpriteBatchNode *blueBatchNode = [CCSpriteBatchNode batchNodeWithFile:#"Blue.png"];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:blue];
[self.parentScene addChild:blueBatchNode];
How do I release these 2 at a laster stage?
[[CCSpriteFrameCache sharedSpriteFrameCache] removeSpriteFramesFromFile:#"Blue.plist"]
Most if not all CCNode derived objects are auto released. So long as you use convenience methods not alloc init.
e.g.
CCSprite *sprite = [CCSprite spriteWithFrameName:#"blahblah"];
Once your CCLayer removes the batchnode as a child, it should release that object, unless there are somehow some things linking to it, perhaps children that didn't get removed (but they should do).
Failing it being removed when that happens, you can also use purgecacheddata to clear out textures.
[[CCDirector sharedDirector] purgeCachedData];
Purging cached data also removes cached spriteframes as mentioned in the question above.