Slime?!?

Started by
7 comments, last by h4tt3n 12 years ago
All right, I'm working on a 2D platformer starring a slime puppy attempting to escape a laboratory (Original, right?). However, I'm kinda new to "dynamic" graphics (Not bound by sprite frames). I have NO idea where to start in making a slime! I tried collecting a bunch of 2D dots in a zone, but that looked funky. I tried sprites, but that looked even funkier.

Now the details: It would be preferred that the slime NOT seperate, so I've been thinking like an ellipse pattern of vertices (in 2D space) that conform to obstacles in its path (i.e. walls) while retaining its "volume." To retain volume, the vertices would need to stay a fixed distance from each other (Again, because it's 2D space I don't have to worry about any Z-axis deform). But even after all of this planning, testing, and trial-and-erroring, I still haven't a clue where to start or how. Any help is appreciated.

"Only idiots quote themselves" - MisterFuzzy

Advertisement
You may want to check out the game Gish, by Edmund McMillen. Apparently it's now open source: http://crypticsea.blogspot.com/2010/05/gish-open-source.html
-Building DIY games since 2010. Daydalus.net
Hello there,

There's a simple method for simulating soft objects like what you describe, but it requires a basic understanding of physics simulation. Do you know simple vector math? Do you know how to implement basic physics stuff, like applying forces to a particle and calculating its acceleration, velocity and position over time?

Cheers,
Mike
In general, this is the kind of thing that people call "Soft Body Simulation." You can approach it with various degrees of physical realism and mathematical sophistication.

Once, when I did something like this, I just whipped up two different ad-hoc methods:

