Underwater displacement/ripple effect? [SOLVED]


(Jordan Magnuson) #1

Hey everyone, it’s been a while since I’ve been on these forums (since before the switch to Discourse), so regards to anyone who’s been around for that long.

I’m looking to make a few tweaks to one of my experimental projects, and am wondering if anyone has a rendering override for a basic underwater ripple/displacement effect? Or any idea on how to best achieve that kind of effect?

Here’s the game I’m working on: http://www.gametrekking.com/the-games/cambodia/a-brief-history-of-cambodia/play-now

I’d just like to make the hand and squares ripple a bit when they’re underwater…

Thanks in advance to anyone who can help!


(Nicole Brauer) #2

Something like this? (only underwater)

I was working on the exact same thing. I did this in HaxePunk but it should work just as well with Flash, but doing this a lot can be quite intensive and maybe slow down your game a bit. Use it with caution.

Here’s how you do it:

You basicly have to get the BitmapData of your entities/graphics, then do some manipulation to it with BitmapData.copyPixels(); For example you could offset all pixels based on a sine curve (which would get you a nice ripple effect, i use something more random where I calculate an Array of offsets with different heights and then animate that downwards to make it seem moving). And then render this BitmapData.

I don’t have time to check it but something along these lines:

public function MyEntity()
{
    //Get the BitmapData of your sprite
    var mybitmapdata:BitmapData = FP.getBitmap(IMAGE_TO_APPLY_RIPPLE_EFFECT_ON);

    graphic = new Image(mybitmapdata);
}

override public function update():void
{
    //You can also do this in the render() function

    for (var i:int = 0; i < mybitmapdata.height; i++) //Go through each row of pixels in mybitmapdata
    {
        //and give it a random offset (you could also use sine curve, or other)
        mybitmapdata.copyPixels(FP.getBitmap(IMAGE_TO_APPLY_RIPPLE_EFFECT_ON), new Rectangle(0, i, mybitmapdata.width, 1), new Point(FP.choose(-1,0,1), i));
        //so we copy a rectange (line) from the original image and offset it by either -1, 0, or 1 pixel

    }

    super.update();
}

You can also do this to the whole screen buffer, FP.buffer, or group multiple images together in one BitmapData so you don’t have to do it individually to each entity/graphic.


(Jordan Magnuson) #3

Thanks @VoEC for the super helpful reply! That’s exactly the kind of effect I was going for.

Based on your input I’ve created a generic RippleImage class that extends Image, and adds a sine ripple and alpha effect to any of the image’s pixels that are below a given “water line” on the screen. In this case I’ve done the “rippling” in the image’s render() function override.

Here’s the code on github, in case anyone else is ever interested in creating this effect: https://gist.github.com/JordanMagnuson/1062f873e1e843bfc4bc

(Let me know if there’s any obvious way the efficiency could be improved, etc.)