110 lines
4.5 KiB
C#
110 lines
4.5 KiB
C#
using Cielonos.MainGame.Characters;
|
|
using Cielonos.MainGame.Inventory;
|
|
using SLSUtilities.General;
|
|
using UnityEngine;
|
|
|
|
namespace Cielonos.MainGame
|
|
{
|
|
public partial class NormalArea : AttackAreaBase
|
|
{
|
|
public override T Initialize<T>(CharacterBase creator, ItemBase itemSource, params Fraction[] targetFractions)
|
|
{
|
|
T area = base.Initialize<T>(creator, itemSource, targetFractions);
|
|
topParent.transform.localScale *= creator.attributeSm[CharacterAttribute.AttackRangeMultiplier];
|
|
return area;
|
|
}
|
|
|
|
private void OnTriggerStay(Collider other)
|
|
{
|
|
HitCharacter(other, default);
|
|
}
|
|
|
|
public override void HitCharacter(Collider characterCollider, Vector3 hitPosition)
|
|
{
|
|
if (!isEnabling)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CharacterBase targetCharacter = characterCollider.GetComponentInParent<CharacterBase>();
|
|
|
|
if (!IsValidTarget(targetCharacter)) return;
|
|
|
|
if (hitSm.checkedObjects.Contains(targetCharacter.gameObject))
|
|
{
|
|
return;
|
|
}
|
|
|
|
hitSm.AddCheckedObject(targetCharacter.gameObject);
|
|
|
|
HitOnTarget(characterCollider, areaCollider.ClosestPoint(targetCharacter.centerPoint.position), out _);
|
|
}
|
|
}
|
|
|
|
public partial class NormalArea
|
|
{
|
|
protected override GameObject GenerateHitEffect(CharacterBase target, Collider hitCollider, Vector3 hitPosition)
|
|
{
|
|
GameObject hitEffect = base.GenerateHitEffect(target, hitCollider, hitPosition);
|
|
if(hitEffect == null) return null;
|
|
Vector3 hitEffectDirection = GetHitEffectDirection(hitCollider.ClosestPoint(transform.position));
|
|
hitEffect.transform.rotation = Quaternion.LookRotation(hitEffectDirection);
|
|
return hitEffect;
|
|
}
|
|
}
|
|
|
|
public partial class NormalArea
|
|
{
|
|
/// <summary>
|
|
/// 计算命中特效应朝向的方向 (Z轴)。
|
|
/// 这个方向是刀光在命中点的旋转切线方向。
|
|
/// </summary>
|
|
/// <param name="hitPosition">世界空间中的命中点</param>
|
|
/// <returns>一个标准化的方向向量 (world space)</returns>
|
|
private Vector3 GetHitEffectDirection(Vector3 hitPosition)
|
|
{
|
|
// 1. 获取刀光旋转的中心点
|
|
// (假设 creator.flexibleCenterPoint.position 是旋转中心)
|
|
Vector3 rotationCenter = creator.centerPoint.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;
|
|
}
|
|
}
|
|
} |