using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; using System.Collections; using System.Collections.Generic; namespace OnlyScove.Scripts { public class SukunaDomainController : MonoBehaviour { [Header("References")] public PlayerStateMachine playerStateMachine; public GameObject slashPrefab; public GameObject shrinePrefab; public VolumeProfile domainVolumeProfile; public Transform cinematicCameraPoint; [Header("Domain Settings")] public float domainRadius = 15f; public float domainDuration = 10f; [Tooltip("Số lượng vệt chém tạo ra mỗi giây")] public float slashRate = 15f; public float shrineRiseHeight = 7f; // Độ sâu bắt đầu của miếu [Tooltip("Khoảng cách từ Pivot của Miếu đến mặt sàn nơi Player đứng")] public float shrineFloorOffset = 0.5f; public float camMoveSpeed = 4f; private bool isActive = false; private List activeSlashes = new List(); private Volume localVolume; private GameObject spawnedShrine; private void Start() { if (playerStateMachine == null) playerStateMachine = GetComponent(); if (playerStateMachine != null && playerStateMachine.Input != null) { playerStateMachine.Input.OnPreviousInteractEvent += HandleDomainExpansion; Debug.Log("[Sukuna] Sẵn sàng. slashRate: " + slashRate + ""); } } private void OnDestroy() { if (playerStateMachine != null && playerStateMachine.Input != null) { playerStateMachine.Input.OnPreviousInteractEvent -= HandleDomainExpansion; } } private void HandleDomainExpansion() { if (isActive) return; Debug.Log("[Sukuna] RYŌIKI TENKAI: FUKUMA MIZUZUSHI!"); StartCoroutine(DomainSequence()); } private IEnumerator DomainSequence() { isActive = true; // Lưu vị trí ban đầu của Player (Vị trí thực tế trên mặt đất) Vector3 playerStartPos = playerStateMachine.transform.position; playerStateMachine.SetControl(false); CameraController camController = playerStateMachine.Cam; bool originalCamEnabled = true; Transform mainCam = Camera.main.transform; if (camController != null) { originalCamEnabled = camController.enabled; camController.enabled = false; } // 1. Tạo Volume (Bóng bong lãnh địa) GameObject volumeObj = new GameObject("SukunaDomainVolume"); volumeObj.transform.position = playerStartPos; localVolume = volumeObj.AddComponent(); localVolume.isGlobal = false; localVolume.priority = 100; localVolume.profile = domainVolumeProfile; SphereCollider volumeCollider = volumeObj.AddComponent(); volumeCollider.isTrigger = true; volumeCollider.radius = 0.1f; // 2. Mọc miếu và đẩy Player if (shrinePrefab != null) { // Spawn miếu ở vị trí rất sâu dưới chân Player Vector3 shrineSpawnPos = playerStartPos - Vector3.up * shrineRiseHeight; spawnedShrine = Instantiate(shrinePrefab, shrineSpawnPos, playerStateMachine.transform.rotation); float riseDuration = 2.0f; float elapsed = 0; while (elapsed < riseDuration) { elapsed += Time.deltaTime; float t = Mathf.SmoothStep(0, 1, elapsed / riseDuration); // Di chuyển miếu lên dần dần Vector3 currentShrinePos = Vector3.Lerp(shrineSpawnPos, playerStartPos, t); spawnedShrine.transform.position = currentShrinePos; // Logic đẩy Player: // floorY là độ cao mặt sàn của miếu tại khung hình hiện tại float floorY = currentShrinePos.y + shrineFloorOffset; // Nếu mặt sàn của miếu đã trồi lên cao hơn vị trí chân Player ban đầu if (floorY > playerStartPos.y) { // Player đi theo miếu playerStateMachine.transform.position = new Vector3(playerStartPos.x, floorY, playerStartPos.z); } else { // Player đứng yên trên mặt đất ban đầu, chờ miếu trồi lên đỡ playerStateMachine.transform.position = playerStartPos; } // Mở rộng bán kính Volume volumeCollider.radius = Mathf.Lerp(0.1f, domainRadius, t); // Lia Camera mượt mà if (cinematicCameraPoint != null) { mainCam.position = Vector3.Lerp(mainCam.position, cinematicCameraPoint.position, Time.deltaTime * camMoveSpeed); mainCam.rotation = Quaternion.Slerp(mainCam.rotation, Quaternion.LookRotation((playerStateMachine.transform.position + Vector3.up * 2f) - mainCam.position), Time.deltaTime * camMoveSpeed); } yield return null; } } // 3. Thực thi chém liên tục dựa trên slashRate float timer = 0; float slashCooldown = 1f / slashRate; float lastSlashTime = 0; while (timer < domainDuration) { timer += Time.deltaTime; if (timer - lastSlashTime >= slashCooldown) { SpawnRandomSlash(playerStateMachine.transform.position); lastSlashTime = timer; } // Camera luôn theo dõi Player trên đỉnh miếu if (cinematicCameraPoint != null) { mainCam.position = Vector3.Lerp(mainCam.position, cinematicCameraPoint.position, Time.deltaTime * camMoveSpeed * 0.5f); mainCam.LookAt(playerStateMachine.transform.position + Vector3.up * 2f); } yield return null; } // 4. Miếu sụp xuống (Player đứng lại vị trí Y ban đầu) if (spawnedShrine != null) { float sinkTime = 1f; float elapsed = 0; Vector3 currentShrinePos = spawnedShrine.transform.position; Vector3 targetSinkPos = currentShrinePos - Vector3.up * shrineRiseHeight; while (elapsed < sinkTime) { elapsed += Time.deltaTime; float t = elapsed / sinkTime; spawnedShrine.transform.position = Vector3.Lerp(currentShrinePos, targetSinkPos, t); // Player từ từ hạ xuống sàn ban đầu float floorY = spawnedShrine.transform.position.y + shrineFloorOffset; if (floorY > playerStartPos.y) playerStateMachine.transform.position = new Vector3(playerStartPos.x, floorY, playerStartPos.z); else playerStateMachine.transform.position = playerStartPos; yield return null; } Destroy(spawnedShrine); } // 5. Thu nhỏ Volume float shrinkDuration = 0.5f; float sElapsed = 0; while (sElapsed < shrinkDuration) { sElapsed += Time.deltaTime; volumeCollider.radius = Mathf.Lerp(domainRadius, 0.1f, sElapsed / shrinkDuration); yield return null; } Destroy(volumeObj); // Dọn dẹp foreach (var s in activeSlashes) if (s != null) Destroy(s); activeSlashes.Clear(); if (camController != null) camController.enabled = originalCamEnabled; playerStateMachine.SetControl(true); isActive = false; } private void SpawnRandomSlash(Vector3 center) { Vector2 randCircle = Random.insideUnitCircle * domainRadius; Vector3 spawnPos = center + new Vector3(randCircle.x, Random.Range(1f, 6f), randCircle.y); if (slashPrefab != null) { GameObject slash = Instantiate(slashPrefab, spawnPos, Random.rotation); slash.transform.localScale *= Random.Range(0.6f, 2.5f); activeSlashes.Add(slash); StartCoroutine(DestroySlashAfterTime(slash, 0.7f)); } } private IEnumerator DestroySlashAfterTime(GameObject slash, float time) { yield return new WaitForSeconds(time); if (activeSlashes != null && activeSlashes.Contains(slash)) activeSlashes.Remove(slash); } } }