350 lines
9.4 KiB
C#
350 lines
9.4 KiB
C#
using UnityEngine;
|
|
|
|
public interface ISpiderState
|
|
{
|
|
void EnterState();
|
|
void UpdateState();
|
|
void ExitState();
|
|
}
|
|
|
|
public abstract class SpiderStateBase : ISpiderState
|
|
{
|
|
protected readonly BossController boss;
|
|
|
|
protected SpiderStateBase(BossController owner)
|
|
{
|
|
boss = owner;
|
|
}
|
|
|
|
public virtual void EnterState() { }
|
|
public abstract void UpdateState();
|
|
public virtual void ExitState() { }
|
|
}
|
|
|
|
public class SpiderIdleState : SpiderStateBase
|
|
{
|
|
public SpiderIdleState(BossController owner) : base(owner) { }
|
|
|
|
public override void EnterState() => boss.Anim.SetTrigger("Idle");
|
|
|
|
public override void UpdateState()
|
|
{
|
|
if (boss.Player == null) return;
|
|
|
|
if (Vector3.Distance(boss.transform.position, boss.Player.position) <= boss.ChaseRange)
|
|
{
|
|
boss.ChangeState<SpiderChaseState>();
|
|
}
|
|
}
|
|
}
|
|
|
|
public class SpiderChaseState : SpiderStateBase
|
|
{
|
|
public SpiderChaseState(BossController owner) : base(owner) { }
|
|
|
|
public override void EnterState() => boss.Agent.isStopped = false;
|
|
|
|
public override void UpdateState()
|
|
{
|
|
if (boss.Player == null) return;
|
|
|
|
float distance = Vector3.Distance(boss.transform.position, boss.Player.position);
|
|
|
|
if (distance >= boss.ChargeMinimumDistance && boss.ChargeCooldownTimer <= 0f)
|
|
{
|
|
boss.ChangeState<SpiderChargeState>();
|
|
return;
|
|
}
|
|
|
|
if (distance <= boss.BiteRange)
|
|
{
|
|
boss.ChangeState<SpiderBiteState>();
|
|
return;
|
|
}
|
|
|
|
boss.Agent.SetDestination(boss.Player.position);
|
|
boss.Anim.SetFloat("Speed", boss.Agent.velocity.magnitude);
|
|
}
|
|
}
|
|
|
|
public class SpiderBiteState : SpiderStateBase
|
|
{
|
|
private float stateTimer;
|
|
private const float TurnSpeed = 4f;
|
|
|
|
public SpiderBiteState(BossController owner) : base(owner) { }
|
|
|
|
public override void EnterState()
|
|
{
|
|
stateTimer = 1.5f;
|
|
boss.Agent.ResetPath();
|
|
boss.Agent.isStopped = true;
|
|
boss.Agent.velocity = Vector3.zero;
|
|
|
|
boss.Anim.SetFloat("Speed", 0f);
|
|
boss.Anim.SetTrigger("Attack_Bite");
|
|
}
|
|
|
|
public override void ExitState()
|
|
{
|
|
boss.Agent.isStopped = false;
|
|
}
|
|
|
|
public override void UpdateState()
|
|
{
|
|
boss.Agent.velocity = Vector3.zero;
|
|
|
|
if (boss.Player != null)
|
|
{
|
|
Vector3 lookDir = (boss.Player.position - boss.transform.position).normalized;
|
|
lookDir.y = 0;
|
|
|
|
if (lookDir != Vector3.zero)
|
|
{
|
|
boss.transform.rotation = Quaternion.Slerp(
|
|
boss.transform.rotation,
|
|
Quaternion.LookRotation(lookDir),
|
|
Time.deltaTime * TurnSpeed
|
|
);
|
|
}
|
|
}
|
|
|
|
stateTimer -= Time.deltaTime;
|
|
if (stateTimer <= 0f)
|
|
{
|
|
if (boss.PendingUltimate) boss.ChangeState<SpiderJumpToCeilingState>();
|
|
else boss.ChangeState<SpiderChaseState>();
|
|
}
|
|
}
|
|
}
|
|
|
|
public class SpiderChargeState : SpiderStateBase
|
|
{
|
|
private float roarTimer;
|
|
private float chargeTimer;
|
|
private Vector3 chargeDirection;
|
|
private bool isChargingPhase;
|
|
|
|
public SpiderChargeState(BossController owner) : base(owner) { }
|
|
|
|
public override void EnterState()
|
|
{
|
|
roarTimer = boss.ChargeRoarDuration;
|
|
chargeTimer = boss.ChargeDuration;
|
|
isChargingPhase = false;
|
|
|
|
boss.Agent.isStopped = true;
|
|
boss.Agent.velocity = Vector3.zero;
|
|
|
|
boss.ResetChargeCooldown();
|
|
boss.Anim.SetTrigger("Attack_Roar");
|
|
}
|
|
|
|
public override void ExitState()
|
|
{
|
|
boss.Anim.SetBool("IsCharging", false);
|
|
boss.Agent.speed = boss.NormalSpeed;
|
|
boss.Agent.acceleration = boss.NormalAcceleration;
|
|
boss.Agent.isStopped = false;
|
|
}
|
|
|
|
public override void UpdateState()
|
|
{
|
|
if (!isChargingPhase)
|
|
{
|
|
roarTimer -= Time.deltaTime;
|
|
boss.Agent.velocity = Vector3.zero;
|
|
|
|
if (boss.Player != null)
|
|
{
|
|
Vector3 lookDir = (boss.Player.position - boss.transform.position).normalized;
|
|
lookDir.y = 0;
|
|
if (lookDir != Vector3.zero)
|
|
{
|
|
boss.transform.rotation = Quaternion.Slerp(boss.transform.rotation, Quaternion.LookRotation(lookDir), Time.deltaTime * 10f);
|
|
}
|
|
}
|
|
|
|
if (roarTimer <= 0f)
|
|
{
|
|
isChargingPhase = true;
|
|
boss.Anim.SetTrigger("ChargeStart");
|
|
boss.Anim.SetBool("IsCharging", true);
|
|
|
|
if (boss.Player != null)
|
|
{
|
|
chargeDirection = (boss.Player.position - boss.transform.position).normalized;
|
|
chargeDirection.y = 0;
|
|
}
|
|
|
|
Vector3 targetDestination = boss.transform.position + chargeDirection * 20f;
|
|
|
|
boss.Agent.isStopped = false;
|
|
boss.Agent.speed = boss.ChargeSpeed;
|
|
boss.Agent.acceleration = 120f;
|
|
boss.Agent.SetDestination(targetDestination);
|
|
}
|
|
return;
|
|
}
|
|
|
|
chargeTimer -= Time.deltaTime;
|
|
|
|
if (chargeTimer <= 0f || (boss.Agent.velocity.magnitude < 0.2f && chargeTimer < (boss.ChargeDuration - 0.3f)))
|
|
{
|
|
boss.ChangeState<SpiderChaseState>();
|
|
}
|
|
}
|
|
}
|
|
|
|
public class SpiderJumpToCeilingState : SpiderStateBase
|
|
{
|
|
private float roarTimer;
|
|
private float jumpProgress;
|
|
private Vector3 startPos;
|
|
private bool isJumpingPhase;
|
|
|
|
public SpiderJumpToCeilingState(BossController owner) : base(owner) { }
|
|
|
|
public override void EnterState()
|
|
{
|
|
roarTimer = boss.JumpRoarDuration;
|
|
jumpProgress = 0f;
|
|
startPos = boss.transform.position;
|
|
isJumpingPhase = false;
|
|
|
|
boss.Agent.enabled = false;
|
|
boss.Anim.SetTrigger("Attack_Roar");
|
|
}
|
|
|
|
public override void UpdateState()
|
|
{
|
|
if (!isJumpingPhase)
|
|
{
|
|
roarTimer -= Time.deltaTime;
|
|
if (roarTimer <= 0f)
|
|
{
|
|
isJumpingPhase = true;
|
|
boss.Anim.SetTrigger("JumpUp");
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (boss.ceilingAnchor == null) return;
|
|
|
|
jumpProgress += Time.unscaledDeltaTime * 1.5f;
|
|
|
|
Vector3 currentPos = Vector3.Lerp(startPos, boss.ceilingAnchor.position, jumpProgress);
|
|
currentPos.y += Mathf.Sin(jumpProgress * Mathf.PI) * 3f;
|
|
|
|
boss.transform.position = currentPos;
|
|
|
|
if (jumpProgress >= 1f)
|
|
{
|
|
boss.transform.position = boss.ceilingAnchor.position;
|
|
boss.ChangeState<SpiderCeilingAttackState>();
|
|
}
|
|
}
|
|
}
|
|
|
|
public class SpiderCeilingAttackState : SpiderStateBase
|
|
{
|
|
private float timer;
|
|
private float shotTimer;
|
|
|
|
public SpiderCeilingAttackState(BossController owner) : base(owner) { }
|
|
|
|
public override void EnterState()
|
|
{
|
|
timer = boss.CeilingAttackDuration;
|
|
shotTimer = 0f;
|
|
|
|
boss.Anim.SetBool("IsOnCeiling", true);
|
|
boss.PendingUltimate = false;
|
|
}
|
|
|
|
public override void ExitState()
|
|
{
|
|
boss.Anim.SetBool("IsOnCeiling", false);
|
|
if (boss.groundAnchor != null) boss.transform.position = boss.groundAnchor.position;
|
|
boss.Agent.enabled = true;
|
|
boss.Anim.SetTrigger("Land");
|
|
}
|
|
|
|
public override void UpdateState()
|
|
{
|
|
timer -= Time.deltaTime;
|
|
shotTimer -= Time.deltaTime;
|
|
|
|
if (shotTimer <= 0f)
|
|
{
|
|
ExecuteRandomWebAttack();
|
|
shotTimer = boss.CeilingShotInterval;
|
|
}
|
|
|
|
if (timer <= 0f)
|
|
{
|
|
boss.ChangeState<SpiderChaseState>();
|
|
}
|
|
}
|
|
|
|
private void ExecuteRandomWebAttack()
|
|
{
|
|
Vector3 targetGroundPos = Vector3.zero;
|
|
int maxAttempts = 15;
|
|
|
|
for (int i = 0; i < maxAttempts; i++)
|
|
{
|
|
Vector2 randomCircle = Random.insideUnitCircle * boss.AttackRadius;
|
|
targetGroundPos = new Vector3(
|
|
boss.groundAnchor.position.x + randomCircle.x,
|
|
boss.groundAnchor.position.y,
|
|
boss.groundAnchor.position.z + randomCircle.y
|
|
);
|
|
|
|
bool isTooClose = false;
|
|
foreach (Vector3 existingPos in boss.WebSpawner.ActiveWebPositions)
|
|
{
|
|
if (Vector3.Distance(targetGroundPos, existingPos) < boss.WebSpawner.WebAvoidanceRadius)
|
|
{
|
|
isTooClose = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!isTooClose) break;
|
|
}
|
|
|
|
boss.WebSpawner.SpawnWarningAndWeb(targetGroundPos, boss.WebWarningDelay, boss.WebDuration);
|
|
}
|
|
}
|
|
|
|
public class SpiderStunState : SpiderStateBase
|
|
{
|
|
private float stunTimer;
|
|
|
|
public SpiderStunState(BossController owner) : base(owner) { }
|
|
|
|
public override void EnterState()
|
|
{
|
|
stunTimer = 4.0f;
|
|
boss.Anim.SetTrigger("StunStart");
|
|
boss.Anim.SetBool("IsStunned", true);
|
|
if (boss.Agent.enabled) boss.Agent.isStopped = true;
|
|
}
|
|
|
|
public override void ExitState()
|
|
{
|
|
boss.Anim.SetBool("IsStunned", false);
|
|
if (boss.Agent.enabled) boss.Agent.isStopped = false;
|
|
}
|
|
|
|
public override void UpdateState()
|
|
{
|
|
stunTimer -= Time.deltaTime;
|
|
if (stunTimer <= 0f)
|
|
{
|
|
if (boss.PendingUltimate) boss.ChangeState<SpiderJumpToCeilingState>();
|
|
else boss.ChangeState<SpiderChaseState>();
|
|
}
|
|
}
|
|
} |