Files
Cielonos/Assets/Scripts/MainGame/AttackArea/Collection/NormalArea.cs
SoulliesOfficial ef7b479712 initial
2025-11-25 08:19:33 -05:00

122 lines
5.1 KiB
C#

using Cielonos.MainGame.Characters;
using SLSFramework.General;
using UnityEngine;
namespace Cielonos.MainGame
{
public partial class NormalArea : AttackAreaBase
{
private void OnTriggerStay(Collider other)
{
HitCharacter(other, default);
}
public override void HitCharacter(Collider characterCollider, Vector3 hitPosition)
{
if (!isEnabling)
{
return;
}
Debug.Log($"{characterCollider.gameObject.name} Hit");
CharacterBase targetCharacter = characterCollider.GetComponentInParent<CharacterBase>();
if (targetCharacter == creator) return;
if (targetCharacter != null)// && targetCharacter.HasAnyTag(targetTagList))
{
if (hitSm.checkedObjects.Contains(targetCharacter.gameObject))
{
return;
}
hitSm.AddCheckedObject(targetCharacter.gameObject);
HitOnTarget(characterCollider, areaCollider.ClosestPoint(targetCharacter.flexibleCenterPoint.position));
}
}
}
public partial class NormalArea
{
protected override GameObject GenerateHitEffect(CharacterBase target, Collider hitCollider, Vector3 hitPosition)
{
GameObject hitEffect = base.GenerateHitEffect(target, hitCollider, hitPosition);
Vector3 hitEffectDirection = GetHitEffectDirection(hitCollider.ClosestPoint(transform.position));
hitEffect.transform.rotation = Quaternion.LookRotation(hitEffectDirection);
return hitEffect;
}
}
public partial class NormalArea
{
private Vector3 SetHitEffectEulerAnglesByNormal(Vector3 hitPosition, Vector3 frontTangent)
{
Vector3 frontCircleNormal = Vector3.up;
Vector3 hitCircleNormal = transform.up;
Quaternion circleNormalRotation = Quaternion.FromToRotation(frontCircleNormal, hitCircleNormal);
Vector3 frontDirection = Vector3.forward;
Quaternion directionToTangentRotation = Quaternion.FromToRotation(frontDirection, frontTangent);
Vector3 hitDirection = (hitPosition - creator.flexibleCenterPoint.position).normalized;
hitDirection.y = 0;
hitDirection = directionToTangentRotation * hitDirection;
hitDirection = circleNormalRotation * hitDirection;
return hitDirection;
}
/// <summary>
/// 计算命中特效应朝向的方向 (Z轴)。
/// 这个方向是刀光在命中点的旋转切线方向。
/// </summary>
/// <param name="hitPosition">世界空间中的命中点</param>
/// <returns>一个标准化的方向向量 (world space)</returns>
private Vector3 GetHitEffectDirection(Vector3 hitPosition)
{
// 1. 获取刀光旋转的中心点
// (假设 creator.flexibleCenterPoint.position 是旋转中心)
Vector3 rotationCenter = creator.flexibleCenterPoint.position;
// 2. 获取刀光旋转的法线 (旋转轴)
// 根据描述, 这是刀光 prefab 的 Y 轴正方向
Vector3 rotationNormal = transform.up; // 刀光的 local Y 轴 (in world space)
// 3. 计算从中心点到命中点的半径向量
Vector3 radiusVector = hitPosition - rotationCenter;
// 4. (重要) 将半径向量投影到旋转平面上.
// 这是为了确保我们得到一个与旋转轴垂直的向量,
// 防止 hitPosition 轻微偏离平面导致计算错误.
// 你的代码中 hitDirection.y = 0 是在错误的平面上投影.
Vector3 radiusOnPlane = Vector3.ProjectOnPlane(radiusVector, rotationNormal);
// 5. 计算切线.
// 需求: "Y轴正方向顺时针旋转"
// 在 Unity (左手坐标系) 中:
// - 轴 (Normal) = Y (0, 1, 0)
// - 半径 (Radius) = X (1, 0, 0)
// - 顺时针旋转 (Clockwise) 是从 +X 转向 -Z.
//
// - Vector3.Cross(rotationNormal, radiusOnPlane)
// = Cross((0,1,0), (1,0,0)) = (0, 0, -1) (-> 指向 -Z)
// - 这正是我们需要的顺时针切线方向.
Vector3 tangentDirection = Vector3.Cross(rotationNormal, radiusOnPlane);
// 6. (安全检查) 处理命中点在中心的情况
// 如果命中点非常接近旋转中心, 半径为0, 叉乘结果也为0.
// .normalized 会返回 NaN, 导致 LookRotation 失败.
if (tangentDirection.sqrMagnitude < 0.0001f)
{
// 此时没有明确的 "切线".
// 我们可以返回刀光的 "forward" (Z轴) 或 "right" (X轴) 作为备用.
// 让我们使用刀光的 X 轴 (即刀光"刀刃"的初始方向).
return transform.right;
}
// 7. 返回标准化的切线方向
return tangentDirection.normalized;
}
}
}