Can I layer a CCSprite between two CCTMXLayers? - cocos2d-iphone

I am making a top-down shooter that makes extensive use of TMX maps created with the "Tiled" application. Within my TMX map, I have a "Background" layer with floor tiles, which appears beneath my characters (CCSprites.)
I have another layer in the TMX file called "Foreground" which I would like to appear "above" my CCSprites, giving the illusion of them walking underneath various objects.
I tried using the vertexZ property of the CCNode class to do this:
CCTMXLayer *backgroundLayer = ...
CCSprite *spriteNode = ...
CCTMXLayer *foregroundLayer = ...
[backgroundLayer setVertexZ:1];
[spriteNode setVertexZ:2];
[foregroundLayer setVertexZ:3];
...but it turns out vertexZ actually alters the node's visual appearance within the openGL view. It effectively causes a CCNode to appear larger, or closer to the user when it has a higher vertexZ value. I don't want that- all I want is a sort of layers-of-an-impossibly-thin-cake effect, without any visual differences between the layers.
So I thought I would try altering the zOrder property of the nodes, like this:
[[backgroundLayer parent] reOrderChild:backgroundLayer z:1];
[[spriteNode parent] reOrderChild:backgroundLayer z:2];
[[foregroundLayer parent] reOrderChild:backgroundLayer z:3];
But I realized there's a fundamental problem with what I'm doing here, since my spriteNode is a direct child of the CCScene, but the background and foreground nodes are both children of my CCTMXTiledMap, which itself is a child of the CCScene.
So I'm basically trying to slip a CCSprite between two layers of the map, which, from the CCScene's perspective, are really just two parts of the same layer.
It seems I could create an additional instance of CCTMXTiledMap just to hold the foreground layer, but that also seems like overkill. My other thought was to create CCSprites to serve the same purpose, but it seems like there's got to be a better way.

Yes, I have used Tiled once very lightly and I do believe there is an option to add an Object Layer into your TMXTiledMap (Tiled -> Layer -> Add Object Layer...), then once imported into your build you can link up a CCSprite with the corresponding Object Layer you have created. I would post your question on the cocos2d forum, as people there are more experienced and equipped to answer this with examples.

Related

cocos2d-x 3 batch drawing explained

I have read this page to understand batch drawing details, but I still have questions. I know that in order to reduce draw call number we need to use batch drawing. I use it like this:
auto spritebatch = SpriteBatchNode::create("ingame.png");
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("ingame.plist");
And now I need to create a Sprite I have to do this:
auto backgroundSprite = Sprite::createWithSpriteFrameName("back_gradient.png");
spritebatch->addChild(backgroundSprite);
But I don't understand the following things:
What if my game has several spritesheets. For example I have HUD spritesheet and ingame spritesheet. Now if I want to show ingame screen with HUD then I need to create 2 SpriteBatchNode? and add them into ingame layer?
What if the same spritesheet should be used in different Scenes. Should I do the following again?
auto spritebatch = SpriteBatchNode::create("ingame.png");
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("ingame.plist");
What if I use sprites with Button, TextEdit, Label and other UI elements.
First of all can I initialize Button state images from spritesheet?
As I know I cannot add UI element as a child to SpriteBatchNode. In this case how to combile UI elements and sprite in the same view/scene?
Sorry for lots of questions. But the fact is that I could not find any resource that contains the explanations to this questions. While they are all related. If you don't know answers to these questions, you don't know how to use SpriteBatchNode.
Don't use CCSpriteBatchNode in cocos2d-x v3. Batching is automatic and best left to the renderer to optimize draw calls through batch drawing. It says so right in the article you've linked:
The Render graph was decoupled from the Scene graph.That means that auto-batching is supported, finally :-) And the new renderer is so fast, that we no longer encourage the use of SpriteBatchNode.
I don't agree, depending not how fast new render is we want to get most of it as we can.
Narek, you are correct.
During rendering the geometry will be sorted to reduce the quantity of GL calls. But don't expect it will sort children of different parents in one line. Example: you have
Node A with children ab and ac
Node B with children bd and be.
if b and d uses textures of same atlas it is not guaranted you will get any perfomance boost of using atlases at all.
But I can confirm, currently it is really fast, and at my case the GL calls are not the bottleneck at all :)

Cocos2d: the best way to compose an object that will contain several Sprites

I need to create an object that contains several sprites (2 for simplicity: the game object and its' shadow).
I need to compose them into the same class, so having the following questions:
what is the best ancestor class to the described one?
I used CCNode for this purpose. I overridden its draw method in the following way:
- (void)draw {
[super draw];
[_item draw];
[_itemShadow draw];
}
and suddenly found that need to change all other CCNode methods in the same way. For ex. change position, visible, etc. in order to change these properties in both Sprites my custom container aggregates:
#interface NBChecker : CCNode {
CCSprite *_item;
CCSprite *_itemShadow;
}
#end
There is the other way I see - to make both sprites parent property pointing to self. This should synchronise positions, visibility, etc. for these sprites.
Who has better ideas?
Would like to use aggregation and not sure I'm right in my thoughts.
Thanks!
Scrap the draw code. All you need to do is to add the two sprites as children of the CCNode subclass. Write your logic code in the CCNode subclass and have two ivars for each sprite for easier access (like you already have).
You don't need to draw the sprites yourself as long as they are part of the scene graph.
The sprites will move and rotate relative to their parent automatically. Move the node to move the sprites in unison, etc.

