HPbarzissou
This commit is contained in:
@@ -1,44 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class BossDebugController : MonoBehaviour
|
||||
{
|
||||
private BossController bossController;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// 同一オブジェクトにあるBossControllerを自動取得
|
||||
bossController = GetComponent<BossController>();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// ─── ★キーボードの『U(Ultimate)』キーを押したら強制発動 ───
|
||||
if (Input.GetKeyDown(KeyCode.U))
|
||||
{
|
||||
TriggerDebugUltimate();
|
||||
}
|
||||
|
||||
// ─── ついでにあると便利な機能:『S(Stun)』キーで即座にパリィスタン ───
|
||||
if (Input.GetKeyDown(KeyCode.S))
|
||||
{
|
||||
TriggerDebugStun();
|
||||
}
|
||||
}
|
||||
|
||||
private void TriggerDebugUltimate()
|
||||
{
|
||||
if (bossController == null) return;
|
||||
|
||||
Debug.Log("🛠️ 【キーボードデバッグ】強制的に必殺技(天井ジャンプ)を発動します。");
|
||||
bossController.PendingUltimate = true;
|
||||
bossController.ChangeState<SpiderJumpToCeilingState>();
|
||||
}
|
||||
|
||||
private void TriggerDebugStun()
|
||||
{
|
||||
if (bossController == null) return;
|
||||
|
||||
Debug.Log("🛡️ 【キーボードデバッグ】強制的にパリィスタン(チャンスタイム)を発動します。");
|
||||
bossController.ChangeState<SpiderStunState>();
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2cd755b0c100204e833df85acb412e8
|
||||
@@ -49,6 +49,9 @@ public class BuffHandler
|
||||
|
||||
private void ExecuteHeal()
|
||||
{
|
||||
Debug.Log($"💚 HP回復バフ発動:回復量 {hpHealAmount}");
|
||||
if (PlayerStatusManager.Instance != null)
|
||||
{
|
||||
PlayerStatusManager.Instance.Heal(hpHealAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ public class EnemyAI : MonoBehaviour, IPauseable
|
||||
|
||||
[Header("攻撃設定")]
|
||||
[SerializeField] private float attackRange = 1.5f;
|
||||
[SerializeField] private float attackDamage = 10f;
|
||||
[SerializeField] private float attackCooldown = 2.0f;
|
||||
[SerializeField] private float telegraphDuration = 0.6f;
|
||||
[SerializeField] private Collider rightHandCollider;
|
||||
|
||||
25
Assets/_Scripts/EnemyDamageHitBox.cs
Normal file
25
Assets/_Scripts/EnemyDamageHitBox.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(Collider))]
|
||||
public class EnemyDamageHitbox : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private float damageAmount = 15f;
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (other.CompareTag("Player"))
|
||||
{
|
||||
IDamageable player = other.GetComponentInParent<IDamageable>();
|
||||
if (player != null)
|
||||
{
|
||||
DamageInfo info = new DamageInfo
|
||||
{
|
||||
amount = damageAmount,
|
||||
hitPosition = transform.position,
|
||||
punchDirection = transform.forward
|
||||
};
|
||||
player.TakeDamage(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/_Scripts/EnemyDamageHitBox.cs.meta
Normal file
2
Assets/_Scripts/EnemyDamageHitBox.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc0e815d758adf14f92abc78ef490f4b
|
||||
@@ -7,8 +7,10 @@ public class EnemyHealth : MonoBehaviour, IDamageable
|
||||
[SerializeField] private float knockbackDuration = 0.5f;
|
||||
|
||||
public float CurrentHealth { get; private set; }
|
||||
public float MaxHealth => maxHealth;
|
||||
public bool IsDead { get; private set; }
|
||||
|
||||
public event Action<float, float> OnHealthChanged; // ★追加:HP変更イベント(現在HP, 最大HP)
|
||||
public event Action<float> OnKnockbackRequested;
|
||||
public event Action OnDeath;
|
||||
|
||||
@@ -26,6 +28,11 @@ public class EnemyHealth : MonoBehaviour, IDamageable
|
||||
col = GetComponent<Collider>();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
OnHealthChanged?.Invoke(CurrentHealth, maxHealth);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (enemyAI != null)
|
||||
@@ -49,6 +56,7 @@ public class EnemyHealth : MonoBehaviour, IDamageable
|
||||
if (IsDead) return;
|
||||
|
||||
CurrentHealth = Mathf.Max(0f, CurrentHealth - damageInfo.amount);
|
||||
OnHealthChanged?.Invoke(CurrentHealth, maxHealth); // ★HP変更をUIに通知
|
||||
|
||||
if (CurrentHealth <= 0f)
|
||||
{
|
||||
|
||||
74
Assets/_Scripts/EnemyHealthBar.cs
Normal file
74
Assets/_Scripts/EnemyHealthBar.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class EnemyHealthBar : MonoBehaviour
|
||||
{
|
||||
[Header("UI設定")]
|
||||
[SerializeField] private Slider hpSlider;
|
||||
[SerializeField] private EnemyHealth targetEnemyHealth;
|
||||
|
||||
[Header("追従設定")]
|
||||
[Tooltip("敵の原点から頭上へどれだけ浮かせるか(メートル)")]
|
||||
[SerializeField] private Vector3 offset = new Vector3(0, 2.0f, 0);
|
||||
|
||||
private Transform targetTransform;
|
||||
private Transform mainCameraTransform;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// ターゲットのEnemyHealthを自動検索
|
||||
if (targetEnemyHealth == null)
|
||||
{
|
||||
targetEnemyHealth = GetComponentInParent<EnemyHealth>();
|
||||
}
|
||||
|
||||
if (targetEnemyHealth != null)
|
||||
{
|
||||
targetTransform = targetEnemyHealth.transform;
|
||||
targetEnemyHealth.OnHealthChanged += UpdateHp;
|
||||
targetEnemyHealth.OnDeath += HandleDeath;
|
||||
|
||||
UpdateHp(targetEnemyHealth.CurrentHealth, targetEnemyHealth.MaxHealth);
|
||||
}
|
||||
|
||||
if (Camera.main != null)
|
||||
{
|
||||
mainCameraTransform = Camera.main.transform;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (targetEnemyHealth != null)
|
||||
{
|
||||
targetEnemyHealth.OnHealthChanged -= UpdateHp;
|
||||
targetEnemyHealth.OnDeath -= HandleDeath;
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (targetTransform == null || mainCameraTransform == null) return;
|
||||
|
||||
// 1. 敵の頭上に位置を追従
|
||||
transform.position = targetTransform.position + offset;
|
||||
|
||||
// 2. 常にカメラの向きへ正対(ビルボード処理:鏡像反転を防ぐためカメラの向きと平行にする)
|
||||
transform.forward = mainCameraTransform.forward;
|
||||
}
|
||||
|
||||
private void UpdateHp(float current, float max)
|
||||
{
|
||||
if (hpSlider != null)
|
||||
{
|
||||
hpSlider.maxValue = max;
|
||||
hpSlider.value = current;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDeath()
|
||||
{
|
||||
// 敵が死んだらバーを即座に非表示
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
2
Assets/_Scripts/EnemyHealthBar.cs.meta
Normal file
2
Assets/_Scripts/EnemyHealthBar.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1443ed714a8be8b47a421694985d521a
|
||||
@@ -1,58 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public class InputManagerLR : MonoBehaviour
|
||||
{
|
||||
private static InputManagerLR instance;
|
||||
|
||||
[SerializeField] private InputActionAsset actionAsset;
|
||||
|
||||
private InputActionMap actionMap;
|
||||
private InputAction primaryButtonR;
|
||||
private InputAction secondaryButtonR;
|
||||
private InputAction primaryButtonL;
|
||||
private InputAction secondaryButtonL;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (instance != null && instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
|
||||
if (actionAsset != null)
|
||||
{
|
||||
actionMap = actionAsset.FindActionMap("Test");
|
||||
if (actionMap != null)
|
||||
{
|
||||
primaryButtonR = actionMap.FindAction("XR_PrimaryButtonR", throwIfNotFound: false);
|
||||
primaryButtonL = actionMap.FindAction("XR_PrimaryButtonL", throwIfNotFound: false);
|
||||
secondaryButtonR = actionMap.FindAction("XR_SecondaryButtonR", throwIfNotFound: false);
|
||||
secondaryButtonL = actionMap.FindAction("XR_SecondaryButtonL", throwIfNotFound: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable() => actionMap?.Enable();
|
||||
private void OnDisable() => actionMap?.Disable();
|
||||
|
||||
public static bool PrimaryButtonR() => instance?.primaryButtonR?.IsPressed() ?? false;
|
||||
public static bool PrimaryButtonR_OnPress() => instance?.primaryButtonR?.WasPressedThisFrame() ?? false;
|
||||
public static bool PrimaryButtonR_OnRelease() => instance?.primaryButtonR?.WasReleasedThisFrame() ?? false;
|
||||
|
||||
public static bool PrimaryButtonL() => instance?.primaryButtonL?.IsPressed() ?? false;
|
||||
public static bool PrimaryButtonL_OnPress() => instance?.primaryButtonL?.WasPressedThisFrame() ?? false;
|
||||
public static bool PrimaryButtonL_OnRelease() => instance?.primaryButtonL?.WasReleasedThisFrame() ?? false;
|
||||
|
||||
public static bool SecondaryButtonR() => instance?.secondaryButtonR?.IsPressed() ?? false;
|
||||
public static bool SecondaryButtonR_OnPress() => instance?.secondaryButtonR?.WasPressedThisFrame() ?? false;
|
||||
public static bool SecondaryButtonR_OnRelease() => instance?.secondaryButtonR?.WasReleasedThisFrame() ?? false;
|
||||
|
||||
public static bool SecondaryButtonL() => instance?.secondaryButtonL?.IsPressed() ?? false;
|
||||
public static bool SecondaryButtonL_OnPress() => instance?.secondaryButtonL?.WasPressedThisFrame() ?? false;
|
||||
public static bool SecondaryButtonL_OnRelease() => instance?.secondaryButtonL?.WasReleasedThisFrame() ?? false;
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5fc595679af414674be369cd3d5bc765
|
||||
@@ -1,62 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class ItemCountDown : MonoBehaviour
|
||||
{
|
||||
|
||||
public GameObject gameObjectRestore; //ゲームオブフェクトの復帰する座標を指定する
|
||||
|
||||
private bool isGrabbed = false;
|
||||
private bool isTouching = false;
|
||||
|
||||
public float grabItemTimeLimit = 5.0f; //ゲームオブジェクトの位置がリセットされるまでのタイマー
|
||||
private float timer; //スクリプト内のタイマーに用いる変数
|
||||
|
||||
void Start()
|
||||
{
|
||||
timer = 0.0f;
|
||||
}
|
||||
|
||||
public void GetGrab()
|
||||
{
|
||||
isGrabbed = true;
|
||||
isTouching = true;
|
||||
}
|
||||
|
||||
public void ExitGrab()
|
||||
{
|
||||
isTouching = false;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
//制限時間が0秒の場合は、位置のリセットを実行しない
|
||||
if (grabItemTimeLimit != 0)
|
||||
{
|
||||
if (isGrabbed == true)
|
||||
{
|
||||
if (isTouching == false)
|
||||
{
|
||||
timer += Time.deltaTime;
|
||||
|
||||
if (timer > grabItemTimeLimit)
|
||||
{
|
||||
//ゲームオブジェクトの速度をリセット
|
||||
var rigidbody = GetComponent<Rigidbody>();
|
||||
rigidbody.linearVelocity = Vector3.zero;
|
||||
//ゲームオブジェクトを指定位置に配置する
|
||||
rigidbody.transform.position = gameObjectRestore.transform.position;
|
||||
rigidbody.transform.rotation = gameObjectRestore.transform.rotation;
|
||||
//ゲームオブジェクトは不動の状態に戻る
|
||||
isGrabbed = false;
|
||||
timer = 0.0f;
|
||||
}
|
||||
}
|
||||
//プレイヤーが触っている場合はカウントダウンをリセット
|
||||
else
|
||||
{
|
||||
timer = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45dd4c486e2a64ef5a8f38d756b9dc2d
|
||||
64
Assets/_Scripts/PlayerHUD.cs
Normal file
64
Assets/_Scripts/PlayerHUD.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class PlayerHUD : MonoBehaviour
|
||||
{
|
||||
[Header("HP表示設定")]
|
||||
[SerializeField] private Slider hpSlider;
|
||||
[SerializeField] private Text hpText;
|
||||
|
||||
[Header("Codingゲージ表示設定")]
|
||||
[SerializeField] private Slider gaugeSlider;
|
||||
[SerializeField] private Text gaugeText;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (PlayerStatusManager.Instance != null)
|
||||
{
|
||||
// 初期値の反映
|
||||
UpdateHpUI(PlayerStatusManager.Instance.CurrentHp, PlayerStatusManager.Instance.MaxHp);
|
||||
UpdateGaugeUI(PlayerStatusManager.Instance.CurrentGauge, PlayerStatusManager.Instance.MaxGauge);
|
||||
|
||||
// イベントの購読
|
||||
PlayerStatusManager.Instance.OnHpChanged += UpdateHpUI;
|
||||
PlayerStatusManager.Instance.OnGaugeChanged += UpdateGaugeUI;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (PlayerStatusManager.Instance != null)
|
||||
{
|
||||
PlayerStatusManager.Instance.OnHpChanged -= UpdateHpUI;
|
||||
PlayerStatusManager.Instance.OnGaugeChanged -= UpdateGaugeUI;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateHpUI(float current, float max)
|
||||
{
|
||||
if (hpSlider != null)
|
||||
{
|
||||
hpSlider.maxValue = max;
|
||||
hpSlider.value = current;
|
||||
}
|
||||
|
||||
if (hpText != null)
|
||||
{
|
||||
hpText.text = $"HP: {Mathf.CeilToInt(current)} / {Mathf.CeilToInt(max)}";
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateGaugeUI(float current, float max)
|
||||
{
|
||||
if (gaugeSlider != null)
|
||||
{
|
||||
gaugeSlider.maxValue = max;
|
||||
gaugeSlider.value = current;
|
||||
}
|
||||
|
||||
if (gaugeText != null)
|
||||
{
|
||||
gaugeText.text = $"GAUGE: {Mathf.FloorToInt(current)}%";
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/_Scripts/PlayerHUD.cs.meta
Normal file
2
Assets/_Scripts/PlayerHUD.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00f8d88793224ea4a8c6af33c944a675
|
||||
@@ -1,39 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class PlayerMove : MonoBehaviour
|
||||
{
|
||||
// パラメータ
|
||||
public float moveSpeed = 5f; // 移動速度
|
||||
public float gravity = -9.8f; // 重力加速度
|
||||
public CharacterController controller; // 移動に使うCharacterController
|
||||
|
||||
// 演算用変数
|
||||
private Vector3 velocity; // 加速度を保持する変数
|
||||
private bool isGrounded; // 地面に着地しているかどうかのフラグ変数
|
||||
|
||||
// ゲーム中実行されるUpdate関数
|
||||
void Update()
|
||||
{
|
||||
// 着地状態のチェック
|
||||
isGrounded = controller.isGrounded;
|
||||
|
||||
// 着地している場合は落下速度をリセット
|
||||
if (isGrounded && velocity.y < 0)
|
||||
{
|
||||
velocity.y = -2f; // 地面に着いた場合、速度をリセット
|
||||
}
|
||||
|
||||
// 入力の取得
|
||||
float h = Input.GetAxis("Horizontal");
|
||||
float v = Input.GetAxis("Vertical");
|
||||
|
||||
// ローカル座標をワールド座標に変換して移動方向を計算
|
||||
Vector3 moveDirection = transform.TransformDirection(new Vector3(h, 0, v)) * moveSpeed;
|
||||
|
||||
// 重力を加算
|
||||
velocity.y += gravity * Time.deltaTime;
|
||||
|
||||
// 移動と重力を一度のcontroller.Moveで処理
|
||||
controller.Move((moveDirection + velocity) * Time.deltaTime);
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c101f16cf16d4195ba45ae89a7f14d8
|
||||
@@ -1,37 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class PlayerPOV : MonoBehaviour
|
||||
{
|
||||
// パラメータ
|
||||
public Transform neck; // プレイヤーの首のTransformを指定
|
||||
public float sensitivity = 2.0f; // マウス感度(視点の移動の速さを調整)
|
||||
public float minVertical = -90.0f; // 視点の最小角度(縦の回転制限)
|
||||
public float maxVertical = 90.0f; // 視点の最大角度(縦の回転制限)
|
||||
|
||||
// 演算用変数
|
||||
private float rotationX = 0f; // 縦方向の回転角度(首の回転)
|
||||
|
||||
// ゲーム開始時に呼ばれる
|
||||
void Start()
|
||||
{
|
||||
// カーソルを非表示&ロック
|
||||
Cursor.lockState = CursorLockMode.Locked; // カーソルを画面中央に固定
|
||||
Cursor.visible = false; // カーソルを非表示にする
|
||||
}
|
||||
|
||||
// 毎フレーム実行される
|
||||
void Update()
|
||||
{
|
||||
// マウス入力の取得
|
||||
float mouseX = Input.GetAxis("Mouse X") * sensitivity; // 横のマウス移動量を取得し、感度で調整
|
||||
float mouseY = Input.GetAxis("Mouse Y") * sensitivity; // 縦のマウス移動量を取得し、感度で調整
|
||||
|
||||
// Player(体)の回転(左右)
|
||||
transform.Rotate(0, mouseX, 0); // プレイヤー(体)の左右の回転をマウスX方向の入力に合わせて行う
|
||||
|
||||
// Neck(首)の回転(上下)
|
||||
rotationX -= mouseY; // マウスY方向の入力によって縦方向の回転を更新
|
||||
rotationX = Mathf.Clamp(rotationX, minVertical, maxVertical); // 回転角度を指定された範囲に制限
|
||||
neck.localRotation = Quaternion.Euler(rotationX, 0, 0); // 首の回転を設定。縦方向のみ回転させる
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20e0bce59a58a401ca841697d32fb339
|
||||
@@ -1,10 +1,20 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.XR;
|
||||
|
||||
public class PlayerStatusManager : MonoBehaviour
|
||||
public class PlayerStatusManager : MonoBehaviour, IDamageable
|
||||
{
|
||||
public static PlayerStatusManager Instance { get; private set; }
|
||||
|
||||
[Header("HP・ステータス設定")]
|
||||
[SerializeField] private float maxHp = 100f;
|
||||
[SerializeField] private float currentHp = 100f;
|
||||
[Tooltip("被ダメージ後の無敵時間(秒)")]
|
||||
[SerializeField] private float invincibilityDuration = 0.8f;
|
||||
|
||||
[Header("デバッグ設定")]
|
||||
[SerializeField] private bool ignoreGaugeForDebug = true;
|
||||
|
||||
@@ -30,30 +40,30 @@ public class PlayerStatusManager : MonoBehaviour
|
||||
[SerializeField] private BuffHandler buffHandler = new BuffHandler();
|
||||
|
||||
private float codingTimer;
|
||||
private bool isInvincible;
|
||||
|
||||
public bool IsCodingMode { get; private set; }
|
||||
public bool IsDead { get; private set; }
|
||||
public float CurrentHp => currentHp;
|
||||
public float MaxHp => maxHp;
|
||||
public float CurrentGauge => currentGauge;
|
||||
public float MaxGauge => maxGauge;
|
||||
public BuffHandler Buffs => buffHandler;
|
||||
|
||||
public event Action<float, float> OnHpChanged;
|
||||
public event Action<float, float> OnGaugeChanged;
|
||||
public event Action OnDeath;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
if (Instance == null) Instance = this;
|
||||
else Destroy(gameObject);
|
||||
|
||||
currentHp = maxHp;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
SetActionsEnabled(true);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
SetActionsEnabled(false);
|
||||
}
|
||||
private void OnEnable() => SetActionsEnabled(true);
|
||||
private void OnDisable() => SetActionsEnabled(false);
|
||||
|
||||
private void SetActionsEnabled(bool enable)
|
||||
{
|
||||
@@ -73,10 +83,14 @@ public class PlayerStatusManager : MonoBehaviour
|
||||
private void Start()
|
||||
{
|
||||
if (codingModeUI != null) codingModeUI.SetActive(false);
|
||||
OnHpChanged?.Invoke(currentHp, maxHp);
|
||||
OnGaugeChanged?.Invoke(currentGauge, maxGauge);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (IsDead) return;
|
||||
|
||||
CheckComboInput();
|
||||
|
||||
if (!IsCodingMode)
|
||||
@@ -95,8 +109,85 @@ public class PlayerStatusManager : MonoBehaviour
|
||||
|
||||
public void AddGauge(float amount)
|
||||
{
|
||||
if (IsCodingMode) return;
|
||||
if (IsCodingMode || IsDead) return;
|
||||
currentGauge = Mathf.Clamp(currentGauge + amount, 0f, maxGauge);
|
||||
OnGaugeChanged?.Invoke(currentGauge, maxGauge);
|
||||
}
|
||||
|
||||
public void TakeDamage(DamageInfo damageInfo)
|
||||
{
|
||||
if (IsDead || isInvincible || IsCodingMode) return;
|
||||
|
||||
// 防御バフ適用(倍率を掛けて被ダメージを軽減)
|
||||
float finalDamage = damageInfo.amount * buffHandler.CurrentDefenseMultiplier;
|
||||
currentHp = Mathf.Max(0f, currentHp - finalDamage);
|
||||
|
||||
OnHpChanged?.Invoke(currentHp, maxHp);
|
||||
Debug.Log($"💥 プレイヤー被ダメージ: {finalDamage:F1} (残HP: {currentHp:F1} / {maxHp})");
|
||||
|
||||
// コントローラーへの被弾振動フィードバック
|
||||
TriggerDamageHaptics(0.6f, 0.15f);
|
||||
|
||||
if (currentHp <= 0f)
|
||||
{
|
||||
Die();
|
||||
}
|
||||
else
|
||||
{
|
||||
StartCoroutine(InvincibilityRoutine());
|
||||
}
|
||||
}
|
||||
|
||||
public void Heal(float amount)
|
||||
{
|
||||
if (IsDead) return;
|
||||
currentHp = Mathf.Min(maxHp, currentHp + amount);
|
||||
OnHpChanged?.Invoke(currentHp, maxHp);
|
||||
Debug.Log($"💚 HP回復: +{amount} (現在HP: {currentHp} / {maxHp})");
|
||||
}
|
||||
|
||||
private IEnumerator InvincibilityRoutine()
|
||||
{
|
||||
isInvincible = true;
|
||||
yield return new WaitForSeconds(invincibilityDuration);
|
||||
isInvincible = false;
|
||||
}
|
||||
|
||||
private void Die()
|
||||
{
|
||||
if (IsDead) return;
|
||||
IsDead = true;
|
||||
|
||||
Debug.LogError("☠️ プレイヤー死亡:GAME OVER");
|
||||
OnDeath?.Invoke();
|
||||
|
||||
SetActionsEnabled(false);
|
||||
if (WorldPauseManager.Instance != null)
|
||||
{
|
||||
WorldPauseManager.Instance.PauseWorld();
|
||||
}
|
||||
|
||||
// 死亡後、2秒待って現在のシーンをリロード(再開)
|
||||
StartCoroutine(GameOverRestartRoutine());
|
||||
}
|
||||
|
||||
private IEnumerator GameOverRestartRoutine()
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(2.5f);
|
||||
if (WorldPauseManager.Instance != null)
|
||||
{
|
||||
WorldPauseManager.Instance.ResumeWorld();
|
||||
}
|
||||
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
|
||||
}
|
||||
|
||||
private void TriggerDamageHaptics(float amplitude, float duration)
|
||||
{
|
||||
UnityEngine.XR.InputDevice left = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand);
|
||||
if (left.isValid) left.SendHapticImpulse(0, amplitude, duration);
|
||||
|
||||
UnityEngine.XR.InputDevice right = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
|
||||
if (right.isValid) right.SendHapticImpulse(0, amplitude, duration);
|
||||
}
|
||||
|
||||
private void CheckComboInput()
|
||||
@@ -131,7 +222,7 @@ public class PlayerStatusManager : MonoBehaviour
|
||||
SetActionState(turnAction, false);
|
||||
|
||||
PuzzleBlock.ResetAllBlocksInScene();
|
||||
|
||||
|
||||
if (WorldPauseManager.Instance != null)
|
||||
{
|
||||
WorldPauseManager.Instance.PauseWorld();
|
||||
@@ -140,15 +231,15 @@ public class PlayerStatusManager : MonoBehaviour
|
||||
if (codingModeUI != null) codingModeUI.SetActive(true);
|
||||
}
|
||||
|
||||
public void ApplyBuffsAndResume(BuffType buff1, BuffType buff2)
|
||||
// PlayerStatusManager.cs
|
||||
public void ApplyBuffAndResume(BuffType buff)
|
||||
{
|
||||
if (successEffectPrefab != null && effectSpawnPoint != null)
|
||||
{
|
||||
Instantiate(successEffectPrefab, effectSpawnPoint.position, effectSpawnPoint.rotation);
|
||||
}
|
||||
|
||||
buffHandler.ActivateBuff(buff1);
|
||||
buffHandler.ActivateBuff(buff2);
|
||||
buffHandler.ActivateBuff(buff);
|
||||
ResumeWorldState(consumeGauge: true);
|
||||
}
|
||||
|
||||
@@ -165,8 +256,14 @@ public class PlayerStatusManager : MonoBehaviour
|
||||
SetActionState(moveAction, true);
|
||||
SetActionState(turnAction, true);
|
||||
|
||||
PuzzleBlock.ResetAllBlocksInScene();
|
||||
|
||||
IsCodingMode = false;
|
||||
if (codingModeUI != null) codingModeUI.SetActive(false);
|
||||
if (consumeGauge) currentGauge = 0f;
|
||||
if (consumeGauge)
|
||||
{
|
||||
currentGauge = 0f;
|
||||
OnGaugeChanged?.Invoke(currentGauge, maxGauge);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,16 @@ public class PuzzleBlock : MonoBehaviour
|
||||
private PuzzleBlock nearbyPartner;
|
||||
private bool isConnected;
|
||||
|
||||
// ★ワールド情報ではなく「親階層」と「ローカル情報」を記憶
|
||||
// 親階層とローカル情報の記憶
|
||||
private Transform initialParent;
|
||||
private Vector3 initialLocalPosition;
|
||||
private Quaternion initialLocalRotation;
|
||||
private Vector3 initialLocalScale;
|
||||
|
||||
// ★追加:初期の物理設定を記憶
|
||||
private bool initialIsKinematic;
|
||||
private bool initialUseGravity;
|
||||
|
||||
private Rigidbody rb;
|
||||
private XRGrabInteractable grabInteractable;
|
||||
|
||||
@@ -35,11 +39,17 @@ public class PuzzleBlock : MonoBehaviour
|
||||
rb = GetComponent<Rigidbody>();
|
||||
grabInteractable = GetComponent<XRGrabInteractable>();
|
||||
|
||||
// ★開始時の「親」と「ローカル座標・回転・スケール」を保持
|
||||
initialParent = transform.parent;
|
||||
initialLocalPosition = transform.localPosition;
|
||||
initialLocalRotation = transform.localRotation;
|
||||
initialLocalScale = transform.localScale;
|
||||
|
||||
// ★初期状態の重力・キネマティック設定を保持
|
||||
if (rb != null)
|
||||
{
|
||||
initialIsKinematic = rb.isKinematic;
|
||||
initialUseGravity = rb.useGravity;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
@@ -109,10 +119,11 @@ public class PuzzleBlock : MonoBehaviour
|
||||
|
||||
OnPuzzleCompleted?.Invoke(Color);
|
||||
|
||||
// PuzzleBlock.cs
|
||||
BuffType buff = ConvertColorToBuffType(Color);
|
||||
if (PlayerStatusManager.Instance != null)
|
||||
{
|
||||
PlayerStatusManager.Instance.ApplyBuffsAndResume(buff, buff);
|
||||
PlayerStatusManager.Instance.ApplyBuffAndResume(buff);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,32 +140,29 @@ public class PuzzleBlock : MonoBehaviour
|
||||
|
||||
public void ResetBlock()
|
||||
{
|
||||
// 1. 手で掴んでいる場合は手離し処理
|
||||
ForceDrop();
|
||||
|
||||
isConnected = false;
|
||||
nearbyPartner = null;
|
||||
|
||||
// 2. ★親オブジェクト(Canvas)の子へ戻す
|
||||
if (initialParent != null && transform.parent != initialParent)
|
||||
{
|
||||
transform.SetParent(initialParent, false);
|
||||
}
|
||||
|
||||
// 3. ★Canvas内のローカル位置・回転・スケールを完全復元
|
||||
transform.localPosition = initialLocalPosition;
|
||||
transform.localRotation = initialLocalRotation;
|
||||
transform.localScale = initialLocalScale;
|
||||
|
||||
// 4. 物理状態の再初期化
|
||||
// ★修正:初期設定(記憶した値)へ正確に復元
|
||||
if (rb != null)
|
||||
{
|
||||
rb.isKinematic = false;
|
||||
rb.linearVelocity = Vector3.zero;
|
||||
rb.angularVelocity = Vector3.zero;
|
||||
rb.isKinematic = initialIsKinematic;
|
||||
rb.useGravity = initialUseGravity;
|
||||
}
|
||||
|
||||
// 5. 掴み機能の再有効化
|
||||
if (grabInteractable != null)
|
||||
{
|
||||
grabInteractable.enabled = true;
|
||||
|
||||
@@ -1,30 +1,82 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class TitleManager : MonoBehaviour
|
||||
{
|
||||
[Header("UI Buttons")]
|
||||
[Header("VR入力設定")]
|
||||
[Tooltip("スタート用の右手トリガー入力(例: XRI RightHand Interaction/Activate など)")]
|
||||
[SerializeField] private InputActionProperty rightTriggerAction;
|
||||
[Tooltip("スタート用の左手トリガー入力(任意)")]
|
||||
[SerializeField] private InputActionProperty leftTriggerAction;
|
||||
|
||||
[Header("UI Buttons(任意)")]
|
||||
[SerializeField] private Button startButton;
|
||||
[SerializeField] private Button exitButton;
|
||||
|
||||
[Header("Scene Settings")]
|
||||
[SerializeField] private string mainGameSceneName = "MainGameScene";
|
||||
|
||||
private bool isStarting = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (startButton != null) startButton.onClick.AddListener(OnStartButtonClicked);
|
||||
if (startButton != null) startButton.onClick.AddListener(StartGame);
|
||||
if (exitButton != null) exitButton.onClick.AddListener(OnExitButtonClicked);
|
||||
}
|
||||
|
||||
private void OnStartButtonClicked()
|
||||
private void OnEnable()
|
||||
{
|
||||
EnableAction(rightTriggerAction);
|
||||
EnableAction(leftTriggerAction);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
DisableAction(rightTriggerAction);
|
||||
DisableAction(leftTriggerAction);
|
||||
}
|
||||
|
||||
private void EnableAction(InputActionProperty prop)
|
||||
{
|
||||
if (prop.action != null) prop.action.Enable();
|
||||
}
|
||||
|
||||
private void DisableAction(InputActionProperty prop)
|
||||
{
|
||||
if (prop.action != null) prop.action.Disable();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (isStarting) return;
|
||||
|
||||
// トリガー入力の判定(右手または左手)
|
||||
if (IsTriggerPressed(rightTriggerAction) || IsTriggerPressed(leftTriggerAction))
|
||||
{
|
||||
StartGame();
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsTriggerPressed(InputActionProperty prop)
|
||||
{
|
||||
if (prop.action == null) return false;
|
||||
return prop.action.triggered || prop.action.ReadValue<float>() > 0.5f;
|
||||
}
|
||||
|
||||
public void StartGame()
|
||||
{
|
||||
if (isStarting) return;
|
||||
isStarting = true;
|
||||
|
||||
if (startButton != null) startButton.interactable = false;
|
||||
Debug.Log("🚀 トリガー入力を検知:メインゲームシーンを読み込みます。");
|
||||
StartCoroutine(LoadSceneRoutine());
|
||||
}
|
||||
|
||||
private void OnExitButtonClicked()
|
||||
public void OnExitButtonClicked()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorApplication.isPlaying = false;
|
||||
|
||||
Reference in New Issue
Block a user