Files
VRProject/Assets/_Scripts/ElevatorSceneTransition.cs
oogushiyuuga 4d3fee6ca5 いろいろやってみた
Playerが蜘蛛にめり込まないようにしたい
2026-07-01 16:23:04 +09:00

142 lines
6.1 KiB
C#
Raw Permalink 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;
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すべてをまとめているオブジェクトを指定してください※プレイヤーは外しておきます")]
[SerializeField] private Transform elevatorCageTransform;
[Tooltip("ガタガタ揺れる激しさ0.010.03あたりが自然です)")]
[SerializeField] private float shakeMagnitude = 0.015f;
[Tooltip("下降中のコントローラーの振動の強さ0.0 1.0")]
[SerializeField] private float hapticAmplitude = 0.15f;
// ─── ★新設:親子関係にしないためのプレイヤー登録枠 ───
[Header("プレイヤーの同期設定")]
[Tooltip("XR OriginまたはXR RigのTransformを直接ドラッグドロップしてください")]
[SerializeField] private Transform playerTransform;
// ─────────────────────────────────────────────────────
private bool isLoadingStarted = false;
private Vector3 originalCagePosition;
private void Start()
{
if (loadingCanvas != null) loadingCanvas.SetActive(false);
if (elevatorCageTransform != null)
{
// ワールド空間での初期位置を記憶localPositionからpositionに変更し、より確実に
originalCagePosition = elevatorCageTransform.position;
}
}
private void OnTriggerEnter(Collider other)
{
if (isLoadingStarted) return;
if (other.CompareTag(playerTag))
{
isLoadingStarted = true;
// ★安全対策接触したプレイヤーのTransformを自動でキャッシュする
if (playerTransform == null)
{
playerTransform = other.transform;
}
Debug.Log("🛗 プレイヤー乗車:親子関係なしのデルタ同期で下降演出を開始します。");
StartCoroutine(LoadSceneAsyncRoutine());
}
}
private IEnumerator LoadSceneAsyncRoutine()
{
if (loadingCanvas != null) loadingCanvas.SetActive(true);
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(bossSceneName);
asyncLoad.allowSceneActivation = false;
float hapticTimer = 0f;
while (asyncLoad.progress < 0.9f)
{
float currentProgress = Mathf.Clamp01(asyncLoad.progress / 0.9f);
if (progressText != null) progressText.text = $"LOADING: {(currentProgress * 100f):F0}%";
if (progressSlider != null) progressSlider.value = currentProgress;
// ─── ★【超重要】親子関係なしでプレイヤーを完全同期させるロジック ───
// 1. 動かす前の、このフレームにおけるエレベーターの現在位置を記録
Vector3 previousCagePosition = elevatorCageTransform.position;
// 2. エレベーターの部屋だけをランダムにガタガタ動かす
if (elevatorCageTransform != null)
{
Vector3 randomOffset = Random.insideUnitSphere * shakeMagnitude;
randomOffset.y = 0; // 横揺れのみ
elevatorCageTransform.position = originalCagePosition + randomOffset;
}
// 3. 「この1フレームでエレベーターが実際に動いた移動差分デルタ」を計算
Vector3 cageDelta = elevatorCageTransform.position - previousCagePosition;
// 4. その移動差分を、プレイヤーの座標にもそのまま上乗せして足し算する
if (playerTransform != null && cageDelta != Vector3.zero)
{
playerTransform.position += cageDelta;
}
// ───────────────────────────────────────────────────────────────────
hapticTimer += Time.deltaTime;
if (hapticTimer >= 0.1f)
{
TriggerBothHandHaptics(hapticAmplitude, 0.08f);
hapticTimer = 0f;
}
yield return null;
}
// 到着後、エレベーターの位置を元の位置に綺麗に戻す
if (elevatorCageTransform != null)
{
// 最後の移動差分を計算してプレイヤーを戻す
Vector3 previousCagePosition = elevatorCageTransform.position;
elevatorCageTransform.position = originalCagePosition;
Vector3 cageDelta = elevatorCageTransform.position - previousCagePosition;
if (playerTransform != null) playerTransform.position += cageDelta;
}
if (progressText != null) progressText.text = "ARRIVED";
if (progressSlider != null) progressSlider.value = 1f;
yield return new WaitForSeconds(1.0f);
Debug.Log("🎉 ボスステージに到着。シーンを切り替えます。");
asyncLoad.allowSceneActivation = true;
}
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);
}
}