I'm developing a game for iOS. I'm using cocos2d libs. I want to have an object, that have 3 parts - beginning, ending and the middle. I've got the image with these components. And the object can be stretched, when created. But only the middle part should be stretched, the beginning and endings should have no scaling. Because this operation is done only once i decided it's a good idea to create a new CCSprite for this object, and not to keep three (for increasing performance).
I'm using CCSPriteBatchNode for rendering, and i don't know if i really need to combine the object's parts (maybe rendering 3 parts using batch will be as fast as rendering one pre-combined object).
So there are two quastions:
Do i need to combine parts in one object?
If, yes - how can i do that?
Instead of combining the textures you could create a node and add the three sprites as children to it. You can then work with the parent node as a single entity.
Something along the lines of:
CCNode *sprites = [CCNode node];
CCSprite *spriteA = [CCSprite spriteWithSpriteFrameName:#"spriteA.png"];
spriteA.position = ccp(-10, 0);
[sprites addChild:spriteA];
CCSprite *spriteB = [CCSprite spriteWithSpriteFrameName:#"spriteB.png"];
spriteB.position = ccp(0, 0);
[sprites addChild:spriteB];
CCSprite *spriteC = [CCSprite spriteWithSpriteFrameName:#"spriteC.png"];
spriteC.position = ccp(10, 0);
[sprites addChild:spriteC];
You can scale and position each individual sprite depending on your parameters then work with the sprites object to position/scale them as a whole.
There might be a small performance hit so I would think twice before using this for a large amount of sprites, but I've been using this method in a few situations and in my case I didn't notice any issues with performance.
Look at the RenderTexture demo.
Instead of using the brush, you can use put your 3 parts onto it using those images instead of the brush.
Related
My current project contains a gravity simulator where sprites move in accordance with the forces they experience in the game scene.
One of my features involve allowing moving sprites to draw a line behind them so you can see what paths they take.
Shown here:
However, as the Sprite continues it's movements around the screen, the FPS begins to dive. This can be seen in this second image where some time has passed since the sprite first started its movement.
When researching, I found other people had posted with similar problems:
Multiple skshapenode in one draw?
However, in the question above, the answer's poster detailed that it (The answer) was meant for a static image, which isn't something I want, because this line will change in real time depending on what influences the sprites path, this was reflected when I tried implementing a function to add a new Line to the old one which didn't work. That Code here
I'm asking if anyone can assist me in finding a way to properly stop this constant FPS drop that comes from all the draw operations. My current draw code consists of two Functions.
-(void)updateDrawPath:(CGPoint)a B:(CGPoint)b
{
CGPathAddLineToPoint(_lineToDraw, NULL, b.x, b.y);
_lineNode.path = _lineToDraw;
}
-(void)traceObject:(SKPlanetNode *)p
{
_lineToDraw = CGPathCreateMutable();
CGPathMoveToPoint((_lineToDraw), NULL, p.position.x, p.position.y);
_lineNode = [SKShapeNode node];
_lineNode.path = _lineToDraw;
_lineNode.strokeColor = [SKColor whiteColor];
_lineNode.antialiased = YES;
_lineNode.lineWidth = 3;
[self addChild:_lineNode];
}
updateDrawPath: Draws line to latest position of Sprite.
traceObject: Takes SKPlanetNode (Subclass of SKSpriteNode), and sets it up to have a line drawn after it.
If anyone can suggest a way to do this and also reduce the terrible overhead I keep accumulating, it would be fantastic!
A couple suggestions:
Consider that SKShapeNode is more or less just a tool for debug drawing mostly, due to the fact that it doesn't draw in batches it's really not suitable to make a game around that or to use it extensively (both many shapes as well as few but complex shapes).
You could draw lines using a custom shader which will likely be faster and more elegant solution, though of course you may have to learn how to write shader programs first.
Be sure to measure performance only on a device, never the simulator.
So I want to divide my game into chunks by using several different CCTMXTiledMaps.
I am able to load the maps into my main 'HelloWorldLayer'. I am also able to detect whether the player sprite collides with a tile with the property of 'collectable'.
My problem occurs when I add several CCTMXTiledMap nodes to the game, as it doesn't do the collectible tile detection on all of them, just the first one.
Here is my working code that does the check, but only for the first added CCTMXTledMap:
CGPoint point = [self getTileCoordForPosition:position :map];
CCTMXLayer *metaLayer = [map layerNamed:#"Meta"];
CCTMXLayer *foregroundLayer = [map layerNamed:#"Foreground"];
CCSprite *metaTile = [metaLayer tileAt:point];
CCSprite *foregroundTile = [foregroundLayer tileAt:point];
if (foregroundTile)
{
NSLog(#"HIT!");
// Remove the meta tile and the foreground tile
[metaLayer removeTileAt:point];
[foregroundLayer removeTileAt:point];
}
How can I make this code do the check for every CCTMXTiledMap node that has been added?
The problem was that I was calculating the tile map positions wrong, in a tile map co-ordinates to map position function.
I was multiplying by the CC_SCALE_RATIO() function, or something like that (going off the top of my head), and it was mis-calculating the pixel positioning.
Just thought I'd write in an answer since I found the solution. Hope it helps somebody!
I have a CCSpriteBatchNode with a configuration like this:
CCSpriteBatchNode
ChildA1
ChildB1
ChildB2
....
ChildB999
ChildA2
ChildA3
...
Where all children (ChildA1,ChildB1,ChildA2...) are CCSprite objects. The CCSpriteBatchNode and all children but ChildA1 is created via:
[CCSprite spriteWithSpriteFrameName:#"FileName.png"];
ChildA1 is created like this:
// Create Parent Sprite
CCSprite* childA1 = [[CCSprite alloc] init];
childA1.contentSize = CGSizeMake(37.5,37.5);
childA1.anchorPoint = ccp(0,0);
[batchNode addChild:childA1 z:0 tag:1];
// Add Child Sprites
[childA1 addChild:childB1 z:0 tag:1];
[childA1 addChild:childB2 z:0 tag:1];
[childA1 addChild:childB3 z:0 tag:1];
// Continue adding childB4-childB999
Note: This renders just fine, and I see the output I expect, where childB1's position is relative to childA1, and moving childA1 results in childB1 moving.
My question is this: Will I see a performance gain in the drawing each of childB1-childB999? From what I understand, the CCSpriteBatchNode optimizes the drawing of all children within a CCSpriteBatchNode by drawing all its child CCSprites together. Does this also apply to the children of those CCSprites?
For those who want to know why I'm doing this:
There are many layers within this game and grouping CCSprites inside of a CCSprite within a CCSpriteBatchNode allows me to manipulate a group of CCSprites by manipulating only the parent of that group of sprites.
Short answer is, yes, CCSpriteBatchNode will make one draw call for all child nodes including all indirect descendants.
However, whether or not this performs better than using regular CCSprites depends on how often you are modifying the sprites. When you use a CCSpriteBatchNode, every time you modify a sprite, it will need to recalculate the texture atlas quad coordinates for that sprite and all its children using the CPU rather than the GPU. For your example, if you move the position of ChildA1, the coordinates for ChildB1 to ChildB999 will be recalculated before the next frame is rendered. In most applications, the reduction in openGL draw calls out weights the cost of the extra calculations, as draw calls are relatively expensive, but ultimately it will depend on your application and how it uses the sprites -- so I would suggest taking actual measurements for your application if this is a performance bottleneck.
Right now, in my game, I am spawning a sprite every second or so at the top of the screen (using a sceduler) using this code:
The init method:
[self schedule:#selector(addMeteor:) interval:1];
The scheduler method:
- (void)addMeteor:(ccTime)dt
{
CCTexture2D *meteor = [[CCTextureCache sharedTextureCache] addImage:#"Frame3.png"];
target = [CCSprite spriteWithTexture:meteor rect:CGRectMake(0, 0, 53, 56)];
//Rest of positioning code was here
}
Doing it this way causes a stutter in the frame rate every second or so (Whenever another sprite is spawned). Is there a way to eliminate that?
Thanks in advance!
Tate
I'm guessing the stutter is more likely coming from other parts of the code. Do you explicitly call removeChild on meteors? That might cause a hiccup, especially with many meteors.
My advice: create N meteor sprites up front. When you need one, make it visible and change its position. When you're done with it, set it to visible = NO to make it disappear.
Dear all,
I have an application that uses cocos2d spacemanager with gravity set to a specific value.
If i want to make a shape in the middle of the screen it will fall down to the floor, if i set the gravity to zero all other object will not move as supposed, if i use a second spacemanager and set its gravity to 0 i cant detect collision between objects from different spacemanagers. how can i add a shape that wont fall down in the middle of the screen and detect its collision while other objects behave correctly according to the gravity set.
Also a question is, should i use shapes (Circle, rectangle, ... etc) with spacemanager and if i want to use a ccsprite (image) i should put it in a shape or i can use the sprite alone (e.g. a tree is not a rectangle or circle collision and reflection wont be natural how can i do this).
regards
Every shape has a property called mass. If you want a shape to be static and respond to collisions just set mass to STATIC_MASS like this:
cpShape *ball = [smgr addCircleAt:cpv(440,70) mass:STATIC_MASS radius:10];
to ad an image, do that:
cpShape *ball = [smgr addCircleAt:cpv(440, 70) mass:STATIC_MASS radius:10];
[super initWithShape:playerShape file:#"ball.png"];
If this doesn't work, set up a cpCCSprite in it with a shape.
You can search for cpCCSprite on google, im sure you'l find something :)