Skip to content

Instantly share code, notes, and snippets.

@abernier
Last active March 26, 2018 05:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save abernier/3411189 to your computer and use it in GitHub Desktop.
Save abernier/3411189 to your computer and use it in GitHub Desktop.
Box2D
html, body {height:100%;}
html {display:table; width:100%;}
body {display:table-cell; text-align:center; vertical-align:bottom;}
* {-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none; -webkit-user-drag:none;-moz-user-drag:none;-ms-user-drag:none;-o-user-drag:none;user-drag:none;}
.ball,
.ball b,
.crate,
.ground {box-sizing:border-box;}
.ball {display:inline-block; width:3em; height:3em; border-radius:100%; border:.4em solid; color:#dc3132; position:relative;}
.ball b {display:block; width:100%; border:.2em solid; border-radius:.2em;}
.ball {padding:.4em 0;}
.ball > div {width:100%; height:100%; position:relative;}
.ball b {position:absolute; left:100%; top:50%;margin-top:-.2em; margin-left:.45em;}
.ball b:first-child,
.ball b:last-child {margin-left:.3em;}
.ball b:first-child {top:0;}
.ball b:last-child {top:auto;margin-top:auto;bottom:0;margin-bottom:-.2em;}
.crate {display:inline-block; width:3em; height:3em; border:.4em solid #30aebf; border-radius:.15em;}
.ground {display:inline-block; width:12em; border:.2em solid; color:#8cc924; border-radius:.15em;}
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>box2d</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div class="ball">
<div>
<b></b>
<b></b>
<b></b>
</div>
</div><br>
<div class="crate"></div><br>
<div class="crate"></div><div class="crate"></div><br>
<div class="ground"></div>
<script src="https://cdn.jsdelivr.net/npm/box2dweb@2.1.0-b/box2d.min.js"></script>
<script src="https://rawgithub.com/paulirish/1579671/raw/rAF.js"></script>
<script src="https://rawgithub.com/abernier/3225993/raw/loop.js"></script>
<script src="https://code.jquery.com/jquery-latest.js"></script>
<script src="index.js"></script>
</body>
</html>
(function () {
// Flatten Box2d (ugly but handy!)
(function b2(o) {
for (k in o) {
if (o.hasOwnProperty(k)) {
if ($.isPlainObject(o[k])) {
b2(o[k]);
} else if (/^b2/.test(k)) {
window[k] = o[k];
}
}
}
}(Box2D));
var world = new b2World(
new b2Vec2(0, 9.81), // gravity
true // allow sleep
);
var SCALE = 30;
//
// Ground
//
(function ($ground) {
// Fixture
var fixDef = new b2FixtureDef;
fixDef.density = 1;
fixDef.friction = 0.5;
fixDef.restitution = 0.2;
// Shape
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsBox(
$ground.outerWidth() / 2 / SCALE, //half width
$ground.outerHeight() / 2 / SCALE //half height
);
// Body
var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_staticBody;
bodyDef.position.x = ($ground.offset().left + $ground.outerWidth() / 2) / SCALE;
bodyDef.position.y = ($ground.offset().top + $ground.outerHeight() / 2) / SCALE;
var body = world.CreateBody(bodyDef);
body.CreateFixture(fixDef);
$ground.data('body', body);
}($('.ground')));
//
// Crates
//
$('.crate').each(function (i, el) {
var $crate = $(el);
// Fixture
var fixDef = new b2FixtureDef;
fixDef.density = 1;
fixDef.friction = 0.5;
fixDef.restitution = 0.2;
// Shape
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsBox(
$crate.outerWidth() / 2 / SCALE, //half width
$crate.outerHeight() / 2 / SCALE //half height
);
// Body
var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.x = ($crate.offset().left + $crate.outerWidth() / 2) / SCALE;
bodyDef.position.y = ($crate.offset().top + $crate.outerHeight() / 2) / SCALE;
var body = world.CreateBody(bodyDef);
body.CreateFixture(fixDef);
$crate.data('body', body);
});
//
// Ball
//
(function ($ball) {
// Fixture
var fixDef = new b2FixtureDef;
fixDef.density = 1;
fixDef.friction = 0.5;
fixDef.restitution = 0.2;
// Shape
fixDef.shape = new b2CircleShape($ball.outerWidth() / 2 / SCALE);
// Body
var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.x = ($ball.offset().left + $ball.outerWidth() / 2) / SCALE;
bodyDef.position.y = ($ball.offset().top + $ball.outerHeight() / 2) / SCALE;
var body = world.CreateBody(bodyDef);
body.CreateFixture(fixDef);
$ball.data('body', body);
}($('.ball')));
//
// MouseJoint
//
var mouse = new b2Vec2();
$(window).mousemove(function (e) {
mouse.Set(e.pageX / SCALE, e.pageY / SCALE);
});
window.mouse = mouse;
(function (mouse) {
var mouseJointDef = new b2MouseJointDef();
mouseJointDef.target = mouse;
mouseJointDef.bodyA = world.GetGroundBody();
mouseJointDef.collideConnected = true;
var mouseJoint;
$('*').on({
mousedown: function (e) {
var body = $(this).data('body');
if (!body) {
return;
}
mouseJointDef.bodyB = body;
mouseJointDef.maxForce = 3000 * body.GetMass();
mouseJoint = world.CreateJoint(mouseJointDef);
mouseJoint.SetTarget(mouse);
function mouseup(e) {
world.DestroyJoint(mouseJoint);
}
$(window).one('mouseup', mouseup);
}
});
}(mouse));
//
// Loops
//
(function () {
var dt = 30;
new Loop(function () {
world.Step(
1/dt, //frame-rate
10, //velocity iterations
10 //position iterations
);
world.ClearForces();
}, 1000/dt).start();
}());
(function () {
var $entities = $('.ball, .crate');
// cache some initial coordinates informations
$entities.each(function (i, el) {
var $el = $(el);
$el.data('origPos', {
left: $el.offset().left,
top: $el.offset().top,
width: $el.outerWidth(),
height: $el.outerHeight()
});
});
$ball = $('.ball');
$tails = $('b', $ball);
new Loop(function (t, t0) {
if (!t0) {
return;
}
var dt = t - t0;
if (dt <= 0) {
return;
}
var i = $entities.length
while (i--) {(function () {
var entity = $entities[i];
var $entity = $(entity);
var body = $entity.data('body');
var pos = body.GetPosition();
var ang = body.GetAngle() * 180 / Math.PI;
var origPos = $entity.data('origPos')
$entity.css('transform', 'translate3d(' + ~~(pos.x*SCALE - origPos.left - origPos.width / 2) + 'px, ' + ~~(pos.y*SCALE - origPos.top - origPos.height / 2) + 'px, 0) rotate3d(0,0,1,' + ~~ang + 'deg)');
}());}
function angleVV(v1, v2) {
var n1 = v1.Length();
var n2 = v2.Length();
return Math.atan2(v1.y/n1, v1.x/n1) - Math.atan2(v2.y/n2, v2.x/n2);
}
var vel = $ball.data('body').GetLinearVelocityFromLocalPoint(new b2Vec2(0,0));
$tails
.parent().css('transform', 'rotate3d(0,0,1,' + ~~((-$ball.data('body').GetAngle() + angleVV(vel, new b2Vec2(0, 1)) - Math.PI / 2) * 180 / Math.PI) + 'deg)').end()
.css({
width: vel.Length() * 10 + '%',
opacity: vel.Length() / 10
});
}).start();
}());
}(jQuery, Box2D));
@abernier
Copy link
Author

@abernier
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment