Files
VRProject/Assets/_Scripts/SpiderIdleState.cs
2026-07-07 16:06:00 +09:00

362 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
public class SpiderIdleState : ISpiderState
{
private BossController boss;
public SpiderIdleState(BossController owner) => boss = owner;
public void EnterState() => boss.Anim.SetTrigger("Idle");
public void ExitState() { }
public void UpdateState()
{
if (boss.Player == null) return;
// プレイヤーを検知したら即座に追跡へ
if (Vector3.Distance(boss.transform.position, boss.Player.position) <= boss.chaseRange)
{
boss.ChangeState<SpiderChaseState>();
}
}
}
public class SpiderChaseState : ISpiderState
{
private BossController boss;
public SpiderChaseState(BossController owner) => boss = owner;
public void EnterState() => boss.Agent.isStopped = false;
public void ExitState()
{
boss.Agent.isStopped = true;
boss.ResetAllAnimationTriggers();
}
public void UpdateState()
{
if (boss.Player == null) return;
float distance = Vector3.Distance(boss.transform.position, boss.Player.position);
// 6m以上かつクールダウン終了 ➔ 1歩も歩かずに即突進
if (distance >= boss.chargeMinimumDistance && boss.ChargeCooldownTimer <= 0f)
{
boss.ChangeState<SpiderChargeState>();
return; // 移行したので以下の歩き処理は実行しない
}
// 判定2至近距離2.5m以内)➔ 通常噛みつき
if (distance <= boss.biteRange)
{
boss.ChangeState<SpiderBiteState>();
return;
}
boss.Agent.SetDestination(boss.Player.position);
boss.Anim.SetFloat("Speed", boss.Agent.velocity.magnitude);
}
}
// ==========================================
// ■ STATE: BITE (完全静止・滑り移動ゼロ修正版)
// ==========================================
public class SpiderBiteState : ISpiderState
{
private BossController boss;
private float stateTimer;
public SpiderBiteState(BossController owner) => boss = owner;
public void EnterState()
{
stateTimer = 1.5f; // 噛みつきアニメーションの時間(環境に合わせて調整してください)
// 1. 【物理ブレーキ】これまでの移動経路を完全に忘却させ、慣性速度も強制ゼロにする
boss.Agent.ResetPath();
boss.Agent.isStopped = true;
boss.Agent.velocity = Vector3.zero;
// 2. 【アニメーションブレーキ】直前の走っていた速度Speedを強制的に0リセット
// これをしないと、速度の減衰が遅れて「歩きながら噛み付く」ブレンドモーションになります
boss.Anim.SetFloat("Speed", 0f);
// 3. 噛みつきモーションを発動
boss.Anim.SetTrigger("Attack_Bite");
Debug.Log("🎯 蜘蛛ボス:噛みつき攻撃! 経路を完全消去してその場に固定しました。");
}
public void ExitState()
{
// 次のステートChaseなどに安全に移行できるよう、ナビゲーションの停止を解除
boss.Agent.isStopped = false;
boss.ResetAllAnimationTriggers();
}
public void UpdateState()
{
// 4. 【徹底防衛】アニメーションの再生中に予期せぬ物理反発や滑りが発生しないよう、毎フレーム速度をゼロに固定
boss.Agent.velocity = Vector3.zero;
stateTimer -= Time.deltaTime;
if (stateTimer <= 0f)
{
if (boss.PendingUltimate) boss.ChangeState<SpiderJumpToCeilingState>();
else boss.ChangeState<SpiderChaseState>();
}
}
}
// ==========================================
// ■ STATE: CHARGE (慣性ブレーキ完全修正版)
// ==========================================
public class SpiderChargeState : ISpiderState
{
private BossController boss;
private float roarTimer;
private float chargeTimer;
private Vector3 chargeDirection;
private bool isChargingPhase;
public SpiderChargeState(BossController owner) => boss = owner;
public void EnterState()
{
roarTimer = 5f; // 溜め(咆哮)時間
chargeTimer = boss.chargeDuration;
isChargingPhase = false;
// ★超重要:ナビゲーションを止め、さらに残っている移動速度(慣性)を完全にゼロリセットする!
boss.Agent.isStopped = true;
boss.Agent.velocity = Vector3.zero; // これにより滑り込みを100%防止します
boss.ResetChargeCooldown();
// その場に完全静止した状態で、満を持して咆哮アニメーションを再生
boss.Anim.SetTrigger("Attack_Roar");
Debug.Log("🔊 蜘蛛ボス:遠距離を検知してその場でピタッと完全停止。咆哮(溜め)を開始!");
}
public void ExitState()
{
boss.Anim.SetBool("IsCharging", false);
boss.Agent.speed = boss.NormalSpeed;
boss.Agent.acceleration = boss.NormalAcceleration;
boss.Agent.isStopped = false;
boss.ResetAllAnimationTriggers();
}
public void UpdateState()
{
// ─── フェーズ1咆哮・溜めロックオンその場で旋回のみ ───
if (!isChargingPhase)
{
roarTimer -= Time.deltaTime;
// ★安全対策溜め期間中、予期せぬ物理の反発などで1ミリも動かないように速度をゼロに固定し続ける
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;
}
// 20m先の目的地に向かって、NavMeshAgentによる超高速突進ダッシュを発射
Vector3 targetDestination = boss.transform.position + chargeDirection * 20f;
boss.Agent.isStopped = false;
boss.Agent.speed = boss.chargeSpeed;
boss.Agent.acceleration = 120f;
boss.Agent.SetDestination(targetDestination);
Debug.Log("🚀 蜘蛛ボス:ロックオン完了。全速力で突進ダッシュを発射!");
}
return;
}
// ─── フェーズ2突進中 ───
chargeTimer -= Time.deltaTime;
// 壁やプレイヤーに激突して急停止したか、設定時間が経過したら通常状態へ戻る
if (chargeTimer <= 0f || (boss.Agent.velocity.magnitude < 0.2f && chargeTimer < (boss.chargeDuration - 0.3f)))
{
boss.ChangeState<SpiderChaseState>();
}
}
}
public class SpiderJumpToCeilingState : ISpiderState
{
private BossController boss;
private float roarTimer;
private float jumpProgress;
private Vector3 startPos;
private bool isJumpingPhase;
public SpiderJumpToCeilingState(BossController owner) => boss = owner;
public void EnterState()
{
roarTimer = 2.0f; // ★天井に飛ぶ前の大威嚇の時間 (2.0秒)
jumpProgress = 0f;
startPos = boss.transform.position;
isJumpingPhase = false;
boss.Agent.enabled = false;
// 1. 必殺技移行を知らせる威嚇の咆哮
boss.Anim.SetTrigger("Attack_Roar");
Debug.Log("🚨 蜘蛛ボス:必殺技前の一大威嚇(咆哮)! このあと天井へ飛びます。");
}
public void ExitState() { }
public void UpdateState()
{
// フェーズ1飛び立つ前の威嚇ポーズその場で足止め
if (!isJumpingPhase)
{
roarTimer -= Time.deltaTime;
if (roarTimer <= 0f)
{
isJumpingPhase = true;
boss.Anim.SetTrigger("JumpUp"); // ジャンプアニメーションへ
}
return;
}
// フェーズ2本来の大ジャンプ空中移動
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 : ISpiderState
{
private BossController boss;
private float stateDuration = 7.0f; // 必殺技全体の長さ(秒)
private float shotInterval = 0.4f; // 糸を降らせる間隔
private float timer = 0f;
private float shotTimer = 0f;
public SpiderCeilingAttackState(BossController owner) => boss = owner;
public void EnterState()
{
timer = stateDuration;
shotTimer = 0f;
boss.Anim.SetBool("IsOnCeiling", true);
boss.PendingUltimate = false; // 発動権を消化
Debug.Log("🕸️ 蜘蛛ボス:天井から無数の糸を乱射中!");
}
public void ExitState()
{
boss.Anim.SetBool("IsOnCeiling", false);
// 地上の着地座標へ位置をリセットしてNavMeshを復帰
if (boss.groundAnchor != null) boss.transform.position = boss.groundAnchor.position;
boss.Agent.enabled = true;
boss.Anim.SetTrigger("Land");
}
public void UpdateState()
{
timer -= Time.deltaTime;
shotTimer -= Time.deltaTime;
if (shotTimer <= 0f)
{
ExecuteRandomWebAttack();
shotTimer = shotInterval;
}
// 時間が来たら、地上へ復帰
if (timer <= 0f)
{
boss.ChangeState<SpiderChaseState>();
}
}
private void ExecuteRandomWebAttack()
{
// ボスの中央(地上座標)を基準に、ランダムな円内に糸を降らせる
Vector2 randomCircle = Random.insideUnitCircle * boss.attackRadius;
Vector3 targetGroundPos = new Vector3(
boss.groundAnchor.position.x + randomCircle.x,
boss.groundAnchor.position.y,
boss.groundAnchor.position.z + randomCircle.y
);
// 予兆を出し、1.0秒後に2.5秒間残る糸を生成する
boss.SpawnWarningAndWeb(targetGroundPos, 1.0f, 2.5f);
}
}
// ==========================================
// ■ STATE: STUN (チャンスタイム - パリィ成功時)
// ==========================================
public class SpiderStunState : ISpiderState
{
private BossController boss;
private float stunTimer;
public SpiderStunState(BossController owner) => boss = owner;
public void EnterState()
{
stunTimer = 4.0f; // 4秒間の完全な無防備状態チャンスタイム
boss.Anim.SetTrigger("StunStart");
boss.Anim.SetBool("IsStunned", true);
if (boss.Agent.enabled) boss.Agent.isStopped = true;
Debug.Log("🛡️ パリィ成功! 蜘蛛ボスがひっくり返ってスタン中! チャンスタイム!");
}
public void ExitState()
{
boss.Anim.SetBool("IsStunned", false);
if (boss.Agent.enabled) boss.Agent.isStopped = false;
}
public void UpdateState()
{
stunTimer -= Time.deltaTime;
if (stunTimer <= 0f)
{
// スンが明けたら、もしHPトリガーが裏で引かれていれば優先して天井へ
if (boss.PendingUltimate) boss.ChangeState<SpiderJumpToCeilingState>();
else boss.ChangeState<SpiderChaseState>();
}
}
}