Minor improvement to rope physics

Now watching some videos on verlet physics
master
Louis Pearson 2022-01-18 12:49:09 -07:00
parent 90ef353288
commit 6852451b73
1 changed files with 80 additions and 12 deletions

View File

@ -73,7 +73,27 @@ const Control = struct {
const Sprite = struct { offset: Vec2f = Vec2f{ 0, 0 }, size: w4.Vec2, index: usize, flags: w4.BlitFlags }; const Sprite = struct { offset: Vec2f = Vec2f{ 0, 0 }, size: w4.Vec2, index: usize, flags: w4.BlitFlags };
const StaticAnim = Anim; const StaticAnim = Anim;
const ControlAnim = struct { anims: []AnimData, state: Anim }; const ControlAnim = struct { anims: []AnimData, state: Anim };
const Kinematic = struct { col: AABB, move: Vec2f = Vec2f{ 0, 0 }, lastCol: Vec2f = Vec2f{ 0, 0 } }; const Kinematic = struct {
col: AABB,
move: Vec2f = Vec2f{ 0, 0 },
lastCol: Vec2f = Vec2f{ 0, 0 },
pub fn inAir(this: @This()) bool {
return approxEqAbs(f32, this.lastCol[1], 0, 0.01);
}
pub fn onFloor(this: @This()) bool {
return approxEqAbs(f32, this.move[1], 0, 0.01) and this.lastCol[1] > 0;
}
pub fn isFalling(this: @This()) bool {
return this.move[1] > 0 and approxEqAbs(f32, this.lastCol[1], 0, 0.01);
}
pub fn onWall(this: @This()) bool {
return this.isFalling() and !approxEqAbs(f32, this.lastCol[0], 0, 0.01);
}
};
const Wire = struct { nodes: std.BoundedArray(Pos, 32), anchored: [2]?union(enum) { stationary, grabbed: u32 } = null }; const Wire = struct { nodes: std.BoundedArray(Pos, 32), anchored: [2]?union(enum) { stationary, grabbed: u32 } = null };
const Physics = struct { gravity: Vec2f, friction: Vec2f }; const Physics = struct { gravity: Vec2f, friction: Vec2f };
const Component = struct { const Component = struct {
@ -153,6 +173,7 @@ export fn start() void {
} }
var indicator: ?Vec2 = null; var indicator: ?Vec2 = null;
var time: usize = 0;
export fn update() void { export fn update() void {
w4.DRAW_COLORS.* = 0x0004; w4.DRAW_COLORS.* = 0x0004;
@ -185,11 +206,17 @@ export fn update() void {
world.process(1, &.{.wire}, wireDrawProcess); world.process(1, &.{.wire}, wireDrawProcess);
if (indicator) |pos| { if (indicator) |pos| {
if (@divTrunc((time % 60), 30) == 0)
w4.DRAW_COLORS.* = 0x0031
else
w4.DRAW_COLORS.* = 0x0030;
w4.oval(pos - w4.Vec2{ 2, 2 }, w4.Vec2{ 5, 5 }); w4.oval(pos - w4.Vec2{ 2, 2 }, w4.Vec2{ 5, 5 });
} }
indicator = null; indicator = null;
input.update(); input.update();
time += 1;
} }
fn is_plug(tile: u8) bool { fn is_plug(tile: u8) bool {
@ -305,9 +332,15 @@ fn wirePhysicsProcess(dt: f32, wire: *Wire) void {
.stationary => nodes[0].pos = nodes[0].last, .stationary => nodes[0].pos = nodes[0].last,
.grabbed => |grabbedBy| { .grabbed => |grabbedBy| {
var entity = world.get(grabbedBy); var entity = world.get(grabbedBy);
// TODO: stop player from pulling the wire through terrain // if (entity.kinematic) |kinematic| {
// if (kinematic.inAir()) {
// constrainNodes(&entity.pos.?, &nodes[0]); // constrainNodes(&entity.pos.?, &nodes[0]);
// world.set(grabbedBy, entity); // world.set(grabbedBy, entity);
// break :anchor;
// }
// }
// TODO: stop player from pulling the wire through terrain
// constrainNodes(&entity.pos.?, &nodes[0]);
nodes[0].pos = entity.pos.?.pos + Vec2f{ 0, -6 }; nodes[0].pos = entity.pos.?.pos + Vec2f{ 0, -6 };
}, },
} }
@ -317,15 +350,23 @@ fn wirePhysicsProcess(dt: f32, wire: *Wire) void {
.stationary => nodes[nodes.len - 1].pos = nodes[nodes.len - 1].last, .stationary => nodes[nodes.len - 1].pos = nodes[nodes.len - 1].last,
.grabbed => |grabbedBy| { .grabbed => |grabbedBy| {
var entity = world.get(grabbedBy); var entity = world.get(grabbedBy);
// TODO: stop player from pulling the wire through terrain // if (entity.kinematic) |kinematic| {
// if (kinematic.inAir()) {
// constrainNodes(&entity.pos.?, &nodes[nodes.len - 1]); // constrainNodes(&entity.pos.?, &nodes[nodes.len - 1]);
// world.set(grabbedBy, entity); // world.set(grabbedBy, entity);
// break :anchor;
// }
// }
// TODO: stop player from pulling the wire through terrain
// constrainNodes(&entity.pos.?, &nodes[nodes.len - 1]);
nodes[nodes.len - 1].pos = entity.pos.?.pos + Vec2f{ 0, -6 }; nodes[nodes.len - 1].pos = entity.pos.?.pos + Vec2f{ 0, -6 };
}, },
} }
} }
if (wire.anchored[0] != null and wire.anchored[1] != null) { if (wire.anchored[0] != null and wire.anchored[1] != null) {
// const a1 = wire.anchored[0].?;
// const a2 = wire.anchored[1].?;
var i: usize = 0; var i: usize = 0;
var left: usize = 1; var left: usize = 1;
var right: usize = nodes.len - 2; var right: usize = nodes.len - 2;
@ -337,6 +378,8 @@ fn wirePhysicsProcess(dt: f32, wire: *Wire) void {
} else { } else {
constrainNodes(&nodes[left - 1], &nodes[left]); constrainNodes(&nodes[left - 1], &nodes[left]);
} }
// collideNode(&nodes[left - 1]);
// collideNode(&nodes[left]);
left += 1; left += 1;
} else { } else {
// Right side // Right side
@ -345,27 +388,52 @@ fn wirePhysicsProcess(dt: f32, wire: *Wire) void {
} else { } else {
constrainNodes(&nodes[right + 1], &nodes[right]); constrainNodes(&nodes[right + 1], &nodes[right]);
} }
// collideNode(&nodes[right + 1]);
// collideNode(&nodes[right]);
right -= 1; right -= 1;
} }
} }
} else if (wire.anchored[0] != null and wire.anchored[1] == null) { } else if (wire.anchored[0] != null and wire.anchored[1] == null) {
// const a1 = wire.anchored[0].?;
var left: usize = 1; var left: usize = 1;
constrainToAnchor(&nodes[left - 1], &nodes[left]);
left += 1;
while (left < nodes.len) : (left += 1) { while (left < nodes.len) : (left += 1) {
// Left side // Left side
if (left == 1) {
constrainToAnchor(&nodes[left - 1], &nodes[left]);
} else {
constrainNodes(&nodes[left - 1], &nodes[left]); constrainNodes(&nodes[left - 1], &nodes[left]);
} // collideNode(&nodes[left - 1]);
// collideNode(&nodes[left]);
} }
} else if (wire.anchored[0] == null and wire.anchored[1] != null) { } else if (wire.anchored[0] == null and wire.anchored[1] != null) {
// const a2 = wire.anchored[0].?;
var right: usize = nodes.len - 2; var right: usize = nodes.len - 2;
while (right > 1) : (right -= 1) {
// Right side
if (right == 1) {
constrainToAnchor(&nodes[right + 1], &nodes[right]); constrainToAnchor(&nodes[right + 1], &nodes[right]);
} else { right -= 1;
while (right >= 0) : (right -= 1) {
// Right side
constrainNodes(&nodes[right + 1], &nodes[right]); constrainNodes(&nodes[right + 1], &nodes[right]);
// collideNode(&nodes[right + 1]);
// collideNode(&nodes[right]);
if (right == 0) break;
}
} else {
// No anchors
var i: usize = 0;
var left: usize = 1;
var right: usize = nodes.len - 2;
while (i < nodes.len) : (i += 1) {
if (i % 2 == 0) {
// Left side
constrainNodes(&nodes[left - 1], &nodes[left]);
// collideNode(&nodes[left - 1]);
// collideNode(&nodes[left]);
left += 1;
} else {
// Right side
constrainNodes(&nodes[right + 1], &nodes[right]);
// collideNode(&nodes[right + 1]);
// collideNode(&nodes[right]);
right -= 1;
} }
} }
} }
@ -397,7 +465,7 @@ const wireSegmentMaxLengthV = @splat(2, @as(f32, wireSegmentMaxLength));
fn constrainToAnchor(anchor: *Pos, node: *Pos) void { fn constrainToAnchor(anchor: *Pos, node: *Pos) void {
var diff = anchor.pos - node.pos; var diff = anchor.pos - node.pos;
var dist = distancef(node.pos, anchor.pos); var dist = distancef(node.pos, anchor.pos);
var wireLength = @maximum(wireSegmentMinLength, dist); var wireLength = @maximum(wireSegmentMaxLength, dist);
node.pos = anchor.pos - (normalize(diff) * @splat(2, @as(f32, wireLength))); node.pos = anchor.pos - (normalize(diff) * @splat(2, @as(f32, wireLength)));
} }