change to state machine

This commit is contained in:
VDH
2025-09-08 09:20:50 +07:00
parent 1d7a284aaf
commit ee8b1d6a98
20 changed files with 442 additions and 3 deletions
+239
View File
@@ -0,0 +1,239 @@
using System;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.LightTransport;
public static class EC_CDR
{
// Cho phép CECHostMove gán mask theo scene (giữ linh hoạt nhưng không phá cấu trúc)
public static LayerMask BrushMask { get; set; } = ~0;
public static LayerMask TerrainMask { get; set; } = ~0;
static LayerMask UsedMask_Ground() => BrushMask | TerrainMask;
// == Thay CollideWithEnv (C++) bằng BoxCast ==
static bool CollideWithEnv_BoxCast(Vector3 vStart, Vector3 vDelta, Vector3 vExt,
LayerMask mask,
out RaycastHit hit, out float fFraction, out Vector3 vHitNormal, out bool bStartSolid,
float skin = 0.01f)
{
hit = default;
vHitNormal = Vector3.up;
bStartSolid = false;
fFraction = 1.0f;
float dist = vDelta.magnitude;
if (dist <= 1e-6f) return false;
// start-in-solid
var overlapped = Physics.OverlapBox(vStart, vExt - Vector3.one * skin, Quaternion.identity, mask, QueryTriggerInteraction.Ignore);
if (overlapped != null && overlapped.Length > 0)
{
bStartSolid = true;
return true;
}
// sweep AABB
Vector3 dir = vDelta / Mathf.Max(dist, 1e-6f);
if (Physics.BoxCast(vStart, vExt - Vector3.one * skin, dir, out hit, Quaternion.identity, dist, mask, QueryTriggerInteraction.Ignore))
{
fFraction = Mathf.Clamp01(hit.distance / Mathf.Max(dist, 1e-6f));
vHitNormal = hit.normal;
return true;
}
return false;
}
// == Thay RetrieveSupportPlane (C++) bằng Raycast xuống ==
static bool DoGroundProbe(Vector3 vStart, Vector3 vExt, float fDeltaY, LayerMask mask,
out Vector3 vEnd, out Vector3 vHitNormal, out bool bSupport,
float skin = 0.01f)
{
vEnd = vStart;
vHitNormal = Vector3.up;
bSupport = false;
float dist = Mathf.Max(fDeltaY, 0f) + vExt.y + skin + 0.05f;
Vector3 origin = vStart + Vector3.up * 0.05f;
if (Physics.Raycast(origin, Vector3.down, out RaycastHit hit, dist, mask, QueryTriggerInteraction.Ignore))
{
vHitNormal = hit.normal;
vEnd = new Vector3(vStart.x, hit.point.y + vExt.y + skin, vStart.z);
bSupport = (vHitNormal.y >= 0f);
return true;
}
return true; // không thấy ground → bSupport=false
}
// ======= STATIC OnGroundMove GIỮ NGUYÊN VAI TRÒ TOÀN CỤC (C API) =======
public static void OnGroundMove(ref CDR_INFO CDRInfo)
{
const float VEL_EPSILON = 1e-4f;
const float DIST_EPSILON = 1e-4f;
const float NORMAL_EPSILON = 1e-2f;
const float VEL_MAX_SPEED = 200f;
const float VEL_REFLECT = 0.3f;
CDRInfo.fMoveDist = 0.0f;
bool bFreeFall = (CDRInfo.vTPNormal.y < CDRInfo.fSlopeThresh);
if (Mathf.Abs(CDRInfo.fYVel) < VEL_EPSILON && Mathf.Abs(CDRInfo.fSpeed) < VEL_EPSILON && !bFreeFall)
return;
float fYVel = CDRInfo.fYVel;
bool bJump = (fYVel > 0.5f);
Vector3 vVelocity = CDRInfo.fSpeed * new Vector3(CDRInfo.vXOZVelDir.x, 0f, CDRInfo.vXOZVelDir.z) + fYVel * Vector3.up;
if (bFreeFall)
{
vVelocity += -CDRInfo.fGravityAccel * CDRInfo.t * Vector3.up;
fYVel += -CDRInfo.fGravityAccel * CDRInfo.t;
}
Vector3 vVelDir = vVelocity;
float fVelSpeed = vVelDir.magnitude;
if (fVelSpeed > 1e-6f) vVelDir /= fVelSpeed; else vVelDir = Vector3.zero;
if (!bFreeFall) fVelSpeed = Mathf.Min(fVelSpeed, VEL_MAX_SPEED);
vVelocity = vVelDir * fVelSpeed;
float dtp = Vector3.Dot(vVelDir, CDRInfo.vTPNormal);
if (dtp < 0f || !bJump)
{
vVelocity = (vVelDir - CDRInfo.vTPNormal * dtp - CDRInfo.vTPNormal * dtp * 0.01f) * fVelSpeed;
}
CDRInfo.vAbsVelocity = vVelocity;
Vector3 vStart = CDRInfo.vCenter;
Vector3 vExt = CDRInfo.vExtent;
float fTime = CDRInfo.t;
Vector3 vDelta, vNormal = Vector3.up, vFinalPos = vStart;
bool bPull = false;
bool bTryPull = false;
int nTry = 0;
LayerMask mask = UsedMask_Ground();
while (nTry < 4)
{
vDelta = vVelocity * fTime;
float fDeltaDist = vDelta.magnitude;
if (fDeltaDist < DIST_EPSILON) break;
bool hasHit = CollideWithEnv_BoxCast(vStart, vDelta, vExt, mask,
out RaycastHit hit, out float fFraction, out Vector3 hitNormal, out bool bStartSolid);
nTry++;
if (bStartSolid)
{
CDRInfo.fMoveDist = 0f;
if (CDRInfo.vTPNormal.y < CDRInfo.fSlopeThresh) CDRInfo.vTPNormal = Vector3.up;
return;
}
if (!hasHit)
{
vFinalPos = vStart + vDelta;
CDRInfo.fMoveDist += fDeltaDist;
break;
}
vStart += vDelta * fFraction;
CDRInfo.fMoveDist += (fDeltaDist * fFraction);
fTime -= fTime * fFraction;
vNormal = hitNormal;
// Step-up (giữ tinh thần bản gốc)
if (!bFreeFall && !bTryPull && !bJump)
{
float skin = 0.01f;
Vector3 vStartUp = vStart + new Vector3(0f, CDRInfo.fStepHeight, 0f);
bool upBlocked = Physics.CheckBox(vStartUp, vExt - Vector3.one * skin, Quaternion.identity, mask, QueryTriggerInteraction.Ignore);
if (!upBlocked)
{
Vector3 vDelta2 = vVelocity;
bool hasHit2 = CollideWithEnv_BoxCast(vStartUp, vDelta2, vExt, mask,
out RaycastHit hit2, out float frac2, out Vector3 hitNormal2, out bool bStartSolid2);
if (hasHit2) vDelta2 *= frac2;
if (vDelta2.sqrMagnitude >= (vExt.x * vExt.x * 4f))
{
vStart = vStartUp;
vDelta = vDelta2;
float distAll = vVelocity.magnitude;
float distMoved = vDelta.magnitude;
if (distAll > 1e-6f) fTime *= Mathf.Clamp01(distMoved / Mathf.Max(distAll, 1e-6f));
bPull = true;
}
}
bTryPull = true;
}
if (!bPull)
{
if (vVelocity.sqrMagnitude > 1e-12f)
{
vVelDir = vVelocity.normalized;
fVelSpeed = vVelocity.magnitude * (1f - nTry * 0.1f);
dtp = Vector3.Dot(vNormal, vVelDir);
float fRelSpeed = Mathf.Min(fVelSpeed, 5.0f);
if (dtp >= 0f && dtp < 1e-4f)
{
vVelocity += vNormal * VEL_REFLECT * fRelSpeed;
}
else
{
vVelocity = (vVelDir - vNormal * dtp) * fVelSpeed - vNormal * dtp * VEL_REFLECT * fRelSpeed;
}
}
if (fYVel > VEL_EPSILON)
{
if (vNormal.y >= CDRInfo.fSlopeThresh || vNormal.y < -NORMAL_EPSILON) fYVel = 0f;
}
else if (fYVel < -VEL_EPSILON)
{
if (vNormal.y >= CDRInfo.fSlopeThresh) fYVel = 0f;
}
}
}
// “vertical ground trace” thay RetrieveSupportPlane
Vector3 vTPNormal = Vector3.zero;
Vector3 vFinal = vFinalPos;
float downDist = 0.3f;
if (bPull) downDist = CDRInfo.fStepHeight + 0.1f;
if (bJump) downDist = 0.0f;
if (downDist > 0f)
{
if (!DoGroundProbe(vFinalPos, vExt, downDist, mask, out Vector3 vEnd, out Vector3 groundNormal, out bool bSupport))
{
CDRInfo.fMoveDist = 0f;
CDRInfo.vTPNormal = Vector3.up;
return;
}
if (bSupport)
{
vFinal = vEnd;
if (!bJump) vTPNormal = groundNormal;
}
}
if ((vTPNormal.y >= CDRInfo.fSlopeThresh && fYVel < 0.0f) || (!bJump && fYVel > 0.0f))
fYVel = 0.0f;
CDRInfo.vCenter = vFinal;
CDRInfo.fYVel = fYVel;
if (vTPNormal != Vector3.zero) CDRInfo.vTPNormal = vTPNormal;
}
}