概要
plunkerで liquidfunやってみた。
練習問題、やってみた。
練習問題
ボールをシミュレーションせよ。
力を加えよ。
写真
サンプルコード
var world = null;
var FPS = 1000 / 60;
var CIRCLE_VOLUME = 20;
var GRAVITY = 30;
var STAGE_WIDTH = 456;
var STAGE_HEIGHT = 456;
var SCALE = 10;
var ITEM_TYPE_CIRCLE = "item_type_circle";
var ITEM_TYPE_POLYGON = "item_type_polygon";
var physicsEngine = PhysicsEngine();
var viewer = Viewer({
id: "canvas"
});
function PhysicsEngine() {
var gravity_ = GRAVITY;
var items_ = [];
world = new b2World(new b2Vec2(0, gravity_));
items_.push(createStaticWall_({
width: STAGE_WIDTH,
height: 20,
x: 0,
y: 0
}));
items_.push(createStaticWall_({
width: STAGE_WIDTH,
height: 20,
x: 0,
y: STAGE_HEIGHT - 20
}));
items_.push(createStaticWall_({
width: 20,
height: STAGE_HEIGHT,
x: 0,
y: 0
}));
items_.push(createStaticWall_({
width: 20,
height: STAGE_HEIGHT,
x: STAGE_WIDTH - 20,
y: 0
}));
items_.push(createDynamicCircle_({
radius: 30,
x: 300,
y: 50,
}));
return {
update: update,
changeGravity: changeGravity,
getItems: getItems
};
function update() {
world.Step(FPS / 1000, 10, 10);
}
function changeGravity() {
items_[4].body.SetLinearVelocity(new b2Vec2(20, -20));
}
function getItems() {
return items_;
}
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 createDynamicCircle_(params) {
var radius = params.radius / SCALE;
var x = params.x / SCALE;
var y = params.y / SCALE;
var bodyDef = new b2BodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.linearDamping = 0.1;
bodyDef.linearVelocity = new b2Vec2(-15.0, -2.0);
bodyDef.position.Set(x, y);
var shape = new b2CircleShape();
shape.radius = radius;
var fixDef = new b2FixtureDef;
fixDef.restitution = 1;
fixDef.shape = shape;
fixDef.density = 0.4;
fixDef.friction = 0.9;
fixDef.restitution = 0.9;
var body = world.CreateBody(bodyDef);
body.CreateFixtureFromDef(fixDef);
return {
type: ITEM_TYPE_CIRCLE,
body: body,
shape: shape
};
}
}
function Viewer(params) {
var canvas_ = document.getElementById(params.id);
var context_ = canvas_.getContext("2d");
return {
update: update
};
function update(params) {
var items = params.items;
context_.clearRect(0, 0, STAGE_WIDTH, STAGE_HEIGHT);
var i = 0,
max;
for (i = 0, max = items.length; i < max; i = i + 1)
{
var item = items[i];
var position = null;
if (item.type === ITEM_TYPE_CIRCLE)
{
position = item.body.GetPosition();
context_.beginPath();
context_.arc(position.x * SCALE, position.y * SCALE, item.shape.radius * SCALE, 0, Math.PI * 2, true);
context_.closePath();
context_.strokeStyle = "rgb(229, 178, 178)";
context_.lineWidth = 1;
context_.stroke();
context_.fillStyle = "rgba(229, 178, 178, 0.5)";
context_.fill();
}
else if (item.type === ITEM_TYPE_POLYGON)
{
position = item.body.GetPosition();
context_.beginPath();
var j = 0,
max2;
for (j = 0, max2 = item.shape.vertices.length; j < max2; j = j + 1)
{
var vector = item.shape.vertices[j];
if (j <= 0)
{
context_.moveTo((vector.x * SCALE) + (position.x * SCALE), (vector.y * SCALE) + (position.y * SCALE));
}
else
{
context_.lineTo((vector.x * SCALE) + (position.x * SCALE), (vector.y * SCALE) + (position.y * SCALE));
}
}
context_.closePath();
context_.strokeStyle = "rgb(127, 229, 127)";
context_.lineWidth = 1;
context_.stroke();
context_.fillStyle = "rgba(127, 229, 127, 0.5)";
context_.fill();
}
}
}
}
setInterval(function() {
physicsEngine.update();
viewer.update({
items: physicsEngine.getItems()
});
}, FPS);
document.addEventListener('mousedown', function(event) {
physicsEngine.changeGravity();
});
成果物
以上。
