いろいろやってみた
Playerが蜘蛛にめり込まないようにしたい
This commit is contained in:
200
Assets/_Scripts/BossController.cs
Normal file
200
Assets/_Scripts/BossController.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[RequireComponent(typeof(NavMeshAgent))]
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public class BossController : MonoBehaviour
|
||||
{
|
||||
#region インスペクター設定項目
|
||||
[Header("ステータス設定")]
|
||||
[SerializeField] private float maxHp = 500f;
|
||||
[SerializeField] private float currentHp = 500f;
|
||||
[SerializeField] public float chaseRange = 15f;
|
||||
[SerializeField] public float biteRange = 2.5f;
|
||||
|
||||
[Header("必殺技(天井)設定")]
|
||||
[Tooltip("天井の待機座標となる空のGameObjectのTransformを指定してください")]
|
||||
[SerializeField] public Transform ceilingAnchor;
|
||||
[Tooltip("地上に戻る際の、中央の着地座標のTransformを指定してください")]
|
||||
[SerializeField] public Transform groundAnchor;
|
||||
[Tooltip("天井から糸を発射する範囲の広さ")]
|
||||
[SerializeField] public float attackRadius = 10f;
|
||||
[Tooltip("糸が降る前の予兆マークのPrefab")]
|
||||
[SerializeField] private GameObject warningMarkerPrefab;
|
||||
[Tooltip("地面に残る糸(コライダー&鈍足スクリプト付き)のPrefab")]
|
||||
[SerializeField] private GameObject webPrefab;
|
||||
|
||||
[Header("突進(体当たり)設定")]
|
||||
[SerializeField] public float chargeSpeed = 14f;
|
||||
[SerializeField] public float chargeDuration = 2f;
|
||||
[SerializeField] public float chargeMinimumDistance = 6f;
|
||||
[SerializeField] public float chargeCooldownDuration = 4f;
|
||||
#endregion
|
||||
|
||||
#region コンポーネント・キャッシュ用(ステートからアクセス可能)
|
||||
[HideInInspector] public NavMeshAgent Agent { get; private set; }
|
||||
[HideInInspector] public Animator Anim { get; private set; }
|
||||
[HideInInspector] public Transform Player { get; private set; }
|
||||
public float ChargeCooldownTimer { get; private set; } = 0f;
|
||||
#endregion
|
||||
|
||||
#region FSM(状態管理)システム
|
||||
private ISpiderState currentState;
|
||||
|
||||
// ステートのインスタンスをキャッシュ(ガベージコレクションの発生を抑える)
|
||||
private Dictionary<System.Type, ISpiderState> stateCache;
|
||||
|
||||
// フェーズ管理用フラグ(50%と25%のトリガー管理)
|
||||
private bool triggered50 = false;
|
||||
private bool triggered25 = false;
|
||||
public bool PendingUltimate { get; set; } = false; // 必殺技の発動権があるか
|
||||
#endregion
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Agent = GetComponent<NavMeshAgent>();
|
||||
Anim = GetComponent<Animator>();
|
||||
|
||||
GameObject pObj = GameObject.FindGameObjectWithTag("Player");
|
||||
if (pObj != null) Player = pObj.transform;
|
||||
|
||||
InitializeFSM();
|
||||
}
|
||||
|
||||
private void InitializeFSM()
|
||||
{
|
||||
stateCache = new Dictionary<System.Type, ISpiderState>
|
||||
{
|
||||
{ typeof(SpiderIdleState), new SpiderIdleState(this) },
|
||||
{ typeof(SpiderChaseState), new SpiderChaseState(this) },
|
||||
{ typeof(SpiderBiteState), new SpiderBiteState(this) },
|
||||
{ typeof(SpiderChargeState), new SpiderChargeState(this) },
|
||||
{ typeof(SpiderJumpToCeilingState), new SpiderJumpToCeilingState(this) },
|
||||
{ typeof(SpiderCeilingAttackState), new SpiderCeilingAttackState(this) },
|
||||
{ typeof(SpiderStunState), new SpiderStunState(this) }
|
||||
};
|
||||
|
||||
// 初期ステートをIdleに設定
|
||||
ChangeState<SpiderIdleState>();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
currentState?.UpdateState();
|
||||
|
||||
// ★新設:突進のクールダウンのみ、通常のUpdateで常に独立して減算する
|
||||
if (ChargeCooldownTimer > 0f)
|
||||
{
|
||||
ChargeCooldownTimer -= Time.deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// オブジェクト指向に基づいた、型安全なステート遷移メソッド
|
||||
/// </summary>
|
||||
public void ChangeState<T>() where T : ISpiderState
|
||||
{
|
||||
if (currentState != null)
|
||||
{
|
||||
currentState.ExitState();
|
||||
Debug.Log($"🕷️ BossSpider [Exit]: {currentState.GetType().Name}");
|
||||
}
|
||||
|
||||
currentState = stateCache[typeof(T)];
|
||||
Debug.Log($"🕷️ BossSpider [Enter]: {currentState.GetType().Name}");
|
||||
currentState.EnterState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ダメージを受け取る外部窓口。HPトリガーによるフェーズ遷移をここで監視する
|
||||
/// </summary>
|
||||
public void TakeDamage(float damage)
|
||||
{
|
||||
currentHp -= damage;
|
||||
currentHp = Mathf.Clamp(currentHp, 0, maxHp);
|
||||
float hpPercentage = (currentHp / maxHp) * 100f;
|
||||
|
||||
Debug.Log($"💥 ボスに {damage} ダメージ。残りHP: {hpPercentage:F1}%");
|
||||
|
||||
// 25%以下カットのトリガー
|
||||
if (hpPercentage <= 25f && !triggered25)
|
||||
{
|
||||
triggered25 = true;
|
||||
PendingUltimate = true;
|
||||
TriggerPhaseTransition();
|
||||
}
|
||||
// 50%以下カットのトリガー
|
||||
else if (hpPercentage <= 50f && !triggered50 && hpPercentage > 25f)
|
||||
{
|
||||
triggered50 = true;
|
||||
PendingUltimate = true;
|
||||
TriggerPhaseTransition();
|
||||
}
|
||||
}
|
||||
|
||||
private void TriggerPhaseTransition()
|
||||
{
|
||||
// 咆哮、ジャンプ、スタン中以外であれば、現在の行動をキャンセルして即座に天井へエスケープ
|
||||
if (currentState is not SpiderJumpToCeilingState &&
|
||||
currentState is not SpiderCeilingAttackState &&
|
||||
currentState is not SpiderStunState)
|
||||
{
|
||||
ChangeState<SpiderJumpToCeilingState>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 【パリィ連携窓口】プレイヤーのVRInputPunchなどから、パリィ成功時にこのメソッドが叩かれる
|
||||
/// </summary>
|
||||
public void TriggerParryStun()
|
||||
{
|
||||
// パリィを受け付ける攻撃ステート(噛みつき、体当たり)のときのみスタンに移行する
|
||||
if (currentState is SpiderBiteState || currentState is SpiderChargeState)
|
||||
{
|
||||
ChangeState<SpiderStunState>();
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetChargeCooldown()
|
||||
{
|
||||
ChargeCooldownTimer = chargeCooldownDuration;
|
||||
}
|
||||
|
||||
#region ファクトリメソッド(エフェクトやオブジェクト生成の保守性を担保)
|
||||
public void SpawnWarningAndWeb(Vector3 targetGroundPos, float delay, float webDuration)
|
||||
{
|
||||
StartCoroutine(SpawnWebRoutine(targetGroundPos, delay, webDuration));
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator SpawnWebRoutine(Vector3 pos, float delay, float duration)
|
||||
{
|
||||
// 1. 地面に予兆マークを生成
|
||||
GameObject marker = null;
|
||||
if (warningMarkerPrefab != null)
|
||||
{
|
||||
marker = Instantiate(warningMarkerPrefab, pos + new Vector3(0, 0.02f, 0), Quaternion.identity);
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(delay);
|
||||
|
||||
// 2. 予兆マークを消し、本物の糸オブジェクトを生成
|
||||
if (marker != null) Destroy(marker);
|
||||
|
||||
if (webPrefab != null)
|
||||
{
|
||||
GameObject web = Instantiate(webPrefab, pos, Quaternion.identity);
|
||||
Destroy(web, duration); // 数秒後に自動消滅
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region 1. ステート共通インターフェース
|
||||
public interface ISpiderState
|
||||
{
|
||||
void EnterState();
|
||||
void UpdateState();
|
||||
void ExitState();
|
||||
}
|
||||
#endregion
|
||||
Reference in New Issue
Block a user