cirnogodot/Scripts/Actors/Boss.cs

193 lines
No EOL
5.7 KiB
C#

using System.Threading.Tasks;
using Cirno.Scripts.Resources;
using Cirno.Scripts.Resources.ScriptableBullets;
using Cirno.Scripts.UI;
using Godot;
using Godot.Collections;
namespace Cirno.Scripts.Actors;
public partial class Boss : Enemy, IActivable
{
[Export] public string BossName { get; private set; }
//[Export] private Array<BossPhase> Phases;
[Export] public BossScript BossScript { get; private set; }
//[Export] private PackedScene BossHudPrefab;
[Export] public Vector2 BossPhaseAnimationStartingPosition = new Vector2(180, 10);
private int currentPhaseIndex = 0;
private bool _started = false;
private bool _waiting = false;
private GameManager _gameManager;
public GameManager GameManager => _gameManager;
private Vector2 _homePosition;
public Vector2 HomePosition => _homePosition;
private BossPhase CurrentPhase => BossScript.Phases[currentPhaseIndex];
private Marker2D _cameraMarker;
[Export]
public Vector2 CameraOffset = Vector2.Zero;
private TextureRect _animationTextureRect;
//[Export] private Texture2D _bossPortraitTexture;
private BossHud _bossHud;
[Signal] public delegate void ActorSpriteChangeEventHandler(Vector2 direction);
public override void _Ready()
{
base._Ready();
if (BossScript is null)
{
GD.PrintErr($"No boss script defined in {this.Name}");
return;
}
_gameManager = this.GetGameManager();
_homePosition = this.GlobalPosition;
_cameraMarker = new Marker2D();
_gameManager.CallDeferred("add_child", _cameraMarker);
_cameraMarker.GlobalPosition = _homePosition + CameraOffset;
if (BossScript.HudPrefab is not null)
{
_bossHud = BossScript.HudPrefab.Instantiate<BossHud>();
_gameManager.CallDeferred("add_child", _bossHud);
_bossHud.Name = $"{BossName}_BossHud";
_bossHud.Visible = false;
_bossHud.BossName = BossName;
_bossHud.BossMaxHealth = this.Health;
_bossHud.BossHealth = this._currentHealth;
_bossHud.SpellCardName = CurrentPhase.PhaseName;
// TODO: Do some translation for health values to match the thresholds
this.HealthChanged += (float newValue) => {_bossHud.BossHealth = newValue;};
if (BossScript.PortraitTexture is not null)
{
// var canvas = new CanvasLayer();
// canvas.Name = "BossPhaseAnimationCanvas";
// _gameManager.CallDeferred("add_child", canvas);
_animationTextureRect = new TextureRect();
_animationTextureRect.Texture = BossScript.PortraitTexture;
_bossHud.CallDeferred("add_child", _animationTextureRect);
_animationTextureRect.Position = BossPhaseAnimationStartingPosition;
_animationTextureRect.Visible = false;
}
}
}
public override void _Process(double delta)
{
base._Process(delta);
if (!_started) return;
if (_waiting) return;
CurrentPhase.UpdatePhase(delta);
if (_currentHealth <= CurrentPhase.Threshold && currentPhaseIndex + 1 < BossScript.Phases.Count)
{
currentPhaseIndex++;
_bossHud.SpellCardName = CurrentPhase.PhaseName;
StartPhase(CurrentPhase);
}
}
protected override void Explode()
{
if (_bossHud is not null)
{
_bossHud.QueueFree();
}
_gameManager.CameraTargetPlayer();
base.Explode();
}
private void StartPhase(BossPhase phase)
{
if (phase.PlayAnimation)
{
_waiting = true;
_invulnerable = true;
_ = Switchphase(phase);
}
else
{
phase.Start(this);
}
}
public void TakeDamage(int amount)
{
if (!_started) return;
_currentHealth -= amount;
}
public bool Activate(ActivationType activationType = ActivationType.Toggle)
{
_started = true;
if (_bossHud is not null)
{
_bossHud.Visible = true;
}
_gameManager.CameraTargetObject(_cameraMarker);
StartPhase(CurrentPhase);
return true;
}
private async Task Switchphase(BossPhase phase)
{
await PlayAnimation();
_waiting = false;
_invulnerable = false;
phase.Start(this);
}
private async Task PlayAnimation()
{
_animationTextureRect.Modulate = new Color(_animationTextureRect.Modulate.R, _animationTextureRect.Modulate.G, _animationTextureRect.Modulate.B, 0f);
_animationTextureRect.Position = BossPhaseAnimationStartingPosition;
_animationTextureRect.Visible = true;
var tween = GetTree().CreateTween();
tween.SetEase(Tween.EaseType.InOut);
tween.SetTrans(Tween.TransitionType.Linear);
tween.TweenProperty(_animationTextureRect, "modulate:a", 1f, 0.2f);
tween.TweenProperty(_animationTextureRect, "global_position", _animationTextureRect.GlobalPosition + new Vector2(-64f, 20f), 1.5f);
tween.TweenProperty(_animationTextureRect, "modulate:a", 0f, 0.2f);
//await Task.Delay(800);
// Wait for the tween to finish
await ToSignal(tween, "finished");
_animationTextureRect.Visible = false;
}
public void ChangeSpriteDirection(Vector2 direction)
{
EmitSignal(SignalName.ActorSpriteChange, direction);
}
}