Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get a child CCSprite to draw on top of its parent?

I'm trying to control the order in which CCSprites are being layered one on top of the other. I'd use zOrder, but I'm animating characters made up of articulated sprites (some sprites parented on others with addChild) and zOrder is only honored among sibling sprites.

Basically, I want to parent my sprites so they can inherit each others' transforms, but I want to determine the draw order.

Looking around, it sounds like using a CCSprite's vertexZ property is the way to go. I've tried that. I set the draw method of my custom CCSprite like so:

- (void)draw
{
    glEnable(GL_BLEND);
    CHECK_GL_ERROR_DEBUG();
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    CHECK_GL_ERROR_DEBUG();
    [super draw];
    glDisable(GL_BLEND);
}

Each of my sprites now has a zOrder of 0 and a unique vertexZ to layer them as I'd like, but it's not working: any sprite that has a parent is not displayed!

Trying some things, I find if I don't set vertexZ, all sprites are displayed. And if I keep the vertexZs and don't parent, they're all displayed. But with vertexZs set, any child sprite won't display.

What's going on here and how can I get it to work?

Update: More clues. I can comment out the GL functions around my call to [super draw] entirely and the results are the same. Also, it turns out child sprites with a vertexZ do display, but wherever they overlap any other sprite they go invisible. The purple paper sprite is a child of the creature's left forearm sprite (on screen right) yet should go on top of it.

There are bites taken out of the purple sprite wherever it's over or under other sprites.

For the picture above, I'm basically doing this in my CCLayer. I want the parenting, but I want hand and paper to be on the top.

[self addChild:lUpperarm];
[self addChild:lForearm];
[self addChild:face];
[self addChild:rUpperarm];
[self addChild:rForearm];
[lForearm addChild:handAndPaper];

lUpperarm.vertexZ = -100;
lForearm.vertexZ = -99;
face.vertexZ = -98;
rUpperarm.vertexZ = -97;
rForearm.vertexZ = -96;
handAndPaper.vertexZ = -95;

This is how I want it to look. (I changed the last line to [self addChild:handAndPaper] which loses lForearm's transformations, not what I want.)

The purple paper covering the other sprites.

Update 2: Some have suggested I add all children with zOrder set to -1: e.g. [lForearm addChild:handAndPaper z:-1]. This changed things a little, but still didn't fix it, alas. Seems either vertexZ is not determining draw order and/or the blending is wrong.

The effects of zOrder -1.

like image 969
Dylan Avatar asked Aug 28 '12 18:08

Dylan


1 Answers

I dealt with this issue when writing an RPG with Cocos2d. The problem is the alpha blending. As you are seeing, the paper is being covered up by the left arm sprite, even though it is transparent. For some reason, when Cocos2d's vertexZ technique is used, this problem can sometimes occur. To fix it, you can try changing your alpha blending level. Try 0.0, 0.5 and 1.0:

-(void) draw
{
    glEnable(GL_ALPHA_TEST);
    glAlphaFunc(GL_GREATER, 0.0f);
    [super draw];
    glDisable(GL_ALPHA_TEST);
}

If that doesn't work, then I recommend a complete workaround solution. Keep all your sprites as part of the same parent node and use regular z ordering. It's not an ideal solution, but if you use a "meta" parent node then you can still transform all the children easily.

like image 80
Nathanael Weiss Avatar answered Oct 24 '22 00:10

Nathanael Weiss