feat(camera): InputAction + DebugVM surface for retail chase camera
Four new InputAction entries for held-key offset integration (CameraZoomIn/Out, CameraRaise/Lower; default unbound). Six new DebugVM mirror properties forwarding to CameraDiagnostics so the upcoming "Chase camera" DebugPanel section can drive them live. Also folds in four small cleanups from the Task 4 code review: - Both CameraDiagnostics-mutating tests in CameraControllerTests now use try/finally save/restore (consistency with Task-3 follow-up B) - Drop unused `using System.Numerics` from CameraControllerTests - Reword the XML doc on CameraController.Active to explain WHY both cameras are held simultaneously (flag flip takes effect on the next Active access without re-entry) rather than restating the getter logic Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e5a5916679
commit
91086adbac
4 changed files with 115 additions and 33 deletions
|
|
@ -11,11 +11,11 @@ public sealed class CameraController
|
|||
public RetailChaseCamera? RetailChase { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The renderer-facing active camera. In chase mode, returns
|
||||
/// <see cref="RetailChase"/> when
|
||||
/// <see cref="CameraDiagnostics.UseRetailChaseCamera"/> is true,
|
||||
/// otherwise <see cref="Chase"/>. In fly mode returns
|
||||
/// <see cref="Fly"/>; default is <see cref="Orbit"/>.
|
||||
/// The renderer-facing active camera. Both the legacy and retail
|
||||
/// chase cameras are held simultaneously so that flipping
|
||||
/// <see cref="CameraDiagnostics.UseRetailChaseCamera"/> takes effect
|
||||
/// on the very next access to this property — no re-entry required,
|
||||
/// no notification mechanism, no stale state.
|
||||
/// </summary>
|
||||
public ICamera Active
|
||||
{
|
||||
|
|
@ -53,9 +53,8 @@ public sealed class CameraController
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enter chase mode with both candidate cameras. Both are held;
|
||||
/// <see cref="Active"/> picks based on
|
||||
/// <see cref="CameraDiagnostics.UseRetailChaseCamera"/>.
|
||||
/// Store both cameras simultaneously; <see cref="Active"/> picks
|
||||
/// between them per-read via the flag — no re-entry needed on flip.
|
||||
/// </summary>
|
||||
public void EnterChaseMode(ChaseCamera legacy, RetailChaseCamera retail)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -262,4 +262,14 @@ public enum InputAction
|
|||
/// <summary>Fly-camera descend (Ctrl) — only meaningful while fly camera
|
||||
/// is active. K.1b binds it to ControlLeft; K.1c may rebind.</summary>
|
||||
AcdreamFlyDown,
|
||||
|
||||
// ── AcdreamCameraCommands ─────────────────────────────
|
||||
/// <summary>Camera zoom in (held key, integrates Distance−= adjSpeed·dt). Default unbound.</summary>
|
||||
CameraZoomIn,
|
||||
/// <summary>Camera zoom out (held key, integrates Distance+= adjSpeed·dt). Default unbound.</summary>
|
||||
CameraZoomOut,
|
||||
/// <summary>Camera raise (held key, integrates Pitch+= adjSpeed·dt·0.02). Default unbound.</summary>
|
||||
CameraRaise,
|
||||
/// <summary>Camera lower (held key, integrates Pitch−= adjSpeed·dt·0.02). Default unbound.</summary>
|
||||
CameraLower,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Numerics;
|
||||
using AcDream.Core.Combat;
|
||||
using AcDream.Core.Physics;
|
||||
using AcDream.Core.Rendering;
|
||||
|
||||
namespace AcDream.UI.Abstractions.Panels.Debug;
|
||||
|
||||
|
|
@ -290,6 +291,50 @@ public sealed class DebugVM
|
|||
set => PhysicsDiagnostics.ProbeAutoWalkEnabled = value;
|
||||
}
|
||||
|
||||
// ── Chase camera tunables (forward to CameraDiagnostics) ──────────
|
||||
|
||||
/// <summary>Runtime mirror of <see cref="CameraDiagnostics.UseRetailChaseCamera"/>.</summary>
|
||||
public bool UseRetailChaseCamera
|
||||
{
|
||||
get => CameraDiagnostics.UseRetailChaseCamera;
|
||||
set => CameraDiagnostics.UseRetailChaseCamera = value;
|
||||
}
|
||||
|
||||
/// <summary>Runtime mirror of <see cref="CameraDiagnostics.AlignToSlope"/>.</summary>
|
||||
public bool CameraAlignToSlope
|
||||
{
|
||||
get => CameraDiagnostics.AlignToSlope;
|
||||
set => CameraDiagnostics.AlignToSlope = value;
|
||||
}
|
||||
|
||||
/// <summary>Runtime mirror of <see cref="CameraDiagnostics.TranslationStiffness"/>.</summary>
|
||||
public float CameraTranslationStiffness
|
||||
{
|
||||
get => CameraDiagnostics.TranslationStiffness;
|
||||
set => CameraDiagnostics.TranslationStiffness = value;
|
||||
}
|
||||
|
||||
/// <summary>Runtime mirror of <see cref="CameraDiagnostics.RotationStiffness"/>.</summary>
|
||||
public float CameraRotationStiffness
|
||||
{
|
||||
get => CameraDiagnostics.RotationStiffness;
|
||||
set => CameraDiagnostics.RotationStiffness = value;
|
||||
}
|
||||
|
||||
/// <summary>Runtime mirror of <see cref="CameraDiagnostics.MouseLowPassWindowSec"/>.</summary>
|
||||
public float CameraMouseLowPassWindowSec
|
||||
{
|
||||
get => CameraDiagnostics.MouseLowPassWindowSec;
|
||||
set => CameraDiagnostics.MouseLowPassWindowSec = value;
|
||||
}
|
||||
|
||||
/// <summary>Runtime mirror of <see cref="CameraDiagnostics.CameraAdjustmentSpeed"/>.</summary>
|
||||
public float CameraAdjustmentSpeed
|
||||
{
|
||||
get => CameraDiagnostics.CameraAdjustmentSpeed;
|
||||
set => CameraDiagnostics.CameraAdjustmentSpeed = value;
|
||||
}
|
||||
|
||||
// ── Action hooks invoked by panel buttons ──────────────────────────
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System.Numerics;
|
||||
using AcDream.App.Rendering;
|
||||
using AcDream.Core.Rendering;
|
||||
using Xunit;
|
||||
|
|
@ -21,47 +20,76 @@ public class CameraControllerTests
|
|||
[Fact]
|
||||
public void ChaseMode_WhenFlagOff_ActiveIsLegacy()
|
||||
{
|
||||
CameraDiagnostics.UseRetailChaseCamera = false;
|
||||
var (ctl, legacy, _) = MakeChaseFixture();
|
||||
Assert.Same(legacy, ctl.Active);
|
||||
Assert.True(ctl.IsChaseMode);
|
||||
bool saved = CameraDiagnostics.UseRetailChaseCamera;
|
||||
try
|
||||
{
|
||||
CameraDiagnostics.UseRetailChaseCamera = false;
|
||||
var (ctl, legacy, _) = MakeChaseFixture();
|
||||
Assert.Same(legacy, ctl.Active);
|
||||
Assert.True(ctl.IsChaseMode);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CameraDiagnostics.UseRetailChaseCamera = saved;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ChaseMode_WhenFlagOn_ActiveIsRetail()
|
||||
{
|
||||
CameraDiagnostics.UseRetailChaseCamera = true;
|
||||
var (ctl, _, retail) = MakeChaseFixture();
|
||||
Assert.Same(retail, ctl.Active);
|
||||
Assert.True(ctl.IsChaseMode);
|
||||
|
||||
// Reset.
|
||||
CameraDiagnostics.UseRetailChaseCamera = false;
|
||||
bool saved = CameraDiagnostics.UseRetailChaseCamera;
|
||||
try
|
||||
{
|
||||
CameraDiagnostics.UseRetailChaseCamera = true;
|
||||
var (ctl, _, retail) = MakeChaseFixture();
|
||||
Assert.Same(retail, ctl.Active);
|
||||
Assert.True(ctl.IsChaseMode);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CameraDiagnostics.UseRetailChaseCamera = saved;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ChaseMode_FlagFlipped_ActiveSwaps()
|
||||
{
|
||||
CameraDiagnostics.UseRetailChaseCamera = false;
|
||||
var (ctl, legacy, retail) = MakeChaseFixture();
|
||||
Assert.Same(legacy, ctl.Active);
|
||||
bool saved = CameraDiagnostics.UseRetailChaseCamera;
|
||||
try
|
||||
{
|
||||
CameraDiagnostics.UseRetailChaseCamera = false;
|
||||
var (ctl, legacy, retail) = MakeChaseFixture();
|
||||
Assert.Same(legacy, ctl.Active);
|
||||
|
||||
CameraDiagnostics.UseRetailChaseCamera = true;
|
||||
Assert.Same(retail, ctl.Active);
|
||||
CameraDiagnostics.UseRetailChaseCamera = true;
|
||||
Assert.Same(retail, ctl.Active);
|
||||
|
||||
CameraDiagnostics.UseRetailChaseCamera = false;
|
||||
Assert.Same(legacy, ctl.Active);
|
||||
CameraDiagnostics.UseRetailChaseCamera = false;
|
||||
Assert.Same(legacy, ctl.Active);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CameraDiagnostics.UseRetailChaseCamera = saved;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExitChaseMode_ClearsBothCameras()
|
||||
{
|
||||
CameraDiagnostics.UseRetailChaseCamera = false;
|
||||
var (ctl, _, _) = MakeChaseFixture();
|
||||
ctl.ExitChaseMode();
|
||||
bool saved = CameraDiagnostics.UseRetailChaseCamera;
|
||||
try
|
||||
{
|
||||
CameraDiagnostics.UseRetailChaseCamera = false;
|
||||
var (ctl, _, _) = MakeChaseFixture();
|
||||
ctl.ExitChaseMode();
|
||||
|
||||
Assert.Null(ctl.Chase);
|
||||
Assert.Null(ctl.RetailChase);
|
||||
Assert.False(ctl.IsChaseMode);
|
||||
Assert.Null(ctl.Chase);
|
||||
Assert.Null(ctl.RetailChase);
|
||||
Assert.False(ctl.IsChaseMode);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CameraDiagnostics.UseRetailChaseCamera = saved;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue