Hello Guest

Author Topic: Coloring sprite/animation on one side dynamicly - water effect  (Read 6491 times)

mrkake

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 17
    • View Profile
Hi,

I am hoping to find some ideas how to approach the following problem.
We are working on a game which takes place on the water.

For example a boat, and when in the water, about 1/3rd of the bottom of the sprite has a transparent blue color over it to make it appear the boat is in water.
Currently, we drew this in the sprite itself, but its quite tedious as there are multiple rotations for each sprite and there are many other sprites which can be in water.

Ideally, I would like to somehow apply automatically the "blue" over the sprite depending if the item is in water or not, and additionally, would like to create a bopping effect for idle animation, which means the blue percentage shift up and down a few pixels each 1/2 second or something like this.

At first I thought this could be solved by just creating a square blue , putting on the layer above the sprite and setting the alpha channel to make it slightly transparent but the problem is that the area of water surrounding also obviously gets this rectangle of blueness on it. Ideally, I can somehow disable the pixels in the blue square when there is not a target sprite below the pixel. Is there some way to achieve this effect?  Or a different approach entirely.

Thanks

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Coloring sprite/animation on one side dynamicly - water effect
« Reply #1 on: April 28, 2015, 03:45:52 pm »
You should use a shader for this, thats probably the easiest option - once you know where your water layer is (eg. 0, 0, 0) you can tint the sprites as it is inside this region.

mrkake

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Coloring sprite/animation on one side dynamicly - water effect
« Reply #2 on: April 28, 2015, 08:43:23 pm »
I guess this is what I was thinking originally, but I was hoping for a different solution I guess, since I don't really have shader knowledge.

Maybe I can find someone to pay to help write a shader

mrkake

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Coloring sprite/animation on one side dynamicly - water effect
« Reply #3 on: May 08, 2015, 06:54:07 pm »
Ok -- update, I have the shader now, but, I'm a bit unclear how to get it working with sprite collection.

the problem is like follows in this example:

we have a crate sprite collection. There are 16 sprites in the collection depending on the rotation of the object. In order to get this to work with the shader, we have also created a grayscale gradient map for each rotation (black is the lowest height and white the highest height).  It's trivial to add the gradient texture/material when its just one sprite, but I'm a little confused how to add it for the sprite collection.

2d toolkit creates a compressed atlas from the sprite collection so do i need to somehow convert the gradient map to be in the same orientation when all 16 are packed? how do i do this? or how can I specify this graident map file actually contains 16 graident maps, one for each rotation in the collection?

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Coloring sprite/animation on one side dynamicly - water effect
« Reply #4 on: May 08, 2015, 08:39:42 pm »
Don't use the UVs, derive them from world position for that - that will be the easiest and probably most sensible thing to do.

mrkake

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Coloring sprite/animation on one side dynamicly - water effect
« Reply #5 on: May 08, 2015, 08:51:09 pm »
I'm not sure what you mean about this, how can I know from the world position when the texture/sprite is perspective based?

It is a 2d game, but we create "rotated" sprites to give the perception of depth inside the game. So, when the sprite is facing forward, the depth is simply, the Y axis  (up / down), but, when rotated 45 degrees, the sprite depth is more like a V shape, when the whole V is the bottom of the crate

check the attached images,  notice the difference in boat and the crate rotations, how the water level when its head on is a line ---- and when turned a V.  But the world position of the sprite is exactly the same, its just using a new sprite from the sprite collection. So as far as I know we need to use the gradient map to determine it?

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Coloring sprite/animation on one side dynamicly - water effect
« Reply #6 on: May 08, 2015, 11:09:11 pm »
Ah ok yeah, no way of doing it without a gradient map in your scenario. You could I suppose turn off rotation in the atlas...
Your sprites don't need a full alpha though - you can use the alpha range to encode your "depth" into the water, i.e. what you're using your gradient for.

mrkake

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Coloring sprite/animation on one side dynamicly - water effect
« Reply #7 on: May 17, 2015, 07:41:28 pm »
Ok I'm having a new problem and I might have to just write a lot of annoying code to fix this, but I wanted to bring it up to see what options are.

The problem I'm having is that, for example with the crate, I have attached this new shader to every crate. Inside the game code, I have some code which changes the settings inside the shader, but the issue is that these settings do not stick when the sprite is changed.

2d toolkit is called the UpdateMaterial() method which detects that something in the material has changed, and then swaps the material back to the original material for the sprite collection which reverts my settings.

I'm not sure how to fix this other than calling my own additional update material method or something after changing the 2dtoolkit sprite.  But I was wondering why it's doing this, I read inside the code some comments that said the purpose of the code is to change the material when switching between sprite collections, but it's clearly not actually checking to see if the sprite collection has been changed, it's just checking if the material is the same exact material... if the code actually checked the sprite collection instead I wouldn't have this problem. But I'm not sure what the impact of that would be for other things.

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Coloring sprite/animation on one side dynamicly - water effect
« Reply #8 on: May 17, 2015, 09:03:32 pm »
You should manage your own material management code, you can do it by hooking into SpriteChanged.
The logic should be something like this -

Code: [Select]
void OnSpriteChanged(sprite)
{
   // you know the system has changed the material
  Renderer renderer = sprite.GetComponent<Renderer>();
  if (!materialLookup.Contains(renderer.sharedMaterial))
  {
    materialLookup[renderer.sharedMaterial] = CreateNewMaterialFrom(renderer.sharedMaterial);
  }
  renderer.sharedMaterial = materialLookup[renderer.sharedMaterial];
}

The answer to why it does it regardless of wether the collection has changed is because you can have multiple materials within one collection (check docs). Its a contrived weird case I know, but that went in a couple years ago and can't change the behaviour now due to people expecting it to work one way.

You do have source though, so if you know you only ever use 1 material in a collection and don't use atlas spanning - you can change UpdateMaterial to only set the material when its null and never modify it otherwise.

mrkake

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Coloring sprite/animation on one side dynamicly - water effect
« Reply #9 on: May 19, 2015, 04:08:09 am »
thanks that was really helpful, I did not realize that the sprite gave access to the spritechanged event, this really worked great. :)