Cocos2d CCLabelBMFont how to add a background to string

I am wondering how can I add a border & background to labels generated via CCLabelBMFont class in cocos2d.
I don't want to use sprites because my labels are generated on the fly and will keep changing and the size of labels are also different.
Also, I want user to touch and move these labels across the screen. When user picks a label it wiggles a bit like in free air. In that case, I wish to keep low complexity and preserve memory and cpu calculations.
Anyone knows best ways to achieve this?
IOS app LetterPress has similar effects.
Create your own class, that will incapsulate creation of complex node.
It will have several layers, for example, the first layer can be simple CCLayerColor of given rect with zOrder -2, the next layer will be your CCLabelBMFont with zOrder -1 and then you can overload draw method to draw border over your control. All that you draw in this method will be drawn with zOrder 0.
Then you can encapsulate any effects in this class. For example, you can rotate it a bit with method pick, etc. Whatever you want.

Communitacting between CCLayers in one Scene

I have 2 CCLayers that needs to communicate with each other in separate .m files
Level1.m (CCScene with Level1 CCLayer) - Holds tiled map and player sprite
HUDLayer.m (links to top of Level1.m) - Holds all buttons
How can I get the following code in HUDLayer.m to talk to player sprite in Level1.m?
- (void)MoveUpSelected {
CCMoveTo* moveup = [CCMoveBy actionWithDuration:1 position:ccp(0,-100)];
CCSequence* sequence = [CCSequence actions: moveup, nil];
[Player runAction:sequence];
}
Please help I've been stuck on this for days. At least if someone can point me in the right direction. Thanks!
I would advice you to use you scene object to control communication between its layers.
You can create a HUD protocol and set the scene as its delegate. And for each HUD event the scene will react accordingly by accessing the proper layer (stored as its member).
This way you won't have to make this layer coupling.
To access another layer, you need a reference to it. There are many ways to do that. In your case just add one property for each layer to the CCScene class. The layers can then access the scene via their parent:
CCLayer* otherLayer = [(YourActualSceneClass*)self.parent otherLayer];
It is very important that you do not store a reference to the other layer in either layer, or if you do, make sure to make it a weak reference, or nil them in the cleanup method. Otherwise you created a retain cycle.
You'll find more info on accessing other nodes here.

Best Practice in Cocos2d

I am at the start of my cocos2d adventure, and have some ideological questions to ask. I am making a small space-shooter game, am I right to use the following class structure?
Scene
Background Layer
Infinite parallax background
Game Layer
Space ships
Bullets
Control Layer
Joystick
Buttons
and a followup question — what is the best practice in accessing objects from other layers? For example, when the joystick is updated, it must rotate the space ship and move the background. Both of these are in other layers. Is there some recommended way to go about this or should I simply get the desired objects by Tag and operate on them?
Cocos is a big singleton-based system, which may not appeal to some developers but is often used in Cocos apps and is the fundamental architecture of the framework. If you have one main scene and many subsequent layers added to that scene, and you want controls from one layer to affect sprites or logic on other layers, there really is nothing wrong with making your main scene a singleton and sending the information from the joystick layer back to the scene to handle for manipulating other layers or sprites. I do this all the the time and this technique is used in countless Cocos tutorials in books and online, so you can feel that you aren't breaking too many rules if you do it this way (and it's also quite easy to do).
If you instead choose to use pointers in one layer to send data to other layers, this can get you into a lot of trouble since one node should never own another node that it doesn't have a specific parent-child relationship with. Doing so can cause crashes and problems with the native Cocos cleanup methods when you remove scenes later, and potentially leak memory. You could use a weak reference in such a case instead, but that is still dependent on one layer expecting another layer to always be around, which may not be the case.
Sending data back to the main game scene to then dispatch and use accordingly is really efficient.
This seems like a perfectly reasonable way to arrange your objects, this is a method I use.
For accessing objects, I would keep an explicit reference to the object as a member variable and use it directly. (Using tags isn't a bad option, I just find it can get a little messy).
#interface Class1 : NSObject
{
CCLayer *backgroundLayer;
CCLayer *contentLayer;
CCLayer *hudLayer;
CCSprite *objectIMayNeedToUseOnBackgroundLayer;
CCNode *objectIMayNeedToUseOnContentLayer;
}
Regarding tags, one method I use to make sure the tag numbers I'm assigning are unique is define an enum as follows:
typedef enum
{
kTag_BackgroundLayer = 100,
kTag_BackgroundImage,
kTag_GameLayer = 200,
kTag_BadGuy,
kTag_GoodGuy,
kTag_Obstacle,
kTag_ControlLayer = 300
kTag_Joystick,
kTag_Buttons
};
Most times I'll also just set zOrder and tag properties of CCNodes (i.e. CCSprites, CCLabelTTFs, etc.) the same, so you can actually use the enum to define your zOrder, too.