plunkerで liquidfun

# 概要
plunkerで liquidfunやってみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/1f783d3a-4cc4-76b6-1173-277d4db747da.png)

# サンプルコード

```

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var w = canvas.width;
var h = canvas.height;
var timeStep = 1.0 / 30.0;
var velocityIterations = 8;
var positionIterations = 3;
var drawScale = 14;
var world = new b2World(new b2Vec2(0, 10));
ctx.font = "normal 14px arial";
ctx.textBaseline = "top";
ctx.textAlign = "left";
var particleRadius = 0.2;

function Vec2(x, y) {
	this.x = x || 0;
	this.y = y || 0;
}
function createBox(x, y, angle, w, h, type, density) {
	var bodyDef = new b2BodyDef();
	bodyDef.type = type || b2_staticBody;
	bodyDef.position.Set(x, y);
	bodyDef.angle = Math.PI / 180 * angle;
	var body = world.CreateBody(bodyDef);
	var shape = new b2PolygonShape();
	shape.SetAsBoxXY(w * 0.5, h * 0.5);
	body.CreateFixtureFromShape(shape, density || 0);
}
function createCircle(x, y, radius, type, density) {
	var bodyDef = new b2BodyDef();
	bodyDef.type = type || b2_staticBody;
	bodyDef.position.Set(x, y);
	var body = world.CreateBody(bodyDef);
	var circle = new b2CircleShape();
	circle.radius = radius;
	var fixtureDef = new b2FixtureDef();
	fixtureDef.density = density || 0;
	fixtureDef.shape = circle;
	fixtureDef.restitution = 0.6;
	body.CreateFixtureFromDef(fixtureDef);
}
function createEdge(x, y, angle, v0, v1, type, density) {
	var bodyDef = new b2BodyDef();
	bodyDef.type = type || b2_staticBody;
	bodyDef.position.Set(x, y);
	bodyDef.angle = Math.PI / 180 * angle;
	var body = world.CreateBody(bodyDef);
	var edge = new b2EdgeShape();
	edge.Set(v0, v1);
	body.CreateFixtureFromShape(edge, density || 0);
}
function createChain(x, y, angle, verts, type, density) {
	var bodyDef = new b2BodyDef();
	bodyDef.type = type || b2_staticBody;
	bodyDef.position.Set(x, y);
	bodyDef.angle = Math.PI / 180 * angle;
	var body = world.CreateBody(bodyDef);
	var chain = new b2ChainShape();
	chain.vertices = verts;
	chain.CreateLoop();
	body.CreateFixtureFromShape(chain, density || 0);
}
function createParticles(x, y, radius, shape, color) {
	var psd = new b2ParticleSystemDef();
	psd.radius = radius;
	psd.dampingStrength = 0.2;
	psd.colorMixingStrength = 0.75;
	var particleSystem = world.CreateParticleSystem(psd);
	var pd = new b2ParticleGroupDef();
	pd.flags = b2_waterParticle | b2_colorMixingParticle;
	pd.position.Set(x, y);
	pd.shape = shape;
	pd.color = color;
	particleSystem.CreateParticleGroup(pd);
}
function ParticleEmitter(x, y, radius) {
	var psd = new b2ParticleSystemDef();
	psd.radius = radius;
	psd.dampingStrength = 0.2;
	this.pos = new Vec2(x, y);
	this.emitRate = 1.0;
	this.emitRemainder = 0;
	this.emitted = 0;
	this.system = world.CreateParticleSystem(psd);
	var pd = new b2ParticleDef();
	pd.color = new b2ParticleColor(0, 255, 0, 255);
	pd.position.Set(this.pos.x + Math.random() * 0.25, this.pos.y + Math.random() * 0.25);
	pd.flags = b2_waterParticle;
	this.pdef = pd;
}
ParticleEmitter.prototype.createParticle = function () {
	var pd = this.pdef;
	pd.position.Set(this.pos.x + Math.random() * 0.25, this.pos.y + Math.random() * 0.25);
	this.system.CreateParticle(pd);
};
ParticleEmitter.prototype.update = function (dt) {
	this.emitRemainder += this.emitRate * dt;
	while (this.emitRemainder > 1.0) 
	{
		this.emitRemainder -= 1.0;
		this.emitted++;
		this.createParticle();
	}
};
function definePolygon(shape, transform) {
	ctx.beginPath();
	for (var i = 0, max = shape.vertices.length; i < max; i++) 
	{
		var v = new b2Vec2();
		b2Vec2.Mul(v, transform, shape.vertices[i]);
		if (i == 0) 
		{
			ctx.moveTo(v.x * drawScale, v.y * drawScale);
		} 
		else 
		{
			ctx.lineTo(v.x * drawScale, v.y * drawScale);
		}
	}
	ctx.closePath();
}
function defineCircle(shape, transform) {
	ctx.beginPath();
	ctx.arc(transform.p.x * drawScale, transform.p.y * drawScale, shape.radius * drawScale, 0, Math.PI * 2, false);
}
function defineEdge(shape, transform) {
	ctx.beginPath();
	var v0 = new b2Vec2(), 
		v1 = new b2Vec2();
	b2Vec2.Mul(v0, transform, shape.vertex1);
	b2Vec2.Mul(v1, transform, shape.vertex2);
	ctx.moveTo(v0.x * drawScale, v0.y * drawScale);
	ctx.lineTo(v1.x * drawScale, v1.y * drawScale);
}
function defineChain(shape, transform) {
	ctx.beginPath();
	for (var i = 0, max = shape.vertices.length; i < max; i++) 
	{
		var v = new b2Vec2();
		b2Vec2.Mul(v, transform, shape.vertices[i]);
		if (i == 0)
		{
			ctx.moveTo(v.x * drawScale, v.y * drawScale);
		}
		else 
		{
			ctx.lineTo(v.x * drawScale, v.y * drawScale);
		}
	}
}
function defineFixture(fixture, transform) {
	var shape = fixture.shape;
	if (shape instanceof b2PolygonShape) 
	{
		definePolygon(shape, transform);
	}
	else if (shape instanceof b2CircleShape) 
	{
		defineCircle(shape, transform);
	}
	else if (shape instanceof b2EdgeShape) 
	{
		defineEdge(shape, transform);
	}
	else if (shape instanceof b2ChainShape) 
	{
		defineChain(shape, transform);
	}
}
function drawBody(body) {
	var maxFixtures = body.fixtures.length;
	var transform = body.GetTransform();
	for (var j = 0; j < maxFixtures; j++) 
	{
		var fixture = body.fixtures[j];
		defineFixture(fixture, transform);
		ctx.strokeStyle = "white";
		ctx.stroke();
	}
}
function drawParticleSystem(system) {
	var count = system.GetParticleCount();
	var positions = system.GetPositionBuffer();
	var colors = system.GetColorBuffer();
	for (var i = 0; i < count; i++) 
	{
		var cx = positions[i * 2 + 0];
		var cy = positions[i * 2 + 1];
		var cr = colors[i * 4 + 0];
		var cg = colors[i * 4 + 1];
		var cb = colors[i * 4 + 2];
		var ca = colors[i * 4 + 3];
		var radius = particleRadius;
		ctx.beginPath();
		ctx.arc(cx * drawScale, cy * drawScale, radius * drawScale, 0, Math.PI * 2, false);
		ctx.fillStyle = "rgba(" + cr + "," + cg + "," + cb + "," + ca + ")";
		ctx.fill();
		drawedParticles++;
	}
}
var frameRequest = function() {
	var i, 
		max;
	emitter.update(0.1);
	world.Step(timeStep, velocityIterations, positionIterations);
	ctx.clearRect(0, 0, w, h);
	ctx.fillStyle = "gray";
	ctx.fillRect(0, 0, w, h);
	ctx.save();
	ctx.translate(w * 0.5, h * 0.5);
	for (i = 0, max = world.bodies.length; i < max; i++) 
	{
		drawBody(world.bodies[i]);
	}
	drawedParticles = 0;
	for (i = 0, max = world.particleSystems.length; i < max; i++) 
	{
		drawParticleSystem(world.particleSystems[i]);
	}
	ctx.restore();
	ctx.fillStyle = "white";
	ctx.fillText("Particles: " + drawedParticles, 10, 10);
	requestAnimationFrame(frameRequest);
};

createBox(0, 10, 0, 25, 1);
//createBox(0, -10, 0, 25, 1);
createBox(-13, 0, 90, 21, 1);
createBox(13, 0, 90, 21, 1);
createEdge(0, -5, 5, new b2Vec2(-12.6, 0), new b2Vec2(11, 0));
createEdge(0, 0, -5, new b2Vec2(-11, 0), new b2Vec2(12.6, 0));
createEdge(0, 5, 5, new b2Vec2(-12.6, 0), new b2Vec2(11, 0));
createCircle(-2, -8, 0.5, b2_dynamicBody, 1.0);
var particleShape = new b2PolygonShape();
particleShape.SetAsBoxXY(4, 1);
createParticles(-8, -8, 0.1, particleShape, new b2ParticleColor(0, 255, 255, 255));
var emitter = new ParticleEmitter(0, -2, 0.1);
var drawedParticles = 0;
var particleImage = (function() {
	var particleCanvas = document.createElement("canvas");
	particleCanvas.width = 32;
	particleCanvas.height = 32;
	var particleCtx = particleCanvas.getContext("2d");
	particleCtx.beginPath();
	particleCtx.arc(16, 16, 8, 0, Math.PI * 2, false);
	particleCtx.fillStyle = "blue";
	particleCtx.fill();
	return particleCanvas;
})();
requestAnimationFrame(frameRequest);




```

# 成果物

https://embed.plnkr.co/plunk/JcHP8R0YCSIfwvdw

以上。