Render-clock tracking timestamps (menu toggle), physics step cap 6, docs for step 2.7
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
22159aa902
commit
ca60df3d75
9 files changed
+111
-11
No files matched your search
@@ -321,7 +321,7 @@ device only; the editor has an XR simulator for dev. Trackers/action map: see `x
|
|||||||
`PhysicsMaterialOverride` before AddChild.**
|
`PhysicsMaterialOverride` before AddChild.**
|
||||||
**Step 2.6:** landing DIP is physics (legs touch down only within reach → leg strength stops the body below
|
**Step 2.6:** landing DIP is physics (legs touch down only within reach → leg strength stops the body below
|
||||||
its stance; big falls fold the legs, Boneworks-style; rise eased so gravity alone can stop it at the stance);
|
its stance; big falls fold the legs, Boneworks-style; rise eased so gravity alone can stop it at the stance);
|
||||||
JUMP on right A (countermovement dip + leg push over the stroke — crouching first jumps higher); STICK CROUCH on
|
JUMP on right A (2.7: hold to charge, release to jump; crouching charges too); STICK CROUCH on
|
||||||
right stick Y (`RagdollDriver.StickCrouch` = virtual floor offset); body facing from `BodyMath.HeadFacing`
|
right stick Y (`RagdollDriver.StickCrouch` = virtual floor offset); body facing from `BodyMath.HeadFacing`
|
||||||
(no flip looking down past vertical); the XR origin is DRAWN interpolated like the bodies (`PlayerRig`
|
(no flip looking down past vertical); the XR origin is DRAWN interpolated like the bodies (`PlayerRig`
|
||||||
`_physOrigin`, restored before physics) — the camera/body "two places at once" desync. Rule learned: play-space
|
`_physOrigin`, restored before physics) — the camera/body "two places at once" desync. Rule learned: play-space
|
||||||
@@ -330,6 +330,13 @@ device only; the editor has an XR simulator for dev. Trackers/action map: see `x
|
|||||||
**The crag** (`Crag.cs`): a 26 m box-rock cliff north of the playground with one graded route (boulders →
|
**The crag** (`Crag.cs`): a 26 m box-rock cliff north of the playground with one graded route (boulders →
|
||||||
ladder → 8 m ledge → jug wall → traverse → overhang → 16 m ledge → chimney → summit with props); the way down
|
ladder → 8 m ledge → jug wall → traverse → overhang → 16 m ledge → chimney → summit with props); the way down
|
||||||
is the "Crag" teleport marker at the base. Regression `scenes/crag_spike.tscn` "CRAG: overall PASS" (layout only).
|
is the "Crag" teleport marker at the base. Regression `scenes/crag_spike.tscn` "CRAG: overall PASS" (layout only).
|
||||||
|
**Step 2.7 (owner 2026-10-02: "Nimso's project is the main source of inspiration/mechanics — don't reinvent
|
||||||
|
the wheel"; check `research/nimso-project-tx.md` + `research/sources/nimso-transcripts/` FIRST for any body
|
||||||
|
mechanic):** ground under the BODY (centre ray + stance-wide sphere footprint), clambering by PRESSURE (higher
|
||||||
|
ground is stood on once the hips are over it and the body presses onto it — no special mantle mechanic),
|
||||||
|
capsule hips (Nimso ~27 cm), heavy physics objects brace like world, arms always collide with held things,
|
||||||
|
SOFT GRAB (`SoftGrab.cs`: eased into the hand before the weld), hold-A-to-charge jump, render-clock-timed
|
||||||
|
tracking (`PoseFilter` sampleTime; menu toggle "Tracking: steady/low lag"), physics step cap 6.
|
||||||
Owner scope: avatar scaling and NPCs later.
|
Owner scope: avatar scaling and NPCs later.
|
||||||
10. **Body physics Stage 2 — PHYSICAL ARMS, implemented 2026-10-02, awaiting owner playtest.**
|
10. **Body physics Stage 2 — PHYSICAL ARMS, implemented 2026-10-02, awaiting owner playtest.**
|
||||||
`PhysicsArms.cs`: per side an upper-arm + forearm RigidBody3D (2.0 / 1.2 kg, layer 5) that
|
`PhysicsArms.cs`: per side an upper-arm + forearm RigidBody3D (2.0 / 1.2 kg, layer 5) that
|
||||||
|
|||||||
+2
-2
@@ -27,9 +27,9 @@ project/assembly_name="VR Messs"
|
|||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
common/physics_ticks_per_second=144
|
common/physics_ticks_per_second=144
|
||||||
common/physics_interpolation=true
|
common/max_physics_steps_per_frame=6
|
||||||
common/max_physics_steps_per_frame=14
|
|
||||||
3d/physics_engine="Box3D Physics"
|
3d/physics_engine="Box3D Physics"
|
||||||
|
common/physics_interpolation=true
|
||||||
|
|
||||||
[rendering]
|
[rendering]
|
||||||
|
|
||||||
|
|||||||
@@ -221,3 +221,23 @@ fall); held poses drift 1 cm with the eye within 7 mm; crawl, mantle, climb, pul
|
|||||||
| Menu summon on left X only | Right A is jump |
|
| Menu summon on left X only | Right A is jump |
|
||||||
|
|
||||||
**Shoulder range (2026-10-02):** the fork's DRIVE now honours angular limits (Box3D motor joint + swing ellipse/twist, `research/godot-box3d-6dof.md`); `PlayerRagdoll.ShoulderRange` (Y −90..+100° mirrored, Z −85..+155°, twist ±80°, frame X = humerus at build). Ragdoll spike unchanged with it on — the limits only engage when something forces the arm.
|
**Shoulder range (2026-10-02):** the fork's DRIVE now honours angular limits (Box3D motor joint + swing ellipse/twist, `research/godot-box3d-6dof.md`); `PlayerRagdoll.ShoulderRange` (Y −90..+100° mirrored, Z −85..+155°, twist ±80°, frame X = humerus at build). Ragdoll spike unchanged with it on — the limits only engage when something forces the arm.
|
||||||
|
|
||||||
|
## Step 2.7 — climbing family, soft grab, charge jump, render-timed tracking (2026-10-02)
|
||||||
|
|
||||||
|
Owner: Nimso's Project TX is the main source of mechanics. His clambering has "no actual mechanics — the physics
|
||||||
|
engine does all the work"; higher ground "doesn't move my body up … until I push on it with enough pressure".
|
||||||
|
|
||||||
|
| Change | Why / measured |
|
||||||
|
|---|---|
|
||||||
|
| **Ground = centre ray + sphere footprint** (r 0.12, face normal from a ray 2 cm inside the contact). Same-level ground from either; higher ground from the centre ray, or from the footprint while clambering | One ray dropped support as the hips swayed off a plank. Spike: 15 cm plank, ±9 cm hip sway → never loses the plank |
|
||||||
|
| **Pressure rule** replaces "hips well above + whole hips over": stand on higher ground when the hips are over it and pressing = airborne, hands braced, lifted, a press within 0.6 s, or legs tucked | The old rule needed a full press-up. Two hands mantle 0.9 m and chest-high 1.2 m; one hand can't do 1.2 m |
|
||||||
|
| **Bracing on physics objects** (≥ 15 kg or frozen; not what the hand carries) | Mantling the 25 kg playground box never counted as bracing (owner screenshot). Now mantles |
|
||||||
|
| **Knee up**: braced (or just pressed) + hips held back tucks the legs collider | Thigh-high box: straight arms can't press while standing |
|
||||||
|
| **Capsule hips** (Nimso) | The box pelvis's bottom edge caught ledge lips 1 cm below it |
|
||||||
|
| **Support goal ≤ straight legs** | A head above the calibrated height (tiptoes) floated the body 35 cm |
|
||||||
|
| **Arms never get collision exceptions** with held objects | Gripping one hold of a crag rock switched the arm off against the whole rock — arms "randomly" phased through the world |
|
||||||
|
| **Soft grab** (`SoftGrab.cs`): grip point = palm-normal cast (else toward the centre); light props (≤ 6 kg) are moved to the palm, otherwise the hand goes to the hold; ~0.1 s, position only, weld when touching or stalled | Welds froze hover gaps. 1 kg cube from 6 cm → 1.5 mm in 0.10 s; bar from 5 cm → 1.2 cm (contact slop) |
|
||||||
|
| **Jump: hold A to charge, release** (support goal sinks at 1.2 m/s, max stroke 0.5 m; JumpForce 2.2 g) | Owner: Boneworks-style. Tap 0.16 m, full charge 0.68 m, crouch + tap 0.66 m |
|
||||||
|
| **Render-clock tracking timestamps** (`PoseFilter.Sample(..., sampleTime)`, `PlayerRig.TrackingAge`, bible v2 recipe) | At 1 m/s the per-tick speed spread is 1.25 m/s by arrival vs 0.013 m/s render-timed — every feed-forward beat at 18 Hz. Constant ~2-tick lag instead. Toggle in the menu to compare |
|
||||||
|
| **max_physics_steps_per_frame 14 → 6** | One hitch could queue 14 ragdoll ticks in a frame (bible v2) |
|
||||||
|
| Tried and reverted: arm aim from the physical shoulder vertically while climbing/tilted | Free-hand error 6.4 → 6.2 cm only, and it weakened pulls. The "tracking off when tilted" screenshots need a recording to diagnose |
|
||||||
@@ -20,6 +20,7 @@ public partial class MainMenu : PanelContainer
|
|||||||
public event Action Clicked;
|
public event Action Clicked;
|
||||||
public event Action<bool> SpectatorToggled;
|
public event Action<bool> SpectatorToggled;
|
||||||
public event Action<bool> SmoothTurnToggled;
|
public event Action<bool> SmoothTurnToggled;
|
||||||
|
public event Action<bool> LowLagTrackingToggled;
|
||||||
public event Action<float> StrengthChanged;
|
public event Action<float> StrengthChanged;
|
||||||
|
|
||||||
public TabContainer Tabs { get; private set; }
|
public TabContainer Tabs { get; private set; }
|
||||||
@@ -155,6 +156,10 @@ public partial class MainMenu : PanelContainer
|
|||||||
SpectatorButton = MakeToggle("Spectator: off", "Spectator: on (grab-fly)", on => SpectatorToggled?.Invoke(on));
|
SpectatorButton = MakeToggle("Spectator: off", "Spectator: on (grab-fly)", on => SpectatorToggled?.Invoke(on));
|
||||||
modeRow.AddChild(SpectatorButton);
|
modeRow.AddChild(SpectatorButton);
|
||||||
player.AddChild(modeRow);
|
player.AddChild(modeRow);
|
||||||
|
// Compare in the headset: tracking timed by the render clock (even motion) or by arrival (less lag).
|
||||||
|
HBoxContainer trackingRow = new();
|
||||||
|
trackingRow.AddChild(MakeToggle("Tracking: steady", "Tracking: low lag", on => LowLagTrackingToggled?.Invoke(on)));
|
||||||
|
player.AddChild(trackingRow);
|
||||||
Tabs.AddChild(player);
|
Tabs.AddChild(player);
|
||||||
|
|
||||||
// World
|
// World
|
||||||
|
|||||||
+25
-1
@@ -15,6 +15,9 @@ public partial class PlayerRig : Node
|
|||||||
public const float MoveAcceleration = 8f; // m/s²
|
public const float MoveAcceleration = 8f; // m/s²
|
||||||
public const float StickDeadzone = 0.2f;
|
public const float StickDeadzone = 0.2f;
|
||||||
public static bool SmoothTurn = false;
|
public static bool SmoothTurn = false;
|
||||||
|
// Tracking timed by the render clock (bible v2: uniform motion, constant ~2-tick lag) vs by
|
||||||
|
// arrival (less lag, 18 Hz speed beat). Menu toggle so both can be compared in the headset.
|
||||||
|
public static bool SteadyTracking = true;
|
||||||
public const float SnapTurnDegrees = 30f;
|
public const float SnapTurnDegrees = 30f;
|
||||||
public const float SmoothTurnSpeed = 2.5f; // rad/s
|
public const float SmoothTurnSpeed = 2.5f; // rad/s
|
||||||
public const float SnapTurnThreshold = 0.7f;
|
public const float SnapTurnThreshold = 0.7f;
|
||||||
@@ -144,7 +147,8 @@ public partial class PlayerRig : Node
|
|||||||
_driver.RebuildRequested |= _rebuild;
|
_driver.RebuildRequested |= _rebuild;
|
||||||
_rebuild = false;
|
_rebuild = false;
|
||||||
Transform3D o = _origin.GlobalTransform;
|
Transform3D o = _origin.GlobalTransform;
|
||||||
_driver.Tick(profile, ref o, _camera.Transform, _left.Transform, _right.Transform, _moveVelocity, dt);
|
_driver.Tick(profile, ref o, _camera.Transform, _left.Transform, _right.Transform, _moveVelocity, dt,
|
||||||
|
SteadyTracking ? TrackingAge() : null);
|
||||||
_origin.GlobalTransform = o;
|
_origin.GlobalTransform = o;
|
||||||
_lastOrigin = _origin.GlobalTransform;
|
_lastOrigin = _origin.GlobalTransform;
|
||||||
_haveLastOrigin = true;
|
_haveLastOrigin = true;
|
||||||
@@ -153,6 +157,24 @@ public partial class PlayerRig : Node
|
|||||||
_interpolateOrigin = true;
|
_interpolateOrigin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The tracking poses read in this tick were delivered with the last frame, predicted for its render
|
||||||
|
// time. In physics ticks: render time of that frame ≈ (physics frames + fraction) at its _process,
|
||||||
|
// plus one frame delta for the frame these ticks belong to (bible v2 recipe).
|
||||||
|
private double TrackingAge()
|
||||||
|
{
|
||||||
|
float rate = Engine.PhysicsTicksPerSecond;
|
||||||
|
ulong frame = Engine.GetProcessFrames();
|
||||||
|
if (frame != _sampleFrame)
|
||||||
|
{
|
||||||
|
_sampleFrame = frame;
|
||||||
|
_sampleTicks = _renderTicks + _renderDelta * rate;
|
||||||
|
}
|
||||||
|
return (Engine.GetPhysicsFrames() - _sampleTicks) / rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double _renderTicks, _renderDelta, _sampleTicks;
|
||||||
|
private ulong _sampleFrame = ulong.MaxValue;
|
||||||
|
|
||||||
// The origin on screen is interpolated; physics must run on the real one. Anyone else who moved
|
// The origin on screen is interpolated; physics must run on the real one. Anyone else who moved
|
||||||
// the origin since (teleport marker, menu) is respected as the new real one.
|
// the origin since (teleport marker, menu) is respected as the new real one.
|
||||||
private void RestorePhysicsOrigin()
|
private void RestorePhysicsOrigin()
|
||||||
@@ -168,6 +190,8 @@ public partial class PlayerRig : Node
|
|||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
|
_renderTicks = Engine.GetPhysicsFrames() + Engine.GetPhysicsInterpolationFraction();
|
||||||
|
_renderDelta = delta;
|
||||||
if (_interpolateOrigin && !Spectator)
|
if (_interpolateOrigin && !Spectator)
|
||||||
{
|
{
|
||||||
Transform3D current = _origin.GlobalTransform;
|
Transform3D current = _origin.GlobalTransform;
|
||||||
|
|||||||
@@ -21,19 +21,25 @@ public sealed class PoseFilter
|
|||||||
|
|
||||||
public void Reset() => _has = false;
|
public void Reset() => _has = false;
|
||||||
|
|
||||||
public Transform3D Sample(Transform3D raw, double now)
|
// sampleTime: when the pose was really measured (the render time of the frame that delivered it),
|
||||||
|
// in the same clock as `now`. Without it a sample is timestamped by the first tick that saw it,
|
||||||
|
// which at 144 Hz under 90 Hz frames alternates 1 and 2 ticks late: the extrapolated motion
|
||||||
|
// then beats at 18 Hz (±30% speed per frame — bible v2, measured). With it the age is exact
|
||||||
|
// and motion uniform, at a constant ~2-tick lag. May be negative (a tick before the sample).
|
||||||
|
public Transform3D Sample(Transform3D raw, double now, double? sampleTime = null)
|
||||||
{
|
{
|
||||||
|
double stamp = sampleTime ?? now;
|
||||||
if (!_has)
|
if (!_has)
|
||||||
{
|
{
|
||||||
_has = true;
|
_has = true;
|
||||||
_last = raw;
|
_last = raw;
|
||||||
_tLast = now;
|
_tLast = stamp;
|
||||||
Velocity = AngularVelocity = Vector3.Zero;
|
Velocity = AngularVelocity = Vector3.Zero;
|
||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
if (raw != _last)
|
if (raw != _last)
|
||||||
{
|
{
|
||||||
float interval = (float)(now - _tLast);
|
float interval = (float)(stamp - _tLast);
|
||||||
if (interval > 1e-4f)
|
if (interval > 1e-4f)
|
||||||
{
|
{
|
||||||
if (raw.Origin.DistanceTo(_last.Origin) > JumpDistance)
|
if (raw.Origin.DistanceTo(_last.Origin) > JumpDistance)
|
||||||
@@ -49,9 +55,9 @@ public sealed class PoseFilter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_last = raw;
|
_last = raw;
|
||||||
_tLast = now;
|
_tLast = stamp;
|
||||||
}
|
}
|
||||||
float age = Mathf.Min((float)(now - _tLast), MaxExtrapolation);
|
float age = Mathf.Clamp((float)(now - _tLast), -MaxExtrapolation, MaxExtrapolation);
|
||||||
Basis spin = AngularVelocity.LengthSquared() > 1e-10f
|
Basis spin = AngularVelocity.LengthSquared() > 1e-10f
|
||||||
? new Basis(AngularVelocity.Normalized(), AngularVelocity.Length() * age) : Basis.Identity;
|
? new Basis(AngularVelocity.Normalized(), AngularVelocity.Length() * age) : Basis.Identity;
|
||||||
return new Transform3D(spin * _last.Basis.Orthonormalized(), _last.Origin + Velocity * age);
|
return new Transform3D(spin * _last.Basis.Orthonormalized(), _last.Origin + Velocity * age);
|
||||||
@@ -78,11 +84,14 @@ public sealed class RagdollDriver
|
|||||||
// origin = play space (modified by the correction); raw* = origin-local tracked poses as last
|
// origin = play space (modified by the correction); raw* = origin-local tracked poses as last
|
||||||
// reported (repeat between tracking updates); moveVelocity = intended origin velocity (stick),
|
// reported (repeat between tracking updates); moveVelocity = intended origin velocity (stick),
|
||||||
// the only origin motion that is real hand motion for the guides' feed-forward.
|
// the only origin motion that is real hand motion for the guides' feed-forward.
|
||||||
|
// trackingAge: how long ago (s) the current tracking poses were measured, if known (PlayerRig
|
||||||
|
// derives it from the render clock); null = timestamp by arrival (the spike's simulated input).
|
||||||
public void Tick(BodyProfile profile, ref Transform3D origin, Transform3D rawHead, Transform3D rawLeft, Transform3D rawRight,
|
public void Tick(BodyProfile profile, ref Transform3D origin, Transform3D rawHead, Transform3D rawLeft, Transform3D rawRight,
|
||||||
Vector3 moveVelocity, float dt)
|
Vector3 moveVelocity, float dt, double? trackingAge = null)
|
||||||
{
|
{
|
||||||
_now += dt;
|
_now += dt;
|
||||||
Transform3D head = Head.Sample(rawHead, _now), left = Left.Sample(rawLeft, _now), right = Right.Sample(rawRight, _now);
|
double? stamp = trackingAge.HasValue ? _now - trackingAge.Value : null;
|
||||||
|
Transform3D head = Head.Sample(rawHead, _now, stamp), left = Left.Sample(rawLeft, _now, stamp), right = Right.Sample(rawRight, _now, stamp);
|
||||||
if (Ragdoll.Built && !RebuildRequested)
|
if (Ragdoll.Built && !RebuildRequested)
|
||||||
origin.Origin += Ragdoll.OriginCorrection((origin * head).Origin, origin.Origin.Y + StickCrouch, dt);
|
origin.Origin += Ragdoll.OriginCorrection((origin * head).Origin, origin.Origin.Y + StickCrouch, dt);
|
||||||
float floorY = origin.Origin.Y + StickCrouch;
|
float floorY = origin.Origin.Y + StickCrouch;
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ public partial class RagdollSpike : Node3D
|
|||||||
AddChild(_ragdoll);
|
AddChild(_ragdoll);
|
||||||
|
|
||||||
_phases.Add(("hinge sign", SetupHinge, TickHinge, 0.3f, FinishHinge));
|
_phases.Add(("hinge sign", SetupHinge, TickHinge, 0.3f, FinishHinge));
|
||||||
|
_phases.Add(("pose filter: render-timed tracking moves evenly (no 18 Hz beat)", Rest, _ => { }, 0.05f, FinishPoseFilter));
|
||||||
_phases.Add(("stands still, head on the camera, hands on the controllers", Rest, _ => { }, 4f, FinishStand));
|
_phases.Add(("stands still, head on the camera, hands on the controllers", Rest, _ => { }, 4f, FinishStand));
|
||||||
_phases.Add(("reaches forward, out and overhead", Rest, TickReach, 4.5f, FinishReach));
|
_phases.Add(("reaches forward, out and overhead", Rest, TickReach, 4.5f, FinishReach));
|
||||||
_phases.Add(("fast arm swings stay attached", Rest, TickSwing, 3f, FinishSwing));
|
_phases.Add(("fast arm swings stay attached", Rest, TickSwing, 3f, FinishSwing));
|
||||||
@@ -233,6 +234,38 @@ public partial class RagdollSpike : Node3D
|
|||||||
|
|
||||||
private int NewSnaps => _ragdoll.Snaps - _snapsAtStart;
|
private int NewSnaps => _ragdoll.Snaps - _snapsAtStart;
|
||||||
|
|
||||||
|
// A controller moving at 1 m/s, sampled once per 90 Hz frame (predicted for that frame's render
|
||||||
|
// time), read by 144 Hz ticks. Per-tick output steps should all be 1/144 m: timestamped by
|
||||||
|
// arrival they alternate (1 or 2 ticks late), timestamped by render time they don't.
|
||||||
|
private static bool FinishPoseFilter()
|
||||||
|
{
|
||||||
|
float Spread(bool stamped)
|
||||||
|
{
|
||||||
|
PoseFilter f = new();
|
||||||
|
float min = float.MaxValue, max = 0f;
|
||||||
|
Vector3 prev = Vector3.Zero;
|
||||||
|
for (int tick = 0; tick < 300; tick++)
|
||||||
|
{
|
||||||
|
double now = tick / 144.0;
|
||||||
|
long frame = (long)Math.Floor(now * 90.0); // the last frame delivered before this tick
|
||||||
|
double render = (frame + 1) / 90.0; // its predicted display time
|
||||||
|
Transform3D raw = new(Basis.Identity, new Vector3((float)render, 0f, 0f));
|
||||||
|
Vector3 p = f.Sample(raw, now, stamped ? render : null).Origin;
|
||||||
|
if (tick > 20)
|
||||||
|
{
|
||||||
|
float step = p.X - prev.X;
|
||||||
|
min = Mathf.Min(min, step);
|
||||||
|
max = Mathf.Max(max, step);
|
||||||
|
}
|
||||||
|
prev = p;
|
||||||
|
}
|
||||||
|
return (max - min) * 144f; // spread of the per-tick speed, m/s
|
||||||
|
}
|
||||||
|
float arrival = Spread(false), stamped = Spread(true);
|
||||||
|
GD.Print($"RAGDOLL: pose filter at 1 m/s: per-tick speed spread {arrival:F3} m/s by arrival, {stamped:F3} m/s render-timed");
|
||||||
|
return stamped < 0.05f && stamped < arrival;
|
||||||
|
}
|
||||||
|
|
||||||
private static StaticBody3D MakeStatic(Vector3 size, Vector3 pos, uint mask = 0)
|
private static StaticBody3D MakeStatic(Vector3 size, Vector3 pos, uint mask = 0)
|
||||||
{
|
{
|
||||||
StaticBody3D body = new() { Position = pos, CollisionMask = mask };
|
StaticBody3D body = new() { Position = pos, CollisionMask = mask };
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://c4rg1kcdtsxni
|
||||||
@@ -79,6 +79,7 @@ public partial class WorldPanel : Node3D
|
|||||||
_menu.ClickVolumeSlider.ValueChanged += v => _click.VolumeDb = Mathf.LinearToDb((float)v / 70f);
|
_menu.ClickVolumeSlider.ValueChanged += v => _click.VolumeDb = Mathf.LinearToDb((float)v / 70f);
|
||||||
_menu.StrengthChanged += v => PlayerRagdoll.Strength = v;
|
_menu.StrengthChanged += v => PlayerRagdoll.Strength = v;
|
||||||
_menu.SmoothTurnToggled += on => PlayerRig.SmoothTurn = on;
|
_menu.SmoothTurnToggled += on => PlayerRig.SmoothTurn = on;
|
||||||
|
_menu.LowLagTrackingToggled += on => PlayerRig.SteadyTracking = !on;
|
||||||
_menu.SpectatorToggled += PlayerRig.SetSpectator;
|
_menu.SpectatorToggled += PlayerRig.SetSpectator;
|
||||||
|
|
||||||
SetPanelActive(false);
|
SetPanelActive(false);
|
||||||
|
|||||||
Reference in new issue
Block a user