I just started learning cocos2d-x.
I am trying to create menu using sprite sheet, below:
CCSpriteFrameCache::sharedSpriteFrameCache()>addSpriteFramesWithFile("my_menu.plist");
CCMenuItem *play = CCMenuItemImage::create("play.png", NULL,NULL,this , menu_selector(StartScene::clickStart));
CCMenu *pMenu = CCMenu::create(play,NULL);
addChild(pMenu);
I got error message:
get data from file (play.png) failed.
I realise something wrong with my create function. I am just wondering how to get the image from sharedSpriteFrameCache?
OK, I just figure it out:
CCMenuItemSprite *play = CCMenuItemSprite::create(CCSprite::createWithSpriteFrameName("play.png"), NULL,NULL,this ,menu_selector(StartScene::clickStart));
spriteWithSpriteFrameName is deprecated, instead, we can use:
CCSprite::createWithSpriteFrameName();
u need to take the plist file in a ccspritebatchnode object and manipulate it using this object.
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"AnimBear.png"];
[self addChild:spriteSheet];
Related
Im trying to create sprite animation in cocos2d 3.0.
In all tutorials that i read there is a class named CCRepeatForever. But in cocos 3.0 it doesn't exists anymore. How can i replace it?
This is my code:
self.walkAction = [CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:walkAnim]];
PS Sorry for my english.
The class is now named CCActionRepeatForever.
Replace it with:
[CCActionRepeatForever actionWithAction:[CCAnimate actionWithAnimation:walkAnim]];
I know how to detect contact on all of my sprites that on screen .
I also know how to run animation forever on a sprite .
But when puting together the code for animation, with sprite sheet- you dont actually add the sprite as a child, but ONLY the sprite-sheet, than the sprite is a child of the sprite-sheet.
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"parrot.plist"];
CCSpriteBatchNode *spriteSheet = [ CCSpriteBatchNode batchNodeWithFile:#"parrot.png"];
fireBall=[CCSprite spriteWithSpriteFrameName:#"parrot1.png"];
fireBall.position=point;
[spriteSheet addChild:fireBall];
[self addChild:spriteSheet];
//here animation action perform on fireBall
In that case when looking for the fireBall for contact detection - you cant find him because he is not added as a child of the scene ,but of the sprite sheet.
How can i detect that sprite later on my code ? or there is another constellation to set the sprite sheet ?
thanks
You can get your fireBall sprite normally, like any other sprite...
There's some ways:
1) Create a property for your fireBall sprite:
#property (nonatomic, retain) CCSprite *fireBall;
And create and use it using self.fireball:
self.fireBall=[CCSprite spriteWithSpriteFrameName:#"parrot1.png"];
...
CGPoint fireBallPosition = self.fireBall.position;
2) Add fireBall as child on spriteSheet using tag, and get it back using the same tag.
[spriteSheet addChild:fireBall z:0 tag:1];
...
theFireBall = [spriteSheet getChildByTag:1];
But keep in mind that the fireBall position is relative of their parent, spriteSheet. So, if you move spriteSheet, you will also move spriteSheet.
I have Building CCNode
It's have property:
in .h file
#property (nonatomic) int testProperty;
in .mm file add tag and set property
[[GB2ShapeCache sharedShapeCache] addShapesWithFile:#"Objects.plist"];
[CCTexture2D PVRImagesHavePremultipliedAlpha:YES];
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
batchNode = [CCSpriteBatchNode batchNodeWithFile:#"sprite.png"];
[self addChild:batchNode];
[[CCSpriteFrameCache sharedSpriteFrameCache]addSpriteFramesWithFile:#"sprite.plist"];
sprite = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:#"%#.png", type]];
[batchNode addChild:sprite];
[sprite setTag:2]; //SET TAG
[self setTestProperty:10]; //SET PROPERTY
...
Also is the ContactListener class
It's work correctly with this code and i'm detecting body by tag fine:
#import "ContactListener.h"
#import "Building.h"
void ContactListener::BeginContact(b2Contact* contact)
{
b2Body* bodyA = contact->GetFixtureA()->GetBody();
b2Body* bodyB = contact->GetFixtureB()->GetBody();
Building *buildA = (Building *)bodyA->GetUserData();
Building *buildB = (Building *)bodyB->GetUserData();
if (buildA.tag == 2) {
NSLog(#"Collision with building");
}
}
PROBLEM:
I don understand how get property from ContactListener
I tried to get it so:
if (buildA.tag == 2) {
NSLog(#"Collision with building");
NSLog(#"testProperty == %i", buildA.testProperty);
}
But buildA.testProperty not work, and get error
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CCSprite testProperty]: unrecognized selector sent to instance 0x434af0'
If your can explain my please how get property from this class. Thanks.
'-[CCSprite testProperty]: unrecognized selector sent to instance 0x434af0'
You store the CCSprite in userdata, not the Building object.
You set the tag like this, then of course checking for the correct tag works:
[sprite setTag:2];
But this is incorrect because user data is not a Building but a sprite:
Building *buildA = (Building *)bodyA->GetUserData();
I assume that Building inherits from CCSprite, this is why accessing the common properties like tag works, but not the Building specific properties.
When I create body, I set into user data sprite.
In the Building.h
body->SetUserData(self);
solved the problem.
I've got a problem in my current game.
I'm trying to move a sprite based on the movement of a other physic body, for a map. This is my code:
...
NSMutableArray *mapObjetcs = [[[NSMutableArray alloc]init]autorelease];
[mapObjetcs addObject:swordman];
[mapObjetcs addObject:icon];
CCCallFuncND* iconMap = [CCCallFuncND actionWithTarget:self selector:#selector(mapLoc:mapObj:) data:mapObjetcs];
CCSequence* iconMapSequence = [CCSequence actions:[CCDelayTime actionWithDuration:1.0f/60.0f], iconMap, nil];;
CCRepeatForever* iconRef = [CCRepeatForever actionWithAction:iconMapSequence];
[self runAction:iconRef];
}
-(void) mapLoc:(ccTime)delta mapObj:(NSMutableArray*)mapObj
{
GB2Sprite *swordmanTemp = (GB2Sprite*)[mapObj objectAtIndex:0];
CCSprite *iconTemp = (CCSprite*)[mapObj objectAtIndex:1];
CGPoint swordmanPos = [swordmanTemp ccPosition];
float pos = (swordmanPos.x/convFactor)+65;
iconTemp.position = ccp(pos, 290);
}
Every time i run the code with the CCRepeatForever the games freezes, if i run the code without the CCRepeatForever the game run grat but dont refresh the icon in map.
Can anybody help me??? Thanks
Its a problem with running CCRepeatForever on layer itself.. Ofcourse it will freeze the game.. You can try for alternate solution I guess.. Instead of using a separate CCRepeatForever loop, use the update method of your layer.. As its already doing same thing that you want to do with your own action..
Another solution is make a same CCRepeatForever for your icon sprite.. and in its CCCallFuncND take the position of other object....
Hope this helps.. Try yourself.. If it doesn't work.. I'll try 2 give you code... Don't run CCRepeatForever Loop on your layer itself.. :)
To avoud such actions you can simply schedule some method with needed interval. smth like
[self schedule: #selector(methodToBeCalled) interval: intervalInSeconds];
just don't forget to unschedule it later
after few headaches i figured out that using CCSpriteBatchNode with cocos2d olny allows to z-order sprites added to it as child (which is obvious, now i see..)
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"token_default.plist"];
CCSpriteBatchNode *tokenSpriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"token_default.png"];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"objects_default.plist"];
CCSpriteBatchNode *objectsSpriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"objects_default.png"];
CCSprite *token = [[[CCSprite alloc] initWithSpriteFrameName:#"token_SE.png"] autorelease];
[token setPosition:tokenSpawnPoint];
CCSprite *enemy = [[[CCSprite alloc] initWithSpriteFrameName:#"token_blak_SE.png"] autorelease];
[enemy setPosition:enemySpawnPoint];
CCSprite *houseA = [[[CCSprite alloc] initWithSpriteFrameName:#"house_small.png"] autorelease];
[houseA setPosition:[self randomHousePosition]];
CCSprite *houseB = [[[CCSprite alloc] initWithSpriteFrameName:#"house_big.png"] autorelease];
[houseB setPosition:[self randomHousePosition]];
[tokenSpriteSheet addChild:token];
[tokenSpriteSheet addChild:enemy];
[objectsSpriteSheet addChild:houseA];
[objectsSpriteSheet addChild:houseB];
and since i have to add them to the display list as follows..
[_isoMap addChild:objectsSpriteSheet];
[_isoMap addChild:tokenSpriteSheet];
there is no way i can change the z-order of single tokens between other houses...
they will be always rendered over the house until i change the order of these batch nodes
btw, i can "merge" all sprites' arts in one big single batch node... doing so it became possible to order sprites using sprite's coordinates
[fullSpriteSheet reorderChild:token z:token.position.y];
i'm a little stuck with it...... is there a way to achieve that, having different sprite bacth nodes? or is possible to programmatically merge two batchnodes? (or something like that)
i found KnightFight, a really interesting open project on github by LozArcher.. he used CCSpriteFrame and CCSprite's setDisplayFrame method, instead of batch nodes... but i can't run it since it seems to be an older version of cocos2d (apparently not working with xcode 4)
i found out that changing the vertexZ property of a CCNode (like a CCSprite) it actually changes its Z position (so it will be slightly bigger/smaller, and also translated)
so, in order to arrange on z-index CCSprites with different spriteSheet i had to use reorderChild method (to just change the rendering order) and mostly i need NOT TO USE CCSpriteBatchNode..
after a little refactoring of the above example, i should have:
CCSprite *token = [CCSprite spriteWithSpriteFrameName:#"token_SE.png"];
[token setPosition:tokenSpawnPoint];
CCSprite *enemy = [CCSprite spriteWithSpriteFrameName:#"token_blak_SE.png"];
[enemy setPosition:enemySpawnPoint];
CCSprite *houseA = [CCSprite spriteWithSpriteFrameName:#"house_small.png"];
[houseA setPosition:[self randomHousePosition]];
CCSprite *houseB = [CCSprite spriteWithSpriteFrameName:#"house_big.png"];
[houseB setPosition:[self randomHousePosition]];
[_isoMap addChild:token];
[_isoMap addChild:enemy];
[_isoMap addChild:houseA];
[_isoMap addChild:houseB];
i also added each sprite to a NSMutableArray
and then in a for loop (inside the update scheduled method):
CCSprite *sprite = [mySpritesArray objectAtIndex:i];
[_isoMap reorderChild:sprite z:(_isoMap.mapSize.height - sprite.y)];
hope this could help someone :)
I still think that is not better solution,
if your objects on map are moving dynamically, you can still stuck in z order issues.
I know its very old post, and people keep coming here by google search,
so I am posting solution here.
float lowestZ = tilemap.map.width +tilemap.map.height ;
float currentZ = self.gridLocation.x + self.gridLocation.y ;
int zOrderDecided = lowestZ + currentZ - 1 ;
[self.parent reorderChild:self z:zOrderDecided];
Set the Sprites Z order to it's Y position on the map. Reorder your dynamic sprites in an update loop. Calculate the Z order using the Sprites current Y position and the visible height of the map.
void LocalGameController::SetZOrderForObject(cocos2d::Sprite *object){
int objectZOrder = visibleSize.height - object->getPositionY();
context->reorderChild(object, objectZOrder);
}