Damage Blink Problems

I’m working on a large-scale metroidvania, and I’ve got quite a lot working. I’m currently trying to make the player blink red when they get hit, and it’s turning out to be much harder than expected.

To begin with, my player is a Spine object enveloped by a wrapper I wrote to make it similar to normal sprite objects. This means it is at heart a display group. I can’t just set the fill color of each object in the display group, because it ends up looking really strange and not like what I want at all. I ended up using a snapshot for the player and writing a custom shader with a blend parameter to phase between a flat-color silhouette and the normal shading of the player in a transition, and it’s working really well. The problem is, by making my player a snapshot, I’m opening my player up to the limitations of snapshots. My physics engine relies on the width and height of objects to decide their collision bounds, and with a snapshot, this isn’t the real size of the object. Thus, the player collides with things at the edge of the snapshot instead of at the edge of the player. If I try to fix this by shrinking the size of the snapshot down to fit the player better and get physics working, the player is clipped off by the edges of the snapshot.

What I’d love is to keep the snapshot (for later effect programming and such) but lose the clipping. Is this possible? If not, is there a way to apply a filter to a group without using a snapshot? If not, is there some other way I can do this? If not, does anyone have any other suggestions?

  • Caleb

sounds like you’re happy with everything except…

My physics engine relies on the width and height of objects to decide their collision bounds

…which is under your control, right?  if so, then maybe just a way to specify/override how the bounds are determined per object??

I’m with Dave. You would most likely be better served using a proxy physics object than the snapshot.

While it would be fairly simple in my physics engine to check for if the object is a snapshot and use object.group[1] dimensions for collision response instead, I also use the object’s width and height properties throughout my engine. Besides being a lot of extra code and complexity checking for snapshots everywhere, it feels wrong to me to use such a “hack” to do what feels like it should be fairly easy. Corona can already use fixed-box snapshots, and Corona can adjust the snapshot viewport area (which might be what I end up going with - adjust viewport for my physics engine sensor setup, then set to a bigger, non-clipping size and set some sort of special properties for the actual object’s size) so why can’t it just automatically adjust to fit its children?

As an alternative approach, is there a way to get the width and height of the snapshot’s actual content, rather than the rectangle? Maybe a special property or something?

  • Caleb

sure, everyone will have their own “bias” as to what feels like a “feature” and what feels like a “hack”.  personally, I’d hate being constrained to only using an object’s content bounds (for any number of reasons, fe imagine a square “sea urchin” sprite image but you might want to collide “tighter” on the “body” and ignore some of the “spikes” area) so I’d store my own versions of width/height (or more, depending on whether i’m also constrained to just AABB’s or other geometry) regardless of whatever corona itself supported (or didn’t).

if corona’s snapshots all of a sudden started sizing themselves dynamically to their content, that would be a breaking change for anyone who might be using them specifically to achieve that “cropping”, so i doubt you’ll see that happen.  (plus you could easily blow up your texture memory)  by extension, that’s also why it’s “not much use” to talk about the “bounds” of a snapshot in terms of its contents – ie, there’s nothing preventing you from putting an object into a 200x00 snapshot at relative “offscreen” coordinates of -1000000,1000000, so is that now a 1-million-square-pixel snapshot?  (cuz i guarantee you don’t have the texture memory to support it :D)

those coords as content bounds would be fine in a group which is essentially just “a list of display objects along with a transform”, but the two are different things, so they behave differently - imo it’s simply not reasonable to expect a snapshot to behave like a group in regard to its dimensions.

wouldn’t it just be simpler to put all your discrete content into a group first, then put the group into the snapshot?  cuz you want group-type bounds, right?  but you want to render that group’s content to texture for effects and what-not, right?  hth

I know about using alternative dimensions throughout my engine. My physics engine is handmade, and works by placing sensors to create complex physics collision rules. I adjust the sensors based on multiples of the width and height, so it dynamically resizes based on the size of the object. I’ve written my engine around flexibility, so I can resize just about anything, remake just about anything, redraw just about anything, or recode just about anything and the rest of the engine adjusts to fit it. I’m not “constrained to only using an object’s content bounds” at all. I literally have a 300-SLOC-long configuration file that sets all the required properties for the rest of the engine to use. But changing the player from a 128-pixel-tall Spine animation to a quarter-screen-sized snapshot (the size required to avoid clipping animations, what with weapon swings and climb repositioning and all) without actually resizing the player’s object, but instead just adding a couple hundred empty pixels to either side, is a breaking change.

so why can’t it just automatically adjust to fit its children?

I’m not suggesting here that Corona change their default snapshot functionality, I’m just saying that it would be really great if the option were available to do it as I’m describing. My phrasing may have been misleading. What I was imagining is this:

local obj = display.newSnapshot() obj.clipChildren = false

that’s also why it’s “not much use” to talk about the “bounds” of a snapshot in terms of its contents – ie, there’s nothing preventing you from putting an object into a 200x00 snapshot at relative “offscreen” coordinates of -1000000,1000000, so is that now a 1-million-square-pixel snapshot?  (cuz i guarantee you don’t have the texture memory to support it :D)

No offense intended to you, but your logic is faulty here. Game engine developers shouldn’t say “If we do X, someone might do Y and wreck it. Thus, we shouldn’t do X.” That would lead to no file I/O of any sort (the file might be corrupted, or too large, or what-have-you), no media functions (the memory might not be sufficient), no math functions (there’s always a risk of division by zero or using a number outside a function’s domain) – the list could go on and on, resulting in death of civilization as we know it ;). Instead of safeguarding against edge cases by removing the feature (note that I’m not saying the Corona devs are doing that; I’m just expanding my argument), programmers should rely on normal computer programming practice:

if size \> MAX\_SUPPORTED\_SIZE then error("The snapshot's children have expanded the snapshot's dimensions beyond the device's texture limit.") end

That way, programmers would code around the limitations themselves instead of being limited by a safety measure to keep people away from an edge case.

wouldn’t it just be simpler to put all your discrete content into a group first, then put the group into the snapshot?  cuz you want group-type bounds, right?  but you want to render that group’s content to texture for effects and what-not, right?

And we’re back to the beginning… My object is a display group. It’s a souped-up Spine animation, each component of which is inserted into a group. I’m inserting it into a snapshot for effects, and I’m having the problems because of that. I can’t insert the whole map into a display group because I only want the player to flash red, and I can’t not use snapshots because I want the player to flash red.

  • Caleb

To get back to the original question: I think I could solve this if there were a way to do a one-shot snapshot render. Something like this:

changeObjectParent(player, snapshot) snapshot:render() changeObjectParent(player, originalParent)

Right now, it looks like the only way to render a snapshot is to invalidate it and wait until the next frame to pass. If the player isn’t in the snapshot when the render loop is called, nothing is rendered to the snapshot. Is there a way to force the snapshot to render when you want it to?

  • Caleb

cheers, “fight the good fight”, more power to ya.  :)  your proposal implies recreating the snapshot (and its shader) every time content bounds change (which, presumably, with a spine animation would be fairly frequently).  i’ll let you consider the performance implications.

so i’m just trying to suggest to you workarounds that might actually work given what corona actually is rather than some wish for what it might be.

how about:  let’s go back to the days before you implemented a snapshot at all.  at that time, apparently, the only thing not working was you didn’t have a “nice” way to shade the images red (cuz just setting the fill color to red, a multiply effect, can cause unusual artifacts, especially if you have little or no red channel to begin with - i get that).  is that a fair re-summary?

if so, then why not apply your shader to the constituent parts?  just as an example, take their “spineboy” example, and substitute this bit, maybe it’ll inspire a new approach?

function skeleton:createImage (attachment) local img = display.newImage( "examples/spineboy/images/" .. attachment.name .. ".png") img.fill.effect = "filter.sepia" return img end

So it looks like these are my options:

Wait for Corona to implement on-demand snapshot rendering. I was meaning to keep a single snapshot to hold the player’s “snapshotted” image and rendering to it each frame rather than recreating it each frame, which, as you say, could get pretty hairy for performance. This would probably be the ideal situation, but (as you mentioned) I know all about waiting for developers to implement features a fringe population needs ;).

Use the shader for each image. This is a good point; I’ve never thought of this. I ruled out a per-child approach when I tried groups and :setFillColor and never came back to it when I made the shader (which should fix the problems :setFillColor() had). I’ll try this out and see how it goes. If it works, this’ll probably be the most efficient and quick way to do things.

Refactor the physics engine to allow for invisible groups. I’ve been trying this and it doesn’t seem to be working. The idea is that the snapshot would work as a sort of invisible layer and, though the player is technically inserted into the snapshot, everything runs as though the player were in the map layer. The problem is, though physics works with :localToContent() and such, I have transitions and other stuff going at times and that would all be relative to the snapshot rather than the map (which is at the same time moving according to offsets, camera movement, parallax, etc.).

Do some sort of mask magic…? Is there a way to make a red rectangle or something over the player and mask it to only paint on the player’s graphic? I haven’t researched this at all, but it feels almost plausible to me.

Do some sort of “blitting”/“painting”/“stamping” to a snapshot…? I’m almost 100% sure this is impossible, unfortunately. This goes with my above post about rendering. It would be great if there was some sort of method like this:

