2025-05-13 19:22:01 +08:00

237 lines
5.6 KiB
C#

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));
}
}