Files
test/Assets/PerfectWorld/Scripts/Move/EC_CDR.cs
T
2025-12-25 18:13:21 +07:00

897 lines
33 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BrewMonster.Network;
using BrewMonster.Scripts;
using BrewMonster.Scripts.Ornament;
using BrewMonster.Scripts.World;
using CSNetwork.GPDataType;
using System;
using UnityEngine;
using static BrewMonster.CECHostMove;
using WORD = System.UInt16;
namespace BrewMonster
{
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; } = 1 << 7;
public static LayerMask TerrainMask { get; set; } = 1 << 6;
public static LayerMask WaterMask { get; set; } = 1 << 8;
public static RaycastHit[] hits = new RaycastHit[5];
const float LOCAL_EPSILON = 1e-5f;
const float FLY_MAX_HEIGHT = 800.0f; // ·ÉÐеÄ×î´ó¸ß¶È£¡
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;
// change this array when some new submap can go!
static uint[,] available_maps =
{
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 1, 1, 1, 1, 1, 1},
{0, 1, 1, 1, 1, 1, 1, 1},
{0, 1, 1, 1, 1, 1, 1, 0},
{0, 1, 1, 1, 1, 1, 1, 0},
{0, 1, 1, 1, 1, 1, 1, 0},
{0, 1, 1, 1, 1, 1, 1, 0},
{0, 1, 1, 1, 1, 1, 1, 0},
{0, 1, 1, 1, 1, 1, 1, 0},
{0, 0, 0, 0, 0, 1, 1, 0},
{1, 1, 0, 0, 0, 0, 0, 0},
};
static uint[,] available_maps4x4 =
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 1, 1, 0},
{0, 0, 0, 0},
};
static uint[,] available_maps3x3 =
{
{0, 0, 0},
{0, 1, 0},
{0, 0, 0},
};
static uint[,] available_maps2x2 =
{
{1, 1},
{0, 0},
};
static uint[,] available_maps_137 =
{
{0, 0, 0, 0, 0, 0},
{0, 1, 1, 1, 0, 0},
{0, 0, 0, 0, 0, 0},
};
static uint[,] available_maps_161 =
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 0, 0, 0},
};
static uint[,] available_maps_162 =
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 0, 0, 0},
};
static uint[,] available_maps_163 =
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 1, 0, 0},
{0, 0, 0, 0},
};
//[Flags]
public static class CDR_EVN
{
public const int CDR_BRUSH = 0x1,
CDR_TERRAIN = 0x2,
CDR_WATER = 0x4;
}
static LayerMask UsedMask_Ground() => TerrainMask;
public static bool CollideWithEnv(ref env_trace_t pEnvTrc)
{
pEnvTrc.fFraction = 100.0f;
pEnvTrc.bStartSolid = false;
pEnvTrc.dwClsFlag = 0;
Vector3 vStart = EC_Utility.ToVector3(pEnvTrc.vStart);
Vector3 vExt = EC_Utility.ToVector3(pEnvTrc.vExt);
Vector3 vDelta = EC_Utility.ToVector3(pEnvTrc.vDelta);
Vector3 vTerStart = EC_Utility.ToVector3(pEnvTrc.vTerStart);
Vector3 dir = Vector3.zero;
if ((pEnvTrc.dwCheckFlag & CDR_EVN.CDR_BRUSH) == CDR_EVN.CDR_BRUSH)
{
dir = vStart + vDelta;
if (Physics.BoxCast(vStart, vExt, dir, out RaycastHit hit, Quaternion.identity, vDelta.magnitude, 1 << 7))
{
pEnvTrc.fFraction = (hit.distance - vExt.x) / vDelta.magnitude;
pEnvTrc.vHitNormal = EC_Utility.ToA3DVECTOR3(hit.normal);
pEnvTrc.dwClsFlag = CDR_EVN.CDR_BRUSH;
}
else
{
pEnvTrc.fFraction = 1f;
}
}
if ((pEnvTrc.dwCheckFlag & CDR_EVN.CDR_TERRAIN) == CDR_EVN.CDR_TERRAIN)
{
float fFractionTerrain = 0f;
dir = vDelta;
if (Physics.Raycast(vTerStart, dir.normalized, out RaycastHit hit, vDelta.magnitude, 1 << 6))
{
fFractionTerrain = (hit.distance) / vDelta.magnitude;
pEnvTrc.vHitNormal = EC_Utility.ToA3DVECTOR3(hit.normal);
pEnvTrc.dwClsFlag = CDR_EVN.CDR_TERRAIN;
}
else
{
fFractionTerrain = 1f;
}
if (fFractionTerrain < pEnvTrc.fFraction)
{
pEnvTrc.fFraction = fFractionTerrain;
}
}
if ((pEnvTrc.dwCheckFlag & CDR_EVN.CDR_WATER) == CDR_EVN.CDR_WATER)
{
float fFraction = 0f;
A3DVECTOR3 vWatNormal = new A3DVECTOR3();
bool bStart = false;
//@todo : TBD: use center or foot? By Kuiwu[10/10/2005]
//if (CollideWithWater(pEnvTrc.vWatStart, pEnvTrc.vDelta, pEnvTrc.bWaterSolid, ref fFraction, ref vWatNormal, ref bStart)
// && fFraction < pEnvTrc.fFraction)
//{
// pEnvTrc.fFraction = fFraction;
// pEnvTrc.vHitNormal = vWatNormal;
// pEnvTrc.bStartSolid = bStart;
// pEnvTrc.dwClsFlag = CDR_EVN.CDR_WATER;
// //# ifdef CDR_DEBUG
// // A3DVECTOR3 vHitPos(pEnvTrc.vWatStart +pEnvTrc.vDelta * fFraction);
// // sprintf(msg, "collide water, fraction %f pos %f %f %f \n", fFraction, vHitPos.x, vHitPos.y, vHitPos.z);
// // OUTPUT_DEBUG_INFO(msg);
// //#endif
//}
}
return (pEnvTrc.fFraction < 1.0f + 1E-4f);
}
// == 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.zero;
bSupport = false;
float dist = fDeltaY + vExt.y;//Mathf.Max(fDeltaY, 0f) + vExt.y;
Vector3 origin = vStart /*+ Vector3.down * vExt.y*/;
int countHits = Physics.RaycastNonAlloc(origin, Vector3.down, hits, dist, mask);
if (countHits > 0)
{
vHitNormal = hits[0].normal;
vEnd = new Vector3(vStart.x, hits[0].point.y + vExt.y, vStart.z);
bSupport = (vHitNormal.y >= 0f);
return true;
}
return true;
}
// ======= STATIC OnGroundMove GIỮ NGUYÊN VAI TRÒ TOÀN CỤC (C API) =======
public static void OnGroundMove(ref CDR_INFO CDRInfo)
{
CDRInfo.fMoveDist = 0.0f;
bool bFreeFall = (CDRInfo.vTPNormal.y < CDRInfo.fSlopeThresh);
if (CDRInfo.fYVel < VEL_EPSILON && CDRInfo.fYVel > -VEL_EPSILON && CDRInfo.fSpeed < VEL_EPSILON && CDRInfo.fSpeed > -VEL_EPSILON && !bFreeFall)
return;
float fYVel = CDRInfo.fYVel;
bool bJump = (fYVel > 0.5f);
Vector3 vVelocity = CDRInfo.fSpeed * EC_Utility.ToVector3(CDRInfo.vXOZVelDir) + fYVel * Vector3.up;
if (bFreeFall)
{
vVelocity += -CDRInfo.fGravityAccel * CDRInfo.t * Vector3.up;
fYVel += -CDRInfo.fGravityAccel * CDRInfo.t;
}
A3DVECTOR3 vVelDir = EC_Utility.ToA3DVECTOR3(vVelocity);
float fVelSpeed = vVelDir.Normalize();
if (!bFreeFall)
{
if (fVelSpeed > VEL_MAX_SPEED)
{
fVelSpeed = VEL_MAX_SPEED;
}
}
vVelocity = EC_Utility.ToVector3(vVelDir) * fVelSpeed;
float dtp = DotProduct(vVelDir, CDRInfo.vTPNormal);
if (dtp < 0f || !bJump)
{
vVelocity = EC_Utility.ToVector3((vVelDir -(CDRInfo.vTPNormal) * dtp - (CDRInfo.vTPNormal) * dtp * 0.01f) * fVelSpeed);
}
CDRInfo.vAbsVelocity = EC_Utility.ToA3DVECTOR3(vVelocity);
Vector3 vStart = EC_Utility.ToVector3(CDRInfo.vCenter);
Vector3 vExt = EC_Utility.ToVector3(CDRInfo.vExtent);
float fTime = CDRInfo.t;
Vector3 vDelta, vNormal = Vector3.zero, vFinalPos = vStart;
bool bPull = false;
bool bTryPull = false;
int nTry = 0;
LayerMask mask = UsedMask_Ground();
env_trace_t trcInfo = new env_trace_t();
trcInfo.dwCheckFlag = CDR_EVN.CDR_TERRAIN | CDR_EVN.CDR_BRUSH;
trcInfo.vExt = CDRInfo.vExtent;
int countHits = 0;
while (nTry < 1)
{
vDelta = vVelocity * (fTime);
float fDeltaDist = vDelta.magnitude;
Vector3 posFoot = vStart - Vector3.up * vExt.y;
vFinalPos = vStart;
if (fDeltaDist < DIST_EPSILON) break;
countHits = Physics.RaycastNonAlloc(vStart, (Vector3.down * vExt.y).normalized, hits, vExt.y, mask);
if (countHits > 0)
{
if (hits[0].point.y >= posFoot.y)
{
posFoot.y = hits[0].point.y;
}
}
//Debug.LogError("fDeltaDist = " + fDeltaDist + " vVelocity = " + vVelocity + " fTime = " + fTime + " speed = " + (fDeltaDist / fTime) + " posFoot + vDelta = " + (posFoot + vDelta) + " posFoot = " + posFoot);
countHits = Physics.RaycastNonAlloc(posFoot, (posFoot + vDelta).normalized, hits, fDeltaDist, mask);
bool bClear = !(countHits > 0);
nTry++;
if (bClear || (countHits > 0 && Vector3.Distance(hits[0].point, posFoot) < 0.0009f)) // Is 0.0009f the tolerance used to check if two points are the same?
{
vFinalPos = vStart + vDelta;
CDRInfo.fMoveDist += fDeltaDist;
break;
}
vStart = hits[0].point + Vector3.up * vExt.y;
vFinalPos = vStart;
countHits = Physics.RaycastNonAlloc(vStart, (Vector3.down).normalized, hits, vExt.y, mask);
if (countHits > 0)
{
vNormal = hits[0].normal;
}
else
{
vNormal = Vector3.zero;
}
// Step-up (giữ tinh thần bản gốc)
if (!bFreeFall && !bTryPull && !bJump)
{
posFoot = vStart - Vector3.up * vExt.y;
countHits = Physics.RaycastNonAlloc(vStart, (vStart + Vector3.down).normalized, hits, vExt.y, mask);
if (countHits > 0)
{
if (hits[0].point.y > posFoot.y)
{
posFoot.y = hits[0].point.y;
}
}
countHits = Physics.RaycastNonAlloc(posFoot, (Vector3.up).normalized, hits, CDRInfo.fStepHeight, mask);
bPull = !(countHits > 0);
if (bPull)
{
vStart += Vector3.up * CDRInfo.fStepHeight;
posFoot = vStart - Vector3.up * vExt.y;
fDeltaDist = (vVelocity.normalized).magnitude;
countHits = Physics.RaycastNonAlloc(posFoot, (posFoot + vVelocity).normalized, hits, fDeltaDist, mask);
bool bMove = !(countHits > 0);
if (!bMove)
{
fDeltaDist *= Vector3.Distance(vFinalPos, (hits[0].point + Vector3.up * vExt.y)) / fDeltaDist;
vFinalPos = hits[0].point + Vector3.up * vExt.y;
}
else
{
vFinalPos += vDelta;
}
if (fDeltaDist < (vExt.x * vExt.x * 4))
{
vFinalPos.y -= CDRInfo.fStepHeight;
bPull = false;
}
}
bTryPull = true;
}
if (!bPull)
{
fVelSpeed = Normalize(EC_Utility.ToA3DVECTOR3(vVelocity), ref vVelDir);
fVelSpeed *= (1 - nTry * 0.1f);
dtp = Vector3.Dot(vNormal, EC_Utility.ToVector3(vVelDir));
float fRelSpeed = Mathf.Min(fVelSpeed, 5.0f);
if (dtp >= 0f && dtp < 1e-4f)
{
vVelocity += vNormal * VEL_REFLECT * fRelSpeed;
}
else
{
vVelocity = (EC_Utility.ToVector3(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;
//mask = BrushMask;
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 = new A3DVECTOR3(0, 1, 0);
return;
}
if (bSupport)
{
vFinal = vEnd;
if (!bJump)
{
vTPNormal = groundNormal;
}
}
}
if ((vTPNormal.y >= CDRInfo.fSlopeThresh && fYVel < 0.0f) || (!bJump && fYVel > 0.0f))
{
fYVel = 0.0f;
}
vDelta = vFinalPos - EC_Utility.ToVector3(CDRInfo.vCenter);
CDRInfo.fMoveDist = vDelta.magnitude;
CDRInfo.vCenter = EC_Utility.ToA3DVECTOR3(vFinal);
CDRInfo.fYVel = fYVel;
CDRInfo.vTPNormal = EC_Utility.ToA3DVECTOR3(vTPNormal);
}
// Get normalize
static float Normalize(A3DVECTOR3 vIn, ref A3DVECTOR3 vOut)
{
float fMag = vIn.Magnitude();
if (fMag < 1e-6 && fMag > -1e-6)
{
vOut.Clear();
fMag = 0.0f;
}
else
{
float f = 1.0f / fMag;
vOut = vIn * f;
}
return fMag;
}
static bool SegmentTriangleIntersect(A3DVECTOR3 vStart, A3DVECTOR3 vDelta, A3DVECTOR3[] vert, ref float fFraction, bool bCull)
{
float dist = 0f;
A3DVECTOR3 vDir = new A3DVECTOR3(vDelta);
dist = vDir.Normalize();
if (dist < 1E-5f)
{
//assert(0 && "too small dist!");
fFraction = 0.0f;
return true;
}
float t = 0f, u = 0f, v = 0f;
if (RayTriangleIntersect(vStart, vDir, vert, ref t, ref u, ref v, bCull) && (t >= 0.0f) && (t <= dist))
{
//fFraction = t/dist;
//fFraction = a_Max( 0.0f, fFraction -1E-4f); //put back
fFraction = (t - 5E-4f) / dist;
AAssist.a_ClampFloor(ref fFraction, 0.0f);
return true;
}
return false;
}
static bool RayTriangleIntersect(A3DVECTOR3 vOrigin, A3DVECTOR3 vDir, A3DVECTOR3[] vert, ref float t, ref float u, ref float v, bool bCull)
{
// find vectors for two edges sharing vert0
A3DVECTOR3 edge1 = vert[1] - vert[0];
A3DVECTOR3 edge2 = vert[2] - vert[0];
// begin calculating determinant - also used to calculate U parameter
A3DVECTOR3 pvec = A3DVECTOR3.CrossProduct(vDir, edge2);
// if determinant is near zero, ray lies in plane of triangle
float det = A3DVECTOR3.DotProduct(edge1, pvec);
if (bCull)
{
if (det < LOCAL_EPSILON)
return false;
// From here, det is > 0.
// Calculate distance from vert0 to ray origin
A3DVECTOR3 tvec = vOrigin - vert[0];
// Calculate U parameter and test bounds
u = A3DVECTOR3.DotProduct(tvec, pvec);
if ((u < 0.0f) || (u > det))
return false;
// prepare to test V parameter
A3DVECTOR3 qvec = A3DVECTOR3.CrossProduct(tvec, edge1);
// calculate V parameter and test bounds
v = A3DVECTOR3.DotProduct(vDir, qvec);
if ((v < 0.0f) || (u + v > det))
return false;
// calculate t, ray intersects triangle
t = A3DVECTOR3.DotProduct(edge2, qvec);
// Det > 0 so we can early exit here
// Intersection point is valid if distance is positive
// (else it can just be a face behind the orig point)
if (t < 0.0f)
{
return false;
}
float OneOverDet = 1.0f / det;
t *= OneOverDet;
u *= OneOverDet;
v *= OneOverDet;
}
else
{
if (det > -LOCAL_EPSILON && det < LOCAL_EPSILON)
return false;
float OneOverDet = 1.0f / det;
// Calculate distance from vert0 to ray origin
A3DVECTOR3 tvec = vOrigin - vert[0];
// calculate U parameter and test bounds
u = A3DVECTOR3.DotProduct(tvec, pvec) * OneOverDet;
if ((u < 0.0f) || (u > 1.0f))
return false;
// prepare to test V parameter
A3DVECTOR3 qvec = A3DVECTOR3.CrossProduct(tvec, edge1);
// calculate V parameter and test bounds
v = A3DVECTOR3.DotProduct(vDir, qvec) * OneOverDet;
if ((v < 0.0f) || (u + v > 1.0f))
return false;
// calculate t, ray intersects triangle
t = A3DVECTOR3.DotProduct(edge2, qvec) * OneOverDet;
}
return true;
}
public static bool CollideWithTerrain(A3DVECTOR3 vStart, A3DVECTOR3 vDelta, ref float fFraction, ref A3DVECTOR3 vHitNormal, ref bool bStart)
{
CECWorld pWorld = CECWorld.Instance; //g_pGame.GetGameRun().GetWorld();
A3DTerrain2 pTerrain = pWorld.GetTerrain();
bStart = false;
float h1 = pTerrain.GetPosHeight(vStart, ref vHitNormal);
if (h1 > vStart.y + 1E-4f)
{//start under terrain
bStart = true;
fFraction = 0.0f;
return true;
}
int nWid, nHei; // in grid, 2 meters
float fMag = vDelta.Magnitude();
nWid = (int)Math.Ceiling(fMag / 2.0f);
nWid = Math.Max(3, nWid);
nHei = nWid;
int nTriangles = nWid * nHei * 2;
A3DVECTOR3[] pVerts = new A3DVECTOR3[(nWid + 1) * (nHei + 1)];
//assert(pVerts != NULL);
//memset(pVerts, 0, sizeof(A3DVECTOR3)* (nWid + 1) * (nHei + 1));
WORD[] pIndices = new WORD[nTriangles * 3];
//assert(pIndices != NULL);
//memset(pIndices, 0, sizeof(WORD)* nTriangles * 3);
if (!pTerrain.GetFacesOfArea(vStart, nWid, nHei, ref pVerts, ref pIndices))
{
//a_freetemp(pVerts);
// a_freetemp(pIndices);
return false;
}
int i;
A3DVECTOR3[] vert = new A3DVECTOR3[3];
//@note : Here init the fraction. By Kuiwu[9/10/2005]
fFraction = 100.0f;
float tmpFraction = fFraction;
for (i = 0; i < nTriangles; i++)
{
vert[0] = pVerts[pIndices[i * 3]];
vert[1] = pVerts[pIndices[i * 3 + 1]];
vert[2] = pVerts[pIndices[i * 3 + 2]];
//A3DVECTOR3 vPt;
//@note: Tomas Moller's JGT code : By Kuiwu[9/10/2005]
//@note: discard the engine version because it put back the hit point too much. By Kuiwu[13/10/2005]
// if(CLS_RayToTriangle(vStart, vDelta, *vert[0], *vert[1], *vert[2], vPt, true, &tmpFraction)
// && (tmpFraction <= 1.0f) && (tmpFraction < fFraction))
if (SegmentTriangleIntersect(vStart, vDelta, vert, ref tmpFraction, true) && (tmpFraction < fFraction))
{
//get the triangle normal
A3DVECTOR3 vEdge1 = vert[1] - vert[0];
A3DVECTOR3 vEdge2 = vert[2] - vert[0];
vHitNormal = A3DVECTOR3.CrossProduct(vEdge1, vEdge2);
vHitNormal.Normalize();
//@note : may be redundant, but to assure. By Kuiwu[17/10/2005]
A3DVECTOR3 vDir = new A3DVECTOR3();
A3DVECTOR3.Normalize(vDelta, out vDir);
if (A3DVECTOR3.DotProduct(vHitNormal, vDir) > 0.01f)
{//leave the hit plane
//assert(0 && "hit a plane with same direction!");
continue;
}
fFraction = Math.Max(0.0f, tmpFraction);
}
}
//a_freetemp(pVerts);
// a_freetemp(pIndices);
return (fFraction <= 1.0f);
}
public static bool AABBCollideWithBrush(ref BrushTraceInfo pInfo)
{
//TO DO: fix later
return false;
//CECWorld pWorld = CECWorld.Instance; //g_pGame.GetGameRun().GetWorld();
//CECOrnamentMan pOrnMan = pWorld.GetOrnamentMan();
//bool bBrush = pOrnMan.TraceWithBrush(ref pInfo);
//BrushTraceInfo info = pInfo;
//CECMatterMan pMatterMan = pWorld.GetMatterMan();
//if (pMatterMan.TraceWithBrush(ref info) && info.fFraction < pInfo.fFraction)
//{
// pInfo = info;
// bBrush = true;
//}
//info = pInfo;
//CECNPCMan pNPCMan = pWorld.GetNPCMan();
//if (pNPCMan.TraceWithBrush(ref info) && info.fFraction < pInfo.fFraction)
//{
// pInfo = info;
// bBrush = true;
//}
//return bBrush;
}
public static void OnAirMove(ref ON_AIR_CDR_INFO awmInfo)
{
//assert(0 && "Not ready yet");
if (awmInfo.bOnAir)
{
AirMove(ref awmInfo);
}
else
{
WaterMove(ref awmInfo);
}
}
static void AirMove(ref ON_AIR_CDR_INFO awmInfo)
{
float DIST_EPSILON = 1e-4f;
int MAX_TRY = 1;
float VEL_REFLECT = 0.0f;
float fTime = awmInfo.t;
//@todo : is it necessary to clamp the speed? By Kuiwu[20/9/2005]
float fSpeed = awmInfo.fSpeed;
if (fSpeed * fTime < DIST_EPSILON)
{
//@todo : set the output param. By Kuiwu[20/9/2005]
return;
}
A3DVECTOR3 vStart = new A3DVECTOR3(awmInfo.vCenter);
A3DVECTOR3 vExt = new A3DVECTOR3(awmInfo.vExtent);
A3DVECTOR3 vVelDir = new A3DVECTOR3(awmInfo.vVelDir);
float dtp = 0f;
A3DVECTOR3 vVelocity = new A3DVECTOR3(vVelDir * fSpeed);
if ((dtp = A3DVECTOR3.DotProduct(vVelDir, awmInfo.vTPNormal)) < 0.0f)
{
//vVelocity = (vVelDir - awmInfo.vTPNormal * dtp - awmInfo.vTPNormal*dtp * 0.01f) * fSpeed;
vVelocity = (vVelDir - awmInfo.vTPNormal * dtp) * fSpeed;
}
A3DVECTOR3 vDelta = new A3DVECTOR3(vVelocity * fTime),
vNormal = new A3DVECTOR3(),
vFinalPos = new A3DVECTOR3(vStart);
int nTry = 0;
bool bClear = true;
env_trace_t trcInfo = new env_trace_t();
trcInfo.bWaterSolid = true;
trcInfo.dwCheckFlag = CDR_EVN.CDR_TERRAIN | CDR_EVN.CDR_BRUSH | CDR_EVN.CDR_WATER;
trcInfo.vExt = vExt;
RaycastHit hit;
while (nTry < MAX_TRY)
{
if (vDelta.SquaredMagnitude() < DIST_EPSILON)
{
break;
}
trcInfo.vStart = vStart;
trcInfo.vDelta = vDelta;
trcInfo.vTerStart = vStart;
trcInfo.vTerStart.y -= vExt.y;
trcInfo.vWatStart = vStart;
trcInfo.vWatStart.y -= vExt.y;
//bClear = !CollideWithEnv(&trcInfo);
bClear = !Physics.BoxCast(EC_Utility.ToVector3(vStart),
EC_Utility.ToVector3(vExt),
EC_Utility.ToVector3(vStart + vVelDir).normalized,
out hit,
Quaternion.identity,
EC_Utility.ToVector3(vDelta).magnitude,
UsedMask_Ground());
++nTry;
if (bClear)
{
vFinalPos = vStart + vDelta;
}
else
{
vFinalPos = EC_Utility.ToA3DVECTOR3(hit.point);
vNormal = EC_Utility.ToA3DVECTOR3(hit.normal);
}
//vStart += vDelta * trcInfo.fFraction;
//vFinalPos = vStart;
//fTime -= fTime * trcInfo.fFraction;
//vNormal = trcInfo.vHitNormal;
//fSpeed = A3DVECTOR3.Normalize(vVelocity,out vVelDir);
//fSpeed *= (1 - nTry * 0.1f);
//dtp = A3DVECTOR3.DotProduct(vNormal, vVelDir);
//vVelocity = (vVelDir - vNormal * dtp - vNormal * dtp * VEL_REFLECT) * fSpeed;
//vDelta = vVelocity * fTime;
}
//@note : prevent moving to the invalid area. By Kuiwu[20/9/2005]
if (!IsPosInAvailableMap(vFinalPos))
{
//@todo : set some flag to notify the caller? By Kuiwu[20/9/2005]
return;
}
//too high
if (vFinalPos.y > FLY_MAX_HEIGHT - 2.0f)
{
return;
}
//see if meet height thresh
Vector3 posVStart = EC_Utility.ToVector3(vFinalPos);
float fDeltaY = awmInfo.fHeightThresh + 0.1f;
if (!Physics.Raycast(posVStart,
(posVStart + Vector3.down * fDeltaY).normalized,
out hit,
fDeltaY,
UsedMask_Ground()))
{
awmInfo.vCenter = vFinalPos;
awmInfo.vTPNormal = vNormal;
return;
}
else
{
vFinalPos = EC_Utility.ToA3DVECTOR3(hit.point);
vNormal = EC_Utility.ToA3DVECTOR3(hit.normal);
awmInfo.vCenter = vFinalPos;
awmInfo.vTPNormal = vNormal;
}
}
static void WaterMove(ref ON_AIR_CDR_INFO awmInfo)
{
}
//////////////////////////////////////////////////////////////////////////
// Note by wenfeng, 05-09-16
// This function is only for the Big world but not applicable for the
// Instance world!
//
//////////////////////////////////////////////////////////////////////////
static bool IsPosInAvailableMap(A3DVECTOR3 vPos)
{
float x, z;
int su, sv;
//bool bFlag = true;
CECWorld pWorld = EC_Game.GetGameRun().GetWorld();
if (pWorld != null)
{
int idInst = pWorld.GetInstanceID();
CECInstance pInst = EC_Game.GetGameRun().GetInstance(idInst);
if (pInst == null)
return false;
x = vPos.x + pInst.GetColNum() * 512.0f;
z = pInst.GetRowNum() * 512.0f - vPos.z;
su = (int)(x / 1024.0f);
sv = (int)(z / 1024.0f);
if (su >= pInst.GetColNum() || su < 0 ||
sv >= pInst.GetRowNum() || sv < 0)
return false;
switch (idInst)
{
case 1:
return available_maps[sv, su] != 0 && vPos.x <= 3877.0f; // ½ûÖ¹ëÊ×åÁÙ½ü¿´µ½µØÍ¼±ßÔµ
case 121:
case 122:
return available_maps4x4[sv, su] != 0 ? true : false;
case 118:
case 119:
case 120:
case 123:
case 125:
return available_maps3x3[sv, su] != 0 ? true : false;
case 134:
return available_maps2x2[sv, su] != 0 ? true : false;
case 137:
return available_maps_137[sv, su] != 0 ? true : false;
case 161:
return available_maps_161[sv, su] != 0;
case 162:
return available_maps_162[sv, su] != 0 ? true : false;
case 163:
return available_maps_163[sv, su] != 0 ? true : false;
default:
return true;
}
}
else
return true;
}
static float DotProduct(A3DVECTOR3 v1, A3DVECTOR3 v2) { return v1.x* v2.x + v1.y* v2.y + v1.z* v2.z;
}
}
public struct OtherPlayer_Move_Info
{
// Bounding sphere of avator
public A3DVECTOR3 vCenter;
public A3DVECTOR3 vExts;
public float fStepHeight;
public A3DVECTOR3 vVelocity;
public float t;
public bool bTraceGround; // Whether trace the ground
public bool bTestTrnOnly; // Trace terrain only
public A3DVECTOR3 vecGroundNormal; // if bTraceGround is true, this will contain the ground normal when returned
};
//@desc :used to trace the environment, brush&terrain&water By Kuiwu[8/10/2005]
public struct env_trace_t
{
public A3DVECTOR3 vStart; // brush start
public A3DVECTOR3 vExt;
public A3DVECTOR3 vDelta;
public A3DVECTOR3 vTerStart;
public A3DVECTOR3 vWatStart;
public uint dwCheckFlag;
public bool bWaterSolid;
public float fFraction;
public A3DVECTOR3 vHitNormal;
public bool bStartSolid; //start in solid
public uint dwClsFlag; //collision flag
};
// for on-air move case
//@note : change to AABB. By Kuiwu[22/9/2005]
public struct ON_AIR_CDR_INFO
{
public A3DVECTOR3 vCenter;
public A3DVECTOR3 vExtent;
// Hold a height from the surface of terrain or building
public float fHeightThresh;
// Velocity Info
public A3DVECTOR3 vVelDir;
public float fSpeed;
// time span ( sec )
public float t;
//@note : SlopeThresh seems useless on air or under water. By Kuiwu[22/9/2005]
// Slope Thresh
//float fSlopeThresh;
// Distance Thresh under the water surface
public float fUnderWaterDistThresh;
public A3DVECTOR3 vTPNormal;
// On air or water, true if on air, false for on water case.
public bool bOnAir;
// After the move action is done, If the fHeightThresh
// still be satisfied, bMeetHeightThresh is set to true.
public bool bMeetHeightThresh;
};
}