using System.Collections; using System.Collections.Generic; using System.ComponentModel; using Godot; using Godot.Bridge; using Godot.NativeInterop; [ScriptPath("res://Scripts/CameraController.cs")] public partial class CameraController : Node2D { public Node2D follow; public float scrollSpeed = 5f; public float shakeTime; public float shakeIntensity = 2f; public Vector2? target; private Vector2? endShake; [Export(PropertyHint.None, "")] public Vector2 offset = defaultOffset; public float speed = 1f; public static CameraController instance; [Export(PropertyHint.None, "")] public Control contents; public static Coroutine transitionRoutine; [Export(PropertyHint.None, "")] public Control cover; public static readonly Vector2 defaultOffset = new Vector2(0f, -16f); public const float defaultShake = 2f; public override void _EnterTree() { base.ProcessPriority = int.MaxValue; instance = this; } public static void Shake(float time = 5f, float intensity = 1f) { instance.shakeTime = time; instance.shakeIntensity = intensity; } public override void _PhysicsProcess(double delta) { if (follow != null) { base.GlobalPosition = base.GlobalPosition.Lerp(follow.GlobalPosition + offset, speed * Main.physisDelta); } else if (target.HasValue) { base.GlobalPosition = base.GlobalPosition.Lerp(target.Value, speed * Main.physisDelta); } if (Room.current != null) { base.GlobalPosition = new Vector2(Mathf.Clamp(base.GlobalPosition.X, Room.current.cameraLimit[0].X, Room.current.cameraLimit[1].X), Mathf.Clamp(base.GlobalPosition.Y, Room.current.cameraLimit[0].Y, Room.current.cameraLimit[1].Y)); } DoShake(); if (shakeTime > 0f) { shakeTime -= Main.physisDelta; } CallDeferred(MethodName.LateUpdate); } private void LateUpdate() { } private void DoShake() { if (shakeTime > 0f) { if (!target.HasValue && follow == null) { Vector2 valueOrDefault = endShake.GetValueOrDefault(); if (!endShake.HasValue) { valueOrDefault = base.GlobalPosition; endShake = valueOrDefault; } } float[] array = new float[2] { Main.RandomRange(0f - shakeIntensity, shakeIntensity), Main.RandomRange(0f - shakeIntensity, shakeIntensity) }; for (int i = 0; i < array.Length; i++) { if (array[i] > -1f && array[i] < 1f) { if (array[i] > 0f) { array[i] = 1f; } else { array[1] = -1f; } } else { array[i] = Mathf.Round(array[i]); } } Vector2 vector = new Vector2(array[0], array[1]); contents.Position = vector; if (!endShake.HasValue) { base.GlobalPosition -= vector; } else { base.GlobalPosition = endShake.Value + vector; } } else { if (!target.HasValue && follow == null && endShake.HasValue) { base.GlobalPosition = endShake.Value; } endShake = null; contents.Position = Vector2.Zero; } } public static void Transition(Color color, float time = 0f, int? sort = null, Color? startColor = null) { if (sort.HasValue) { instance.cover.ZIndex = sort.Value; } else { instance.cover.ZIndex = 4000; } instance.cover.Visible = true; if (time == 0f) { instance.cover.SelfModulate = color; return; } instance.cover.SelfModulate = (startColor.HasValue ? startColor.Value : instance.cover.SelfModulate); Coroutine coroutine = transitionRoutine; if (coroutine != null && !coroutine.done) { Coroutine.Stop(transitionRoutine); } transitionRoutine = Coroutine.Start(DelayedTransition(color, time, instance.cover.SelfModulate)); } private static IEnumerator DelayedTransition(Color to, float time, Color start) { for (float a = 0f; a <= time; a += Main.deltaTime) { instance.cover.SelfModulate = start.Lerp(to, a / time); yield return null; } instance.cover.SelfModulate = to; } public static IEnumerator PanToObj(Node2D targetObj, float time = 1f, bool fixedRate = true, bool addOffset = true, bool setTarget = true) { Coroutine c = Coroutine.Start(PanToObj(instance.GlobalPosition, targetObj, time, fixedRate, addOffset, setTarget)); while (!c.done) { yield return null; } } public static IEnumerator PanToObj(Vector2 startPos, Node2D targetObj, float time = 1f, bool fixedRate = true, bool addOffset = true, bool setTarget = true) { Coroutine routine = Coroutine.Start(Pan(startPos, targetObj.GlobalPosition + (addOffset ? instance.offset : Vector2.Zero), time, fixedRate)); while (!routine.done) { yield return null; } if (setTarget) { instance.follow = targetObj; } } public static IEnumerator Pan(Vector2 pos, float time, bool fixedRate = true, float failsafe = 400f) { Coroutine c = Coroutine.Start(Pan(instance.GlobalPosition, pos, time, fixedRate, failsafe)); while (!c.done) { yield return null; } } public static IEnumerator Pan(Vector2 startPos, Vector2 pos, float time, bool fixedRate = true, float failsafe = 400f) { instance.follow = null; if (fixedRate) { while (failsafe > 0f) { float num = instance.GlobalPosition.DistanceSquaredTo(pos); if (!(num > 1.1f)) { break; } instance.GlobalPosition += instance.GlobalPosition.DirectionTo(pos).Snapped(Vector2.One) * time * Mathf.Clamp(num / 3f, 0f, 1f); failsafe -= Main.deltaTime; yield return null; } if (failsafe <= 0f) { instance.GlobalPosition = pos; } } else { for (float a = 0f; a < time; a += Main.deltaTime) { instance.GlobalPosition = startPos.Lerp(pos, a / time); yield return null; } } instance.GlobalPosition = new Vector2(Mathf.Round(pos.X), Mathf.Round(pos.Y)); } }