Arranging sprite sorting within xTile's spritebatch call blocks

Mar 31, 2012 at 12:42 AM

Forgive me, I hope this question isn't too newb, but I cannot seem to figure it out on my own.

I have a character that I'm drawing in worldspace between two layers using the AfterDraw event. My character sprite is drawing and behaving properly, however my issue lies when I try to draw things and layer them within worldspace using layerdepth (between the same map layers).

To be more specific: my character produces particles that I would like to encircle him. They draw properly all except for the part where I would like the particles to pass behind my character. Layerdepth seems to have no affect whatsoever, and all particles are always drawn on top of my character sprite, when I would like them to be drawn behind him.  After digging through your source code, I found that the spritebatch begin and end blocks are called within your XnaDisplayDevice class, which has the begin block's SpriteSortMode set to Deferred. So, with that, I have no idea how to go about sorting my sprites within world space, do you have any insight on how I would work this out?

Thanks in advance for reading this.

Mar 31, 2012 at 4:58 PM

Wont it just work drawing them in order? Not using the Depth?

Or you mean that you want it to be able to switch? From front to behind and so on...

Mar 31, 2012 at 9:37 PM

I have particles that I want to change depth to make them look like they're 'swirling' around my character sprite, so that they should be drawn in front of him as they pass one way, and then their layer depth changes as they make their pass back around to appear behind my character. I've sort of rigged my character's draw method so that it works, but it feels sloppy to me, I'll post it, but I wonder if there isn't a better way to do this?

Here's the code that calls my character's draw method within the AfterDraw event:

 

private void OnAfterLayerDraw(object sender, LayerEventArgs layerEventArgs)
        {
            SpriteBatch spriteBatch = ScreenManager.mainGame.mapDisplayDevice.SpriteBatchAlpha;

            if (visible)
            {
                Character.Draw(spriteBatch);
            }
        }

Here's the code for said draw method:

        public override void Draw(SpriteBatch spriteBatch)
        {
            base.Draw(spriteBatch);

            spriteBatch.End();
            //ends the spritebatch call block from xTile's initial call.

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
            //uses the same spritebatch, beginning a new block with new sprite sort mode.

            if (animations.ContainsKey(currentAnimation))
            {
                SpriteEffects effect = SpriteEffects.None;
                if (flipped)
                {
                    effect = SpriteEffects.FlipHorizontally;
                }
                spriteBatch.Draw(animations[currentAnimation].Frames[animations[currentAnimation].currentFrame].Image,
                    new Microsoft.Xna.Framework.Rectangle((int)location.X, (int)location.Y,frameWidth, frameHeight),
                    animations[currentAnimation].Frames[animations[currentAnimation].currentFrame].SizeAndsource,
                    Color.White * animations[currentAnimation].Frames[animations[currentAnimation].currentFrame].Alpha,
                    0.0f,
                    Vector2.Zero,
                    effect,
                    drawDepth);
            }

            foreach (FireParticle particle in fireParticles)
            {
                particle.Draw(spriteBatch);
            }
            foreach (SnowflakeParticle particle in waterParticles)
            {
                particle.Draw(spriteBatch);
            }
            foreach (WindParticle particle in airParticles)
            {
                particle.Draw(spriteBatch);
            }
            foreach (WindParticle2 particle in airParticles2)
            {
                particle.Draw(spriteBatch);
            }

            spriteBatch.End();
            //ends the spritebatch call block for my character.

            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
            //restarts the spritebatch call block in the same manner that xTile had started it.
        }

 

Mar 31, 2012 at 9:43 PM

Why don't you just use a RenderTarget? I thing it would be the best solution to this...

Mar 31, 2012 at 9:45 PM

I've never used a RenderTarget before, can you direct me to any useful documentation or tutorials on how they work?

Mar 31, 2012 at 10:01 PM

Okey, RenderTarget....

 

RenderTarget2D renderTarget;

// Function ...
{
rendertarget = new RenderTarget2D( 
                    Engine.GraphicsDevice,
                Engine.GraphicsDevice.PresentationParameters.BackBufferWidth,
                    Engine.GraphicsDevice.PresentationParameters.BackBufferHeight, false,
                    Engine.GraphicsDevice.PresentationParameters.BackBufferFormat,
                    DepthFormat.None);

                Engine.GraphicsDevice.SetRenderTarget(rendertarget);

Engine.GraphicsDevice.Clear(Color.Transparent); // Clear Screen

// Render your stuff here

Engine.GraphicsDevice.SetRenderTarget(null);



// After

Batch.Begin();

Batch.Draw(renderTarget, Engine.FullScreen, Color.White);
                    
Batch.End();

 

This is just a example from my engine, but when using RenderTarget it will clear the screen so you should do this befor you render the game sceen.

So I use GameScreenManager from Apphub, but managed so with this I have added a beforRender function. So it will render all stuff befor the main scene.

This is just a fast explanation of what it dose to let you know. 

Mar 31, 2012 at 10:07 PM

No offense, but that didn't tell me very much about what a RenderTarget does or how it would help me with my depth sorting within the spritebatch call blocks. I'll do some searching to find more in-depth information on RenderTargets, thank you for the help you've given me. :D

Mar 31, 2012 at 10:12 PM

Yeah, sorry I am really tired. But it renders all stuff to a Texture2D and then you can render that.

Jun 20, 2012 at 11:28 PM

Still looking for any sort of help with this, if possible. I found a work around myself by putting end calls and begin calls within my characters' draw methods, but it's sort of a hackjob and as my game grows larger, it would be really inefficient and will probably cause fps issues if I leave it as is until release.