230 lines
9.5 KiB
C#
230 lines
9.5 KiB
C#
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<GameObject> activeSlashes = new List<GameObject>();
|
|
private Volume localVolume;
|
|
private GameObject spawnedShrine;
|
|
|
|
private void Start()
|
|
{
|
|
if (playerStateMachine == null)
|
|
playerStateMachine = GetComponent<PlayerStateMachine>();
|
|
|
|
if (playerStateMachine != null && playerStateMachine.Input != null)
|
|
{
|
|
playerStateMachine.Input.OnPreviousInteractEvent += HandleDomainExpansion;
|
|
Debug.Log("<color=green>[Sukuna] Sẵn sàng. slashRate: " + slashRate + "</color>");
|
|
}
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (playerStateMachine != null && playerStateMachine.Input != null)
|
|
{
|
|
playerStateMachine.Input.OnPreviousInteractEvent -= HandleDomainExpansion;
|
|
}
|
|
}
|
|
|
|
private void HandleDomainExpansion()
|
|
{
|
|
if (isActive) return;
|
|
Debug.Log("<color=red>[Sukuna] RYŌIKI TENKAI: FUKUMA MIZUZUSHI!</color>");
|
|
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<Volume>();
|
|
localVolume.isGlobal = false;
|
|
localVolume.priority = 100;
|
|
localVolume.profile = domainVolumeProfile;
|
|
SphereCollider volumeCollider = volumeObj.AddComponent<SphereCollider>();
|
|
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);
|
|
}
|
|
}
|
|
}
|