130 lines
5.4 KiB
C#
130 lines
5.4 KiB
C#
using UnityEngine;
|
||
using UnityEngine.SceneManagement;
|
||
using UnityEngine.UI;
|
||
using UnityEngine.XR; // 振動機能のために必要
|
||
using System.Collections;
|
||
|
||
public class ElevatorSceneTransition : MonoBehaviour
|
||
{
|
||
[Header("遷移先の設定")]
|
||
[SerializeField] private string bossSceneName = "BossStage";
|
||
[SerializeField] private string playerTag = "Player";
|
||
|
||
[Header("ローディングUI設定")]
|
||
[SerializeField] private GameObject loadingCanvas;
|
||
[SerializeField] private Text progressText;
|
||
[SerializeField] private Slider progressSlider;
|
||
|
||
// ─── ★ここから下降演出用の設定項目を追加 ───
|
||
[Header("エレベーター下降演出設定")]
|
||
[Tooltip("エレベーターの部屋(壁や床、UIすべて)をまとめている一番親のTransformを指定してください")]
|
||
[SerializeField] private Transform elevatorCageTransform;
|
||
|
||
[Tooltip("ガタガタ揺れる激しさ(ミリ単位。0.01~0.03あたりがVR酔いしにくく自然です)")]
|
||
[SerializeField] private float shakeMagnitude = 0.015f;
|
||
|
||
[Tooltip("下降中のコントローラーの振動の強さ(0.0 ~ 1.0)")]
|
||
[SerializeField] private float hapticAmplitude = 0.15f;
|
||
// ─────────────────────────────────────────
|
||
|
||
private bool isLoadingStarted = false;
|
||
private Vector3 originalCagePosition; // 揺らす前のエレベーターの初期位置を記憶する用
|
||
|
||
private void Start()
|
||
{
|
||
if (loadingCanvas != null)
|
||
{
|
||
loadingCanvas.SetActive(false);
|
||
}
|
||
|
||
// 部屋の初期位置を保存
|
||
if (elevatorCageTransform != null)
|
||
{
|
||
originalCagePosition = elevatorCageTransform.localPosition;
|
||
}
|
||
}
|
||
|
||
private void OnTriggerEnter(Collider other)
|
||
{
|
||
if (isLoadingStarted) return;
|
||
|
||
if (other.CompareTag(playerTag))
|
||
{
|
||
isLoadingStarted = true;
|
||
Debug.Log("🛗 プレイヤー乗車:下降演出と非同期ロードを開始します。");
|
||
StartCoroutine(LoadSceneAsyncRoutine());
|
||
}
|
||
}
|
||
|
||
private IEnumerator LoadSceneAsyncRoutine()
|
||
{
|
||
if (loadingCanvas != null) loadingCanvas.SetActive(true);
|
||
|
||
// 次のシーンの非同期ロードを開始(画面切り替えはまだロックする)
|
||
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(bossSceneName);
|
||
asyncLoad.allowSceneActivation = false;
|
||
|
||
// コントローラーの振動のタイミングを計るためのタイマー
|
||
float hapticTimer = 0f;
|
||
|
||
// ロード中(progressが0.9未満の間)、ずっとループして演出を実行
|
||
while (asyncLoad.progress < 0.9f)
|
||
{
|
||
// 1. UIの進捗率(%)を更新
|
||
float currentProgress = Mathf.Clamp01(asyncLoad.progress / 0.9f);
|
||
if (progressText != null) progressText.text = $"LOADING: {(currentProgress * 100f):F0}%";
|
||
if (progressSlider != null) progressSlider.value = currentProgress;
|
||
|
||
// 2. 【演出:部屋をガタガタ揺らす】
|
||
// 初期位置をベースに、毎フレームごくわずかなランダム座標を計算して部屋を揺らす
|
||
if (elevatorCageTransform != null)
|
||
{
|
||
Vector3 randomOffset = Random.insideUnitSphere * shakeMagnitude;
|
||
// ※左右前後のブレ(X, Z)のみを揺らし、Y(上下)はあえて固定すると「ガタガタ感」が出ます
|
||
randomOffset.y = 0;
|
||
elevatorCageTransform.localPosition = originalCagePosition + randomOffset;
|
||
}
|
||
|
||
// 3. 【演出:両手のコントローラーを定期的に微振動させる】
|
||
hapticTimer += Time.deltaTime;
|
||
if (hapticTimer >= 0.1f) // 0.1秒ごとにブルブルと脈打つような振動を送る
|
||
{
|
||
TriggerBothHandHaptics(hapticAmplitude, 0.08f);
|
||
hapticTimer = 0f;
|
||
}
|
||
|
||
yield return null;
|
||
}
|
||
|
||
// ─── ロード完了後の処理 ───
|
||
|
||
// 4. 【演出の停止】エレベーターの揺れをピタッと止め、位置を綺麗にリセットする
|
||
if (elevatorCageTransform != null)
|
||
{
|
||
elevatorCageTransform.localPosition = originalCagePosition;
|
||
}
|
||
|
||
if (progressText != null) progressText.text = "ARRIVED";
|
||
if (progressSlider != null) progressSlider.value = 1f;
|
||
|
||
// 到着後の余韻(ガタガタが止まってから、扉が開いてシーンが変わるまでの静寂1秒)
|
||
yield return new WaitForSeconds(1.0f);
|
||
|
||
Debug.Log("🎉 ボスステージに到着。シーンを切り替えます。");
|
||
asyncLoad.allowSceneActivation = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 左右両方のコントローラーを同時に微振動させるヘルパーメソッド
|
||
/// </summary>
|
||
private void TriggerBothHandHaptics(float amplitude, float duration)
|
||
{
|
||
// 左手
|
||
InputDevice leftDevice = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand);
|
||
if (leftDevice.isValid) leftDevice.SendHapticImpulse(0, amplitude, duration);
|
||
|
||
// 右手
|
||
InputDevice rightDevice = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
|
||
if (rightDevice.isValid) rightDevice.SendHapticImpulse(0, amplitude, duration);
|
||
}
|
||
} |