plunkerで liquidfun その4

# 概要
plunkerで liquidfunやってみた。
エンジン、やってみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/f2b26fbd-2834-2987-5621-7cddb74551e7.png)

# サンプルコード

```

var world = null;
var FPS = 1000 / 45;
var STAGE_WIDTH = 456;
var STAGE_HEIGHT = 456;
var SCALE = 10;
var ITEM_TYPE_PARTICLE = "particle";
var ITEM_TYPE_POLYGON = "polygon";
var ITEM_TYPE_CIRCLE = "circle";
var physicsEngine = PhysicsEngine();
var viewer = Viewer({
	id: "canvas"
});
function PhysicsEngine() {
	var GRAVITY = 10;
	var PARTICLE_DENSITY = 1;
	var PARTICLE_SIZE = 20;
	var PARTICLE_FLAGS = b2_waterParticle;
	var items_ = [];
	world = new b2World(new b2Vec2(0, GRAVITY));
	items_.push(createParticle_({
		shapeRadius: PARTICLE_SIZE,
		particleRadius: PARTICLE_DENSITY,
		x: 200,
		y: 50
	}));
	items_.push(createStaticWall_({
		x: 170,
		y: 20,
		width: 60,
		height: 5
	}));
	items_.push(createStaticWall_({
		x: 170,
		y: 20,
		width: 5,
		height: 215
	}));
	items_.push(createStaticWall_({
		x: 230,
		y: 30,
		width: 5,
		height: 205
	}));
	var p0 = createBox({
		x: 175,
		y: 100,
		width: 60,
		height: 50
	});
	items_.push(p0);
	var c0 = createCircle({
		x: 200,
		y: 250,
		r: 14
	});
	items_.push(c0);
	var b0 = createcircle({
		x: 200,
		y: 300,
		r: 35
	});
	items_.push(b0);
	var joint2 = new b2DistanceJointDef();
	joint2.collideConnected = false;
	joint2.frequencyHz = 0;
	joint2.dampingRatio = 0;
	joint2.length = 9.0 / SCALE;
	var j2 = joint2.InitializeAndCreate(p0.body, c0.body, p0.body.GetWorldCenter(), c0.body.GetWorldCenter());
	var joint1 = new b2RevoluteJointDef();
	joint1.enableMotor = true;
	joint1.motorSpeed = 2 * Math.PI;
	joint1.maxMotorTorque = 1e7;
	var j1 = joint1.InitializeAndCreate(b0.body, c0.body, b0.body.GetWorldCenter());
	return {
		update: update,
		getItems: getItems
	};
	function update() {
		world.Step(FPS / 1000, 10, 10);
	}
	function getItems() {
		return items_;
	}
	function createParticle_(params) {
		var shapeRadius = params.shapeRadius / SCALE;
		var particleRadius = params.particleRadius / SCALE;
		var x = params.x / SCALE;
		var y = params.y / SCALE;
		var particleSystemDef = new b2ParticleSystemDef();
		particleSystemDef.radius = particleRadius;
		particleSystemDef.dampingStrength = 0.1;
		var particleSystem = world.CreateParticleSystem(particleSystemDef);
		var shape = new b2CircleShape();
		shape.radius = shapeRadius;
		var particleGroupDef = new b2ParticleGroupDef();
		particleGroupDef.shape = shape;
		particleGroupDef.position.Set(x, y);
		particleGroupDef.flags = PARTICLE_FLAGS;
		particleSystem.CreateParticleGroup(particleGroupDef);
		return {
			type: ITEM_TYPE_PARTICLE,
			particleSystem: particleSystem,
			particleRadius: particleRadius
		}
	}
	function createStaticWall_(params) {
		var width = params.width / SCALE;
		var height = params.height / SCALE;
		var x = params.x / SCALE;
		var y = params.y / SCALE;
		var bodyDef = new b2BodyDef();
		bodyDef.type = b2_staticBody;
		bodyDef.position.Set(x, y);
		var body = world.CreateBody(bodyDef);
		var shape = new b2PolygonShape;
		shape.vertices[0] = new b2Vec2(0, 0);
		shape.vertices[1] = new b2Vec2(width, 0);
		shape.vertices[2] = new b2Vec2(width, height);
		shape.vertices[3] = new b2Vec2(0, height);
		body.CreateFixtureFromShape(shape, 0.5);
		return {
			type: ITEM_TYPE_POLYGON,
			body: body,
			shape: shape
		};
	}
	function createcircle(params) {
		var x = params.x / SCALE;
		var y = params.y / SCALE;
		var r = params.r / SCALE;
		var bodyDef = new b2BodyDef;
		bodyDef.type = b2_staticBody;
		bodyDef.position.Set(x, y);
		var body = world.CreateBody(bodyDef);
		var circle = new b2CircleShape;
		circle.radius = r;
		var fixtureDef = new b2FixtureDef();
		fixtureDef.density = 0;
		fixtureDef.shape = circle;
		fixtureDef.restitution = 0.6;
		body.CreateFixtureFromDef(fixtureDef);
		return {
			type: ITEM_TYPE_CIRCLE,
			body: body,
			shape: circle
		};
	}
	function createCircle(params) {
		var x = params.x / SCALE;
		var y = params.y / SCALE;
		var r = params.r / SCALE;
		var bodyDef = new b2BodyDef;
		bodyDef.type = b2_dynamicBody;
		bodyDef.position.Set(x, y);
		var body = world.CreateBody(bodyDef);
		var circle = new b2CircleShape;
		circle.radius = r;
		var fixtureDef = new b2FixtureDef();
		fixtureDef.density = 0.1;
		fixtureDef.friction = 1.0;
		fixtureDef.restitution = 0.1;
		fixtureDef.shape = circle;
		body.CreateFixtureFromDef(fixtureDef);
		return {
			type: ITEM_TYPE_CIRCLE,
			body: body,
			shape: circle
		};
	}
	function createBox(params) {
		var width = params.width / SCALE;
		var height = params.height / SCALE;
		var x = params.x / SCALE;
		var y = params.y / SCALE;
		var bodyDef = new b2BodyDef();
		bodyDef.type = b2_dynamicBody;
		bodyDef.position.Set(x, y);
		var body = world.CreateBody(bodyDef);
		var shape = new b2PolygonShape;
		shape.vertices[0] = new b2Vec2(0, 0);
		shape.vertices[1] = new b2Vec2(width, 0);
		shape.vertices[2] = new b2Vec2(width, height);
		shape.vertices[3] = new b2Vec2(0, height);
		body.CreateFixtureFromShape(shape, 1.6);
		return {
			type: ITEM_TYPE_POLYGON,
			body: body,
			shape: shape
		};
	}
}
function Viewer(params) {
	var canvas_ = document.getElementById(params.id);
	var ctx = canvas_.getContext("2d");
	return {
		update: update
	};
	function update(params) {
		var items = params.items;
		ctx.clearRect(0, 0, STAGE_WIDTH, STAGE_HEIGHT);
		var i;
		var j;
		for (i = 0; i < items.length; i++)
		{
			var item = items[i];
			var position = null;
			if (item.type === ITEM_TYPE_PARTICLE)
			{
				var buffer = item.particleSystem.GetPositionBuffer();
				for (j = 0; j < buffer.length; j = j + 2)
				{
					ctx.beginPath();
					ctx.arc(buffer[j] * SCALE, buffer[j + 1] * SCALE, item.particleRadius * SCALE, 0, Math.PI * 2, true);
					ctx.closePath();
					ctx.fillStyle = "rgba(229, 178, 178, 1)";
					ctx.fill();
				}
			}
			else if (item.type === ITEM_TYPE_POLYGON)
			{
				position = item.body.GetPosition();
				ctx.beginPath();
				for (j = 0; j < item.shape.vertices.length; j++)
				{
					var vector = item.shape.vertices[j];
					if (j <= 0)
					{
						ctx.moveTo((vector.x + position.x) * SCALE, (vector.y + position.y) * SCALE);
					}
					else
					{
						ctx.lineTo((vector.x + position.x) * SCALE, (vector.y + position.y) * SCALE);
					}
				}
				ctx.closePath();
				ctx.strokeStyle = "rgb(127, 229, 127)";
				ctx.lineWidth = 1;
				ctx.stroke();
				ctx.fillStyle = "rgba(127, 229, 127, 0.5)";
				ctx.fill();
			}
			else if (item.type === ITEM_TYPE_CIRCLE)
			{
				position = item.body.GetPosition();
				ctx.beginPath();
				ctx.arc(position.x * SCALE, position.y * SCALE, item.shape.radius * SCALE, 0, Math.PI * 2, false);
				ctx.closePath();
				ctx.strokeStyle = "rgb(127, 229, 127)";
				ctx.lineWidth = 1;
				ctx.stroke();
				ctx.fillStyle = "rgba(127, 229, 127, 0.5)";
				ctx.fill();
			}
		}
	}
}
setInterval(function() {
	physicsEngine.update();
	viewer.update({
		items: physicsEngine.getItems()
	});
}, FPS);



```

# 成果物

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


以上。