Files
test/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs
T
2025-10-25 17:28:46 +07:00

692 lines
26 KiB
C#

using BrewMonster;
using BrewMonster.Managers;
using BrewMonster.Scripts;
using CSNetwork;
using CSNetwork.GPDataType;
using CSNetwork.Protocols.RPCData;
using System;
using UnityEngine;
namespace PerfectWorld.Scripts.Player
{
public class EC_ElsePlayer : CECPlayer
{
A3DVECTOR3 m_vMoveDir; // Player's velocity
public A3DVECTOR3 m_vServerPos; // Player's real position on server
A3DVECTOR3 m_vStopDir; // The direction when player stop moving
// 是否是依附者 = Is it a dependent/attacher?
bool m_bHangerOn;
// 依附者或被依附者id = The ID of the attacher (dependent) or the attached target.
int m_iBuddyId;
bool m_bStopMove; // Stop move flag
public const float MAX_LAGDIST = 10.0f; // Maximum lag distance
A3DVECTOR3 g_vAxisY = new A3DVECTOR3(0.0f, 1.0f, 0.0f);
long m_dwLastMoveTime = 0; // Last move command arrived time
float m_fMoveSpeed; // Move speed
OtherPlayer_Move_Info m_cdr = new OtherPlayer_Move_Info();
float m_fDistToHost = 0f; // Distance to host player
float m_fDistToHostH = 0f; // Horizontal distance to host player
public CECCounter m_FightCnt;
CECEPWorkMan m_pEPWorkMan;
CECHostPlayer pHost => EC_ManMessageMono.Instance?.GetECManPlayer?.GetHostPlayer();
public void Init(RoleInfo roleInfo, info_player_1 Info)
{
m_dwResFlags = (uint)PlayerResourcesReadyFlag.RESFG_ALL;
m_pEPWorkMan = new CECEPWorkMan(this);
m_iProfession = roleInfo.occupation;
m_iGender = roleInfo.gender;
CalcPlayerAABB();
SetServerPos(Info.pos);
SetPos(Info.pos);
m_cdr.fStepHeight = m_MoveConst.fStepHei;
m_cdr.vExts = m_aabbServer.Extents;
m_cdr.vVelocity.Clear();
m_FightCnt = new CECCounter();
m_FightCnt.SetPeriod(15000);
m_FightCnt.Reset(true);
A3DVECTOR3 vPos = GetPos();
m_aabb.Center = vPos + new A3DVECTOR3(0.0f, m_aabb.Extents.y, 0.0f);
m_aabb.CompleteMinsMaxs();
m_aabbServer.Center = vPos + new A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f);
m_aabbServer.CompleteMinsMaxs();
if (TryGetComponent<PlayerVisual>(out var visual))
{
visual.InitHostPlayerEventDoneHandler();
}
}
public void MoveTo(cmd_object_move Cmd)
{
BrewMonster.BMLogger.Log("HoangDev : MoveToMoveTo");
if (Cmd.use_time == 0)
return;
SetServerPos(Cmd.dest);
m_vMoveDir = Cmd.dest - GetPos();
float fDist = m_vMoveDir.Normalize();
m_bStopMove = false;
// If destination position is too far to us, forcely pull player
// to that position.
if (fDist >= MAX_LAGDIST)
{
BrewMonster.BMLogger.Log("HoangDev : fDist >= MAX_LAGDIST");
SetPos(Cmd.dest);
//m_pEPWorkMan.FinishWork(CECEPWork::WORK_MOVE);
return;
}
int iMoveMode = Cmd.move_mode;
m_cdr.bTraceGround = true;
if (((GPMoveMode)iMoveMode & GPMoveMode.GP_MOVE_AIR) != 0)
{
m_iMoveEnv = (int)MoveEnvironment.MOVEENV_AIR;
m_cdr.bTraceGround = false;
}
else if (((GPMoveMode)iMoveMode & GPMoveMode.GP_MOVE_WATER) != 0)
{
m_iMoveEnv = (int)MoveEnvironment.MOVEENV_WATER;
m_cdr.bTraceGround = false;
//ShowWing(false);
}
else
{
m_iMoveEnv = (int)MoveEnvironment.MOVEENV_GROUND;
//if (!IsFlying())
// ShowWing(false);
}
switch ((GPMoveMode)iMoveMode & GPMoveMode.GP_MOVE_MASK)
{
case GPMoveMode.GP_MOVE_WALK: m_iMoveMode = (int)MoveMode.MOVE_MOVE; m_bWalkRun = false; break;
case GPMoveMode.GP_MOVE_RUN: m_iMoveMode = (int)MoveMode.MOVE_MOVE; m_bWalkRun = true; break;
case GPMoveMode.GP_MOVE_SLIDE: m_iMoveMode = (int)MoveMode.MOVE_SLIDE; break;
case GPMoveMode.GP_MOVE_FALL: m_iMoveMode = (int)MoveMode.MOVE_FREEFALL; m_cdr.bTraceGround = false; break;
case GPMoveMode.GP_MOVE_FLYFALL: m_cdr.bTraceGround = false; break;
case GPMoveMode.GP_MOVE_JUMP: m_iMoveMode = (int)MoveMode.MOVE_JUMP; m_cdr.bTraceGround = false; break;
}
long dwTimeNow = Environment.TickCount;
long dwDeltaTime = (dwTimeNow > m_dwLastMoveTime) ? (dwTimeNow - m_dwLastMoveTime) : 0;
m_dwLastMoveTime = dwTimeNow;
if (dwDeltaTime < 500)
dwDeltaTime = 500;
if (dwDeltaTime > 1000)
dwDeltaTime = 1000;
float fSpeed = (Cmd.sSpeed) / 256f; // short / 256 <=> FIX8TOFLOAT(short)
m_fMoveSpeed = fDist / (dwDeltaTime * 0.001f);
Mathf.Clamp(m_fMoveSpeed, 0.0f, fSpeed * 1.2f);
//if (!m_pPlayerModel) return;
//if (!IsValidAction(iCurAction)) return;
PlayAction(GetMoveStandAction(true), true, 1, false);
}
public bool MovingTo(float dwDeltaTime)
{
bool bRet = false;
A3DVECTOR3 vPos, vCurPos = GetPos();
float fDeltaTime = dwDeltaTime;
if (m_bStopMove)
{
A3DVECTOR3 vDir = m_vServerPos - vCurPos;
float fDist = vDir.Normalize();
if (vDir.IsZero()) return false;
Quaternion targetRotation = Quaternion.LookRotation(EC_Utility.ToVector3(vDir));
if (Quaternion.Angle(transform.rotation, targetRotation) < 0.5f)
transform.rotation = targetRotation;
else
transform.rotation = Quaternion.Slerp(
transform.rotation,
targetRotation,
rotationSpeed * Time.deltaTime
);
vPos = MoveStep(vDir, m_fMoveSpeed, fDeltaTime);
float fMoveDelta = A3d_Magnitude(vPos - vCurPos);
if (Math.Abs(fMoveDelta - 0f) <= float.Epsilon || fMoveDelta >= fDist) //!fMoveDelta <=> (Math.Abs(fMoveDelta - 0f) <= float.Epsilon) Compare with 0
{
SetPos(m_vServerPos);
PlayAction(GetMoveStandAction(false), true, 1, false);
bRet = true;
}
else
{
SetPos(vPos);
}
}
else // Just move on
{
// If we have move so far from destination and still don't
// receive new 'move' or 'stop move' command, it's better to
// stop moving and goto last destination at once
if (m_vMoveDir.IsZero()) return false;
A3DVECTOR3 vDir = m_vMoveDir;
vDir.Normalize();
Quaternion targetRotation = Quaternion.LookRotation(EC_Utility.ToVector3(vDir));
if (Quaternion.Angle(transform.rotation, targetRotation) < 0.5f)
transform.rotation = targetRotation;
else
transform.rotation = Quaternion.Slerp(
transform.rotation,
targetRotation,
rotationSpeed * Time.deltaTime
);
vPos = MoveStep(vDir, m_fMoveSpeed, fDeltaTime);
SetPos(vPos);
float fDist = A3d_Magnitude(m_vServerPos - vCurPos);
if (fDist >= MAX_LAGDIST)
{
SetPos(m_vServerPos);
return true;
}
}
return bRet;
}
public void StopMoveTo(cmd_object_stop_move Cmd)
{
m_vMoveDir = Cmd.dest - GetPos();
m_bStopMove = true;
m_fMoveSpeed = (Cmd.sSpeed) / 256f;
m_vStopDir = glb_DecompressDirH(Cmd.dir);
SetServerPos(Cmd.dest);
float fDist = m_vMoveDir.Normalize();
BrewMonster.BMLogger.Log($"HoangDev : {fDist} : {MAX_LAGDIST} || {m_fMoveSpeed}");
if (fDist >= MAX_LAGDIST || m_fMoveSpeed < 0.01f)
{
m_bStopMove = false;
SetPos(Cmd.dest);
PlayAction(GetMoveStandAction(true), true, 1, false);
return;
}
int iMoveMode = Cmd.move_mode;
m_cdr.bTraceGround = true;
if (((GPMoveMode)iMoveMode & GPMoveMode.GP_MOVE_AIR) != 0)
{
m_iMoveEnv = (int)MoveEnvironment.MOVEENV_AIR;
m_cdr.bTraceGround = false;
}
else if (((GPMoveMode)iMoveMode & GPMoveMode.GP_MOVE_WATER) != 0)
{
m_iMoveEnv = (int)MoveEnvironment.MOVEENV_WATER;
m_cdr.bTraceGround = false;
}
else
m_iMoveEnv = (int)MoveEnvironment.MOVEENV_GROUND;
switch ((GPMoveMode)iMoveMode & GPMoveMode.GP_MOVE_MASK)
{
case GPMoveMode.GP_MOVE_WALK: m_iMoveMode = (int)MoveMode.MOVE_MOVE; m_bWalkRun = false; break;
case GPMoveMode.GP_MOVE_RUN: m_iMoveMode = (int)MoveMode.MOVE_MOVE; m_bWalkRun = true; break;
case GPMoveMode.GP_MOVE_SLIDE: m_iMoveMode = (int)MoveMode.MOVE_SLIDE; break;
case GPMoveMode.GP_MOVE_FALL: m_iMoveMode = (int)MoveMode.MOVE_FREEFALL; m_cdr.bTraceGround = false; break;
case GPMoveMode.GP_MOVE_FLYFALL: m_cdr.bTraceGround = false; break;
case GPMoveMode.GP_MOVE_JUMP: m_iMoveMode = (int)MoveMode.MOVE_JUMP; m_cdr.bTraceGround = false; break;
}
PlayAction(GetMoveStandAction(true), true, 1, false);
}
public float GetDistToHost() { return m_fDistToHost; }
// Decompress horizontal direction
A3DVECTOR3 glb_DecompressDirH(byte byDir)
{
float fInter = 360.0f / 256.0f;
float fRad = Mathf.Deg2Rad * (byDir * fInter);
A3DVECTOR3 v;
v.x = (float)Math.Cos(fRad);
v.z = (float)Math.Sin(fRad);
v.y = 0.0f;
return v;
}
public void EnterFightState()
{
m_FightCnt.Reset(false);
}
private A3DVECTOR3 MoveStep(A3DVECTOR3 vDir, float fSpeed, float fTime)
{
A3DVECTOR3 vRealDir = vDir;
// OnAirMove only accept positive speed value
if (fSpeed < 0.0f)
{
vRealDir = -vDir;
fSpeed = -fSpeed;
}
m_cdr.vCenter = m_aabbServer.Center;
//Debug.LogError("m_aabbServer.Center = " + m_aabbServer.Center.x + "," + m_aabbServer.Center.y + ","+ m_aabbServer.Center.z);
m_cdr.vVelocity = vRealDir * fSpeed;
//Debug.LogError("vVelocity = " + m_cdr.vVelocity.x + "," + m_cdr.vVelocity.y + "," + m_cdr.vVelocity.z);
m_cdr.t = fTime;
m_cdr.bTestTrnOnly = false;
//OtherPlayerMove(m_cdr);
A3DVECTOR3 vDelta = m_cdr.t * m_cdr.vVelocity;
m_cdr.vCenter += vDelta;
m_cdr.vecGroundNormal = g_vAxisY;
//if (m_cdr.bTraceGround)
// SetGroundNormal(m_cdr.vecGroundNormal);
//else
// SetGroundNormal(g_vAxisY);
return m_cdr.vCenter - g_vAxisY * m_cdr.vExts.y;
}
void OtherPlayerMove(OtherPlayer_Move_Info OPMoveInfo)
{
A3DVECTOR3 vDelta = OPMoveInfo.t * OPMoveInfo.vVelocity;
OPMoveInfo.vCenter += vDelta;
OPMoveInfo.vecGroundNormal = g_vAxisY;
A3DVECTOR3 vGroundPos, vNormal;
// Now, we directly interpolate the pos, and we don't use bTraceGround
//if (OPMoveInfo.bTestTrnOnly)
//{
// GetTerrainInfo(OPMoveInfo.vCenter, vGroundPos, vNormal);
// vGroundPos.y += OPMoveInfo.vExts.y;
// if (OPMoveInfo.vCenter.y < vGroundPos.y + 0.1f)
// OPMoveInfo.vecGroundNormal = vNormal;
// // verify not below the terrain
// if (OPMoveInfo.vCenter.y < vGroundPos.y)
// OPMoveInfo.vCenter.y = vGroundPos.y;
//}
//else
//{
// if (VertRayTrace(OPMoveInfo.vCenter, vGroundPos, vNormal, 3.0f))
// {
// OPMoveInfo.vecGroundNormal = vNormal;
// vGroundPos.y += OPMoveInfo.vExts.y;
// // verify not below the ground
// if (OPMoveInfo.vCenter.y < vGroundPos.y)
// OPMoveInfo.vCenter.y = vGroundPos.y;
// }
//}
}
private float A3d_Magnitude(A3DVECTOR3 v)
{
return Mathf.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
}
// Set server position
public void SetServerPos(A3DVECTOR3 vPos)
{
BrewMonster.BMLogger.Log("SetServerPos ");
m_vServerPos = vPos;
// If this player is a mule, change it's rider's server pos too.
if (m_iBuddyId != 0 && !m_bHangerOn)
{
var pPlayer = EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(m_iBuddyId);
if (pPlayer)
pPlayer.SetServerPos(vPos);
}
}
private void Update()
{
MovingTo(Time.deltaTime);
if (pHost != null /*&& pHost.IsSkeletonReady()*/)
{
m_fDistToHost = CalcDist(pHost.GetPos(), true);
m_fDistToHostH = CalcDist(pHost.GetPos(), false);
}
m_pEPWorkMan?.Tick(Time.deltaTime);
}
public void SetPos(A3DVECTOR3 vPos)
{
Vector3 vector = new Vector3();
vector.x = vPos.x;
vector.y = vPos.y;
vector.z = vPos.z;
transform.position = vector;
m_aabb.Center = vPos + new A3DVECTOR3(0.0f, m_aabb.Extents.y, 0.0f);
m_aabb.CompleteMinsMaxs();
m_aabbServer.Center = vPos + new A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f);
m_aabbServer.CompleteMinsMaxs();
}
public A3DVECTOR3 GetPos()
{
A3DVECTOR3 result = new A3DVECTOR3();
result.x = transform.position.x;
result.y = transform.position.y;
result.z = transform.position.z;
return result;
}
// Get player's real position on server
public A3DVECTOR3 GetServerPos() { return m_vServerPos; }
public bool ProcessMessage(ECMSG Msg)
{
switch (Msg.dwMsg)
{
case long value when value == EC_MsgDef.MSG_PM_PLAYERATKRESULT:
OnMsgPlayerAtkResult(Msg);
break;
}
return true;
}
void OnMsgPlayerAtkResult(ECMSG Msg)
{
cmd_object_atk_result pCmd = GPDataTypeHelper.FromBytes<cmd_object_atk_result>((byte[])Msg.dwParam1);
//ASSERT(pCmd && pCmd.attacker_id == m_PlayerInfo.cid);
// Face to target
TurnFaceTo(pCmd.target_id);
// TO DO: fix later
int attackTime = int.MinValue;
PlayAttackEffect(pCmd.target_id, 0, 0, -1, (uint)pCmd.attack_flag, pCmd.speed* 50, ref attackTime);
if (!m_pEPWorkMan.FindWork(CECEPWorkMan.Work_type.WT_NORMAL, CECEPWork.EP_work_ID.WORK_HACKOBJECT)){
m_pEPWorkMan.StartNormalWork(new CECEPWorkMelee(m_pEPWorkMan, pCmd.target_id));
}
// Enter fight state
EnterFightState();
}
// Play an attack effect
//void PlayAttackEffect(int idTarget, int idSkill, int skillLevel, int nDamage,
// uint dwModifier, int nAttackSpeed, int[] piAttackTime/* NULL */, int nSection)
//{
// if (!IsAllResReady())
// return;
// if (idSkill == 0)
// {
// int idWeapon = IsShapeChanged() ? 0 : GetWeaponID();
// int nTimeFly = 10;
// if (idWeapon != 0)
// {
// // ¿´¿´ÊDz»ÊÇÔ¶³ÌÎäÆ÷
// DATA_TYPE dt;
// WEAPON_ESSENCE pWeapon = (WEAPON_ESSENCE)g_pGame.GetElementDataMan().get_data_ptr(idWeapon, ID_SPACE_ESSENCE, dt);
// //ASSERT(dt == DT_WEAPON_ESSENCE);
// if (dt == DT_WEAPON_ESSENCE && pWeapon && pWeapon.require_projectile)
// {
// nTimeFly = 700;
// if (m_aEquips[EQUIPIVTR_PROJECTILE])
// idWeapon = m_aEquips[EQUIPIVTR_PROJECTILE]; // set weapon to the projectile
// }
// }
// if (g_pGame.GetGameRun().GetWorld().GetAttacksMan().FindAttackByAttacker(GetPlayerInfo().cid))
// {
// // signal early attack event
// ClearComActFlagAllRankNodes(true);
// }
// // melee attack
// CECAttackEvent pAttack = g_pGame.GetGameRun().GetWorld().GetAttacksMan().AddMeleeAttack(
// GetPlayerInfo().cid, idTarget, idWeapon, dwModifier, nDamage, nTimeFly);
// if (pAttack != null)
// {
// if (!IsDead() && (dwModifier & CECAttackEvent::MOD_RETORT) == 0
// && (dwModifier & CECAttackEvent::MOD_ATTACK_AURA) == 0
// && PlayAttackAction(nAttackSpeed, piAttackTime, &pAttack.m_bSignaled)
// && (dwModifier & CECAttackEvent::MOD_BEAT_BACK) == 0)
// {
// }
// else
// {
// pAttack.m_bSignaled = true;
// }
// }
// }
// else
// {
// if (skillLevel == 0)
// {
// if (m_pCurSkill)
// skillLevel = m_pCurSkill.GetSkillLevel();
// else
// skillLevel = 1;
// }
// CECAttackEvent pAttack = null;
// // first try to find if there is already a skill attack event in attackman
// CECAttackerEvents attackerEvents = g_pGame.GetGameRun().GetWorld().GetAttacksMan().FindAttackByAttacker(GetPlayerInfo().cid);
// if (attackerEvents)
// {
// CECAttackEvent pAttack = attackerEvents.Find(idSkill, nSection);
// if (() != null)
// {
// // Ãæ¹¥»÷µÄ·ÇµÚÒ»´ÎÉ˺¦ÏûÏ¢
// pAttack.AddTarget(idTarget, dwModifier, nDamage);
// goto EXIT;
// }
// else
// {
// attackerEvents.Signal();
// }
// }
// if (GNET::ElementSkill::IsGoblinSkill(idSkill) &&
// GNET::ElementSkill::GetType(idSkill) == 2)
// {
// pAttack = g_pGame.GetGameRun().GetWorld().GetAttacksMan().AddSkillAttack(
// GetPlayerInfo().cid, GetPlayerInfo().cid, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage);
// }
// else
// {
// // begin a skill attack
// pAttack = g_pGame.GetGameRun().GetWorld().GetAttacksMan().AddSkillAttack(
// GetPlayerInfo().cid, m_idCurSkillTarget, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage);
// }
// if (pAttack)
// {
// pAttack.SetSkillSection(nSection);
// if (!IsDead() && (dwModifier & CECAttackEvent::MOD_RETORT) == 0
// && (dwModifier & CECAttackEvent::MOD_ATTACK_AURA) == 0
// && PlaySkillAttackAction(idSkill, nAttackSpeed, NULL, nSection, &pAttack.m_bSignaled)
// && (dwModifier & CECAttackEvent::MOD_BEAT_BACK) == 0)
// {
// }
// else
// {
// pAttack.m_bSignaled = true;
// }
// }
// EXIT:
// // For skill attacking, time is always set to 0
// if (piAttackTime)
// *piAttackTime = 0;
// }
//}
//public A3DVECTOR3 GetPos()
//{
// return new A3DVECTOR3(transform.position.x, transform.position.y, transform.position.z);
//}
}
// Player appear flag
public enum PlayerAppearFlag
{
APPEAR_DISAPPEAR = -1, // Player disappear
APPEAR_ENTERWORLD = 0, // Player join world
APPEAR_RUNINTOVIEW, // Player run into view
APPEAR_GHOST, // Player is in ghost state, in player list but not active
};
public struct OtherPlayer_Move_Info
{
// Bounding sphere of avator
public A3DVECTOR3 vCenter;
public A3DVECTOR3 vExts;
public float fStepHeight;
// Velocity
public A3DVECTOR3 vVelocity;
// time span ( sec )
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
}
public class A3DAABB
{
public A3DVECTOR3 Center;
public A3DVECTOR3 Extents;
public A3DVECTOR3 Mins;
public A3DVECTOR3 Maxs;
public A3DAABB() { }
public A3DAABB(A3DAABB aabb)
{
Center = aabb.Center;
Extents = aabb.Extents;
Mins = aabb.Mins;
Maxs = aabb.Maxs;
}
public A3DAABB(A3DVECTOR3 mins, A3DVECTOR3 maxs)
{
Mins = mins;
Maxs = maxs;
Center = (mins + maxs) * 0.5f;
Extents = maxs - Center;
}
// Reset AABB về trạng thái rỗng
public void Clear()
{
Mins = new A3DVECTOR3(999999f, 999999f, 999999f);
Maxs = new A3DVECTOR3(-999999f, -999999f, -999999f);
Center = new A3DVECTOR3(0f, 0f, 0f);
Extents = new A3DVECTOR3(0f, 0f, 0f);
}
// Thêm 1 điểm vào AABB
public void AddVertex(A3DVECTOR3 v)
{
if (v.x < Mins.x) Mins.x = v.x;
if (v.y < Mins.y) Mins.y = v.y;
if (v.z < Mins.z) Mins.z = v.z;
if (v.x > Maxs.x) Maxs.x = v.x;
if (v.y > Maxs.y) Maxs.y = v.y;
if (v.z > Maxs.z) Maxs.z = v.z;
CompleteCenterExts();
}
// Hợp nhất 2 AABB
public void Merge(A3DAABB subAABB)
{
if (subAABB.Mins.x < Mins.x) Mins.x = subAABB.Mins.x;
if (subAABB.Mins.y < Mins.y) Mins.y = subAABB.Mins.y;
if (subAABB.Mins.z < Mins.z) Mins.z = subAABB.Mins.z;
if (subAABB.Maxs.x > Maxs.x) Maxs.x = subAABB.Maxs.x;
if (subAABB.Maxs.y > Maxs.y) Maxs.y = subAABB.Maxs.y;
if (subAABB.Maxs.z > Maxs.z) Maxs.z = subAABB.Maxs.z;
CompleteCenterExts();
}
// Cập nhật Mins, Maxs từ Center + Extents
public void CompleteMinsMaxs()
{
Mins = Center - Extents;
Maxs = Center + Extents;
}
// Cập nhật Center + Extents từ Mins, Maxs
public void CompleteCenterExts()
{
Center = (Mins + Maxs) * 0.5f;
Extents = Maxs - Center;
}
// Kiểm tra điểm có nằm trong AABB không
public bool IsPointIn(A3DVECTOR3 v)
{
return !(v.x > Maxs.x || v.x < Mins.x ||
v.y > Maxs.y || v.y < Mins.y ||
v.z > Maxs.z || v.z < Mins.z);
}
// Kiểm tra 1 AABB khác có nằm trong AABB này không
public bool IsAABBIn(A3DAABB aabb)
{
return (aabb.Mins.x >= Mins.x && aabb.Maxs.x <= Maxs.x &&
aabb.Mins.y >= Mins.y && aabb.Maxs.y <= Maxs.y &&
aabb.Mins.z >= Mins.z && aabb.Maxs.z <= Maxs.z);
}
// Xây AABB từ một tập vertices
public void Build(A3DVECTOR3[] vertices)
{
Clear();
foreach (var v in vertices)
AddVertex(v);
}
// Lấy các vertices (8 điểm) của AABB
public A3DVECTOR3[] GetVertices()
{
A3DVECTOR3[] verts = new A3DVECTOR3[8];
verts[0] = new A3DVECTOR3(Mins.x, Mins.y, Mins.z);
verts[1] = new A3DVECTOR3(Maxs.x, Mins.y, Mins.z);
verts[2] = new A3DVECTOR3(Maxs.x, Maxs.y, Mins.z);
verts[3] = new A3DVECTOR3(Mins.x, Maxs.y, Mins.z);
verts[4] = new A3DVECTOR3(Mins.x, Mins.y, Maxs.z);
verts[5] = new A3DVECTOR3(Maxs.x, Mins.y, Maxs.z);
verts[6] = new A3DVECTOR3(Maxs.x, Maxs.y, Maxs.z);
verts[7] = new A3DVECTOR3(Mins.x, Maxs.y, Maxs.z);
return verts;
}
}
}