using System; using System.Collections; using System.Threading; using System.Threading.Tasks; using Cirno.Scripts.Components.FSM; using Godot; using GTweensGodot.Extensions; namespace Cirno.Scripts.Activables; [Tool] public partial class Teleporter : Activable { [Export] public bool IsEnabled { get; set; } [Export] public bool Invisible { get; set; } = false; public bool IsPrimed { get; private set; } [Export] public Teleporter Target { get; set; } [Export] public float ParticleEmitTime { get; private set; } = 2f; [Export] public float TeleportAnimationLength { get; private set; } = 0.5f; [Export] public Vector2 TeleportOffset { get; private set; } = new Vector2(0, -4f); private double _particleTimer; private AnimatedSprite2D _animatedSprite; // [Export] // public GpuParticles2D Particles { get; set; } protected GpuParticles2D _particles; private AudioStreamPlayer2D _teleportStartSound; private AudioStreamPlayer2D _teleportEndSound; public override void _Ready() { _animatedSprite = GetNode("AnimatedSprite2D"); _animatedSprite.Play(IsEnabled ? "Active" : "Default"); if (Engine.IsEditorHint()) return; _particles = GetNode("./Particles"); IsPrimed = true; _particles.Emitting = false; _particleTimer = 0; this.Visible = !Invisible; _teleportStartSound = GetNodeOrNull("TeleportStart"); _teleportEndSound = GetNodeOrNull("TeleportEnd"); } public override void _Process(double delta) { if (Engine.IsEditorHint()) return; if (!_particles.Emitting) return; _particleTimer += delta; if (_particleTimer >= ParticleEmitTime) { _particleTimer = 0; _particles.Emitting = false; } } public override bool Activate(ActivationType activationType = ActivationType.Toggle) { switch (activationType) { case ActivationType.Toggle: // Enables/Disables teleporter break; case ActivationType.Enable: // Enables Teleporter IsEnabled = true; _animatedSprite.Play("Active"); break; case ActivationType.Disable: IsEnabled = false; _animatedSprite.Play("Default"); // Disables Teleporter break; case ActivationType.Use: // Teleports break; case ActivationType.Destroy: // Destroys break; } return true; } public void PrepareForReceiving() { IsPrimed = false; _particles.Emitting = true; } public void FireParticles() { _particles.Emitting = true; _particleTimer = 0; } private void _on_area_entered(Area2D area) { GD.Print("Something entered the teleporter"); if (!IsEnabled) return; if (area is not InteractionController interactionController) return; GD.Print("Player entered the teleporter"); if (!IsPrimed) { IsPrimed = true; //_particles.Emitting = false; return; } // Teleport player to target if active if (!IsEnabled) return; GD.Print("Teleporting..."); // Call Teleport here _ = Teleport(interactionController.StateMachine); } protected virtual async Task Teleport(IStateMachine player) { if (Target is null) return; //player.RequestMovementDisable(true); player.SetState(PlayerState.Cutscene); await TweenPlayer(player.MainObject); PlayTeleportStartSound(); //_particles.Emitting = true; FireParticles(); //await player.Teleport(); player.SetState(PlayerState.Teleporting); await Task.Delay((int)(0.6f * 1000)); await Task.Delay((int)(TeleportAnimationLength * 1000)); Target.PrepareForReceiving(); player.MainObject.GlobalPosition = Target.GlobalPosition + TeleportOffset; Target.PlayTeleportEndSound(); //await player.UnTeleport(); player.SetState(PlayerState.UnTeleporting); await Task.Delay((int)(0.6f * 1000)); //player.RequestMovementDisable(false); player.SetState(PlayerState.Active); } public void PlayTeleportStartSound() { _teleportStartSound?.Play(); } public void PlayTeleportEndSound() { _teleportEndSound?.Play(); } protected async Task TweenPlayer(CharacterBody2D player) { await player.TweenGlobalPosition(GlobalPosition + new Vector2(0, -4f), TeleportAnimationLength).PlayAsync(CancellationToken.None); // Create a Tween for the teleport animation // Tween tween = GetTree().CreateTween(); // tween.SetEase(Tween.EaseType.InOut); // tween.SetTrans(Tween.TransitionType.Sine); // tween.TweenProperty(player, "global_position", GlobalPosition + new Vector2(0,-4f), TeleportAnimationLength); // // // Wait for the tween to finish // await ToSignal(tween, "finished"); } }