Files
Cielonos/Assets/Scripts/MainGame/Effects/VFX/Assistance/VFXRaycastInteraction.cs
2026-04-18 13:57:19 -04:00

140 lines
5.2 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 System.Collections.Generic;
using Lean.Pool;
using Sirenix.OdinInspector;
using UnityEngine;
namespace Cielonos.MainGame
{
public class VFXRaycastInteraction : MonoBehaviour, IPoolable
{
[Header("核心设置")]
[Tooltip("在特效生成时是否立刻启用渐变,注意,必须通过对象池生成。\n为true时渐变效果从targetLight的默认intensity开始否则需要调用EnableFade方法启用渐变")]
public bool playOnSpawn = true;
public float life = 1f;
public List<float> checkPoints;
public int currentCheckPointIndex = 0;
public bool isEnabling = true;
public Transform startPoint; // 刀尖的位置(用于发射射线)
public LayerMask collisionLayers; // 地面图层
public float rayLength = 0.5f; // 射线长度(稍微比刀刃离地距离长一点)
[Header("特效资源")]
public GameObject sparkPrefab; // 火星特效 Prefab
public GameObject decalPrefab; // 划痕 Decal Prefab
[HideInEditorMode]
[SerializeField]
private bool isFading;
[HideInEditorMode]
[SerializeField]
private float time;
private Vector3 _lastTipPosition;
private void Reset()
{
startPoint = transform;
collisionLayers = LayerMask.GetMask("Wall", "Ground");
}
public void OnSpawn()
{
if (playOnSpawn && !isEnabling)
{
isEnabling = true;
time = 0f;
currentCheckPointIndex = 0;
}
_lastTipPosition = startPoint.position;
}
public void OnDespawn()
{
isEnabling = false;
}
void Update()
{
time += Time.deltaTime;
if (time >= life)
{
isEnabling = false;
}
if (!isEnabling || Time.timeScale == 0 || checkPoints.Count == 0) return;
// 1. 计算刀尖速度方向(用于决定划痕朝向)
Vector3 velocity = (startPoint.position - _lastTipPosition) / Time.deltaTime;
_lastTipPosition = startPoint.position;
//1. 检查是否到达下一个检查点
if (currentCheckPointIndex < checkPoints.Count)
{
if (time >= checkPoints[currentCheckPointIndex])
{
currentCheckPointIndex++;
}
else
{
return; // 未到达检查点,跳过本次更新
}
}
else
{
return; // 所有检查点已处理完,跳过本次更新
}
// 2. 发射射线检测地面
// 这里我们向下发射射线。如果你的游戏支持墙壁划痕,可以改为 velocity.normalized
RaycastHit hit;
if (Physics.Raycast(startPoint.position, startPoint.forward, out hit, rayLength, collisionLayers))
{
SpawnEffects(hit, velocity);
}
}
void SpawnEffects(RaycastHit hit, Vector3 slashVelocity)
{
Vector3 projectedSlashDir = Vector3.ProjectOnPlane(slashVelocity, hit.normal).normalized;
// --- 处理火星 (Spark) ---
if (sparkPrefab != null)
{
// 关键点:使用 Quaternion.LookRotation(hit.normal)
// 这会让火星特效的 Z轴发射方向严格对准地面法线垂直向上right方向和挥动方向对齐
LeanPool.Spawn(sparkPrefab, hit.point, Quaternion.LookRotation(hit.normal, Vector3.Cross(projectedSlashDir, hit.normal)));
}
// --- 处理划痕 (Decal) ---
if (decalPrefab != null)
{
// 计算划痕的朝向:
// 我们希望划痕贴在地面上(法线对齐 hit.normal
// 同时划痕的延伸方向要对齐刀的挥动方向slashVelocity
if (projectedSlashDir != Vector3.zero)
{
// 计算 Decal 的旋转Decal的forward和地面法线对齐right方向和挥动方向对齐
Quaternion decalRotation = Quaternion.LookRotation(hit.normal, Vector3.Cross(projectedSlashDir, hit.normal));
// 生成 Decal稍微抬高一点点避免 Z-Fighting
GameObject decal = LeanPool.Spawn(decalPrefab, hit.point + hit.normal * 0.01f, decalRotation);
// 记得在 Prefab 里设置自动销毁,或者在这里写 Destroy
LeanPool.Despawn(decal, 5f);
}
}
}
// 用于在 Scene 窗口调试射线,方便你调整 rayLength
void OnDrawGizmos()
{
if (startPoint != null)
{
Gizmos.color = Color.yellow;
Gizmos.DrawLine(startPoint.position, startPoint.position + transform.forward * rayLength);
}
}
}
}