From 8508ad873f6cde0ec822c1763aa6a694beb8b58b Mon Sep 17 00:00:00 2001 From: Tungdv Date: Wed, 31 Dec 2025 15:09:10 +0700 Subject: [PATCH] fix: update logic swim. --- .../Scripts/Managers/EC_HPWorkStand.cs | 48 ++-- Assets/PerfectWorld/Scripts/Move/EC_CDR.cs | 247 +++++++++++++++--- ProjectSettings/TagManager.asset | 2 +- 3 files changed, 245 insertions(+), 52 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkStand.cs b/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkStand.cs index acf0204737..bca0dd01ec 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkStand.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkStand.cs @@ -175,8 +175,8 @@ namespace BrewMonster.Scripts { if (m_pHost.m_iMoveEnv == CECPlayer.Move_environment.MOVEENV_GROUND) Tick_Walk(fDeltaTime); - /* else // AIR or WATER - Tick_FlySwim(fDeltaTime);*/ + else // AIR or WATER + Tick_FlySwim(fDeltaTime); } if (m_iPoseAction == (int)PLAYER_ACTION_TYPE.ACT_STAND) @@ -236,25 +236,37 @@ namespace BrewMonster.Scripts } // Tick routine of flying or swimming - /* bool Tick_FlySwim(float fDeltaTime) - { - m_bMoving = false; + bool Tick_FlySwim(float fDeltaTime) + { + m_bMoving = false; - if (m_pHost.m_iMoveEnv == CECPlayer.Move_environment.MOVEENV_WATER && !m_bWaterStop) - { - // Handle floating at water surface after falling into water - A3DVECTOR3 vCurPos = m_pHost.GetPos(); - // ON_AIR_CDR_INFO not available in current C# port; approximate using CDR_INFO where applicable - float fSpeed = m_pHost.GetSwimSpeedSev(); + if (m_pHost.m_iMoveEnv == CECPlayer.Move_environment.MOVEENV_WATER && !m_bWaterStop) + { + // Handle floating at water surface after falling into water + A3DVECTOR3 vCurPos = m_pHost.GetPos(); + ON_AIR_CDR_INFO cdr = m_pHost.m_AirCDRInfo; + float fSpeed = m_pHost.GetSwimSpeedSev(); - // As we don't have water height/extent readily available on host in this port, - // retain structure and leave movement here minimal. - // If water height APIs are added, restore the original logic. - // m_bMoving = true; // enable when full water logic is available - } + if (m_pHost.m_GndInfo.fWaterHei - vCurPos.y < cdr.vExtent.y + m_pHost.m_MoveConst.fWaterSurf) + { + m_bMoving = true; - return true; - }*/ + vCurPos = m_pHost.m_MoveCtrl.AirWaterMove(-GPDataTypeHelper.g_vAxisY, fSpeed, fDeltaTime, false, false); + m_pHost.SetPos(EC_Utility.ToVector3(vCurPos)); + + if (m_pHost.m_MoveCtrl.MoveBlocked() >= 3 || + m_pHost.m_GndInfo.fWaterHei - vCurPos.y >= cdr.vExtent.y + m_pHost.m_MoveConst.fWaterSurf) + { + m_bWaterStop = true; + m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fSpeed, (int)GPMoveMode.GP_MOVE_WATER | (int)GPMoveMode.GP_MOVE_RUN); + } + else + m_pHost.m_MoveCtrl.SendMoveCmd(vCurPos, 2, GPDataTypeHelper.g_vOrigin, -GPDataTypeHelper.g_vAxisY * fSpeed, (int)GPMoveMode.GP_MOVE_WATER | (int)GPMoveMode.GP_MOVE_RUN); + } + } + + return true; + } // Get stop sliding flag public bool GetStopSlideFlag() diff --git a/Assets/PerfectWorld/Scripts/Move/EC_CDR.cs b/Assets/PerfectWorld/Scripts/Move/EC_CDR.cs index afda5d9a8c..d3d6ab78f9 100644 --- a/Assets/PerfectWorld/Scripts/Move/EC_CDR.cs +++ b/Assets/PerfectWorld/Scripts/Move/EC_CDR.cs @@ -18,6 +18,8 @@ namespace BrewMonster public static LayerMask WaterMask { get; set; } = 1 << 8; public static RaycastHit[] hits = new RaycastHit[5]; + public static RaycastHit[] fHitsTerrain = new RaycastHit[5]; + public static RaycastHit[] fHitsWater = new RaycastHit[5]; const float LOCAL_EPSILON = 1e-5f; const float FLY_MAX_HEIGHT = 800.0f; // ·ÉÐеÄ×î´ó¸ß¶È£¡ @@ -113,62 +115,99 @@ namespace BrewMonster Vector3 vExt = EC_Utility.ToVector3(pEnvTrc.vExt); Vector3 vDelta = EC_Utility.ToVector3(pEnvTrc.vDelta); Vector3 vTerStart = EC_Utility.ToVector3(pEnvTrc.vTerStart); + Vector3 vWatStart = EC_Utility.ToVector3(pEnvTrc.vWatStart); Vector3 dir = Vector3.zero; + int countHits = 0; 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)) + dir = vDelta; + countHits = Physics.BoxCastNonAlloc(vStart, vExt, dir.normalized, hits, Quaternion.identity, vDelta.magnitude, 1 << 7); + if (countHits > 0 && Vector3.Distance(hits[0].point, vStart) > 0.0009f) { - pEnvTrc.fFraction = (hit.distance - vExt.x) / vDelta.magnitude; - pEnvTrc.vHitNormal = EC_Utility.ToA3DVECTOR3(hit.normal); + pEnvTrc.fFraction = (hits[0].distance - vExt.x) / vDelta.magnitude; + pEnvTrc.vHitNormal = EC_Utility.ToA3DVECTOR3(hits[0].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)) + float fFractionTerrain = 100f; + dir = vTerStart + vDelta; + + countHits = 0; + countHits = Physics.RaycastNonAlloc(vTerStart, dir.normalized, fHitsTerrain, vDelta.magnitude, 1 << 6); + if (countHits > 0 && Vector3.Distance(fHitsTerrain[0].point, vTerStart) > 0.0009f) { - fFractionTerrain = (hit.distance) / vDelta.magnitude; - pEnvTrc.vHitNormal = EC_Utility.ToA3DVECTOR3(hit.normal); + fFractionTerrain = (hits[0].distance) / vDelta.magnitude; + pEnvTrc.vHitNormal = EC_Utility.ToA3DVECTOR3(hits[0].normal); pEnvTrc.dwClsFlag = CDR_EVN.CDR_TERRAIN; } - else - { - fFractionTerrain = 1f; - } if (fFractionTerrain < pEnvTrc.fFraction) { + hits = fHitsTerrain; pEnvTrc.fFraction = fFractionTerrain; } } if ((pEnvTrc.dwCheckFlag & CDR_EVN.CDR_WATER) == CDR_EVN.CDR_WATER) { - float fFraction = 0f; - A3DVECTOR3 vWatNormal = new A3DVECTOR3(); + float fFraction = 100f; + Vector3 vWatNormal = Vector3.zero; 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 + if (pEnvTrc.bWaterSolid && (vDelta.y > LOCAL_EPSILON)) + { + fFraction = 0; + } + else if (!pEnvTrc.bWaterSolid && (vDelta.y < -LOCAL_EPSILON)) + { + fFraction = 0; + } + else if (vDelta.y < LOCAL_EPSILON && vDelta.y > -LOCAL_EPSILON) + { //parallel the water plane + fFraction = 0; + } + else + { + float h0 = 0f; + int countHits0 = Physics.RaycastNonAlloc(vWatStart, Vector3.down, fHitsWater, 1000f, 1 << 8); + if (countHits0 > 0) + { + h0 = fHitsWater[0].point.y; + } + float h1 = 0f; + countHits0 = Physics.RaycastNonAlloc((vWatStart + vDelta), Vector3.down, fHitsWater, 1000f, 1 << 8); + if(countHits0 > 0) + { + h1 = fHitsWater[0].point.y; + } + float hWater = Mathf.Max(h0, h1); + vWatNormal = Vector3.up; + float t = (hWater - vWatStart.y) / pEnvTrc.vDelta.y; + if (t >= 0.0f && t <= 1.0f) + { + fFraction = Mathf.Max(0.0f, t - 1E-2f); + if (pEnvTrc.bWaterSolid && h0 > vStart.y) + { + fFraction = 0.0f; + bStart = true; + } - //} + if (!pEnvTrc.bWaterSolid && h0 < vStart.y) + { + fFraction = 0.0f; + bStart = true; + } + + if(fFraction < pEnvTrc.fFraction) + { + pEnvTrc.fFraction = fFraction; + pEnvTrc.vHitNormal = EC_Utility.ToA3DVECTOR3(vWatNormal); + pEnvTrc.bStartSolid = bStart; + pEnvTrc.dwClsFlag = CDR_EVN.CDR_WATER; + } + } + } } return (pEnvTrc.fFraction < 1.0f + 1E-4f); @@ -751,7 +790,149 @@ namespace BrewMonster static void WaterMove(ref ON_AIR_CDR_INFO awmInfo) { + 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 = awmInfo.vCenter; + A3DVECTOR3 vExt = awmInfo.vExtent; + A3DVECTOR3 vVelDir = awmInfo.vVelDir; + float dtp = 0f; + A3DVECTOR3 vVelocity = vVelDir* fSpeed; + + if ((dtp = DotProduct(vVelDir, awmInfo.vTPNormal)) < 0.0f) + { + vVelocity = (vVelDir - awmInfo.vTPNormal * dtp - awmInfo.vTPNormal * dtp * 0.01f) * fSpeed; + } + + A3DVECTOR3 vDelta = (vVelocity* fTime), vNormal, vFinalPos = vStart; + int nTry = 0; + bool bClear = true; + env_trace_t trcInfo = new env_trace_t(); + trcInfo.bWaterSolid = false; + trcInfo.dwCheckFlag = CDR_EVN.CDR_TERRAIN | CDR_EVN.CDR_BRUSH | CDR_EVN.CDR_WATER; + trcInfo.vExt = vExt; + + while (nTry < 1) + { + 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 += awmInfo.fUnderWaterDistThresh; //shoulder + + + bClear = !CollideWithEnv(ref trcInfo); + + ++nTry; + if (bClear || (trcInfo.bStartSolid && ((trcInfo.dwClsFlag & CDR_EVN.CDR_WATER) != CDR_EVN.CDR_WATER))) + { + vFinalPos = vStart + vDelta; + break; + } + vStart += vDelta * trcInfo.fFraction; + fTime -= fTime * trcInfo.fFraction; + fSpeed = Normalize(vVelocity,ref vVelDir); + fSpeed *= (1 - nTry * 0.1f); + if ((trcInfo.dwClsFlag & CDR_EVN.CDR_WATER) == CDR_EVN.CDR_WATER) + { + if (trcInfo.bStartSolid) + {//rescue from solid + //@note : it may cause some problems. By Kuiwu[11/10/2005] + float fHWater = 0f; + int countHits0 = Physics.RaycastNonAlloc(EC_Utility.ToVector3(vStart), Vector3.down, fHitsWater, 1000f, 1 << 8); + if(countHits0 > 0) + { + fHWater = fHitsWater[0].point.y; + } + vStart.y = fHWater; + } + vVelDir.y = 0.0f; + vVelocity = vVelDir * fSpeed; + } + else + { + vNormal = trcInfo.vHitNormal; + dtp = DotProduct(vNormal, vVelDir); + vVelocity = (vVelDir - vNormal * dtp - vNormal * dtp * VEL_REFLECT) * fSpeed; + } + vDelta = vVelocity * fTime; + vFinalPos = vStart; + + } + + //@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; + } + + + //see if meet height thresh + Vector3 v3Start = EC_Utility.ToVector3(vFinalPos); + Vector3 v3Ext = EC_Utility.ToVector3(vExt); + float fDeltaY = awmInfo.fHeightThresh + 0.1f; + + if (!DoGroundProbe(v3Start, v3Ext, fDeltaY, UsedMask_Ground(), out Vector3 vEnd, out Vector3 groundNormal, out bool bSupport)) + { + return; + } + + A3DVECTOR3 vTpNormal = new A3DVECTOR3(0.0f); + A3DVECTOR3 vOverTp = vFinalPos; + bool bAdjust = false; + awmInfo.bMeetHeightThresh = true; + + if (bSupport) + { + bAdjust = true; + vOverTp = EC_Utility.ToA3DVECTOR3(vEnd); + vTpNormal = EC_Utility.ToA3DVECTOR3(groundNormal); + } + + if (bAdjust && (vOverTp.y + awmInfo.fHeightThresh > vFinalPos.y)) + { + float fHWater = 0f; + int countHits = Physics.RaycastNonAlloc(EC_Utility.ToVector3(vFinalPos), Vector3.down, fHitsWater, 1000f, 1 << 8); + if (countHits > 0) + { + fHWater = fHitsWater[0].point.y; + } + + float fAllow = fHWater - awmInfo.fUnderWaterDistThresh - vFinalPos.y; + if (fAllow > 1E-4f) + { + vDelta.Clear(); + vDelta.y = vOverTp.y + awmInfo.fHeightThresh - vFinalPos.y; + fAllow = EC_Utility.a_Min(fAllow, 0.15f); + AAssist.a_ClampRoof(ref vDelta.y, fAllow); + Vector3 dir = EC_Utility.ToVector3(vDelta); + countHits = Physics.BoxCastNonAlloc(v3Start, v3Ext, dir.normalized, hits, Quaternion.identity, dir.magnitude, 1 << 7); + if (countHits > 0) + { + vFinalPos += EC_Utility.ToA3DVECTOR3(hits[0].point); + } + else + { + vFinalPos += vDelta; + } + awmInfo.bMeetHeightThresh = (vFinalPos.y - vOverTp.y > awmInfo.fHeightThresh); + } + } + + awmInfo.vCenter = vFinalPos; + awmInfo.vTPNormal = vTpNormal; } ////////////////////////////////////////////////////////////////////////// diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index 6ec4c82730..18e7f6c412 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -13,7 +13,7 @@ TagManager: - UI - Terrain - Brush - - + - Water - - -