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 && characterCollider.gameObject.layer != LayerMask.GetMask("HurtBox")) { return; } /*Debug.Log($"{characterCollider.gameObject.name} Hit");*/ CharacterBase targetCharacter = characterCollider.GetComponentInParent(); 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; } /// /// 计算命中特效应朝向的方向 (Z轴)。 /// 这个方向是刀光在命中点的旋转切线方向。 /// /// 世界空间中的命中点 /// 一个标准化的方向向量 (world space) 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; } } }