Keep a dragged rigidbody on the mouse while the game plays
Dragging a sprite with a dynamic rigidbody in the scene view during play barely moved it. Only a quick drag and release got through. A dragged object should follow the mouse as if it had no rigidbody and start from rest when it is let go. - The scene view reports the dragged objects as held through EditorState. The game tick no longer writes its own position over a drag position that has not been read in yet. This affected every object in play, not only rigidbodies. - A held dynamic body turns kinematic and is set straight to the drag target. Gravity and velocity no longer pull it away between two mouse moves, and the "moved directly" warning stays quiet. - A body counts as held when the object itself, an object above it or its rigidbody is dragged. - On release the body turns dynamic again with linear and angular velocity set to 0. Not changed: a press on an unselected crate still lands on its same-sized collider (rule from #203). Dragging while play is paused and in the editor run is untouched. Tests: - ./check.sh: 155 files, 2273 tests, CHECK EXIT 0 (before 2271). - e2e 41 alone: 21 checks. e2e 1-16,39-43: 641 checks, all passed. - 2 unit tests: a held body stays where the drag puts it and starts from rest, also for a grip shorter than one physics step. The tick does not overwrite a drag position that is not read in yet. - 1 e2e check in 41b: the crate is lifted 150 units with the real mouse, holds exactly at -3490 for a second, then falls from rest (1.3 px, then 5.1 px) with an empty log. - Counter-checks: without holding in physics the crate falls back to the ground and the old warning shows. With the tick writing back the unit test fails. Without zeroing, a short grip keeps 490 px/s and the test fails. - Check total 1356 + 1 = 1357, calculated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d444b27fae
commit
d257298bc7
8 files changed
+136
-4
No files matched your search
@@ -88,6 +88,8 @@ interface Body {
|
||||
turns: boolean;
|
||||
/** The mass it carries of its own because no collider gives it one (kg, 0 = none). */
|
||||
ownMass: number;
|
||||
/** A dynamic body the editor is dragging: kinematic until let go, then at rest (`World.holds`). */
|
||||
held: boolean;
|
||||
/** Where the pose was last put, by us or by the object moving. */
|
||||
placed: Pose;
|
||||
/** A dynamic body's pose before and after the last step, for drawing in between. */
|
||||
@@ -426,6 +428,7 @@ export class PhysicsSystem implements System, CollisionSource {
|
||||
settingsKey: '',
|
||||
turns: false,
|
||||
ownMass: 0,
|
||||
held: false,
|
||||
placed: pose,
|
||||
previous: pose,
|
||||
current: pose,
|
||||
@@ -451,21 +454,32 @@ export class PhysicsSystem implements System, CollisionSource {
|
||||
/**
|
||||
* Puts the body where its object is. A dynamic body is only moved when something else moved the
|
||||
* object since we last wrote it – that is a teleport, and the body keeps its velocity (#146, 3).
|
||||
* One the editor drags goes where the drag puts it, as if it had no rigidbody, and is let go at rest.
|
||||
*/
|
||||
private place(body: Body, want: Wanted, key: Entity, world: World): void {
|
||||
const settings = want.settings;
|
||||
const held = settings?.type === 'dynamic' && world.holds(key);
|
||||
const letGo = body.held && !held;
|
||||
if (held !== body.held) {
|
||||
body.held = held;
|
||||
body.settingsKey = '';
|
||||
}
|
||||
const settingsKey = settings ? JSON.stringify(settings) + hasTransformProps(key.type) : '';
|
||||
if (settings && settingsKey !== body.settingsKey) {
|
||||
body.settingsKey = settingsKey;
|
||||
this.applySettings(body, settings, key);
|
||||
}
|
||||
if (letGo) {
|
||||
body.body.setLinvel({ x: 0, y: 0 }, true);
|
||||
body.body.setAngvel(0, true);
|
||||
}
|
||||
const on = isHandleEnabled(key);
|
||||
if (body.body.isEnabled() !== on) body.body.setEnabled(on);
|
||||
const pose = this.poseWanted(want, key);
|
||||
if (samePose(pose, body.placed)) return;
|
||||
body.placed = pose;
|
||||
const t = { x: toMetres(pose.x), y: toMetres(pose.y) };
|
||||
if (body.body.isKinematic() && want.kind === 'rigid') {
|
||||
if (body.body.isKinematic() && want.kind === 'rigid' && !body.held) {
|
||||
body.body.setNextKinematicTranslation(t);
|
||||
body.body.setNextKinematicRotation(pose.angle);
|
||||
return;
|
||||
@@ -485,7 +499,7 @@ export class PhysicsSystem implements System, CollisionSource {
|
||||
|
||||
private applySettings(target: Body, settings: RigidbodySettings, owner: Entity): void {
|
||||
const body = target.body;
|
||||
body.setBodyType(this.bodyType(settings.type), true);
|
||||
body.setBodyType(this.bodyType(target.held ? 'kinematic' : settings.type), true);
|
||||
body.setGravityScale(settings.gravityScale, true);
|
||||
body.setLinearDamping(settings.linearDamping);
|
||||
body.setAngularDamping(settings.angularDamping);
|
||||
|
||||
Reference in new issue
Block a user