using Godot; using MaxEffort.Code.Core; namespace MaxEffort.Code.Systems; [GlobalClass] public partial class CameraShakeSystem : Node { [Export] private Camera2D _camera; [Export] private float _decayRate = 0.8f; // How fast shaking stops [Export] private float _maxOffset = 20.0f; // Max pixels to shake [Export] private float _maxRoll = 0.1f; // Max rotation (radians) private float _trauma = 0f; // Current shake intensity (0 to 1) private float _currentFocus = 0f; private RandomNumberGenerator _rng = new(); public override void _Ready() { EventBus.OnCameraTrauma += AddTrauma; EventBus.OnFocusChanged += OnFocusChanged; } public override void _ExitTree() { EventBus.OnCameraTrauma -= AddTrauma; EventBus.OnFocusChanged -= OnFocusChanged; } public override void _Process(double delta) { if (_camera == null) return; if (_currentFocus > 0.75f) { AddTrauma(1.5f * (float)delta); } if (_trauma > 0) { _trauma -= _decayRate * (float)delta; _trauma = Mathf.Max(0, _trauma); var shake = _trauma * _trauma; var offsetX = _maxOffset * shake * _rng.RandfRange(-1, 1); var offsetY = _maxOffset * shake * _rng.RandfRange(-1, 1); var rotation = _maxRoll * shake * _rng.RandfRange(-1, 1); _camera.Offset = new Vector2(offsetX, offsetY); _camera.Rotation = rotation; } else { if (_camera.Offset != Vector2.Zero) { _camera.Offset = _camera.Offset.Lerp(Vector2.Zero, (float)delta * 5f); _camera.Rotation = Mathf.Lerp(_camera.Rotation, 0, (float)delta * 5f); } } } private void OnFocusChanged(float focus) { _currentFocus = focus; } private void AddTrauma(float amount) { _trauma = Mathf.Clamp(_trauma + amount, 0f, 1f); } }