From 7cf6ea267a75b7d271e4cb70b7b5794fc93a09b3 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 10 Apr 2026 20:25:19 +0200 Subject: [PATCH] feat(app): add FlyCamera with WASD + mouse look Co-Authored-By: Claude Sonnet 4.6 --- src/AcDream.App/Rendering/FlyCamera.cs | 71 ++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/AcDream.App/Rendering/FlyCamera.cs diff --git a/src/AcDream.App/Rendering/FlyCamera.cs b/src/AcDream.App/Rendering/FlyCamera.cs new file mode 100644 index 0000000..9dcd2a5 --- /dev/null +++ b/src/AcDream.App/Rendering/FlyCamera.cs @@ -0,0 +1,71 @@ +// 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; + + public float MoveSpeed { get; set; } = 100f; // world units per second + 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); + + /// + /// 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. + /// + public void Update(double dt, bool w, bool a, bool s, bool d, bool up, bool down) + { + float step = (float)(MoveSpeed * 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; + } + + /// + /// Apply accumulated mouse deltas (pixels since last frame). Positive deltaX + /// rotates the view to the right (decreases yaw), positive deltaY rotates + /// down (decreases pitch). + /// + 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)); + } +}