Skip to content

Commit cbc03a1

Browse files
committed
fix(vr): review - discard cancels a nudge, an unmoved nudge stages nothing
1 parent dbbe770 commit cbc03a1

3 files changed

Lines changed: 59 additions & 9 deletions

File tree

‎shock2vr/src/interaction.rs‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1938,6 +1938,8 @@ impl VrInteraction {
19381938
let Some(tool) = self.pose_tool.as_mut() else {
19391939
return;
19401940
};
1941+
// A nudge in progress would stage again on release.
1942+
tool.cancel_nudge();
19411943
let Some(staged) = tool.staged.take() else {
19421944
return;
19431945
};
@@ -4556,7 +4558,7 @@ mod tests {
45564558
assert!(tool.staged.is_none(), "only the view");
45574559
assert_eq!(grip(&interaction).offset, before.offset);
45584560

4559-
// Test hold, the squeeze still held from the bench: no nudge.
4561+
// A squeeze held as test hold starts: no nudge.
45604562
let personal = crate::world_scale::WorldScale::active().personal();
45614563
interaction.stage_grip(before.clone().rescaled(1.0 / personal));
45624564
interaction.pose_tool_button(Handedness::Left, crate::hand_buttons::HandButton::Lower);
@@ -4666,6 +4668,31 @@ mod tests {
46664668
assert!(tool.test_hold.unwrap().nudge.is_none());
46674669
assert_eq!(grip(&interaction).offset, nudged.offset);
46684670
assert!((tool.item_placed.unwrap().position - rest.position).magnitude() < 1e-5);
4671+
4672+
// Discarded mid-nudge: back to the grip from before, and letting go
4673+
// stages nothing.
4674+
input.left_hand.rotation = Quaternion::from_angle_z(Deg(15.0));
4675+
input.left_hand.squeeze_value = 0.0;
4676+
step(&mut interaction, &input);
4677+
input.left_hand.squeeze_value = 1.0;
4678+
step(&mut interaction, &input);
4679+
input.left_hand.position += vec3(0.0, -0.05, 0.0);
4680+
step(&mut interaction, &input);
4681+
assert!(
4682+
interaction
4683+
.pose_tool
4684+
.as_ref()
4685+
.unwrap()
4686+
.test_hold
4687+
.unwrap()
4688+
.nudge
4689+
.is_some()
4690+
);
4691+
interaction.pose_tool_button(Handedness::Left, crate::hand_buttons::HandButton::Upper);
4692+
input.left_hand.squeeze_value = 0.0;
4693+
step(&mut interaction, &input);
4694+
assert!(interaction.pose_tool.as_ref().unwrap().staged.is_none());
4695+
assert_eq!(grip(&interaction).offset, before.offset);
46694696
}
46704697

46714698
/// A gun's rest snapshot stores the hand exactly where it was tracked:

‎shock2vr/src/interaction/pose_tool.rs‎

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ const BEAM_MISS_LENGTH: f32 = 1.0;
7272
/// `weapon_muzzle`'s, shared with dark_explorer).
7373
const AIM_LINE_HALO: f32 = 0.004;
7474
const AIM_LINE_CORE: f32 = 0.0012;
75+
/// A test-hold nudge let go within this of where it started stages nothing.
76+
const NUDGE_MIN_MM: f32 = 0.1;
77+
const NUDGE_MIN_DEG: f32 = 0.01;
7578

7679
/// Whether a hand's controller is held, so aims the panel ray. The runtime
7780
/// must track it; the posing hand's is set down once that hand is tracked.
@@ -564,11 +567,8 @@ impl GripPoseTool {
564567
self.triggers = [panel::TriggerArbiter::new(); 2];
565568
self.requested = true;
566569
self.pinch_lost = true;
567-
self.squeezed = true;
570+
self.cancel_nudge();
568571
self.turning = None;
569-
if let Some(hold) = self.test_hold.as_mut() {
570-
hold.nudge = None;
571-
}
572572
self.stick_armed = false;
573573
self.poke = Default::default();
574574
// Frames from before the pause are not part of a steady window now.
@@ -749,12 +749,22 @@ impl GripPoseTool {
749749
self.squeezed = squeeze;
750750
}
751751

752+
/// Drop a nudge in progress unstaged (pausing, discarding); the squeeze
753+
/// acts again only once let go.
754+
pub fn cancel_nudge(&mut self) {
755+
if let Some(hold) = self.test_hold.as_mut() {
756+
hold.nudge = None;
757+
}
758+
self.squeezed = true;
759+
}
760+
752761
/// Test hold's nudge: from the leading edge of the free controller's
753762
/// squeeze (`controller`, its world pose, `None` while it aims no ray)
754763
/// the item, at `item` as held now, keeps its pose relative to that
755764
/// controller. Returns where the item is as the squeeze lets go, for the
756-
/// grip to hold it there. Losing either controller drops the nudge
757-
/// unstaged, and the squeeze is disarmed until let go in hand.
765+
/// grip to hold it there, unless that is still where it is held (a
766+
/// squeeze without a move is no edit). Losing either controller drops
767+
/// the nudge unstaged, and the squeeze is disarmed until let go in hand.
758768
pub fn nudge_with(
759769
&mut self,
760770
controller: Option<GripPose>,
@@ -776,7 +786,15 @@ impl GripPoseTool {
776786
}
777787
None
778788
} else {
779-
hold.nudge.take().map(|nudge| nudge.item())
789+
hold.nudge
790+
.take()
791+
.map(|nudge| nudge.item())
792+
.filter(|released| {
793+
millimetres((released.position - item.position).magnitude()) > NUDGE_MIN_MM
794+
|| crate::weapon_muzzle::turn_deg(
795+
item.rotation.normalize().conjugate() * released.rotation,
796+
) > NUDGE_MIN_DEG
797+
})
780798
};
781799
self.squeezed = squeeze;
782800
released
@@ -2139,6 +2157,11 @@ mod tests {
21392157
let released = tool.nudge_with(Some(moved), item, false).expect("released");
21402158
assert!(close(released, expected));
21412159
assert!(tool.test_hold.unwrap().nudge.is_none());
2160+
// A squeeze let go without a move is no edit.
2161+
assert!(tool.nudge_with(Some(moved), expected, true).is_none());
2162+
assert!(tool.test_hold.unwrap().nudge.is_some());
2163+
assert!(tool.nudge_with(Some(moved), expected, false).is_none());
2164+
assert!(tool.test_hold.unwrap().nudge.is_none());
21422165
}
21432166

21442167
/// Losing either controller mid-nudge drops it with nothing to stage,

‎tools/shock2-sdk/test/vr-grip-pose-tool.e2e.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1362,7 +1362,7 @@ test(
13621362
const freeAt = (position: Vec3, rotation: Quat) => setHandWorldPose(game, player, "left", position, rotation);
13631363
await freeAt(add(grabbedAt, scale([0, 0.05, 0], 1 / unit)), grabbedTurn);
13641364
await game.step({ frames: 2 });
1365-
assert.equal((await tool()).test_hold?.nudging, false, "held over from the bench");
1365+
assert.equal((await tool()).test_hold?.nudging, false, "held as test hold starts");
13661366
assert.ok(distance(await gunAt(), held) < 1e-4, "the gun stays in the glove");
13671367

13681368
// Let go and squeeze again: the gun follows the left controller.

0 commit comments

Comments
 (0)