SOLVED Overlaying 2 or More Sprites

hughrock18

Member
I COMPLETELY understand the concept of using surfaces (or shaders) to overlay one sprite image on top (or below) another.

Is that the only way(s) to do it though? If I want to, for example, overlay a player sprite with an armor sprite (sub images and all), are surfaces/shaders the only ways to do it? The sprite_merge function SOUNDED like it'd do what I wanted at first, but after reading the documentation, it seems like it'd only place the sub images of one sprite at the end of the other.

Is there a better way? I'm not too keen on the thought of looping through each sub image index (up to 8 per sprite at 128x128px) and using surfaces to draw one sprite over another. I'm not as confident with shaders (at least not enough to pull this off. I'm still relatively new to the subject). I thought of using the surface idea to create multiple sprites that would be cleared from memory when no longer used (instead of drawing the surface itself each step). That way, the code would loop through the sub images, making 1 surface at a time and appending it (got to remember how) to the end of a newly created sprite. The only issue I feared with that was the time it'd take for the device to cycle through the many sprites that'd need this. Even if it cycled only once, we're talking about a couple hundred sprites at the end of it all. I could run this once at the beginning of a room and just for the sprites within that room, but each sprite has so many directions and actions they can take... maybe I'm overthinking this. It's a lot to setup for testing on this scale...

Just to be clear. Each sprite has 8 directions, and (up to) 12 actions that they can perform. Leg sprites, body sprites, and head sprites all drawn to move in sync create a body. You can do multiple tasks while walking and running. Seemed easier than redrawing the same stupid leg animations over and over, and requiring a "walking" version and a "running" version of each action. This isn't even taking into account the armor you can equip to your character that would be drawn on to the near-naked leg/body/head sprites.

Anyone have any experience with this? I know I asked this already, but seriously, is there a better way? Any information would be appreciated. Thanks everyone!
 

NightFrost

Member
One approach people use is to split the player into separate spritesheets: legs, torso, hands, head. Player instance then just draws them in order so they overlap in intended manner. This lets the logic easily swap sheets of specific body parts, and you can draw new sheets more quickly by modifying just the necessary sheets into new skins.
 

hughrock18

Member
@night- this sounds promising. Can you point me to more info on this? I'm not sure how to implement it.

EDIT: I just reread your post, and it sounds like it's just using several draw function calls to draw the sprites (broken up). I was already using that method, and I wanted to see if I couldn't reduce the number of draw functions being called per step (at 60 steps per second). I mean, it'd be 6-9 draw function calls per character object and (up to) 15-ish characters visible on-screen at any given moment. Hmm... now that I have actually typed it out, it doesn't seem so bad... maybe I WAS overthinking it. I guess the point of this thread was to find out if there was a "better" way to go about it instead of a million draw calls.
 
Last edited:

NightFrost

Member
Yes that was what I was proposing. If you use surfaces, you'd have to draw sprites to surfaces anyway, and you'd save time only on steps when you don't need to redraw the characer (they don't turn) and you'd only need to draw surface to screen. But a relatively small amount of characters doing multiple draw calls won't have much impact. If your project is at a stage where you can test, have the characters just draw a number copies of a dummy sprite (just a black box) and see if performance is impacted.

If you want to go the surface route, you'd set up something like following. 1) In character object Create event, set up a variable to store surface and set -1 as value. 2) In Draw event, check if surface exists, and if it doesn't: 2A) create surface the size of character 2B) set surface as draw target 2C) draw sprites to the surface in order 2D) reset draw target. 3) Still in draw event, draw the surface to screen. Note that surface origin is upper left so when you draw at [x,y] that's how it orients. Downside is, this alone will not give you a collision box if you need it, as it is just a draw. You have to attach a dummy sprite to the object so a collision box is registered from it. The dummy does not need to be draw, it just needs to be the object's sprite.
 

hughrock18

Member
@NightFrost - I was afraid you might say that. Not to worry, I'm already aware of the idiosyncrasies between draw functions and bounding boxes. I use a simple "mask" sprite to define the character's position on the map. Basically their shadows on the ground.

What I'm getting from this is that there isn't a "better" way as far as you're aware. Not what I wanted, but unless someone says otherwise...
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Moderator
EDIT: I just reread your post, and it sounds like it's just using several draw function calls to draw the sprites (broken up). I was already using that method, and I wanted to see if I couldn't reduce the number of draw functions being called per step (at 60 steps per second). I mean, it'd be 6-9 draw function calls per character object and (up to) 15-ish characters visible on-screen at any given moment. Hmm... now that I have actually typed it out, it doesn't seem so bad... maybe I WAS overthinking it. I guess the point of this thread was to find out if there was a "better" way to go about it instead of a million draw calls.
Yes, you are overthinking it. Draw calls like this are cheap as long as the sprites being used are all on the same texture page and you aren't doing anything fancy like changing blend modes between each sprite draw. And for merging sprites that are going to constantly be animated, there really isn't a better way to do it....
 

hughrock18