local canvas = display.newSnapshot() -- In enterFrame listener canvas:stamp(object, x, y) -- canvas gets the image of the object -- Later canvas:useShaderToBeColoredHowIWantIt() -- Awesome function, ain't it?

I think I’ll go with your suggestion about applying the filter to each child and see how that goes.

  • Caleb

Looks like applying the filter to each child works perfectly. Thanks for thinking of that!

  • Caleb

I don’t have time to answer all the interesting bits, but you might want to look into the new texture canvas feature in the daily builds to let you build the spline frames and store them before you run the game (IE preprocessing them to get all the frames). I am not yet sure if you can use a canvas object in a sprite sheet, but you *probably* can, since they are referenced just like any other image. Think of them as a snapshot you can share between sprites etc.

@rakoonic:

Interesting idea. I’ll do some research into that.

  • Caleb

sounds like you’re happy with everything except…

My physics engine relies on the width and height of objects to decide their collision bounds

…which is under your control, right?  if so, then maybe just a way to specify/override how the bounds are determined per object??

I’m with Dave. You would most likely be better served using a proxy physics object than the snapshot.

While it would be fairly simple in my physics engine to check for if the object is a snapshot and use object.group[1] dimensions for collision response instead, I also use the object’s width and height properties throughout my engine. Besides being a lot of extra code and complexity checking for snapshots everywhere, it feels wrong to me to use such a “hack” to do what feels like it should be fairly easy. Corona can already use fixed-box snapshots, and Corona can adjust the snapshot viewport area (which might be what I end up going with - adjust viewport for my physics engine sensor setup, then set to a bigger, non-clipping size and set some sort of special properties for the actual object’s size) so why can’t it just automatically adjust to fit its children?

As an alternative approach, is there a way to get the width and height of the snapshot’s actual content, rather than the rectangle? Maybe a special property or something?

  • Caleb

sure, everyone will have their own “bias” as to what feels like a “feature” and what feels like a “hack”.  personally, I’d hate being constrained to only using an object’s content bounds (for any number of reasons, fe imagine a square “sea urchin” sprite image but you might want to collide “tighter” on the “body” and ignore some of the “spikes” area) so I’d store my own versions of width/height (or more, depending on whether i’m also constrained to just AABB’s or other geometry) regardless of whatever corona itself supported (or didn’t).

if corona’s snapshots all of a sudden started sizing themselves dynamically to their content, that would be a breaking change for anyone who might be using them specifically to achieve that “cropping”, so i doubt you’ll see that happen.  (plus you could easily blow up your texture memory)  by extension, that’s also why it’s “not much use” to talk about the “bounds” of a snapshot in terms of its contents – ie, there’s nothing preventing you from putting an object into a 200x00 snapshot at relative “offscreen” coordinates of -1000000,1000000, so is that now a 1-million-square-pixel snapshot?  (cuz i guarantee you don’t have the texture memory to support it :D)

those coords as content bounds would be fine in a group which is essentially just “a list of display objects along with a transform”, but the two are different things, so they behave differently - imo it’s simply not reasonable to expect a snapshot to behave like a group in regard to its dimensions.

wouldn’t it just be simpler to put all your discrete content into a group first, then put the group into the snapshot?  cuz you want group-type bounds, right?  but you want to render that group’s content to texture for effects and what-not, right?  hth

I know about using alternative dimensions throughout my engine. My physics engine is handmade, and works by placing sensors to create complex physics collision rules. I adjust the sensors based on multiples of the width and height, so it dynamically resizes based on the size of the object. I’ve written my engine around flexibility, so I can resize just about anything, remake just about anything, redraw just about anything, or recode just about anything and the rest of the engine adjusts to fit it. I’m not “constrained to only using an object’s content bounds” at all. I literally have a 300-SLOC-long configuration file that sets all the required properties for the rest of the engine to use. But changing the player from a 128-pixel-tall Spine animation to a quarter-screen-sized snapshot (the size required to avoid clipping animations, what with weapon swings and climb repositioning and all) without actually resizing the player’s object, but instead just adding a couple hundred empty pixels to either side, is a breaking change.

so why can’t it just automatically adjust to fit its children?

I’m not suggesting here that Corona change their default snapshot functionality, I’m just saying that it would be really great if the option were available to do it as I’m describing. My phrasing may have been misleading. What I was imagining is this:

local obj = display.newSnapshot() obj.clipChildren = false

that’s also why it’s “not much use” to talk about the “bounds” of a snapshot in terms of its contents – ie, there’s nothing preventing you from putting an object into a 200x00 snapshot at relative “offscreen” coordinates of -1000000,1000000, so is that now a 1-million-square-pixel snapshot?  (cuz i guarantee you don’t have the texture memory to support it :D)

