169 lines
5.3 KiB
C#
169 lines
5.3 KiB
C#
using Godot;
|
|
|
|
public partial class PlayerCamera : Camera3D
|
|
{
|
|
[ExportCategory("Camera Movement")]
|
|
[Export] public float CameraPanSpeed { get; set; } = 20f;
|
|
[Export] public float CameraZoomSpeed { get; set; } = 20f;
|
|
[Export] public float CameraZoomMin { get; set; } = 10f;
|
|
[Export] public float CameraZoomMax { get; set; } = 50f;
|
|
|
|
[ExportCategory("Edge Scrolling")]
|
|
[Export] public float EdgeScrollMargin { get; set; } = 20f;
|
|
[Export] public float EdgeScrollSpeed { get; set; } = 15f;
|
|
|
|
[ExportCategory("Rotation")]
|
|
[Export] public float YawSensitivity { get; set; } = 0.5f;
|
|
[Export] public float PitchSensitivity { get; set; } = 0.18f;
|
|
[Export] public float StepDegreeMax { get; set; } = 3f;
|
|
[Export] public float PitchDegreeMin { get; set; } = 10f;
|
|
[Export] public float PitchDegreeMax { get; set; } = 80f;
|
|
[Export] public bool CaptureMiddleButton { get; set; } = false;
|
|
|
|
Vector3 origin = Vector3.Zero;
|
|
float orbitDistance = 25f;
|
|
float currentHeight = 20f;
|
|
float orbitRadius = 20f;
|
|
bool isMiddleMouseRotating = false;
|
|
float yaw = 0f;
|
|
float pitch = 0f;
|
|
|
|
public override void _Ready()
|
|
{
|
|
var pitchMin = Mathf.DegToRad(PitchDegreeMin);
|
|
var pitchMax = Mathf.DegToRad(PitchDegreeMax);
|
|
|
|
pitch = Mathf.Clamp(pitch, pitchMin, pitchMax);
|
|
|
|
UpdateCameraPosition();
|
|
}
|
|
|
|
public override void _Process(double delta)
|
|
{
|
|
var movement = Vector3.Zero;
|
|
|
|
// Keyboard Input
|
|
if (Input.IsActionPressed("camera_pan_right"))
|
|
{
|
|
movement.X += 1f;
|
|
}
|
|
if (Input.IsActionPressed("camera_pan_left"))
|
|
{
|
|
movement.X -= 1f;
|
|
}
|
|
if (Input.IsActionPressed("camera_pan_up"))
|
|
{
|
|
movement.Z += 1f;
|
|
}
|
|
if (Input.IsActionPressed("camera_pan_down"))
|
|
{
|
|
movement.Z -= 1f;
|
|
}
|
|
|
|
// Edge Scrolling
|
|
var mousePosition = GetViewport().GetMousePosition();
|
|
var viewportSize = GetViewport().GetVisibleRect().Size;
|
|
|
|
if (mousePosition.X < EdgeScrollMargin)
|
|
{
|
|
movement.X -= 1f;
|
|
}
|
|
if (mousePosition.X > viewportSize.X - EdgeScrollMargin)
|
|
{
|
|
movement.X += 1f;
|
|
}
|
|
if (mousePosition.Y < EdgeScrollMargin)
|
|
{
|
|
movement.Z -= 1f;
|
|
}
|
|
if (mousePosition.Y > viewportSize.Y - EdgeScrollMargin)
|
|
{
|
|
movement.Z += 1f;
|
|
}
|
|
|
|
// Rotating
|
|
if (movement.Length() > 0f)
|
|
{
|
|
movement = movement.Normalized().Rotated(Vector3.Up, yaw);
|
|
origin += movement * CameraPanSpeed * (float)delta;
|
|
|
|
UpdateCameraPosition();
|
|
}
|
|
}
|
|
|
|
public override void _UnhandledInput(InputEvent @event)
|
|
{
|
|
if (@event is InputEventMouseButton mouseButtonEvent)
|
|
{
|
|
if (mouseButtonEvent.Pressed)
|
|
{
|
|
var delta = (float)GetProcessDeltaTime();
|
|
|
|
if (mouseButtonEvent.ButtonIndex is MouseButton.WheelUp)
|
|
{
|
|
orbitDistance = Mathf.Max(CameraZoomMin, orbitDistance - CameraZoomSpeed * delta);
|
|
}
|
|
else if (mouseButtonEvent.ButtonIndex is MouseButton.WheelDown)
|
|
{
|
|
orbitDistance = Mathf.Min(CameraZoomMax, orbitDistance + CameraZoomSpeed * delta);
|
|
}
|
|
|
|
UpdateCameraPosition();
|
|
}
|
|
|
|
if (mouseButtonEvent.ButtonIndex is MouseButton.Middle)
|
|
{
|
|
isMiddleMouseRotating = mouseButtonEvent.Pressed;
|
|
|
|
if (CaptureMiddleButton)
|
|
{
|
|
Input.MouseMode = mouseButtonEvent.Pressed
|
|
? Input.MouseModeEnum.Captured
|
|
: Input.MouseModeEnum.Visible;
|
|
}
|
|
}
|
|
}
|
|
else if (@event is InputEventMouseMotion mouseMotionEvent && isMiddleMouseRotating)
|
|
{
|
|
var viewportSize = GetViewport().GetVisibleRect().Size;
|
|
var viewMin = (float)Mathf.Min(viewportSize.X, viewportSize.Y);
|
|
var delta = (float)GetProcessDeltaTime() * 60f;
|
|
|
|
// px => normalized fraction of screen -> radians, scaled by dt
|
|
var dx = (mouseMotionEvent.Relative.X / viewMin) * YawSensitivity * Mathf.Tau * delta;
|
|
var dy = (mouseMotionEvent.Relative.Y / viewMin) * PitchSensitivity * Mathf.Tau * delta;
|
|
|
|
// Safety cap per event
|
|
var maxStep = Mathf.DegToRad(StepDegreeMax);
|
|
|
|
dx = Mathf.Clamp(dx, -maxStep, maxStep);
|
|
dy = Mathf.Clamp(dy, -maxStep, maxStep);
|
|
|
|
yaw -= dx;
|
|
pitch += dy;
|
|
|
|
var pitchMin = Mathf.DegToRad(PitchDegreeMin);
|
|
var pitchMax = Mathf.DegToRad(PitchDegreeMax);
|
|
|
|
pitch = Mathf.Clamp(pitch, pitchMax, pitchMax);
|
|
|
|
UpdateCameraPosition();
|
|
}
|
|
}
|
|
|
|
void UpdateCameraPosition()
|
|
{
|
|
var direction = new Vector3(
|
|
x: Mathf.Sin(yaw) * Mathf.Cos(pitch),
|
|
y: Mathf.Sin(pitch),
|
|
z: Mathf.Cos(yaw) * Mathf.Cos(pitch)
|
|
).Normalized();
|
|
|
|
Position = origin + direction * orbitDistance;
|
|
LookAt(origin, Vector3.Up);
|
|
|
|
currentHeight = orbitDistance * Mathf.Sin(pitch);
|
|
orbitRadius = orbitDistance * Mathf.Cos(pitch);
|
|
}
|
|
}
|