Member
@Nocturne - the 3 main body segments (head body and legs) are drawn as white (very ghost looking) skin. The point was to allow the player to recolor the skin. I was planning on using blend modes for this. Would you recommend against this or is it another thing I shouldn't worry TOO much about?
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Moderator
@Nocturne - the 3 main body segments (head body and legs) are drawn as white (very ghost looking) skin. The point was to allow the player to recolor the skin. I was planning on using blend modes for this. Would you recommend against this or is it another thing I shouldn't worry TOO much about?
Well, it depends... If they are just white then you can simply set the image_blend variable to the colour you require and it'll (generally) be fine. changing the image_blend doesn't change the texture batching in any way and so is basically a "free" effect. In fact, I've used this idea myself in many a game and prototype! As long as the base sprites are black/white/grey then the image_blend value will work great. If they use other colours then it won't and you'd have to look at using shaders for it, in which case you would then also have to look at alternative ways to draw using batched sprites from a controller object.
 

TheouAegis

Member
I mean, if sprite_create_from_surface is still around, you could prerender everything onto a surface and then create a new sprite. But you'd need to destroy all the sprites and redo it every time the player changes equipment.
 

hughrock18

Member
@Nocturne - When you say "other colors", what do you mean by that? Are we talking green, blue, red kind of "other colors"? The base sprites are all gray (or rather various shades of gray). Add a hint of pink or red and it looks much like peach colored skin. You know. A simple effect to that aim. Does that count as this "free effect"?

@TheouAegis - I thought about that, but with 8 directions and up to 12 actions per direction and up to 9 frames per sprite; We are talking about a lot of sprites. I could run this surface building concept once at the beginning of a room, but I don't want a 10 second loading time when entering or exiting a building. Even if the player sprite is persistent and only runs this lengthy process once at the beginning of the game, the player has the ability to swap armor and weapons, and then will have to wait for this lengthy process each time they are simply moving from 1 piece of equipment to another just to show off the result of what they plan to equip. I was even thinking about allow the game to build the "base" sprite (using legs, body, and head). Then, allow for a separate code block that would build the armor and weapons (like a suit with nobody inside). Afterward, I could draw these sprites, one on top of the other, to make a complete character with armor. The issue there is that it really wouldn't do much except cut the number of draw calls per loop, but will still loop the same number of times to account for all directions and actions. If only there was a function that could easily create a new sprite by draw one (and its sub images) on top of another. I'm no programming expert, so for all I know, there'd be no different (performance-wise). In the end, it sounds like allowing 6-9 draw calls per step will be the "best" way to go about this. At least that way, the performance hit is spread out, so to speak...
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Moderator
@Nocturne - When you say "other colors", what do you mean by that? Are we talking green, blue, red kind of "other colors"? The base sprites are all gray (or rather various shades of gray). Add a hint of pink or red and it looks much like peach colored skin. You know. A simple effect to that aim. Does that count as this "free effect"?
Yes, that'll work fine. You can simply do something like "image_blend = merge_colour(c_red, c_white, 0.9);" and you'll get the effect you want and yes, it's cheap and "free" essentially. But, and this is what I meant by "other-colours", this ONLY looks good and works well on black/white/grey sprites. If the sprite has any other colours in it, it'll look... well... a bit crap!
 

hughrock18

Member
@Nocturne - That's about what I figured. I really appreciate the detailed answers. It has been extremely helpful, and now I have a solid idea of what comes next.

I'd consider this issue... solved.
 

kburkhart84

Firehammer Games
This is all my opinion...I haven't done these things and haven't done any testing, but I'll share anyway.

For combining sprites like this...I personally don't like the idea of using surfaces and creating sprites from that. Any run-time created sprites will be stuck on their own texture pages, and so you lose a lot of the benefit of those. Texture swaps aren't the massive performance hits some people think they are, but they aren't actually free either. And whatever the overhead is of creating those surfaces, you will have that hit everytime you swap armor. Also, surfaces aren't guaranteed to not get lost at any time, so you will need to either pull a buffer from the surface to store it, or recreate it anytime that happens. I understand that it isn't a common thing, but it should still be considered.

My opinion is that the better option to go with is what is suggested before, just breaking the sprites up and drawing them manually in draw events. You already have code for this in some form anyway since you would have to have it for the surfaces creation part. And the textures should already be loaded anyway so you aren't doing any extra texture swaps. It is a common method of making this happen.

Another consideration however...that performance concern you have with the speed of the surface creation, etc... I feel like you should do some testing on that. I think you will be pleasantly surprised with how fast redrawing those sprites to the surfaces and then making sprites is. I don't think it will be more than a portion of a second, unless you have a LOT of sprites you are redoing. If you prefer the surfaces method, I would run some tests before discarding it on the basis of speed of recreating the surfaces.

About the image blending...it is a good way to handle it, as mentioned though the sprites need to be designed as gray scale. This means you do have the limitation of a single "hue" unless you split things up, but the performance is really nice. Its a great way to go for many things. And if you are using this method on a few sprites that make up a final sprite(as discussed above), you can still get plenty of variety in color by the time you are done.
 

hughrock18

Member
@kburkhart84 - Thank you for your input. A small bit of testing shows that building surfaces isn't so bad (even when done each step). Although, I have decided to go the route of using several draw calls each step. As mentioned above, my base sprites are all drawn in shades of gray for the sake of customizing skin color. Armor and weapons are always rendered in the same color as they're drawn, so they are quite colorful. The separate draw calls make it a bit easier to handle color blending too. Once I have a better grasp of shaders then I'll be using those for the overlay fx (like a red tint when burning).
 
Top