acdream/src/AcDream.App/Rendering/FlyCamera.cs
Erik 979802c49c feat(app): slow default fly speed and add Shift-boost
The user noted that the previous 35 u/s default felt too fast for
exploring scenery — overshooting buildings and skipping past entities
constantly. Drop default to 12 u/s (≈AC's run speed), and bind Shift
to a 50 u/s boost for fast travel between landblocks. Backwards
compatible: the new boost parameter on FlyCamera.Update has a default
of false, so any existing caller behaves the same.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:19:12 +02:00

79 lines
2.8 KiB
C#

// src/AcDream.App/Rendering/FlyCamera.cs
using System.Numerics;
namespace AcDream.App.Rendering;
public sealed class FlyCamera : ICamera
{
public Vector3 Position { get; set; } = new(96, 96, 150);
public float Yaw { get; set; } = MathF.PI / 2f; // facing +Y
public float Pitch { get; set; } = -0.3f; // looking slightly down
public float FovY { get; set; } = MathF.PI / 3f;
public float Aspect { get; set; } = 16f / 9f;
/// <summary>
/// Default move speed in world units per second. AC's character walks
/// at ~4 u/s and runs at ~7 u/s; 12 here is comfortable for navigating
/// scenery without overshooting and roughly tracks a fast jog. Hold
/// shift while moving to enter "boost" mode at <see cref="BoostSpeed"/>.
/// </summary>
public float MoveSpeed { get; set; } = 12f;
public float BoostSpeed { get; set; } = 50f;
public float MouseSensitivity { get; set; } = 0.003f;
private const float PitchLimit = 1.5533f; // ~89 degrees
public Matrix4x4 View
{
get
{
var forward = Forward();
return Matrix4x4.CreateLookAt(Position, Position + forward, Vector3.UnitZ);
}
}
public Matrix4x4 Projection
=> Matrix4x4.CreatePerspectiveFieldOfView(FovY, Aspect, 1f, 5000f);
/// <summary>
/// Integrate position for one frame based on WASD + vertical keys.
/// W/S move forward/back in the horizontal plane (ignoring pitch).
/// A/D strafe left/right. Up/down translate along world Z.
/// </summary>
public void Update(double dt, bool w, bool a, bool s, bool d, bool up, bool down, bool boost = false)
{
float speed = boost ? BoostSpeed : MoveSpeed;
float step = (float)(speed * dt);
// Forward in the horizontal plane (ignore pitch so W doesn't dive into ground).
var flatForward = new Vector3(MathF.Cos(Yaw), MathF.Sin(Yaw), 0f);
var right = new Vector3(MathF.Sin(Yaw), -MathF.Cos(Yaw), 0f);
if (w) Position += flatForward * step;
if (s) Position -= flatForward * step;
if (a) Position -= right * step;
if (d) Position += right * step;
if (up) Position += Vector3.UnitZ * step;
if (down) Position -= Vector3.UnitZ * step;
}
/// <summary>
/// Apply accumulated mouse deltas (pixels since last frame). Positive deltaX
/// rotates the view to the right (decreases yaw), positive deltaY rotates
/// down (decreases pitch).
/// </summary>
public void Look(float deltaX, float deltaY)
{
Yaw -= deltaX * MouseSensitivity;
Pitch = Math.Clamp(Pitch - deltaY * MouseSensitivity, -PitchLimit, PitchLimit);
}
private Vector3 Forward()
{
float cp = MathF.Cos(Pitch);
return new Vector3(
cp * MathF.Cos(Yaw),
cp * MathF.Sin(Yaw),
MathF.Sin(Pitch));
}
}