LADXHD/InGame/GameObjects/MidBoss/MBossGrimCreeperFly.cs
2023-12-14 17:21:22 -05:00

246 lines
8.7 KiB
C#

using Microsoft.Xna.Framework;
using ProjectZ.InGame.GameObjects.Base;
using ProjectZ.InGame.GameObjects.Base.Components;
using ProjectZ.InGame.GameObjects.Base.CObjects;
using ProjectZ.InGame.GameObjects.Base.Components.AI;
using ProjectZ.InGame.SaveLoad;
using ProjectZ.InGame.Things;
using ProjectZ.InGame.Map;
using System;
namespace ProjectZ.InGame.GameObjects.Enemies
{
internal class MBossGrimCreeperFly : GameObject
{
private readonly BodyComponent _body;
private readonly AiComponent _aiComponent;
private readonly Animator _animator;
private readonly CSprite _sprite;
private readonly DamageFieldComponent _damageField;
private readonly HittableComponent _hittableComponent;
private readonly AiDamageState _damageState;
private readonly BodyDrawShadowComponent _shadowComponent;
private readonly Vector2 _targetPosition;
private const float FlySpeed = 1;
private const float AttackSpeed = 2;
private const float FadeTime = 100;
private float _fadeCounter;
private Vector2 _roomCenter;
private Vector2 _centerPosition;
private Vector2 _leaveStart;
private Vector2 _leaveEnd;
private float _leaveCounter;
private float _circlingOffset;
private float _circleSpeed;
// TODO: sync animations
public MBossGrimCreeperFly(Map.Map map, Vector2 position, Vector2 targetPosition) : base(map)
{
Tags = Values.GameObjectTag.Enemy;
EntityPosition = new CPosition(position.X, position.Y, 28);
EntitySize = new Rectangle(-8, -42, 16, 42);
_roomCenter = Map.GetRoomCenter(targetPosition.X, targetPosition.Y - 43);
_targetPosition = targetPosition;
_animator = AnimatorSaveLoad.LoadAnimator("MidBoss/grim creeper fly");
_animator.Play("idle");
_sprite = new CSprite(EntityPosition) { Color = Color.Transparent };
var animatorComponent = new AnimationComponent(_animator, _sprite, Vector2.Zero);
_body = new BodyComponent(EntityPosition, -6, -12, 12, 12, 8)
{
IgnoresZ = true,
IgnoreHoles = true,
Bounciness = 0.25f,
Gravity = -0.175f,
CollisionTypes = Values.CollisionTypes.None
};
_aiComponent = new AiComponent();
var stateSpawn = new AiState(UpdateSpawn);
var stateIdle = new AiState();
var stateAttack = new AiState(UpdateAttacking) { Init = InitAttack };
var stateFadeout = new AiState(UpdateFadeout) { Init = InitFadeout };
// grim creeper states
var stateCircling = new AiState(UpdateCircling);
var stateLeave = new AiState(UpdateLeave);
_aiComponent.States.Add("spawn", stateSpawn);
_aiComponent.States.Add("idle", stateIdle);
_aiComponent.States.Add("attack", stateAttack);
_aiComponent.States.Add("fadeout", stateFadeout);
_damageState = new AiDamageState(this, _body, _aiComponent, _sprite, 1)
{
OnBurn = OnBurn
};
_aiComponent.States.Add("circling", stateCircling);
_aiComponent.States.Add("leave", stateLeave);
_aiComponent.ChangeState("spawn");
var damageBox = new CBox(EntityPosition, -5, -12, 0, 10, 10, 8, true);
var hittableBox = new CBox(EntityPosition, -7, -14, 0, 14, 14, 8, true);
AddComponent(DamageFieldComponent.Index, _damageField = new DamageFieldComponent(damageBox, HitType.Enemy, 2) { IsActive = false });
AddComponent(HittableComponent.Index, _hittableComponent = new HittableComponent(hittableBox, _damageState.OnHit) { IsActive = false });
AddComponent(AiComponent.Index, _aiComponent);
AddComponent(BodyComponent.Index, _body);
AddComponent(BaseAnimationComponent.Index, animatorComponent);
AddComponent(DrawComponent.Index, new BodyDrawComponent(_body, _sprite, Values.LayerPlayer) { WaterOutline = false });
AddComponent(DrawShadowComponent.Index, _shadowComponent = new BodyDrawShadowComponent(_body, _sprite) { Transparency = 0 });
}
public void StartSequenceMode()
{
EntityPosition.Z = 0;
_centerPosition = EntityPosition.Position;
_body.VelocityTarget = Vector2.Zero;
_sprite.Color = Color.White;
_aiComponent.ChangeState("circling");
_circlingOffset = Game1.RandomNumber.Next(0, 20) / 5f;
_circleSpeed = Game1.RandomNumber.Next(100, 125);
}
public void ToLeave()
{
_aiComponent.ChangeState("leave");
_leaveStart = EntityPosition.Position;
_leaveEnd = _targetPosition;
}
public void FightInit()
{
Game1.GameManager.PlaySoundEffect("D360-49-31");
}
private void OnBurn()
{
_body.IgnoresZ = false;
}
private void UpdateSpawn()
{
UpdateFading(false);
// move towards the target position
var direction = _targetPosition - EntityPosition.Position;
if (direction.Length() > FlySpeed * Game1.TimeMultiplier)
{
direction.Normalize();
_body.VelocityTarget = direction * FlySpeed;
}
else
{
// reached the target position
_body.VelocityTarget = Vector2.Zero;
EntityPosition.Set(_targetPosition);
_aiComponent.ChangeState("idle");
}
}
private void UpdateLeave()
{
_leaveCounter += Game1.DeltaTime;
var percentage = 1 - MathF.Cos(_leaveCounter / 1000 * MathF.PI / 2);
var newPosition = Vector2.Lerp(_leaveStart, _leaveEnd, percentage);
EntityPosition.Set(newPosition);
// fade out
var transparency = Math.Clamp((1000 - _leaveCounter) / FadeTime, 0, 1);
_sprite.Color = Color.White * transparency;
if (percentage > 1)
{
Map.Objects.DeleteObjects.Add(this);
}
}
private void UpdateCircling()
{
var newPosition = _centerPosition + new Vector2(
MathF.Sin((float)Game1.TotalGameTime / _circleSpeed + _circlingOffset) * 1,
MathF.Sin((float)Game1.TotalGameTime / _circleSpeed + 1.0f + _circlingOffset) * 2);
EntityPosition.Set(newPosition);
}
public void StartAttack()
{
_aiComponent.ChangeState("attack");
}
public bool IsAlive()
{
return _damageState.CurrentLives > 0;
}
private void InitAttack()
{
Game1.GameManager.PlaySoundEffect("D360-49-31");
_damageField.IsActive = true;
_hittableComponent.IsActive = true;
// fly towards the player
var direction = MapManager.ObjLink.EntityPosition.Position - new Vector2(EntityPosition.X, EntityPosition.Y - 12);
if (direction != Vector2.Zero)
{
direction.Normalize();
_body.VelocityTarget = direction * AttackSpeed;
}
}
private void UpdateAttacking()
{
if (EntityPosition.Z > 12)
EntityPosition.Z -= 0.5f * Game1.TimeMultiplier;
var direction = _roomCenter - new Vector2(EntityPosition.X, EntityPosition.Y - EntityPosition.Z);
// fade out?
if (direction.Length() > 120)
_aiComponent.ChangeState("fadeout");
}
private void InitFadeout()
{
_fadeCounter = 0;
}
private void UpdateFadeout()
{
if (UpdateFading(true))
Map.Objects.DeleteObjects.Add(this);
}
private bool UpdateFading(bool fadeOut)
{
_fadeCounter += Game1.DeltaTime;
if (_fadeCounter > FadeTime)
_fadeCounter = FadeTime;
var transparency = _fadeCounter / FadeTime;
if (fadeOut)
transparency = 1 - transparency;
_sprite.Color = Color.White * transparency;
_shadowComponent.Transparency = transparency;
return _fadeCounter == FadeTime;
}
}
}