概要
plunkerで liquidfunやってみた。
エンジン、やってみた。
写真
サンプルコード
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);
成果物
以上。