mirror of
https://github.com/logsol/chuck.js.git
synced 2026-05-11 10:37:34 +00:00
Fix debug draw and physics positioning issues
- Fix critical bug in PlanckDebugDraw.js where circles were drawn at body center instead of local positions - Add DEBUG_DRAW_SENSORS support with orange styling and no outlines - Fix Chuck's sprite positioning to align with physics body center (pivot adjustments) - Correct fixture Y coordinates so Chuck stands upright instead of on his head - Position foot sensor correctly below legs for proper ground detection - Remove cyan crosses and make yellow center-of-mass crosses smaller - Make debug lines thinner for cleaner visualization
This commit is contained in:
parent
d584065757
commit
49f4591d3a
5 changed files with 205 additions and 162 deletions
|
|
@ -140,7 +140,7 @@ function (Parent, Settings, nc, Exception, ColorConverter, Layer) {
|
|||
visible: false,
|
||||
pivot: {
|
||||
x: 0,
|
||||
y: 40 * 4
|
||||
y: 21 * 4
|
||||
},
|
||||
xScale: 0.25,
|
||||
yScale: 0.25,
|
||||
|
|
@ -187,7 +187,7 @@ function (Parent, Settings, nc, Exception, ColorConverter, Layer) {
|
|||
pivot: {
|
||||
//x: 35/2 * 4,
|
||||
x: 0,
|
||||
y: 40 * 4
|
||||
y: 21 * 4 // Reduced from 40 to 20 to match body pivot
|
||||
},
|
||||
width: 35,
|
||||
height: 40,
|
||||
|
|
@ -288,7 +288,7 @@ function (Parent, Settings, nc, Exception, ColorConverter, Layer) {
|
|||
this.headMesh,
|
||||
{
|
||||
x: this.body.getPosition().x * Settings.RATIO,
|
||||
y: this.body.getPosition().y * Settings.RATIO - this.height + this.headHeight
|
||||
y: this.body.getPosition().y * Settings.RATIO - this.height/2 + this.headHeight +1
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ function (Settings) {
|
|||
joints: false,
|
||||
aabb: false,
|
||||
pairs: false,
|
||||
centerOfMass: false
|
||||
centerOfMass: true
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ function (Settings) {
|
|||
|
||||
this.ctx.translate(transformedX, transformedY);
|
||||
this.ctx.scale(this.scale * this.cameraZoom, this.scale * this.cameraZoom);
|
||||
this.ctx.lineWidth = 0.5 / this.scale;
|
||||
this.ctx.lineWidth = 0.3 / this.scale; // Made thinner (was 0.5)
|
||||
|
||||
// Iterate through all bodies
|
||||
for (var body = world.getBodyList(); body; body = body.getNext()) {
|
||||
|
|
@ -51,11 +51,26 @@ function (Settings) {
|
|||
for (var fixture = body.getFixtureList(); fixture; fixture = fixture.getNext()) {
|
||||
var shape = fixture.getShape();
|
||||
|
||||
// Skip sensor fixtures to match old Box2D behavior
|
||||
if (fixture.isSensor()) {
|
||||
// Check if this is a sensor
|
||||
var isSensor = fixture.isSensor();
|
||||
|
||||
// Skip sensor fixtures if DEBUG_DRAW_SENSORS is false
|
||||
if (isSensor && !Settings.DEBUG_DRAW_SENSORS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip non-sensor fixtures if they were sensors in the old logic
|
||||
if (!isSensor && !Settings.DEBUG_DRAW_SENSORS) {
|
||||
// This was the old logic - skip sensors, but we're keeping non-sensors
|
||||
}
|
||||
|
||||
// Set colors based on sensor status and body type
|
||||
if (isSensor) {
|
||||
// Sensors: orange with more visibility, no stroke
|
||||
this.ctx.strokeStyle = 'rgba(0, 0, 0, 0)'; // No stroke
|
||||
this.ctx.fillStyle = 'rgba(255, 165, 0, 0.3)'; // Orange with higher alpha
|
||||
} else {
|
||||
// Regular fixtures: colored by body type
|
||||
if (body.isDynamic()) {
|
||||
this.ctx.strokeStyle = '#ff0000'; // Red for dynamic bodies
|
||||
this.ctx.fillStyle = 'rgba(255, 0, 0, 0.1)';
|
||||
|
|
@ -66,45 +81,64 @@ function (Settings) {
|
|||
this.ctx.strokeStyle = '#0000ff'; // Blue for kinematic bodies
|
||||
this.ctx.fillStyle = 'rgba(0, 0, 255, 0.1)';
|
||||
}
|
||||
}
|
||||
|
||||
this.drawShape(shape, transform);
|
||||
this.drawShape(shape, transform, isSensor);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw center of mass for each body
|
||||
if (this.flags.centerOfMass) {
|
||||
for (var body = world.getBodyList(); body; body = body.getNext()) {
|
||||
var transform = body.getTransform();
|
||||
this.drawCenterOfMass(transform);
|
||||
// Removed drawBodyOrigin call since origin and center of mass are the same in Planck.js
|
||||
}
|
||||
}
|
||||
|
||||
this.ctx.restore();
|
||||
};
|
||||
|
||||
PlanckDebugDraw.prototype.drawShape = function(shape, transform) {
|
||||
PlanckDebugDraw.prototype.drawShape = function(shape, transform, isSensor) {
|
||||
var type = shape.getType();
|
||||
|
||||
if (type === 'circle') {
|
||||
this.drawCircle(shape, transform);
|
||||
this.drawCircle(shape, transform, isSensor);
|
||||
} else if (type === 'polygon') {
|
||||
this.drawPolygon(shape, transform);
|
||||
this.drawPolygon(shape, transform, isSensor);
|
||||
} else if (type === 'edge') {
|
||||
this.drawEdge(shape, transform);
|
||||
this.drawEdge(shape, transform, isSensor);
|
||||
} else if (type === 'chain') {
|
||||
this.drawChain(shape, transform);
|
||||
this.drawChain(shape, transform, isSensor);
|
||||
}
|
||||
};
|
||||
|
||||
PlanckDebugDraw.prototype.drawCircle = function(shape, transform) {
|
||||
var center = transform.p;
|
||||
PlanckDebugDraw.prototype.drawCircle = function(shape, transform, isSensor) {
|
||||
var radius = shape.getRadius();
|
||||
|
||||
// Get the circle's local position (center relative to body)
|
||||
var localCenter = shape.m_p || planck.Vec2(0, 0);
|
||||
|
||||
// Transform the local position to world coordinates
|
||||
var worldCenter = this.transformVertex(localCenter, transform);
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.arc(center.x, center.y, radius, 0, 2 * Math.PI);
|
||||
this.ctx.arc(worldCenter.x, worldCenter.y, radius, 0, 2 * Math.PI);
|
||||
this.ctx.fill();
|
||||
|
||||
// Only draw stroke for non-sensors
|
||||
if (!isSensor) {
|
||||
this.ctx.stroke();
|
||||
|
||||
// Draw radius line to show rotation
|
||||
// Draw radius line to show rotation (only for non-sensors)
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(center.x, center.y);
|
||||
this.ctx.lineTo(center.x + radius, center.y);
|
||||
this.ctx.moveTo(worldCenter.x, worldCenter.y);
|
||||
this.ctx.lineTo(worldCenter.x + radius, worldCenter.y);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
};
|
||||
|
||||
PlanckDebugDraw.prototype.drawPolygon = function(shape, transform) {
|
||||
PlanckDebugDraw.prototype.drawPolygon = function(shape, transform, isSensor) {
|
||||
var vertices = shape.m_vertices;
|
||||
if (!vertices || vertices.length < 3) return;
|
||||
|
||||
|
|
@ -122,20 +156,28 @@ function (Settings) {
|
|||
|
||||
this.ctx.closePath();
|
||||
this.ctx.fill();
|
||||
|
||||
// Only draw stroke for non-sensors
|
||||
if (!isSensor) {
|
||||
this.ctx.stroke();
|
||||
}
|
||||
};
|
||||
|
||||
PlanckDebugDraw.prototype.drawEdge = function(shape, transform) {
|
||||
PlanckDebugDraw.prototype.drawEdge = function(shape, transform, isSensor) {
|
||||
var v1 = this.transformVertex(shape.m_vertex1, transform);
|
||||
var v2 = this.transformVertex(shape.m_vertex2, transform);
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(v1.x, v1.y);
|
||||
this.ctx.lineTo(v2.x, v2.y);
|
||||
|
||||
// Only draw stroke for non-sensors
|
||||
if (!isSensor) {
|
||||
this.ctx.stroke();
|
||||
}
|
||||
};
|
||||
|
||||
PlanckDebugDraw.prototype.drawChain = function(shape, transform) {
|
||||
PlanckDebugDraw.prototype.drawChain = function(shape, transform, isSensor) {
|
||||
var vertices = shape.m_vertices;
|
||||
if (!vertices || vertices.length < 2) return;
|
||||
|
||||
|
|
@ -149,7 +191,10 @@ function (Settings) {
|
|||
this.ctx.lineTo(v.x, v.y);
|
||||
}
|
||||
|
||||
// Only draw stroke for non-sensors
|
||||
if (!isSensor) {
|
||||
this.ctx.stroke();
|
||||
}
|
||||
};
|
||||
|
||||
PlanckDebugDraw.prototype.transformVertex = function(vertex, transform) {
|
||||
|
|
@ -163,6 +208,25 @@ function (Settings) {
|
|||
};
|
||||
};
|
||||
|
||||
PlanckDebugDraw.prototype.drawCenterOfMass = function(transform) {
|
||||
var centerX = transform.p.x;
|
||||
var centerY = transform.p.y;
|
||||
var size = 0.05; // Made much smaller (was 0.2)
|
||||
|
||||
this.ctx.strokeStyle = '#ffff00'; // Yellow color for center of mass
|
||||
this.ctx.lineWidth = 1 / this.scale; // Made thinner (was 2)
|
||||
|
||||
// Draw a cross at the center of mass
|
||||
this.ctx.beginPath();
|
||||
// Horizontal line
|
||||
this.ctx.moveTo(centerX - size, centerY);
|
||||
this.ctx.lineTo(centerX + size, centerY);
|
||||
// Vertical line
|
||||
this.ctx.moveTo(centerX, centerY - size);
|
||||
this.ctx.lineTo(centerX, centerY + size);
|
||||
this.ctx.stroke();
|
||||
};
|
||||
|
||||
PlanckDebugDraw.prototype.setFlags = function(flags) {
|
||||
this.flags = flags;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,11 +35,12 @@ function () {
|
|||
ORIGINAL_TILE_SIZE: 25,
|
||||
TILE_SIZE: 20,
|
||||
CAMERA_IS_ORTHOGRAPHIC: true,
|
||||
CAMERA_GLIDE: 6, // % of the way per frame
|
||||
CAMERA_GLIDE: 2, // % of the way per frame
|
||||
VIEW_CONTROLLER: 0 ? "Three" : "Pixi",
|
||||
ARROW_GLIDE: 30, // % of the way per frame
|
||||
ARROW_GLIDE: 20, // % of the way per frame
|
||||
SHOW_LAYER_INFO: false,
|
||||
ENABLE_POINTER_LOCK_FILTER: false,
|
||||
DEBUG_DRAW_SENSORS: true,
|
||||
|
||||
// GAME PLAY
|
||||
WALK_SPEED: 4,
|
||||
|
|
|
|||
|
|
@ -61,53 +61,45 @@ function (Parent, Exception, planck, Settings, CollisionDetector, Item, nc, Asse
|
|||
};
|
||||
|
||||
Doll.prototype.createFixtures = function () {
|
||||
Assert.number(this.width, this.height);
|
||||
Assert.number(this.reachDistance);
|
||||
Assert.number(this.areaSize);
|
||||
Assert.number(this.width, this.height, this.reachDistance, this.areaSize);
|
||||
|
||||
var self = this;
|
||||
const R = Settings.RATIO, w = this.width, h = this.height, r = this.reachDistance, a = this.areaSize;
|
||||
const self = this;
|
||||
|
||||
var fixtureDef = { shape: null, density: 1.0, friction: 0.3, restitution: 0.0, isSensor: false };
|
||||
fixtureDef.density = Settings.PLAYER_DENSITY;
|
||||
fixtureDef.friction = 0;
|
||||
fixtureDef.restitution = Settings.PLAYER_RESTITUTION;
|
||||
// Helper to create and attach fixture
|
||||
const addFixture = (def) => this.body.createFixture(def);
|
||||
|
||||
var radius = this.width / 2 / Settings.RATIO;
|
||||
var headShape = planck.Circle(
|
||||
radius,
|
||||
planck.Vec2(0, -(this.height - (this.width / 2)) / Settings.RATIO)
|
||||
);
|
||||
fixtureDef.shape = headShape;
|
||||
fixtureDef.isSensor = false;
|
||||
fixtureDef.userData = {
|
||||
onCollisionChange: this.onImpact.bind(this)
|
||||
};
|
||||
// Head (positioned at top of body box)
|
||||
addFixture({
|
||||
shape: planck.Circle(planck.Vec2(0, -(h - w) / 2 / R), w / 2 / R),
|
||||
density: Settings.PLAYER_DENSITY,
|
||||
friction: 0,
|
||||
restitution: Settings.PLAYER_RESTITUTION,
|
||||
isSensor: false,
|
||||
userData: { onCollisionChange: this.onImpact.bind(this) }
|
||||
});
|
||||
|
||||
this.body.createFixture(fixtureDef);
|
||||
// Body (simplified positioning)
|
||||
addFixture({
|
||||
shape: planck.Box(w / 2 / R, (h - w) / 2 / R, planck.Vec2(0, 0), 0),
|
||||
density: Settings.PLAYER_DENSITY,
|
||||
friction: 0,
|
||||
restitution: Settings.PLAYER_RESTITUTION,
|
||||
isSensor: false
|
||||
});
|
||||
|
||||
var bodyShape = planck.Box(
|
||||
this.width / 2 / Settings.RATIO,
|
||||
(this.height - this.width) / 2 / Settings.RATIO,
|
||||
planck.Vec2(0, -this.height / 2 / Settings.RATIO),
|
||||
0
|
||||
);
|
||||
fixtureDef.shape = bodyShape;
|
||||
fixtureDef.isSensor = false;
|
||||
this.body.createFixture(fixtureDef);
|
||||
// Legs (positioned at bottom of body box)
|
||||
this.legs = addFixture({
|
||||
shape: planck.Circle(planck.Vec2(0, (h - w) / 2 / R), w / 2 / R),
|
||||
density: Settings.PLAYER_DENSITY,
|
||||
friction: Settings.PLAYER_FRICTION,
|
||||
restitution: Settings.PLAYER_RESTITUTION,
|
||||
isSensor: false
|
||||
});
|
||||
|
||||
var legsShape = planck.Circle(
|
||||
this.width / 2 / Settings.RATIO,
|
||||
planck.Vec2(0, -this.width / 2 / Settings.RATIO)
|
||||
);
|
||||
fixtureDef.shape = legsShape;
|
||||
fixtureDef.friction = Settings.PLAYER_FRICTION;
|
||||
fixtureDef.isSensor = false;
|
||||
|
||||
this.legs = this.body.createFixture(fixtureDef);
|
||||
|
||||
// Create a fresh fixture definition for the foot sensor
|
||||
var footSensorDef = {
|
||||
shape: null,
|
||||
// Foot sensor (positioned below legs)
|
||||
this.footSensor = addFixture({
|
||||
shape: planck.Circle(planck.Vec2(0, (h - w) / 2 / R + 2 / R), (w - 1) / 2 / R),
|
||||
density: 0,
|
||||
friction: 0,
|
||||
restitution: 0,
|
||||
|
|
@ -116,84 +108,47 @@ function (Parent, Exception, planck, Settings, CollisionDetector, Item, nc, Asse
|
|||
onCollisionChange: this.onFootSensorDetection.bind(this),
|
||||
isFootSensor: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var feetShape = planck.Circle(
|
||||
(this.width - 1) / 2 / Settings.RATIO, // the -1 one prevents collisions with walls
|
||||
planck.Vec2(0, -20 / Settings.RATIO) // 20 pixels down from center (dramatic test)
|
||||
);
|
||||
footSensorDef.shape = feetShape;
|
||||
// // Grab sensors (left/right)
|
||||
// ["left", "right"].forEach(side => {
|
||||
// const sign = side === "left" ? -1 : 1;
|
||||
// addFixture({
|
||||
// shape: planck.Box(
|
||||
// r / 2 / R,
|
||||
// (h / 2 + r / 4) / R,
|
||||
// planck.Vec2(sign * r / 2 / R, h / 2 / R)
|
||||
// ),
|
||||
// density: 0,
|
||||
// friction: 0,
|
||||
// restitution: 0,
|
||||
// isSensor: true,
|
||||
// userData: {
|
||||
// onCollisionChange: function(isColliding, fixture) {
|
||||
// self.onFixtureWithinReach(isColliding, side, fixture);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
|
||||
this.footSensor = this.body.createFixture(footSensorDef);
|
||||
|
||||
var grabSensorLeftShape = planck.Box(
|
||||
this.reachDistance / 2 / Settings.RATIO,
|
||||
((this.height / 2) + this.reachDistance / 4) / Settings.RATIO,
|
||||
planck.Vec2(
|
||||
-this.reachDistance / 2 / Settings.RATIO,
|
||||
-this.height / 2 / Settings.RATIO
|
||||
)
|
||||
);
|
||||
fixtureDef.shape = grabSensorLeftShape;
|
||||
fixtureDef.isSensor = true;
|
||||
fixtureDef.userData = {
|
||||
onCollisionChange: function(isColliding, fixture) {
|
||||
self.onFixtureWithinReach(isColliding, "left", fixture);
|
||||
}
|
||||
};
|
||||
this.body.createFixture(fixtureDef);
|
||||
|
||||
var grabSensorRightShape = planck.Box(
|
||||
this.reachDistance / 2 / Settings.RATIO,
|
||||
((this.height / 2) + this.reachDistance / 4) / Settings.RATIO,
|
||||
planck.Vec2(
|
||||
this.reachDistance / 2 / Settings.RATIO,
|
||||
-this.height / 2 / Settings.RATIO
|
||||
)
|
||||
);
|
||||
fixtureDef.shape = grabSensorRightShape;
|
||||
fixtureDef.isSensor = true;
|
||||
|
||||
fixtureDef.userData = {
|
||||
onCollisionChange: function(isColliding, fixture) {
|
||||
self.onFixtureWithinReach(isColliding, "right", fixture);
|
||||
}
|
||||
};
|
||||
|
||||
this.body.createFixture(fixtureDef);
|
||||
|
||||
// Area Sensor
|
||||
var areaSensorShape = planck.Box(
|
||||
(this.width + this.areaSize) / 2 / Settings.RATIO,
|
||||
(this.height + this.areaSize) / 2 / Settings.RATIO,
|
||||
planck.Vec2(
|
||||
0,
|
||||
-this.height / 2 / Settings.RATIO
|
||||
)
|
||||
);
|
||||
fixtureDef.shape = areaSensorShape;
|
||||
fixtureDef.isSensor = true;
|
||||
|
||||
fixtureDef.userData = {
|
||||
onCollisionChange: function(isColliding, fixture) {
|
||||
var userData = fixture.getBody().getUserData();
|
||||
if(userData instanceof Doll) {
|
||||
var doll = userData;
|
||||
var i = self.nearbyDolls.indexOf(doll);
|
||||
if(isColliding) {
|
||||
if(i === -1) {
|
||||
self.nearbyDolls.push(doll);
|
||||
}
|
||||
} else {
|
||||
if(i !== -1) {
|
||||
self.nearbyDolls.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.body.createFixture(fixtureDef);
|
||||
// // Area sensor
|
||||
// addFixture({
|
||||
// shape: planck.Box((w + a) / 2 / R, (h + a) / 2 / R, planck.Vec2(0, h / 2 / R)),
|
||||
// density: 0,
|
||||
// friction: 0,
|
||||
// restitution: 0,
|
||||
// isSensor: true,
|
||||
// userData: {
|
||||
// onCollisionChange: function(isColliding, fixture) {
|
||||
// var userData = fixture.getBody().getUserData();
|
||||
// if (userData instanceof Doll) {
|
||||
// var i = self.nearbyDolls.indexOf(userData);
|
||||
// if (isColliding && i === -1) self.nearbyDolls.push(userData);
|
||||
// else if (!isColliding && i !== -1) self.nearbyDolls.splice(i, 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
};
|
||||
|
||||
Doll.prototype.setActionState = function(state) {
|
||||
|
|
@ -219,7 +174,7 @@ function (Parent, Exception, planck, Settings, CollisionDetector, Item, nc, Asse
|
|||
var pos = this.body.getPosition();
|
||||
return {
|
||||
x: pos.x,
|
||||
y: pos.y - (this.height - this.headHeight / 2) / Settings.RATIO
|
||||
y: pos.y + (this.height - this.headHeight / 2) / Settings.RATIO
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -318,11 +273,7 @@ function (Parent, Exception, planck, Settings, CollisionDetector, Item, nc, Asse
|
|||
};
|
||||
|
||||
Doll.prototype.setStanding = function (isStanding) {
|
||||
if (this.standing == isStanding) {
|
||||
console.log('setStanding called but no change needed, already:', isStanding);
|
||||
return;
|
||||
}
|
||||
console.log('*** STANDING STATE CHANGE: ', this.standing, '->', isStanding, '***');
|
||||
if (this.standing == isStanding) return;
|
||||
this.standing = isStanding;
|
||||
if(isStanding) this.setActionState("stand");
|
||||
};
|
||||
|
|
|
|||
27
app/Game/Core/GameObjects/testbed.js
Normal file
27
app/Game/Core/GameObjects/testbed.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Licensed under the MIT License
|
||||
* Copyright (c) Erin Catto
|
||||
*/
|
||||
|
||||
// TODO_ERIN test joints on compounds.
|
||||
planck.testbed('CompoundShapes', function(testbed) {
|
||||
var pl = planck, Vec2 = pl.Vec2, Transform = pl.Transform;
|
||||
var world = new pl.World(Vec2(0, -10));
|
||||
|
||||
world.createBody(Vec2(0.0, 0.0)).createFixture(pl.Edge(Vec2(50.0, 0.0), Vec2(-50.0, 0.0)), 0.0);
|
||||
|
||||
var headshape = pl.Circle(Vec2(0.0, 1.0), 0.5);
|
||||
var legsshape = pl.Circle(Vec2(0.0, -1.0), 0.5);
|
||||
var bodyshape = pl.Box(0.25, 0.5);
|
||||
|
||||
// Create one body with circles and polygons
|
||||
var body = world.createDynamicBody({
|
||||
position : Vec2(pl.Math.random(-0.1, 0.1), 1.05),
|
||||
angle : pl.Math.random(-Math.PI, Math.PI)
|
||||
});
|
||||
body.createFixture(headshape, 2.0);
|
||||
body.createFixture(legsshape, 0.0);
|
||||
body.createFixture(bodyshape, 2.0);
|
||||
|
||||
return world;
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue