using System; using Godot; namespace AceFieldNewHorizon.Scripts.Entities; public partial class Player : CharacterBody2D { [Export] public float MaxSpeed = 400.0f; [Export] public float SprintMultiplier = 1.8f; // 80% faster when sprinting [Export] public float Acceleration = 1500.0f; [Export] public float SprintAcceleration = 1800.0f; // Slightly faster acceleration when sprinting [Export] public float Deceleration = 1200.0f; [Export] public float RotationSpeed = 3.0f; [Export] public float MinZoom = 0.5f; [Export] public float MaxZoom = 2.0f; [Export] public float BaseZoomSpeed = 0.1f; [Export] public float MaxZoomSpeed = 0.5f; [Export] public float ZoomAcceleration = 0.05f; [Export] public float ZoomDecay = 0.9f; [Export] public float ZoomSmoothing = 10.0f; private Camera2D _camera; private Vector2 _cameraTargetZoom = Vector2.One; private float _currentZoomSpeed; private int _lastZoomDirection; private double _lastZoomTime; public override void _Ready() { _camera = GetNode("Camera2D"); _cameraTargetZoom = _camera.Zoom; } public override void _Input(InputEvent @event) { // Handle mouse wheel zoom if (@event is InputEventMouseButton mouseEvent) { switch (mouseEvent.ButtonIndex) { case MouseButton.WheelDown when mouseEvent.Pressed: HandleZoomInput(1); break; case MouseButton.WheelUp when mouseEvent.Pressed: HandleZoomInput(-1); break; } } } private void HandleZoomInput(int direction) { var currentTime = Time.GetTicksMsec(); // If same direction as last time, accelerate if (direction == _lastZoomDirection && (currentTime - _lastZoomTime) < 300) { _currentZoomSpeed = Mathf.Min(_currentZoomSpeed + ZoomAcceleration, MaxZoomSpeed); } else { _currentZoomSpeed = BaseZoomSpeed; } _lastZoomDirection = direction; _lastZoomTime = currentTime; // Apply zoom with current speed var zoomFactor = 1.0f + (_currentZoomSpeed * -direction); _cameraTargetZoom = _camera.Zoom * zoomFactor; // Clamp target zoom _cameraTargetZoom.X = Mathf.Clamp(_cameraTargetZoom.X, MinZoom, MaxZoom); _cameraTargetZoom.Y = Mathf.Clamp(_cameraTargetZoom.Y, MinZoom, MaxZoom); } public override void _Process(double delta) { // Get direction to mouse and calculate angle var mousePos = GetGlobalMousePosition(); var direction = GlobalPosition.DirectionTo(mousePos); Rotation = direction.Angle(); // Smoothly interpolate to target zoom var deltaF = (float)delta; _camera.Zoom = _camera.Zoom.Lerp(_cameraTargetZoom, ZoomSmoothing * deltaF); // Decay zoom speed when not zooming if ((Time.GetTicksMsec() - _lastZoomTime) > 300) { _currentZoomSpeed = Mathf.Max(_currentZoomSpeed * ZoomDecay, BaseZoomSpeed); } } public override void _PhysicsProcess(double delta) { // Get movement input var moveForward = Input.GetActionStrength("move_up") - Input.GetActionStrength("move_down"); var moveHorizontal = Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left"); var isSprinting = Input.IsActionPressed("move_sprint"); // Calculate movement parameters based on sprint state var currentMaxSpeed = isSprinting ? MaxSpeed * SprintMultiplier : MaxSpeed; var currentAcceleration = isSprinting ? SprintAcceleration : Acceleration; // Calculate desired movement direction var forwardVector = Vector2.Right.Rotated(Rotation); var rightVector = new Vector2(-forwardVector.Y, forwardVector.X); // Calculate target velocity based on input var targetVelocity = (forwardVector * moveForward + rightVector * moveHorizontal).Normalized() * currentMaxSpeed; // Apply acceleration or deceleration var currentSpeed = Velocity.Length(); var isAccelerating = targetVelocity != Vector2.Zero; if (isAccelerating) { // Accelerate towards target velocity Velocity = Velocity.MoveToward(targetVelocity, (float)(currentAcceleration * delta)); } else { // Apply deceleration when no input if (currentSpeed > 0) { var decelAmount = (float)(Deceleration * delta); if (currentSpeed <= decelAmount) Velocity = Vector2.Zero; else Velocity = Velocity.Normalized() * (currentSpeed - decelAmount); } } // Apply the movement MoveAndSlide(); } }