13
\$\begingroup\$

My game is created using Phaser, but the question itself is engine-agnostic.

In my game I have several environments, essentially polygonal areas that player characters can move into and be affected by. For example ice, fire, poison etc' The graphic element of these areas is the color filled polygon area itself, and particles of the suitable type (in this example ice shards). This is how I'm currently implementing this - with a polygon mask covering a tilesprite with the particle pattern:

enter image description here

The hard edge looks bad. I'd like to improve by doing two things: 1. Making the polygon fill area to have a soft edge, and blend into the background. 2. Have some of the shards go out of the polygon area, so that they are not cut in the middle and the area doesn't have a straight line

for example (mockup):

enter image description here

I think 1 can be achieved with blurring the polygon, but I'm not sure how to go about with 2.

How would you go about implementing this?

\$\endgroup\$
  • 2
    \$\begingroup\$ That looks awesome. Can I have a link to your game please? :) \$\endgroup\$ – ashes999 May 30 '14 at 13:47
  • \$\begingroup\$ @GameAlchemist Here's the tile image i.imgur.com/y54CeQ9.png \$\endgroup\$ – OpherV May 30 '14 at 13:51
  • \$\begingroup\$ @ashes999 It's still a work in progress. I'll definitely post a link here once I have it up :) \$\endgroup\$ – OpherV May 30 '14 at 13:52
  • \$\begingroup\$ Notice it's a transparent PNG with white objects. If you view it on a white background (as as often the case when opening a picture in a browser) you won't see anything \$\endgroup\$ – OpherV May 30 '14 at 14:33
  • \$\begingroup\$ @OpherV that would be great. Please just edit your question and post a link -- that's probably the most on-topic way to market it on this site :) \$\endgroup\$ – ashes999 May 30 '14 at 15:25
2
\$\begingroup\$

