Migrate Box2D to Planck.js in core game logic, items, debug draw, and menu. Remove legacy Box2D references, update level and item loading, and improve debug draw for Planck.

This commit is contained in:
Karl Pannek 2025-07-17 18:50:16 +02:00
parent 799601f24d
commit da6e9a244b
15 changed files with 66 additions and 201 deletions

View file

@ -51,18 +51,17 @@ function (Parent, Item, Box2D, nc, Assert) {
var ownVelocity = this.body.getLinearVelocity();
var b2Math = Box2D.Common.Math.b2Math;
var absItemVelocity = b2Math.AbsV(itemVelocity);
var absItemVelocity = { x: Math.abs(itemVelocity.x), y: Math.abs(itemVelocity.y) };
var min = 1;
var damage = 0;
if(absItemVelocity.x > min || absItemVelocity.y > min) {
if(item.lastMoved && item.lastMoved.player != this.player) {
var collision = b2Math.SubtractVV(itemVelocity, ownVelocity);
var collision = planck.Vec2(itemVelocity).sub(planck.Vec2(ownVelocity));
// Tested max velocity banana: 50
var velocityDamage = collision.Length() / 50;
var velocityDamage = collision.length() / 50;
// Max weight of piano: 15
var weightDamage = item.options.weight / 15;

View file

@ -115,6 +115,13 @@ function (Settings, nc, Screenfull, Graph, pointerLockManager) {
li.appendChild(this.ping);
this.devToolsContainer.appendChild(li);
// Add 'planck' label in its own li next to fullscreen
li = document.createElement("li");
var planckLabel = document.createElement("label");
planckLabel.style.fontWeight = "bold";
planckLabel.textContent = "planck";
li.appendChild(planckLabel);
this.devToolsContainer.appendChild(li);
// create debug mode
li = document.createElement("li");
@ -129,7 +136,6 @@ function (Settings, nc, Screenfull, Graph, pointerLockManager) {
li.appendChild(label);
this.devToolsContainer.appendChild(li);
// create Fullscreen
li = document.createElement("li");
li.id = "fullscreen";

View file

@ -6,174 +6,13 @@ function (Box2D) {
"use strict";
var Parent = Box2D.Dynamics.b2DebugDraw;
function DebugDraw() {
Parent.call(this);
this.m_drawScale = 1;
// Wrapper for PlanckDebugDraw
function DebugDraw(canvas) {
// Use the PlanckDebugDraw implementation
var PlanckDebugDraw = require('./PlanckDebugDraw');
return new PlanckDebugDraw(canvas);
}
DebugDraw.prototype = Object.create(Parent.prototype);
DebugDraw.prototype.setColor = function(color) {
this.m_ctx.debugColor = color.color;
this.m_ctx.debugFillAlpha = this.m_fillAlpha;
this.m_ctx.lineStyle(1, this.m_ctx.debugColor, this.m_alpha);
};
DebugDraw.prototype.SetSprite = function(sprite) {
this.m_ctx = sprite;
this.m_sprite = {
graphics: {
clear: function () {
sprite.clear();
sprite.lineStyle(1, 0xffffff, 0.8);
}
}
};
this.m_ctx.beginPath = function() {
this.beginFill(this.debugColor, this.debugFillAlpha);
};
this.m_ctx.closePath = function() {
this.endFill();
};
this.m_ctx.fill = function() {
this.endFill();
};
this.m_ctx.stroke = function() {
// do nothing
};
this.m_ctx.arc = function(x, y, radius, startingAngle, endingAngle, counterClockwise) {
this.drawCircle(x, y, radius);
}
};
DebugDraw.prototype.DrawPolygon = function (vertices, vertexCount, color) {
this.setColor(color);
Parent.prototype.DrawPolygon.call(this, arguments);
};
DebugDraw.prototype.DrawSolidPolygon = function (vertices, vertexCount, color) {
this.setColor(color);
Parent.prototype.DrawSolidPolygon.apply(this, arguments);
};
DebugDraw.prototype.DrawCircle = function (center, radius, color) {
this.setColor(color);
Parent.prototype.DrawCircle.apply(this, arguments);
};
DebugDraw.prototype.DrawSolidCircle = function (center, radius, axis, color) {
this.setColor(color);
Parent.prototype.DrawSolidCircle.apply(this, arguments);
};
DebugDraw.prototype.DrawSegment = function (p1, p2, color) {
this.setColor(color);
Parent.prototype.DrawSegment.apply(this, arguments);
};
DebugDraw.prototype.DrawTransform = function (xf) {
this.setColor(0xff0000);
Parent.prototype.DrawTransform.apply(this, arguments);
};
/*
DebugDraw.prototype.DrawPolygon = function (vertices, vertexCount, color) {
if (!vertexCount) return;
var s = this.m_ctx;
var drawScale = this.m_drawScale;
s.beginPath();
s.strokeStyle = this._color(color.color, this.m_alpha);
s.moveTo(vertices[0].x * drawScale, vertices[0].y * drawScale);
for (var i = 1; i < vertexCount; i++) {
s.lineTo(vertices[i].x * drawScale, vertices[i].y * drawScale);
}
s.lineTo(vertices[0].x * drawScale, vertices[0].y * drawScale);
s.closePath();
s.stroke();
};
DebugDraw.prototype.DrawSolidPolygon = function (vertices, vertexCount, color) {
if (!vertexCount) return;
var s = this.m_ctx;
var drawScale = this.m_drawScale;
s.beginPath();
s.strokeStyle = this._color(color.color, this.m_alpha);
s.fillStyle = this._color(color.color, this.m_fillAlpha);
s.moveTo(vertices[0].x * drawScale, vertices[0].y * drawScale);
for (var i = 1; i < vertexCount; i++) {
s.lineTo(vertices[i].x * drawScale, vertices[i].y * drawScale);
}
s.lineTo(vertices[0].x * drawScale, vertices[0].y * drawScale);
s.closePath();
s.fill();
s.stroke();
};
DebugDraw.prototype.DrawCircle = function (center, radius, color) {
if (!radius) return;
var s = this.m_ctx;
var drawScale = this.m_drawScale;
s.beginPath();
s.strokeStyle = this._color(color.color, this.m_alpha);
s.arc(center.x * drawScale, center.y * drawScale, radius * drawScale, 0, Math.PI * 2, true);
s.closePath();
s.stroke();
};
DebugDraw.prototype.DrawSolidCircle = function (center, radius, axis, color) {
if (!radius) return;
var s = this.m_ctx,
drawScale = this.m_drawScale,
cx = center.x * drawScale,
cy = center.y * drawScale;
s.moveTo(0, 0);
s.beginPath();
s.strokeStyle = this._color(color.color, this.m_alpha);
s.fillStyle = this._color(color.color, this.m_fillAlpha);
s.arc(cx, cy, radius * drawScale, 0, Math.PI * 2, true);
s.moveTo(cx, cy);
s.lineTo((center.x + axis.x * radius) * drawScale, (center.y + axis.y * radius) * drawScale);
s.closePath();
s.fill();
s.stroke();
};
DebugDraw.prototype.DrawSegment = function (p1, p2, color) {
var s = this.m_ctx,
drawScale = this.m_drawScale;
s.strokeStyle = this._color(color.color, this.m_alpha);
s.beginPath();
s.moveTo(p1.x * drawScale, p1.y * drawScale);
s.lineTo(p2.x * drawScale, p2.y * drawScale);
s.closePath();
s.stroke();
};
DebugDraw.prototype.DrawTransform = function (xf) {
var s = this.m_ctx,
drawScale = this.m_drawScale;
s.beginPath();
s.strokeStyle = this._color(0xff0000, this.m_alpha);
s.moveTo(xf.position.x * drawScale, xf.position.y * drawScale);
s.lineTo((xf.position.x + this.m_xformScale * xf.R.col1.x) * drawScale, (xf.position.y + this.m_xformScale * xf.R.col1.y) * drawScale);
s.strokeStyle = this._color(0xff00, this.m_alpha);
s.moveTo(xf.position.x * drawScale, xf.position.y * drawScale);
s.lineTo((xf.position.x + this.m_xformScale * xf.R.col2.x) * drawScale, (xf.position.y + this.m_xformScale * xf.R.col2.y) * drawScale);
s.closePath();
s.stroke();
};
*/
return DebugDraw;
});

View file

@ -91,7 +91,7 @@ function () {
CHANNEL_END_ROUND_TIME: 20, //10,
CHANNEL_DEFAULT_MAX_USERS: 10,
CHANNEL_DEFAULT_SCORE_LIMIT: 5,
CHANNEL_DEFAULT_LEVELS: ["debug"],
CHANNEL_DEFAULT_LEVELS: ["stones", "gangsta", "residence"],
CHANNEL_RECORD_SESSION: false,
// ME STATE

View file

@ -117,7 +117,7 @@ function (Parent, Exception, planck, Settings, CollisionDetector, Item, nc, Asse
shape: planck.Box(
r / 2 / R,
(h / 2 + r / 4) / R,
planck.Vec2(sign * r / 2 / R, h / 2 / R)
planck.Vec2(sign * r / 2 / R, 0)
),
density: 0,
friction: 0,
@ -133,7 +133,7 @@ function (Parent, Exception, planck, Settings, CollisionDetector, Item, nc, Asse
// Area sensor
addFixture({
shape: planck.Box((w + a) / 2 / R, (h + a) / 2 / R, planck.Vec2(0, h / 2 / R)),
shape: planck.Box((w + a) / 2 / R, (h + a) / 2 / R, planck.Vec2(0, 0)),
density: 0,
friction: 0,
restitution: 0,
@ -319,15 +319,20 @@ function (Parent, Exception, planck, Settings, CollisionDetector, Item, nc, Asse
Assert.number(this.lookDirection);
var handPosition = planck.Vec2(
bodyPosition.x + ((this.width / 2 / Settings.RATIO) * this.lookDirection),
bodyPosition.y - this.height / 4 * 2 / Settings.RATIO // 2/3 of the body height
bodyPosition.y - 0 / Settings.RATIO // 2/3 of the body height
);
this.holdingItem.reposition(handPosition, this.lookDirection);
var jointDef = new Box2D.Dynamics.Joints.b2WeldJointDef();
jointDef.initialize(this.body, this.holdingItem.body, this.holdingItem.getGrabPoint());
this.holdingJoint = this.body.getWorld().createJoint(jointDef);
// Planck.js WeldJoint
var jointDef = {
bodyA: this.body,
bodyB: this.holdingItem.body,
localAnchorA: this.body.getLocalPoint(this.holdingItem.getGrabPoint()),
localAnchorB: this.holdingItem.body.getLocalPoint(this.holdingItem.getGrabPoint()),
referenceAngle: 0
};
this.holdingJoint = this.body.getWorld().createJoint(planck.WeldJoint(jointDef));
}
};

View file

@ -8,7 +8,7 @@ define([
"Lib/Utilities/Assert"
],
function (Parent, Box2D, optionsHelper, Settings, Exception, nc, Assert) {
function (Parent, planck, optionsHelper, Settings, Exception, nc, Assert) {
"use strict";
@ -35,10 +35,10 @@ function (Parent, Box2D, optionsHelper, Settings, Exception, nc, Assert) {
Parent.call(this, physicsEngine, uid);
this.createFixture();
this.body.ResetMassData();
this.body.resetMassData();
this.flipDirection = 1;
if (this.body.getMass() < 1) {
this.body.SetBullet(true);
this.body.setBullet(true);
}
nc.trigger(nc.ns.core.game.worldUpdateObjects.add, this);
@ -124,8 +124,8 @@ function (Parent, Box2D, optionsHelper, Settings, Exception, nc, Assert) {
handPosition.x + ((this.options.width / Settings.RATIO / 2) * direction),
handPosition.y
);
this.body.SetPosition(position);
this.body.SetAngle((this.options.grabAngle || 0.0) * direction);
this.body.setPosition(position);
this.body.setAngle((this.options.grabAngle || 0.0) * direction);
this.flip(direction);
};
@ -148,7 +148,7 @@ function (Parent, Box2D, optionsHelper, Settings, Exception, nc, Assert) {
var x = options.x * Settings.MAX_THROW_FORCE / this.options.weight + carrierVelocity.x;
var y = -options.y * Settings.MAX_THROW_FORCE / this.options.weight + carrierVelocity.y;
var vector = planck.Vec2(x, y);
body.SetLinearVelocity(vector);
body.setLinearVelocity(vector);
var av = -options.av * Settings.MAX_THROW_ANGULAR_VELOCITY;
body.setAngularVelocity(av);

View file

@ -8,7 +8,7 @@ define([
"Game/Config/ItemSettings",
],
function (Parent, Box2D, Settings, nc, Assert, optionsHelper, ItemSettings) {
function (Parent, planck, Settings, nc, Assert, optionsHelper, ItemSettings) {
"use strict";

View file

@ -4,7 +4,7 @@ define([
"Game/Config/Settings"
],
function (Parent, Box2D, Settings) {
function (Parent, planck, Settings) {
"use strict";

View file

@ -9,7 +9,7 @@ define([
// "json!Game/Asset/RubeDoll.json" // Temporarily disabled during Planck.js migration
],
function (Parent, /* RubeLoader, */ Box2D, Settings, Assert, nc, Matrix /* , RubeDollJson */) {
function (Parent, /* RubeLoader, */ planck, Settings, Assert, nc, Matrix /* , RubeDollJson */) {
"use strict";

View file

@ -5,7 +5,7 @@ define([
"Lib/Utilities/Assert"
],
function (Parent, Box2D, Settings, Assert) {
function (Parent, planck, Settings, Assert) {
"use strict";
@ -159,15 +159,7 @@ function (Parent, Box2D, Settings, Assert) {
var wheelBody = this.body.getWorld().createBody(bodyDef);
wheelBody.createFixture(fixtureDef);
//var revoluteJointDef = new Box2D.Dynamics.Joints.b2RevoluteJointDef();
var revoluteJointDef = new Box2D.Dynamics.Joints.b2WeldJointDef();
//revoluteJointDef.enableMotor = false;
revoluteJointDef.initialize(this.body, wheelBody, wheelBody.getWorldCenter());
var j = this.body.getWorld().createJoint(revoluteJointDef);
// See top of file for Planck.js joint creation reference.
// FIXME this means, that we will have bodies in the world, which must not be
// updated (wheels) because they are always connected to a body which will be updated.

View file

@ -3,7 +3,7 @@ define([
"Lib/Vendor/Planck"
],
function (Parent, Box2D) {
function (Parent, planck) {
"use strict";

View file

@ -10,7 +10,7 @@ define([
"Game/" + GLOBALS.context + "/GameObjects/Items/RagDoll",
"Game/" + GLOBALS.context + "/GameObjects/Items/RubeDoll"
], function (Settings, Box2D, nc, Abstract, CollisionDetector, Tile, Item, Skateboard, RagDoll, RubeDoll) {
], function (Settings, planck, nc, Abstract, CollisionDetector, Tile, Item, Skateboard, RagDoll, RubeDoll) {
"use strict";

View file

@ -13,7 +13,7 @@ define([
"Game/" + GLOBALS.context + "/GameObjects/Item",
"Game/" + GLOBALS.context + "/GameObjects/Items/Skateboard",
], function (Parent, Settings, ItemSettings, Box2D, optionsHelper, Exception, nc, Assert, AbstractLayer, CollisionDetector, Tile, Item, Skateboard) {
], function (Parent, Settings, ItemSettings, planck, optionsHelper, Exception, nc, Assert, AbstractLayer, CollisionDetector, Tile, Item, Skateboard) {
"use strict";