228 lines
7.8 KiB
C#
228 lines
7.8 KiB
C#
using UnityEngine;
|
|
|
|
namespace BrewMonster
|
|
{
|
|
/// <summary>
|
|
/// Random walk movement with Bezier curves.
|
|
/// Mirrors C++ CGfxRandMove exactly (A3DSkillGfxEvent2.cpp:358-458).
|
|
/// 随机游走移动(带贝塞尔曲线),完全镜像C++ CGfxRandMove。
|
|
/// </summary>
|
|
public class CGfxRandMove : CGfxMoveBase
|
|
{
|
|
protected float m_fStep;
|
|
protected float m_fSpeed;
|
|
protected float m_fTimeSpan;
|
|
protected float m_fCurSpan;
|
|
protected Vector3[] m_CtrlPoints = new Vector3[6];
|
|
|
|
private const float _move_step_co = 1.0f / 2.0f; // step coefficient, same as C++
|
|
private const float _max_yaw = 90.0f * Mathf.Deg2Rad; // max yaw angle (radians), same as C++
|
|
|
|
public CGfxRandMove(GfxMoveMode mode) : base(mode) { }
|
|
|
|
/// <summary>
|
|
/// Calculate step size based on size parameters.
|
|
/// 根据尺寸参数计算步长。
|
|
/// </summary>
|
|
protected void CalcStep()
|
|
{
|
|
m_fStep = 0;
|
|
if (m_vSize.x > m_fStep) m_fStep = m_vSize.x;
|
|
if (m_vSize.y > m_fStep) m_fStep = m_vSize.y;
|
|
if (m_vSize.z > m_fStep) m_fStep = m_vSize.z;
|
|
m_fStep *= _move_step_co;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculate vertical vector perpendicular to direction.
|
|
/// 计算垂直于方向的垂直向量。
|
|
/// </summary>
|
|
protected Vector3 CalcVertVec(Vector3 vDir)
|
|
{
|
|
Vector3 vUp = Vector3.up;
|
|
if (Mathf.Abs(Vector3.Dot(vDir, vUp)) > 0.9f)
|
|
{
|
|
vUp = Vector3.forward;
|
|
}
|
|
Vector3 vVert = Vector3.Cross(vDir, vUp);
|
|
Normalize(ref vVert);
|
|
return vVert;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check if position is within range bounds.
|
|
/// 检查位置是否在范围边界内。
|
|
/// </summary>
|
|
protected bool IsPosInRange(Vector3 vPos)
|
|
{
|
|
if (m_Shape == EmitShape.enumBox)
|
|
{
|
|
if (Mathf.Abs(vPos.x) > m_vSize.x) return false;
|
|
if (Mathf.Abs(vPos.y) > m_vSize.y) return false;
|
|
if (Mathf.Abs(vPos.z) > m_vSize.z) return false;
|
|
return true;
|
|
}
|
|
else if (m_Shape == EmitShape.enumSphere)
|
|
{
|
|
return vPos.sqrMagnitude <= m_fSquare;
|
|
}
|
|
else if (m_Shape == EmitShape.enumCylinder)
|
|
{
|
|
if (Mathf.Abs(vPos.y) > m_vSize.y) return false;
|
|
if (vPos.x * vPos.x + vPos.z * vPos.z > m_fSquareH) return false;
|
|
return true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculate next step position in random walk.
|
|
/// 计算随机游走中的下一步位置。
|
|
/// </summary>
|
|
protected Vector3 GetNextStep(Vector3 vPos, Vector3 vDir, Vector3 vCenter)
|
|
{
|
|
Vector3 vUp, vNewDir, vNewPos;
|
|
|
|
vUp = CalcVertVec(vDir);
|
|
// Random rotation around direction axis
|
|
// 围绕方向轴的随机旋转
|
|
float fRotAngle = Random.value * Mathf.PI * 2f;
|
|
Quaternion q = Quaternion.AngleAxis(fRotAngle * Mathf.Rad2Deg, vDir);
|
|
vUp = q * vUp;
|
|
|
|
// Random yaw rotation
|
|
// 随机偏航旋转
|
|
float fYawAngle = Random.value * _max_yaw;
|
|
Quaternion q2 = Quaternion.AngleAxis(fYawAngle * Mathf.Rad2Deg, vUp);
|
|
vNewDir = q2 * vDir;
|
|
vNewPos = vPos + vNewDir * m_fStep;
|
|
|
|
// If out of range, move toward center
|
|
// 如果超出范围,向中心移动
|
|
if (!IsPosInRange(vNewPos - vCenter))
|
|
{
|
|
vNewDir = (vCenter - vPos).normalized;
|
|
vNewPos = vPos + vNewDir * m_fStep;
|
|
}
|
|
|
|
return vNewPos;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bezier curve interpolation (4 control points).
|
|
/// 贝塞尔曲线插值(4个控制点)。
|
|
/// </summary>
|
|
protected Vector3 Bezier4(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
|
|
{
|
|
float u = 1.0f - t;
|
|
float tt = t * t;
|
|
float uu = u * u;
|
|
float uuu = uu * u;
|
|
float ttt = tt * t;
|
|
|
|
return uuu * p0 + 3 * uu * t * p1 + 3 * u * tt * p2 + ttt * p3;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize random walk movement.
|
|
/// 初始化随机游走移动。
|
|
/// </summary>
|
|
public override void StartMove(Vector3 vHost, Vector3 vTarget)
|
|
{
|
|
CalcStep();
|
|
m_fTimeSpan = m_fStep / m_fSpeed;
|
|
m_fCurSpan = 0;
|
|
|
|
if (m_bArea)
|
|
{
|
|
CalcRange((vTarget - vHost).normalized);
|
|
m_vPos = vTarget + GetRandOff();
|
|
}
|
|
else
|
|
{
|
|
m_vPos = vTarget;
|
|
}
|
|
|
|
// Random initial direction
|
|
// 随机初始方向
|
|
m_vMoveDir.x = Random.Range(-1f, 1f);
|
|
m_vMoveDir.y = Random.Range(-1f, 1f);
|
|
m_vMoveDir.z = Random.Range(-1f, 1f);
|
|
Normalize(ref m_vMoveDir);
|
|
|
|
// Initialize Bezier control points
|
|
// 初始化贝塞尔控制点
|
|
m_CtrlPoints[0] = m_vPos;
|
|
m_CtrlPoints[3] = GetNextStep(m_vPos, m_vMoveDir, vTarget);
|
|
Vector3 vDelta1 = m_CtrlPoints[3] - m_vPos;
|
|
m_CtrlPoints[5] = GetNextStep(m_CtrlPoints[3], vDelta1.normalized, vTarget);
|
|
|
|
Vector3 vDiff = (m_CtrlPoints[5] - m_vPos) / 6.0f;
|
|
m_CtrlPoints[2] = m_CtrlPoints[3] - vDiff;
|
|
m_CtrlPoints[4] = m_CtrlPoints[3] + vDiff;
|
|
m_CtrlPoints[1] = m_CtrlPoints[2] + vDelta1 / 3.0f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tick random walk movement. Returns false (hit triggered by timeout).
|
|
/// 更新随机游走移动。返回false(命中由超时触发)。
|
|
/// </summary>
|
|
public override bool TickMove(uint dwDeltaTime, Vector3 vHostPos, Vector3 vTargetPos)
|
|
{
|
|
m_fCurSpan += dwDeltaTime / 1000.0f;
|
|
|
|
if (m_fCurSpan >= m_fTimeSpan)
|
|
{
|
|
// Move to next control point and calculate new path
|
|
// 移动到下一个控制点并计算新路径
|
|
m_vPos = m_CtrlPoints[3];
|
|
m_fCurSpan = 0;
|
|
|
|
m_CtrlPoints[0] = m_vPos;
|
|
m_CtrlPoints[3] = m_CtrlPoints[5];
|
|
Vector3 vDelta1 = m_CtrlPoints[3] - m_vPos;
|
|
m_CtrlPoints[5] = GetNextStep(m_CtrlPoints[3], vDelta1.normalized, vTargetPos);
|
|
|
|
m_CtrlPoints[1] = m_CtrlPoints[4];
|
|
Vector3 vDiff = (m_CtrlPoints[5] - m_vPos) / 6.0f;
|
|
m_CtrlPoints[2] = m_CtrlPoints[3] - vDiff;
|
|
m_CtrlPoints[4] = m_CtrlPoints[3] + vDiff;
|
|
}
|
|
else
|
|
{
|
|
// Interpolate along Bezier curve
|
|
// 沿贝塞尔曲线插值
|
|
Vector3 vOldPos = m_vPos;
|
|
|
|
m_vPos = Bezier4(
|
|
m_CtrlPoints[0],
|
|
m_CtrlPoints[1],
|
|
m_CtrlPoints[2],
|
|
m_CtrlPoints[3],
|
|
m_fCurSpan / m_fTimeSpan
|
|
);
|
|
|
|
Vector3 vNewDir = m_vPos - vOldPos;
|
|
float fMag = Normalize(ref vNewDir);
|
|
if (fMag > 0.0001f)
|
|
{
|
|
m_vMoveDir = vNewDir;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Override to also read speed from param value.
|
|
/// 重写以从参数值中读取速度。
|
|
/// </summary>
|
|
public override void SetParam(GFX_SKILL_PARAM param)
|
|
{
|
|
base.SetParam(param);
|
|
m_fSpeed = param.value.fVal; // C# union access: param.value.fVal
|
|
}
|
|
}
|
|
}
|