using Godot; using System; public partial class WorldCamera : Camera3D { [Export] Node3D target; [Export] private Mode mode = Mode.Follow; private Vector3 posDest; //current destination of camera private Vector3 offset = new Vector3(0, 5, -10); //offset from target private Vector3 vel; //current velocity of camera private float accelCoeff = 10f; //acceleration coefficient private float ct = 0.5f; //time to reach destination [Export] private float rotateSpeed = 2f; //radians per second [Export] private float mouseSensitivity = 0.005f; private bool midDrag = false; private enum Mode { Follow, Fixed, Rotate //rotates around target } public override void _Ready() { Global.camera = this; CallDeferred(nameof(InitTarget)); } private void InitTarget() { if (target == null){ target = Global.player; } } public override void _Input(InputEvent @event) { if (@event is InputEventMouseButton mb && mb.ButtonIndex == MouseButton.Middle) { midDrag = mb.Pressed; } else if (@event is InputEventMouseMotion motion && midDrag) { // Horizontal orbit offset = offset.Rotated(Vector3.Up, -motion.Relative.X * mouseSensitivity); // Vertical orbit around the axis perpendicular to offset in the XZ plane Vector3 right = Vector3.Up.Cross(offset).Normalized(); if (right.LengthSquared() > 0.001f) { Vector3 newOffset = offset.Rotated(right, -motion.Relative.Y * mouseSensitivity); // Clamp to prevent flipping over top or going below horizontal float angle = newOffset.AngleTo(Vector3.Up); if (angle > 0.15f && angle < Mathf.Pi * 0.85f) offset = newOffset; } } } public override void _Process(double delta) { float rotInput = Input.GetAxis("cam_rotate_cw", "cam_rotate_ccw"); switch (mode){ case Mode.Follow: case Mode.Rotate: if (rotInput != 0) offset = offset.Rotated(Vector3.Up, rotateSpeed * rotInput * (float)delta); break; case Mode.Fixed: break; } } public override void _PhysicsProcess(double delta) { if (mode == Mode.Follow){ posDest = target.GlobalPosition + offset; if (posDest != Position){ Vector3 dir = (posDest - Position).Normalized(); float d = (posDest - Position).Length(); //displacement //vel = dir * accelCoeff * (float)delta + (posDest - Position) * .1f; vel = (posDest-Position)/ct; // we want to reach the destination in ct seconds Position += vel * (float)delta + .5f * accelCoeff * dir * (float)(delta*delta); } LookAt(target.GlobalPosition); } } }