1. The most computationally-efficient method (which sounds a bit like what you're describing) involved simulating a two-dimensional "balloon" with basic physics. In essence, there was a line segment loop, whose vertices were simulated point masses. These masses experienced four forces: (1) a normal force, proportional to the deviation of the signed area of the loop from some constant; (2) tangential forces (i.e., springs connecting adjacent vertices); (3) damping forces (i.e., dashpots connecting adjacent vertices); and (4) driving forces.

2. Another more flexible method used interacting particles. By "flexible," I mean that the topology of the blob could change (i.e., it could develop holes, or split into pieces, etc). Then, by summing Gaussians or b-spline basis functions centered at the particles, you get a scalar field; I used Marching Triangles to build polygons representing a sublevel set of this scalar field, and drew them. A pixel-shader approach could also work, and avoid the generation of geometry altogether.

In fact, I have some code for the first method that I can share (I won't share a full, working program; just enough to show you how I computed forces and used them to update positions and velocities).


void Amoeba::updateForces(float mouseX, float mouseY, bool mouseLbut)
// This function makes reference to the following members of the Amoeba class:
// const int N = 100; // Number of vertices
// double x[N]; // X cooordinates of vertex positions
// double y[N]; // Y coordinates of vertex positions
// double vx[N]; // X components of vertex velocities
// double vy[N]; // Y components of vertex velocities
// double Fx[N]; // X components of forces on vertices
// double Fy[N]; // Y components of forces on vertices
{
int k, kprev, knext;

double A = polyArea(x, y, N);

// Compute O(N) forces
kprev = N-1;
k = 0;
knext = 1;
for(;;)
{
double laplacX = x[kprev] - 2*x[k] + x[knext];
double laplacY = y[kprev] - 2*y[k] + y[knext];
double laplacVx = vx[kprev] - 2*vx[k] + vx[knext];
double laplacVy = vy[kprev] - 2*vy[k] + vy[knext];
double diffX = x[knext]-x[kprev];
double diffY = y[knext]-y[kprev];

// Pressure force
double Fpx = -cp*diffY*pow7(A - A0);
double Fpy = cp*diffX*pow7(A - A0);

// Surface tension (spring) force
double Fkx = ck*laplacX;
double Fky = ck*laplacY;

// Drag force
double Fdx = cd*laplacVx;
double Fdy = cd*laplacVy;

// Mouse force input
double Fmousex = 0.0;
double Fmousey = 0.0;
double mouseDistSq = square(x[k] - mouseX) + square(y[k] - mouseY);
if(mouseLbut && mouseDistSq < mouseRsq)
{
double mouseDist = sqrt(mouseDistSq);
double Fmag = mouseFmag*cube(1.0 - mouseDistSq/mouseRsq)/mouseDist;
Fmousex = Fmag*(x[k] - mouseX);
Fmousey = Fmag*(y[k] - mouseY);
}

// Force sum
Fx[k] = Fpx + Fkx + Fdx + Fmousex;
Fy[k] = Fpy + Fky + Fdy + Fmousey;

// Update indexes
if(k == N-1)
break;
kprev = k;
k = knext;
knext = (knext+1)%N;
}

}

void Amoeba::updateSimulation(float mouseX, float mouseY, bool mouseLbut)
// This function makes use of the following class members:
// const double dt = 0.01;
// const double Fmax = 100;
// ...and the others mentioned previously.
{

// Velocity Verlet integration

for(int k = 0; k < N; ++k)
{
x[k] += vx[k]*dt + 0.5*Fx[k]*(dt*dt);
y[k] += vy[k]*dt + 0.5*Fy[k]*(dt*dt);

vx[k] += (0.5*dt)*Fx[k];
vy[k] += (0.5*dt)*Fy[k];
}

updateForces(mouseX, mouseY, mouseLbut); // The previous function

for(int k=0; k<N; ++k)
{
Fx[k] = clamp(Fx[k], -Fmax, Fmax);
Fy[k] = clamp(Fy[k], -Fmax, Fmax);
}

for(int k = 0; k < N; ++k)
{
vx[k] += (0.5*dt)*Fx[k];
vy[k] += (0.5*dt)*Fy[k];
}
}


You may need to tweak the various constants used, and may want to package this up in some other way. I'd also encourage you not to use native arrays (like I did) in your own code.
Hmmm... Thanks for the replies!

And thanks emergent for that chunk of code... I'll examine it more thoroughly when I have some more time on my hands.

"Only idiots quote themselves" - MisterFuzzy


You may want to check out the game Gish, by Edmund McMillen. Apparently it's now open source: http://crypticsea.bl...pen-source.html


Sorry for being pedantic, but Edmund wasn't the sole developer of Gish -- he did the graphics, and Alex Austin did the programming.

Since the OP's question concerns the programming more than the artwork, and since your link points to Alex's site rather than Edmund's, surely it's more appropriate to mention Alex rather than Edmund?
To make a "slime ball" like in GISH is simple, just do like this:

(1) put a number of particles in a circle
(2) connect neighboring particles with Hooke's law damped springs, forming a rubberband
(3) calculate the area of the polygon formed by the particles using this equation
(4) set that area as the slime's rest area
(5) for each loop calculate the slimes new area using the same equation
(6) calculate slime pressure p = k * (area - rest area), where k is a stiffnes coefficient
(7) apply a normal ("inwards" / "outwards") pressure force to each particle pair
(8) voila, now your slime actsas a peace of jelly!

All sorts of modifications can be made, but this is the gist of the idea. I might have a code sample lying around (BASIC dialect and C dialect), I'll post it if I fall over it.

Cheers,
Mike

To make a "slime ball" like in GISH is simple, just do like this:

(1) put a number of particles in a circle
(2) connect neighboring particles with Hooke's law damped springs, forming a rubberband
(3) calculate the area of the polygon formed by the particles using this equation
(4) set that area as the slime's rest area
(5) for each loop calculate the slimes new area using the same equation
(6) calculate slime pressure p = k * (area - rest area), where k is a stiffnes coefficient
(7) apply a normal ("inwards" / "outwards") pressure force to each particle pair
(8) voila, now your slime actsas a peace of jelly!

All sorts of modifications can be made, but this is the gist of the idea. I might have a code sample lying around (BASIC dialect and C dialect), I'll post it if I fall over it.

Cheers,
Mike


Nice description. Let me point out, in case it isn't clear to the original poster, that this is almost exactly what the code I posted implements (the only difference is that my pressure grows with the 5th power, not linearly (any monotonic function will do)).

Nice description. Let me point out, in case it isn't clear to the original poster, that this is almost exactly what the code I posted implements (the only difference is that my pressure grows with the 5th power, not linearly (any monotonic function will do)).


Thanks. Okay, here's a compilation of all the "blob" experiments I've done in the past years. There's a lot of stuff in there, ranging from simple beginner's tutorial demos to game sandboxes and advanced stuff with angular springs, global damping, collision detection, cubic spline surface rendering and whatnot. There may be an occational instance of bad coding practice, but it all works.

Have fun!

Cheers,
Mike

This topic is closed to new replies.

Advertisement