1.If you want something that's close to your mockup I'd use particles (It doesn't have to be a fully blown particle system).

Render your particles in the form of the polygon on a RenderTexture. Make sure to use additive blending on the particles. The particles inside of the polygon will smoothly blend into each other while the particles on the outside will give the soft edge that you want. (An example of the effect can be watched in this youtube video: Additive Particles Video Now render the RenderTexture onto your main screen and you're done. The RenderTexture is necessary so that the particles don't blend with your background.

You can try to put the triangles directly onto the particle texture and see how this works out. Otherwise render them on top of your "particle soup" as a separate layer.

Created a quick mockup in an updated jsfiddle that looks like this Demo You can find the updated demo here

2.Each particle has a velocity and an origin. When your player touches the polygon, you change each particles velocity proportional to the players velocity. The farther a particle is away from your player, the less it is affected by the players velocity.

The formula to calculate a particles velocity would be something like this:

//player.velocity and particle.velocity are vectors 
//k is a factor to enhance or weaken the influence of players velocity
var distanceToPlayer = (player.position - particle.position).length();
particle.velocity = particle.velocity + ((k * player.velocity) + particle.velocity) * (1/distanceToPlayer);

To calculate the position of the particle you put this in your update method:

var speedY = -(springConstant * (particle.position.y - particle.origin.y)) - (dampingFactor * particle.velocity.y);
var speedX = -(springConstant * (particle.position.x - particle.origin.x)) - (dampingFactor * particle.velocity.x);

particle.position.y = particle.position.y + speedY;
particle.position.x = particle.position.x + speedX;

particle.velocity.x = particle.velocity.x + speedX;
particle.velocity.y = particle.velocity.y + speedY;

This should give you a "fluid" where each particle swings around its origin when the player stirs the fluid. The springConstant changes how much a particle swings away from its origin and the dampingFactor how fast the particle comes to rest. You may have to tweak the code since its the modified version of a 1d simulation I use in my game.

Now with a demo: Demo Just tweak the 3 constants at the top until the fluid behaves like you want it to.

\$\endgroup\$
  • \$\begingroup\$ That's a really interesting idea to solve #1! I like it. How would you suggest implementing the triangle movement\spacing? \$\endgroup\$ – OpherV May 31 '14 at 13:11
  • 1
    \$\begingroup\$ I edited the original post to answer question #2. \$\endgroup\$ – zilluss May 31 '14 at 18:19
  • \$\begingroup\$ added a small demo of the particle effect. I think you could get your desired effect with a little tweaking. \$\endgroup\$ – zilluss Jun 3 '14 at 8:57
  • \$\begingroup\$ I ended up using your solution, it's the closest to the effect I was looking to achieve. Thanks! One question though - how would I clamp the springiness in your examples, so that really slight movements won't cause the particles to jump such huge distances? \$\endgroup\$ – OpherV Jun 4 '14 at 14:24
  • \$\begingroup\$ You can play around with the dampingFactor and the springConstant. A high damping will bring the particles faster to a rest. A lower spring constant lowers the speed of the particles. Unfortunately, both values let the particle soup feel more viscous. So instead, when your player touches the particle, you can clamp the maximum velocity the player adds to the particle, like this: particle.velocity.x = clamp(maxVelocity, -maxVelocity, particle.velocity.x + ((playerInfluenceFactor * deltaVelocityX) + particle.velocity.x) * (1/distanceToPlayer)); for clamp see: stackoverflow.com/a/11409944 \$\endgroup\$ – zilluss Jun 6 '14 at 16:03
4
\$\begingroup\$

My thoughts about these two points:

  1. You could use shader blur, but that's going to be very expensive. Instead I would draw an extra border of triangles that fade from translucent in the center to transparent at the edges, to simulate the "blur". I've done that in a game of mine and it works pretty well. Here are two screenshots of a rainbow-ish booster in my game.

    enter image description here enter image description here

    The outer border has a gradient. In my situation, the border doesn't start at the same opacity as the inner part, but if you set those opacities equal, you will have a nice fade.

  2. I would program a particle system and make the particles follow the polygon. By doing so, you don't have to worry about what will happen at the edges. The dynamics of your particle system will make sure that the particles are inside the polygon and evenly distributed. You could try to make the closest particles push each other away, but make it with a lot of "mass" so you have inertia and it looks smooth. To make this thing fast, there are some possibilities, but the big problem is going to be the time complexity of the pushing each other mechanism. If you make each particle push every other particle, you will have O(n^2), which is not good, if you're having for example 100 particles in your system. A good read about how you can optimize this is this presentation of PixelJunk: http://fumufumu.q-games.com/gdc2010/shooterGDC.pdf

    A simpler approach would be to connect each particle to three or four other particles when constructing the particle system. Now every particle will only have to push the four other particles it is connected to. However, this approach makes turbulences in your particle system impossible. But this doesn't seem to be a problem, since your current situation uses a static texture. This approach will be O(n) which is great.

\$\endgroup\$
  • \$\begingroup\$ Thanks! 1. I'm having a hard time visualizing this. Can you please post a mockup of how it it looks\works in your game? 2. Interesting! will read up on that \$\endgroup\$ – OpherV May 30 '14 at 13:45
  • \$\begingroup\$ Thanks for the images. I can see how that would work in a tube or line based shape, but how will that work with a polygon? Won't the gradients of the triangles projected from each side not line up nicely...? \$\endgroup\$ – OpherV May 30 '14 at 15:47
  • \$\begingroup\$ Make them fit nicely. That is the idea. This involves some math and computing points of intersection etc. You could also subdivide the border and smooth it out. Tons of possibilities. \$\endgroup\$ – Martijn Courteaux May 30 '14 at 16:15
3
\$\begingroup\$

The idea i had when reading your post was this one :
• build a set of tiles that you'll use for your areas.
• render the area polygon on a small temporary canvas at the tile resolution (ex : if tiles are 16X16, render at a (16X,16X) lower resolution).
• use that temporary canvas to decide wether to render tiles or not on the main canvas :
if a point is set on the low-res canvas, draw a 'random' tile on the main canvas. if a point is just a neighbor of a set point, draw a 'random' tile at a lower opacity (to make transition) on the main canvas.

I was afraid that lowering resolution would create a block effect, but even with 20X20 tiles, it looks quite good :

enter image description here

Steps for this are : take your polygon :
enter image description here

Draw the polygon at your tile resolution : enter image description here (!! yes it's the mall red thing).

Then use the imageData of the low-resolution canvas to decide wether to draw a tile or note.
If a pixel is set on the low-res canvas, it means we should draw the tile : pick up a 'random' tile index to choose which tile to draw. That random index should always be the same for a given area/tile.
If a point is empty but next to a filled point, also draw a tile, but with half opacity.

enter image description here

So let's draw the tiles :

enter image description here

For the polygon i just draw several times the polygon, scaling it down, and increasing opacity on each draw (one might use the globalCompositeOperation 'lighter', also ).

enter image description here

Once you add up everything, it gives :

enter image description here

fiddle is here :

http://jsfiddle.net/gamealchemist/T7b4Y/

let me know if this helps.

\$\endgroup\$
  • \$\begingroup\$ Thanks for elaborating on your solution and providing the code! What do you mean by "Then use the imageData of the low-resolution canvas to decide wether to draw a tile or note". How do you use the small image data to decide where\how to draw on the big image? And using this method how can I avoid the overlap of the triangles so achieve spacing similar to my mockup? \$\endgroup\$ – OpherV May 31 '14 at 14:09
  • \$\begingroup\$ I mean it's a complete boolean test : Do i need to fill this tile ? , true or false, is given by the test of the low-res test on imageData[(x+y*width)*4] != 0, that is to say == 'did i draw something on the lower res canvas at that tile place ?'. Then if yes, i use some elaborated prime-number-filled formula (getRandomNumber) to go from (x,y) to a 'random' tile index that will always provide the same number for a given area + (x,y). I don't see how things could overlap if you properly define your polygon so i don't get your second question. \$\endgroup\$ – GameAlchemist May 31 '14 at 15:28
1
\$\begingroup\$

Just an idea:

In your tile, the "pieces" are about 80px wide at most. I would suggest, making 2 areas. You draw your original polygon, and you make a mockup of it about 80 pixels out from each edge. You then draw your tiles into the bigger polygon.

Then, All "pieces" which have a pixel outside of the inner polygon, and no intersection with the inner polygon you can flood fill them out with transparency.

This is very high level, but I figured I'd share it with you. There's a lot of detail to be determined here.

A crude image to demonstrate:

enter image description here

If the inner black polygon were the original, you would erase all of the polygons with a red dot.

\$\endgroup\$
  • \$\begingroup\$ How would you check for intersection for the pieces embedded in the tile image with the inner polygon though? \$\endgroup\$ – OpherV May 30 '14 at 15:45
  • \$\begingroup\$ @OpherV Uhmm, You can determine if point X is in a polygon right? You can loop through all the pixels in the outer polygon, and for each white pixel, flood check all pixels, and see if any lie in the inner/outers. This doesn't sound particularly efficient though, but once you have something you can think of ways to optimize? \$\endgroup\$ – user46560 May 30 '14 at 15:48
  • \$\begingroup\$ That's post-processing done on the CPU. Hardly optimizable on itself. Your idea could work well if the inner polygon and the outer get connected by a triangle strip. The the OP could add vertex attribute info and tag each vertex as inside or outside. Then, in the vertex shader, the opacity/alpha can be linearly interpolated from a less transparent value to a complete opaque one. \$\endgroup\$ – teodron May 30 '14 at 16:23
  • \$\begingroup\$ @teodron This is the point I tried to make in the answer. It's a high level idea, and I'm not really a game developer. I just had an idea. \$\endgroup\$ – user46560 May 30 '14 at 17:06
  • \$\begingroup\$ @user46560 yeah, but this way you don't have to compute what pixels are in that inter-polygon band at all.. neither on the GPU, nor on the CPU. Since you're not accustomed to the ways of game development as you say, you deserve a +1 for your idea :). \$\endgroup\$ – teodron May 30 '14 at 19:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.