Tutorial: cocos2d metaballs

i wanna make this short so let’s begin
i found a great article on how to make meatballs but the implementation was written in javascript!

http://jamie-wong.com/2014/08/19/metaballs-and-marching-squares/

so i converted it to c++ cocos2d-x with some tweaks and the results were very good.

here is the simulation in action.

before we start i wanna warn you that my implementation still has some bugs (some lines are not drawn because they didn’t intersect) … maybe you can fix theme.

you should first read and try to understand the article above before continuing on:

here is a brief explanation on how i’m doing it:

split the screen into cells each is just a cocos2dx::Rect
each cell has four edge values and i, j index which corresponds to its location in the matrix

create a matrix from the cells
eg: 4 cells if converted into a matrix become a matrix of 3*3 elements
each element in the matrix has a flag that determines if its already calculated or not

Iterate through every cell and check if it intersects a circle
if it intersects a circle then
calculate the sum values for each of the four corners
but before you calculate any of the values check the flag to see if its calculated and if it is then just get the value

if not then calculate and store the calculated values in the matrix and change the flag to true which means its calculated.

at last add it to toDraw vector

after the Iteration is done Iterate through every cell in toDraw vector
calculate the cell configuration and then draw it if its between [1…14]
reset the matrix values

tweak these variables to get a simulation to your liking`

constexpr int CellSize = 10; // don't make it less than 5
constexpr int NumCircles = 10;
constexpr float MinRadius = 20.f;
constexpr float MaxRadius = 40.f;

just remember that it’s a trade off between fps and NumCircles and CellSize.

if you have any questions please ask!

the code needs some cleaning and the video quality is not that good either(sorry i haven’t got time).

GameScene h cpp.zip (4.3 KB)

PS: if anyone has improvements please contribute

References

http://jamie-wong.com/2014/08/19/metaballs-and-marching-squares/

https://www.gamedev.net/resources/_/technical/graphics-programming-and-theory/exploring-metaballs-and-isosurfaces-in-2d-r2556

Edit:

i wanna share some improvements and solutions to the bug that i’ve talked about earlier.

i discovered that the bug can be fixed at the expense of fps by checking if a cell intersects Circle() but on a bigger diameter which should be altered in Circle::create method

// Circle::create
c->diameter = radius * 3;

keep increasing the diameter until the problem is fixed(but the bad news is as i said …it’s on the expense of fps)

• FPS enhancements

i also discovered that checking if a cell lays in a circle field is better then checking if a cell intersects Circle (about +10 fps)

it can be done like this:

auto dist = cpos.distance(cell.center);
bool insideField = dist <= circle->diameter && dist >= (circle->r * 0.5f);
if (insideField)

instead of this:

if (cell.intersectsCircle(cpos, circle->diameter))

but you must first add a new member variable to the cell class and name it center and initialize it in the constructor so you can do what i proposed:

class Cell : Rect{

	.....

	// ctor
	explicit Cell(const Rect& rect, Vec2 topMiddle, Vec2 bottomMiddle, Vec2 leftMiddle, Vec2 rightMiddle) {
                .....
		center = Vec2(getMidX(), getMidY());
	}
	
	Vec2 center;
}

• fieldForceAt() enhancements

i found out that the fieldForceAt() function can be enhanced like this:

inline float fieldForceAt(const Vec2& point) const
{
	float dx = _position.x - point.x;
	float dy = _position.y - point.y;
	return r2 / (dx * dx + dy * dy);
}

i noticed an increase in fps by 2-3

8 Likes

This is very cool. I can help tidy it up.

i forgot to mention that you can easily use physiques with the simulation if you want!!

1 Like