Files
VRProject/Assets/_Scripts/SpiderIdleState.cs
oogushiyuuga bb90c969b4 妥協案
慣性をゼロにして蜘蛛と重ならないようにする
2026-07-06 17:59:19 +09:00

342 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;
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;
// ★超重要:噛みつきモーションに入った瞬間、移動を「完全強制停止」してめり込みを防ぐ
boss.Agent.isStopped = true;
boss.Agent.velocity = Vector3.zero; // 慣性もゼロにする
boss.Anim.SetTrigger("Attack_Bite");
Debug.Log("🎯 蜘蛛ボス:噛みつき攻撃!(その場に完全固定)");
}
public void ExitState()
{
// ステートを出るときに停止ロックを解除する
boss.Agent.isStopped = false;
}
public void UpdateState()
{
stateTimer -= Time.deltaTime;
if (stateTimer <= 0f)
{
if (boss.PendingUltimate) boss.ChangeState<SpiderJumpToCeilingState>();
else boss.ChangeState<SpiderChaseState>();
}
}
}
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 = 1.5f; // 溜め(咆哮)時間
chargeTimer = boss.chargeDuration;
isChargingPhase = false;
// ★重要突進の溜め中は、NavMeshAgentの自動移動を「一時停止」にしてその場に固定する
boss.Agent.isStopped = true;
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;
}
public void UpdateState()
{
// ─── フェーズ1咆哮・溜めロックオンその場で旋回のみ ───
if (!isChargingPhase)
{
roarTimer -= Time.deltaTime;
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);
// 1. 発射する直線ベクトルを確定
if (boss.Player != null)
{
chargeDirection = (boss.Player.position - boss.transform.position).normalized;
chargeDirection.y = 0;
}
// 2. ★プロの技:ボスの正面方向の「遥か彼方(例: 20m先」に、突進の目的地座標を計算
Vector3 targetDestination = boss.transform.position + chargeDirection * 20f;
// 3. ★移動をNavMeshAgentに一任する超高速化
boss.Agent.isStopped = false; // 移動再開
boss.Agent.speed = boss.chargeSpeed; // スピードを全速力14fなど
boss.Agent.acceleration = 120f; // 即座に最高速に達するように加速を爆上げする
// 目的地を設定NavMeshの壁やプレイヤーのCharacterControllerを考慮して自動で進むようになる
boss.Agent.SetDestination(targetDestination);
Debug.Log("🚀 蜘蛛ボスNavMesh突進ダッシュ発射");
}
return;
}
// ─── フェーズ2突進中NavMeshAgentが自動で走っているので、スクリプト側はタイマーを監視するだけ ───
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>();
}
}
}