阶段性完成

This commit is contained in:
SoulliesOfficial
2025-12-08 05:27:53 -05:00
parent ef7b479712
commit f7af60351b
8770 changed files with 15637030 additions and 208354 deletions

View File

@@ -0,0 +1,140 @@
using System.Collections.Generic;
using Lean.Pool;
using Sirenix.OdinInspector;
using UnityEngine;
namespace SLSUtilities.Effects
{
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);
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0217139a1a991f947ac6135f8ea20a0c

View File

@@ -370,6 +370,13 @@ namespace SLSUtilities.FunctionalAnimation
}
return defaultValue;
}
public VariableCollection Clone()
{
VariableCollection clone = new VariableCollection();
clone.variables = new Dictionary<string, string>(this.variables);
return clone;
}
}
public static class FuncAnimExtensions

View File

@@ -9,6 +9,7 @@ namespace SLSUtilities.FunctionalAnimation
public class RuntimeFuncAnim
{
public FuncAnimData funcAnimData;
public string animationName => funcAnimData.animInfo.animationName;
public bool isLooping => funcAnimData.animationClip.isLooping;
public CharacterBase executor;
@@ -19,6 +20,7 @@ namespace SLSUtilities.FunctionalAnimation
public EventCollection dataEvents;
public EventCollection runtimeEvents;
public VariableCollection runtimeVariables;
public Dictionary<string, bool> updateUntilStatus;
private List<FuncAnimEvent> playedEndEvents;
@@ -32,6 +34,7 @@ namespace SLSUtilities.FunctionalAnimation
runtimeEvents = new EventCollection();
updateUntilStatus = new Dictionary<string, bool>();
playedEndEvents = new List<FuncAnimEvent>();
runtimeVariables = funcAnimData.variableCollection!= null ? funcAnimData.variableCollection.Clone() : new VariableCollection();
dataEvents.animEvents.ForEach(animEvt => animEvt.payload.runtimeFuncAnim = this);
dataEvents.startEvents.ForEach(payload => payload.runtimeFuncAnim = this);