Here is the setup. I have a orthogonal tile map made with Tiled. There are 5 layers. The bottom 4 comprise the background, while the top layer is the foreground that I will refer to as the “tree” layer. I have a hero sprite that I have added as a child of the tile map at the same node zorder as the tree layer.
The issue that invariably comes up with this scenario is that I want my hero to be in front of trees that he is “below”, but behind those trees that he is “above”. Below and above are determined by the Y coordinate of the hero versus the Y coordinate of any given tree.
The Cocos2d programming guide contains a section for tile maps, and in that section it specifically discusses how to achieve the affect I have described. This information can be found here.
http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:tiled_maps
The solution is pretty simple. Enable the depth buffer in my code. Add a cc_vertexz property with a value of -1000 to each layer that the hero will be above. Then add a cc_vertexz property to the tree layer with a value of “automatic” as well as a cc_alpha_func property with a value of .5. Then as your hero moves re-adjust its sprite’s vertexz value based on its position within the map.
I did all this and it worked great. However, a problem appeared as soon as I added other “enemy” sprites to this map. As with the hero sprite these sprites were added to the map with the same node zorder as the tree layer, and they too have their vertexz values changed based on their Y coordinate within the map. It should be noted that the hero sprite is added after the enemy sprites. In addition, both the hero and enemy sprites are animated and their textures are not part of the tile map textures. Based on the Cocos2d documentation this should not matter.
The problem is this. If my hero is below an enemy sprite on the map then everything looks and works fine. However, if my hero is above an enemy sprite on the map then as the enemy passes over the hero sprite the background comes through rather than the hero sprite. The best way to describe it is to say that as soon as the enemy sprite begins to pass over the hero sprite, the transparent areas of the enemy sprite begin to fill with the background and the hero sprite is partially obscured until then enemy sprite moves off the hero. It is like the hero sprite is not there.
I know this is related to the order that the sprites are added to the map, because if I change this and have the hero sprite added to the map before the enemy sprites, then the effect reverses in that the background comes through the transparent areas of the hero sprite rather than the enemy sprites. It is almost like the vertexz property is not absolutely determining the order that things are drawn.
Looking into this it appears to be a blending issue and I found what seems to be the solution, which is to subclass the CCSprite class and override the draw method with the following:
-(void) draw {
glEnable(GL_ALPHA_TEST);
glAlphaFunc( GL_GREATER, 0 );
[super draw];
glDisable(GL_ALPHA_TEST);
}
The problem however is that this code is not applicable to the version of Cocos2d that I use, which is Cocos2d 2.1. In addition this appears to be handled by the CCTMXLayer drawing function if automatic vertexz is enabled. As such I do not know if subclassing CCSprite would just be redundant. See below for how CCTMXLayer handles this:
// CCTMXLayer drawing function
-(void) draw
{
if( useAutomaticVertexZ_ ) {
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, alphaFuncValue_);
}
[super draw];
if( useAutomaticVertexZ_ )
glDisable(GL_ALPHA_TEST);
}
I am not new to Cocos2d, but I am very new to anything related to OpenGL. So in short, is the solution just to subclass CCSprite and find the Cocos2d 2.1 equivalent to the above code snippet, or am I simply doing something wrong? I suspect the latter.
Any help would be very much appreciated. Thanks!
Answer
This has been resolved. The solution was to use the following on my sprites or sprite sheets as the case may be:
mySprite.shaderProgram = [[CCShaderCache sharedShaderCache]programForKey:kCCShader_PositionTextureColorAlphaTest];
This essentially takes the place of sub-classing CCSprite and overriding the draw method, which is the prescribed method for Cocos2d 1.x, whereas I am using Cocos2d 2.x.
No comments:
Post a Comment