No offense intended to you, but your logic is faulty here. Game engine developers shouldn’t say “If we do X, someone might do Y and wreck it. Thus, we shouldn’t do X.” That would lead to no file I/O of any sort (the file might be corrupted, or too large, or what-have-you), no media functions (the memory might not be sufficient), no math functions (there’s always a risk of division by zero or using a number outside a function’s domain) – the list could go on and on, resulting in death of civilization as we know it ;). Instead of safeguarding against edge cases by removing the feature (note that I’m not saying the Corona devs are doing that; I’m just expanding my argument), programmers should rely on normal computer programming practice:

if size \> MAX\_SUPPORTED\_SIZE then error("The snapshot's children have expanded the snapshot's dimensions beyond the device's texture limit.") end

That way, programmers would code around the limitations themselves instead of being limited by a safety measure to keep people away from an edge case.

wouldn’t it just be simpler to put all your discrete content into a group first, then put the group into the snapshot?  cuz you want group-type bounds, right?  but you want to render that group’s content to texture for effects and what-not, right?

And we’re back to the beginning… My object is a display group. It’s a souped-up Spine animation, each component of which is inserted into a group. I’m inserting it into a snapshot for effects, and I’m having the problems because of that. I can’t insert the whole map into a display group because I only want the player to flash red, and I can’t not use snapshots because I want the player to flash red.

  • Caleb

To get back to the original question: I think I could solve this if there were a way to do a one-shot snapshot render. Something like this:

changeObjectParent(player, snapshot) snapshot:render() changeObjectParent(player, originalParent)

Right now, it looks like the only way to render a snapshot is to invalidate it and wait until the next frame to pass. If the player isn’t in the snapshot when the render loop is called, nothing is rendered to the snapshot. Is there a way to force the snapshot to render when you want it to?

  • Caleb

cheers, “fight the good fight”, more power to ya.  :)  your proposal implies recreating the snapshot (and its shader) every time content bounds change (which, presumably, with a spine animation would be fairly frequently).  i’ll let you consider the performance implications.

so i’m just trying to suggest to you workarounds that might actually work given what corona actually is rather than some wish for what it might be.

how about:  let’s go back to the days before you implemented a snapshot at all.  at that time, apparently, the only thing not working was you didn’t have a “nice” way to shade the images red (cuz just setting the fill color to red, a multiply effect, can cause unusual artifacts, especially if you have little or no red channel to begin with - i get that).  is that a fair re-summary?

if so, then why not apply your shader to the constituent parts?  just as an example, take their “spineboy” example, and substitute this bit, maybe it’ll inspire a new approach?

function skeleton:createImage (attachment) local img = display.newImage( "examples/spineboy/images/" .. attachment.name .. ".png") img.fill.effect = "filter.sepia" return img end

So it looks like these are my options:

Wait for Corona to implement on-demand snapshot rendering. I was meaning to keep a single snapshot to hold the player’s “snapshotted” image and rendering to it each frame rather than recreating it each frame, which, as you say, could get pretty hairy for performance. This would probably be the ideal situation, but (as you mentioned) I know all about waiting for developers to implement features a fringe population needs ;).

Use the shader for each image. This is a good point; I’ve never thought of this. I ruled out a per-child approach when I tried groups and :setFillColor and never came back to it when I made the shader (which should fix the problems :setFillColor() had). I’ll try this out and see how it goes. If it works, this’ll probably be the most efficient and quick way to do things.

Refactor the physics engine to allow for invisible groups. I’ve been trying this and it doesn’t seem to be working. The idea is that the snapshot would work as a sort of invisible layer and, though the player is technically inserted into the snapshot, everything runs as though the player were in the map layer. The problem is, though physics works with :localToContent() and such, I have transitions and other stuff going at times and that would all be relative to the snapshot rather than the map (which is at the same time moving according to offsets, camera movement, parallax, etc.).

Do some sort of mask magic…? Is there a way to make a red rectangle or something over the player and mask it to only paint on the player’s graphic? I haven’t researched this at all, but it feels almost plausible to me.

Do some sort of “blitting”/“painting”/“stamping” to a snapshot…? I’m almost 100% sure this is impossible, unfortunately. This goes with my above post about rendering. It would be great if there was some sort of method like this:

local canvas = display.newSnapshot() -- In enterFrame listener canvas:stamp(object, x, y) -- canvas gets the image of the object -- Later canvas:useShaderToBeColoredHowIWantIt() -- Awesome function, ain't it?

I think I’ll go with your suggestion about applying the filter to each child and see how that goes.

  • Caleb