using this gta sa snippet (CPed, CPhysics etc...) how to make same behavior for jumping and falling in my code (with minimal change): m_fMass = 70.0f; m_fTurnMass = 100.0f; m_fAirResistance = 0.4f / m_fMass; m_fElasticity = 0.05f; void CPed::SetJump(void) { if (!bInVehicle && #if defined VC_PED_PORTS || defined FIX_BUGS m_nPedState != PED_JUMP && !RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_JUMP_LAUNCH) && #endif (m_nSurfaceTouched != SURFACE_STEEP_CLIFF || DotProduct(GetForward(), m_vecDamageNormal) >= 0.0f)) { SetStoredState(); SetPedState(PED_JUMP); CAnimBlendAssociation *jumpAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_JUMP_LAUNCH, 8.0f); jumpAssoc->SetFinishCallback(FinishLaunchCB, this); m_fRotationDest = m_fRotationCur; } } void CPed::FinishLaunchCB(CAnimBlendAssociation *animAssoc, void *arg) { CPed *ped = (CPed*)arg; if (ped->m_nPedState != PED_JUMP) return; CVector forward(0.15f * ped->GetForward() + ped->GetPosition()); forward.z += CModelInfo::GetColModel(ped->GetModelIndex())->spheres->center.z + 0.25f; CEntity *obstacle = CWorld::TestSphereAgainstWorld(forward, 0.25f, nil, true, true, false, true, false, false); if (!obstacle) { // Forward of forward forward += 0.15f * ped->GetForward(); forward.z += 0.15f; obstacle = CWorld::TestSphereAgainstWorld(forward, 0.25f, nil, true, true, false, true, false, false); } if (obstacle) { animAssoc->flags |= ASSOC_DELETEFADEDOUT; // ANIM_HIT_WALL in VC (which makes more sense) CAnimBlendAssociation *handsCoverAssoc = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_STD_HANDSCOWER, 8.0f); handsCoverAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; handsCoverAssoc->SetFinishCallback(FinishHitHeadCB, ped); ped->bIsLanding = true; return; } float velocityFromAnim = 0.1f; CAnimBlendAssociation *sprintAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_STD_RUNFAST); if (sprintAssoc) { velocityFromAnim = 0.05f * sprintAssoc->blendAmount + 0.17f; } else { CAnimBlendAssociation *runAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_STD_RUN); if (runAssoc) { velocityFromAnim = 0.07f * runAssoc->blendAmount + 0.1f; } } if (ped->IsPlayer() #ifdef VC_PED_PORTS || ped->m_pedInObjective && ped->m_pedInObjective->IsPlayer() #endif ) ped->ApplyMoveForce(0.0f, 0.0f, 8.5f); else ped->ApplyMoveForce(0.0f, 0.0f, 4.5f); if (sq(velocityFromAnim) > ped->m_vecMoveSpeed.MagnitudeSqr2D() #ifdef VC_PED_PORTS || ped->m_pCurrentPhysSurface #endif ) { #ifdef FREE_CAM if (TheCamera.Cams[0].Using3rdPersonMouseCam() && !CCamera::bFreeCam) { #else if (TheCamera.Cams[0].Using3rdPersonMouseCam()) { #endif float fpsAngle = ped->WorkOutHeadingForMovingFirstPerson(ped->m_fRotationCur); ped->m_vecMoveSpeed.x = -velocityFromAnim * Sin(fpsAngle); ped->m_vecMoveSpeed.y = velocityFromAnim * Cos(fpsAngle); } else { ped->m_vecMoveSpeed.x = -velocityFromAnim * Sin(ped->m_fRotationCur); ped->m_vecMoveSpeed.y = velocityFromAnim * Cos(ped->m_fRotationCur); } #ifdef VC_PED_PORTS if (ped->m_pCurrentPhysSurface) { ped->m_vecMoveSpeed.x += ped->m_pCurrentPhysSurface->m_vecMoveSpeed.x; ped->m_vecMoveSpeed.y += ped->m_pCurrentPhysSurface->m_vecMoveSpeed.y; } #endif } ped->bIsStanding = false; ped->bIsInTheAir = true; animAssoc->blendDelta = -1000.0f; CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_STD_JUMP_GLIDE); if (ped->bDoBloodyFootprints) { CVector bloodPos(0.0f, 0.0f, 0.0f); ped->TransformToNode(bloodPos, PED_FOOTL); bloodPos.z -= 0.1f; bloodPos += 0.2f * ped->GetForward(); CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, 0.26f * ped->GetForward().x, 0.26f * ped->GetForward().y, 0.14f * ped->GetRight().x, 0.14f * ped->GetRight().y, 255, 255, 0, 0, 4.0f, 3000, 1.0f); bloodPos = CVector(0.0f, 0.0f, 0.0f); ped->TransformToNode(bloodPos, PED_FOOTR); bloodPos.z -= 0.1f; bloodPos += 0.2f * ped->GetForward(); CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, 0.26f * ped->GetForward().x, 0.26f * ped->GetForward().y, 0.14f * ped->GetRight().x, 0.14f * ped->GetRight().y, 255, 255, 0, 0, 4.0f, 3000, 1.0f); if (ped->m_bloodyFootprintCountOrDeathTime <= 40) { ped->m_bloodyFootprintCountOrDeathTime = 0; ped->bDoBloodyFootprints = false; } else { ped->m_bloodyFootprintCountOrDeathTime -= 40; } } } void CPed::FinishJumpCB(CAnimBlendAssociation *animAssoc, void *arg) { CPed *ped = (CPed*)arg; ped->bResetWalkAnims = true; ped->bIsLanding = false; animAssoc->blendDelta = -1000.0f; } bool CPed::CheckIfInTheAir(void) { if (bInVehicle) return false; CVector pos = GetPosition(); CColPoint foundColPoint; CEntity *foundEntity; float startZ = pos.z - 1.54f; bool foundGround = CWorld::ProcessVerticalLine(pos, startZ, foundColPoint, foundEntity, true, true, false, true, false, false, nil); if (!foundGround && m_nPedState != PED_JUMP) { pos.z -= FEET_OFFSET; if (CWorld::TestSphereAgainstWorld(pos, 0.15f, this, true, false, false, false, false, false)) foundGround = true; } return !foundGround; } void CPlayerPed::PlayerControl1stPersonRunAround(CPad *padUsed) { float leftRight = padUsed->GetPedWalkLeftRight(); float upDown = padUsed->GetPedWalkUpDown(); float padMove = CVector2D(leftRight, upDown).Magnitude(); float padMoveInGameUnit = padMove / PAD_MOVE_TO_GAME_WORLD_MOVE; if (padMoveInGameUnit > 0.0f) { m_fRotationDest = CGeneral::LimitRadianAngle(TheCamera.Orientation); m_fMoveSpeed = Min(padMoveInGameUnit, 0.07f * CTimer::GetTimeStep() + m_fMoveSpeed); } else { m_fMoveSpeed = 0.0f; } if (m_nPedState == PED_JUMP) { if (bIsInTheAir) { if (bUsesCollision && !bHitSteepSlope && (!bHitSomethingLastFrame || m_vecDamageNormal.z > 0.6f) && m_fDistanceTravelled < CTimer::GetTimeStepInSeconds() && m_vecMoveSpeed.MagnitudeSqr() < 0.01f) { float angleSin = Sin(m_fRotationCur); // originally sin(DEGTORAD(RADTODEG(m_fRotationCur))) o_O float angleCos = Cos(m_fRotationCur); ApplyMoveForce(-angleSin * 3.0f, 3.0f * angleCos, 0.05f); } } else if (bIsLanding) { m_fMoveSpeed = 0.0f; } } if (!CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->IsFlagSet(WEAPONFLAG_HEAVY) && padUsed->GetSprint()) { m_nMoveState = PEDMOVE_SPRINT; } if (m_nPedState != PED_FIGHT) SetRealMoveAnim(); if (!bIsInTheAir && !(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->IsFlagSet(WEAPONFLAG_HEAVY)) && padUsed->JumpJustDown() && m_nPedState != PED_JUMP) { ClearAttack(); ClearWeaponTarget(); if (m_nEvadeAmount != 0 && m_pEvadingFrom) { SetEvasiveDive((CPhysical*)m_pEvadingFrom, 1); m_nEvadeAmount = 0; m_pEvadingFrom = nil; } else { SetJump(); } } } void CPhysical::ApplyMoveForce(float jx, float jy, float jz) { m_vecMoveSpeed += CVector(jx, jy, jz)*(1.0f/m_fMass); } void CPhysical::ApplyTurnForce(float jx, float jy, float jz, float px, float py, float pz) { CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass); CVector turnimpulse = CrossProduct(CVector(px, py, pz)-com, CVector(jx, jy, jz)); m_vecTurnSpeed += turnimpulse*(1.0f/m_fTurnMass); } void CPhysical::ApplyAirResistance(void) { if(m_fAirResistance > 0.1f){ float f = Pow(m_fAirResistance, CTimer::GetTimeStep()); m_vecMoveSpeed *= f; m_vecTurnSpeed *= f; }else{ float f = Pow(1.0f/Abs(m_fAirResistance*0.5f*m_vecMoveSpeed.MagnitudeSqr() + 1.0f), CTimer::GetTimeStep()); m_vecMoveSpeed *= f; m_vecTurnSpeed *= 0.99f; } } void CPhysical::ProcessControl(void) { if(!IsPed()) bIsInWater = false; bHasContacted = false; bIsInSafePosition = false; bWasPostponed = false; bHasHitWall = false; if(GetStatus() == STATUS_SIMPLE) return; m_nCollisionRecords = 0; bHasCollided = false; m_nDamagePieceType = 0; m_fDamageImpulse = 0.0f; m_pDamageEntity = nil; if(!bIsStuck){ if(IsObject() || IsPed() && !bPedPhysics){ m_vecMoveSpeedAvg = (m_vecMoveSpeedAvg + m_vecMoveSpeed)/2.0f; m_vecTurnSpeedAvg = (m_vecTurnSpeedAvg + m_vecTurnSpeed)/2.0f; float step = CTimer::GetTimeStep() * 0.003f; if(m_vecMoveSpeedAvg.MagnitudeSqr() < step*step && m_vecTurnSpeedAvg.MagnitudeSqr() < step*step){ m_nStaticFrames++; if(m_nStaticFrames > 10){ m_nStaticFrames = 10; SetIsStatic(true); m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); m_vecMoveFriction = m_vecMoveSpeed; m_vecTurnFriction = m_vecTurnSpeed; return; } }else m_nStaticFrames = 0; } } ApplyGravity(); ApplyFriction(); ApplyAirResistance(); } void CPhysical::ApplyGravity(void) { if(bAffectedByGravity) m_vecMoveSpeed.z -= GRAVITY * CTimer::GetTimeStep(); } bool CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, float &impulseB) { float eA, eB; CPhysical *A = this; CObject *Bobj = (CObject*)B; bool ispedcontactA = false; bool ispedcontactB = false; float massFactorA; if(B->bPedPhysics){ massFactorA = 10.0f; if(B->IsPed() && ((CPed*)B)->m_pCurrentPhysSurface == A) ispedcontactA = true; }else massFactorA = A->bIsHeavy ? 2.0f : 1.0f; float massFactorB; if(A->bPedPhysics){ if(A->IsPed() && ((CPed*)A)->IsPlayer() && B->IsVehicle() && (B->GetStatus() == STATUS_ABANDONED || B->GetStatus() == STATUS_WRECKED || A->bHasHitWall)) massFactorB = 2200.0f / B->m_fMass; else massFactorB = 10.0f; if(A->IsPed() && ((CPed*)A)->m_pCurrentPhysSurface == B) ispedcontactB = true; }else massFactorB = B->bIsHeavy ? 2.0f : 1.0f; float speedA, speedB; if(B->GetIsStatic()){ if(A->bPedPhysics){ speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal); if(speedA < 0.0f){ if(B->IsObject()){ impulseA = -speedA * A->m_fMass; impulseB = impulseA; if(impulseA > Bobj->m_fUprootLimit){ if(IsGlass(B->GetModelIndex())) CGlass::WindowRespondsToCollision(B, impulseA, A->m_vecMoveSpeed, colpoint.point, false); else if(!B->bInfiniteMass) B->SetIsStatic(false); }else{ if(IsGlass(B->GetModelIndex())) CGlass::WindowRespondsToSoftCollision(B, impulseA); if(!A->bInfiniteMass) A->ApplyMoveForce(colpoint.GetNormal() * (1.0f + A->m_fElasticity) * impulseA); return true; } }else if(!B->bInfiniteMass) B->SetIsStatic(false); if(B->bInfiniteMass){ impulseA = -speedA * A->m_fMass; impulseB = 0.0f; if(!A->bInfiniteMass) A->ApplyMoveForce(colpoint.normal*(1.0f + A->m_fElasticity)*impulseA); return true; } } }else{ CVector pointposA = colpoint.point - A->GetPosition(); speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal); if(speedA < 0.0f){ if(B->IsObject()){ if(A->bHasHitWall) eA = -1.0f; else eA = -(1.0f + A->m_fElasticity); impulseA = eA * speedA * A->GetMass(pointposA, colpoint.normal); impulseB = impulseA; if(Bobj->m_nCollisionDamageEffect && impulseA > 20.0f){ Bobj->ObjectDamage(impulseA); if(!B->bUsesCollision){ if(!A->bInfiniteMass){ A->ApplyMoveForce(colpoint.normal*0.2f*impulseA); A->ApplyTurnForce(colpoint.normal*0.2f*impulseA, pointposA); } return false; } } if((impulseA > Bobj->m_fUprootLimit || A->bIsStuck) && !B->bInfiniteMass){ if(IsGlass(B->GetModelIndex())) CGlass::WindowRespondsToCollision(B, impulseA, A->m_vecMoveSpeed, colpoint.point, false); else B->SetIsStatic(false); int16 model = B->GetModelIndex(); if(model == MI_FIRE_HYDRANT && !Bobj->bHasBeenDamaged){ CParticleObject::AddObject(POBJECT_FIRE_HYDRANT, B->GetPosition() - CVector(0.0f, 0.0f, 0.5f), true); Bobj->bHasBeenDamaged = true; }else if(B->IsObject() && !IsExplosiveThingModel(model)) Bobj->bHasBeenDamaged = true; }else{ if(IsGlass(B->GetModelIndex())) CGlass::WindowRespondsToSoftCollision(B, impulseA); CVector f = colpoint.GetNormal() * impulseA; if(A->IsVehicle() && colpoint.normal.z < 0.7f) f.z *= 0.3f; if(!A->bInfiniteMass){ A->ApplyMoveForce(f); if(!A->IsVehicle() || !CWorld::bNoMoreCollisionTorque) A->ApplyTurnForce(f, pointposA); } return true; } }else if(!B->bInfiniteMass) B->SetIsStatic(false); } } if(B->GetIsStatic()) return false; if(!B->bInfiniteMass) B->AddToMovingList(); } // B is not static if(A->bPedPhysics && B->bPedPhysics){ // negative if A is moving towards B speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal); // positive if B is moving towards A // not interested in how much B moves into A apparently? // only interested in cases where A collided into B speedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal); float speedSum = Max(0.0f, DotProduct(B->m_vecMoveSpeed, colpoint.normal)); // A has moved into B if(speedA < speedSum){ if(A->bHasHitWall) eA = speedSum; else eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; impulseA = (eA-speedA) * A->m_fMass * massFactorA; if(!A->bInfiniteMass) A->ApplyMoveForce(colpoint.normal*(impulseA/massFactorA)); return true; } }else if(A->bPedPhysics){ CVector pointposB = colpoint.point - B->GetPosition(); speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal); speedB = DotProduct(B->GetSpeed(pointposB), colpoint.normal); float mA = A->m_fMass*massFactorA; float mB = B->GetMassTweak(pointposB, colpoint.normal, massFactorB); float speedSum = (mB*speedB + mA*speedA)/(mA + mB); if(speedA < speedSum){ if(A->bHasHitWall) eA = speedSum; else eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; if(B->bHasHitWall) eB = speedSum; else eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; impulseA = (eA - speedA) * mA; impulseB = -(eB - speedB) * mB; CVector fA = colpoint.normal*(impulseA/massFactorA); CVector fB = colpoint.normal*(-impulseB/massFactorB); if(!A->bInfiniteMass){ if(fA.z < 0.0f) fA.z = 0.0f; if(ispedcontactB){ fA.x *= 2.0f; fA.y *= 2.0f; } A->ApplyMoveForce(fA); } if(!B->bInfiniteMass && !ispedcontactB){ B->ApplyMoveForce(fB); B->ApplyTurnForce(fB, pointposB); } return true; } }else if(B->bPedPhysics){ CVector pointposA = colpoint.point - A->GetPosition(); speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal); speedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal); float mA = A->GetMassTweak(pointposA, colpoint.normal, massFactorA); float mB = B->m_fMass*massFactorB; float speedSum = (mB*speedB + mA*speedA)/(mA + mB); if(speedA < speedSum){ if(A->bHasHitWall) eA = speedSum; else eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; if(B->bHasHitWall) eB = speedSum; else eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; impulseA = (eA - speedA) * mA; impulseB = -(eB - speedB) * mB; CVector fA = colpoint.normal*(impulseA/massFactorA); CVector fB = colpoint.normal*(-impulseB/massFactorB); if(!A->bInfiniteMass && !ispedcontactA){ if(fA.z < 0.0f) fA.z = 0.0f; A->ApplyMoveForce(fA); A->ApplyTurnForce(fA, pointposA); } if(!B->bInfiniteMass){ if(fB.z < 0.0f){ fB.z = 0.0f; if(Abs(speedA) < 0.01f) fB *= 0.5f; } if(ispedcontactA){ fB.x *= 2.0f; fB.y *= 2.0f; } B->ApplyMoveForce(fB); } return true; } }else{ CVector pointposA = colpoint.point - A->GetPosition(); CVector pointposB = colpoint.point - B->GetPosition(); speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal); speedB = DotProduct(B->GetSpeed(pointposB), colpoint.normal); float mA = A->GetMassTweak(pointposA, colpoint.normal, massFactorA); float mB = B->GetMassTweak(pointposB, colpoint.normal, massFactorB); float speedSum = (mB*speedB + mA*speedA)/(mA + mB); if(speedA < speedSum){ if(A->bHasHitWall) eA = speedSum; else eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; if(B->bHasHitWall) eB = speedSum; else eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f; impulseA = (eA - speedA) * mA; impulseB = -(eB - speedB) * mB; CVector fA = colpoint.normal*(impulseA/massFactorA); CVector fB = colpoint.normal*(-impulseB/massFactorB); if(A->IsVehicle() && !A->bHasHitWall){ fA.x *= 1.4f; fA.y *= 1.4f; if(colpoint.normal.z < 0.7f) fA.z *= 0.3f; if(A->GetStatus() == STATUS_PLAYER) pointposA *= 0.8f; if(CWorld::bNoMoreCollisionTorque){ A->ApplyFrictionMoveForce(fA*-0.3f); A->ApplyFrictionTurnForce(fA*-0.3f, pointposA); } } if(B->IsVehicle() && !B->bHasHitWall){ fB.x *= 1.4f; fB.y *= 1.4f; if(-colpoint.normal.z < 0.7f) fB.z *= 0.3f; if(B->GetStatus() == STATUS_PLAYER) pointposB *= 0.8f; if(CWorld::bNoMoreCollisionTorque){ #ifdef FIX_BUGS B->ApplyFrictionMoveForce(fB*-0.3f); B->ApplyFrictionTurnForce(fB*-0.3f, pointposB); #else A->ApplyFrictionMoveForce(fB*-0.3f); A->ApplyFrictionTurnForce(fB*-0.3f, pointposB); #endif } } if(!A->bInfiniteMass){ A->ApplyMoveForce(fA); A->ApplyTurnForce(fA, pointposA); } if(!B->bInfiniteMass){ if(B->bIsInSafePosition) B->UnsetIsInSafePosition(); B->ApplyMoveForce(fB); B->ApplyTurnForce(fB, pointposB); } return true; } } return false; } how to make same behavior for jumping and falling in my code (with minimal change): inline void Player::Update(float deltaTime) { glm::vec3 currentPosition = GetPosition(); glm::vec3 newPosition = currentPosition; bool positionChanged = false; // Apply gravity and forward movement when jumping or falling if (m_isJumping || m_isFalling) { // Apply gravity to vertical movement if (m_isJumping) { m_jumpVelocity -= m_gravity * deltaTime; newPosition.y += m_jumpVelocity * deltaTime; if (m_jumpVelocity <= 0) { m_isJumping = false; m_isFalling = true; } } else if (m_isFalling) { float fallGravityScale = 2.0f; m_fallVelocity = std::min(m_fallVelocity + (m_gravity * fallGravityScale * deltaTime), 30.0f); // Limit the max fall speed newPosition.y -= m_fallVelocity * deltaTime; } // Continue forward movement during the jump and fall glm::quat rotation = GetRotation(); glm::vec3 forward = glm::normalize(rotation * glm::vec3(0, 0, 1)); // Forward direction newPosition += forward * m_jumpForwardSpeed * deltaTime; positionChanged = true; } // Check for ground collision float rayLength = 3.0f; // Adjust this to match your world's height glm::vec3 rayStart = currentPosition + glm::vec3(0, 0.1f, 0); glm::vec3 rayEnd = rayStart - glm::vec3(0, rayLength, 0); auto hitResult = m_world->RaycastWithPlayerCollision(rayStart, rayEnd, *this); if (hitResult) { glm::vec3 hitPosition = hitResult; float groundY = hitPosition.y; if (newPosition.y <= groundY + 0.1f) { newPosition.y = groundY + 0.1f; // Keep slightly above ground if (m_isJumping || m_isFalling) { m_isJumping = false; m_isFalling = false; m_fallVelocity = 0; positionChanged = true; } } } else if (!m_isFalling && !m_isJumping) { m_isFalling = true; positionChanged = true; } // Apply the new position if (positionChanged) { SetPosition(newPosition); } } class Player { bool m_isJumping; bool m_isFalling; float m_jumpVelocity; float m_fallVelocity; float m_jumpHeight; float m_gravity; float m_jumpForwardSpeed; public: Player(dtCrowd crowd, World* world); ~Player(); void Update(float deltaTime); void SetRotation(const glm::quat& rotation); glm::quat GetRotation() const; void SetPosition(const glm::vec3& position); glm::vec3 GetPosition() const; void SetLookAt(const glm::vec3& target); glm::vec3 GetLookAt() const; void MoveTo(const glm::vec3& destination); void SetServer(uint16_t serverId); uint16_t GetServer() const; void SetSpeed(const glm::vec3& speed); glm::vec3 GetSpeed() const; bool CalculatePathTo(const glm::vec3& destination); std::pair<glm::vec3, glm::vec3> GetBoundingBox() const; void Jump() { if (!m_isJumping && !m_isFalling) { m_isJumping = true; m_jumpVelocity = sqrt(2 * m_gravity * m_jumpHeight); // Set a forward speed for the jump (e.g. 4.0f) m_jumpForwardSpeed = 4.0f; // Adjust as needed } } private: dtCrowd* m_crowd; glm::quat m_rotation; glm::vec3 m_lookAt; glm::vec3 m_position; uint16_t m_serverId; glm::vec3 m_moveSpeed; int m_agentIndex; bool m_ProcessMoveToPoint; World* m_world; }; inline void Player::SetRotation(const glm::quat& rotation) { m_rotation = rotation; // Update look-at based on new rotation glm::vec3 currentPos = GetPosition(); m_lookAt = currentPos + glm::rotate(m_rotation, glm::vec3(0.0f, 0.0f, -1.0f)); } inline glm::quat Player::GetRotation() const { return m_rotation; } inline void Player::SetPosition(const glm::vec3& newPosition) { m_position = newPosition; } inline glm::vec3 Player::GetPosition() const { return m_position; } inline void Player::SetLookAt(const glm::vec3& target) { m_lookAt = target; glm::vec3 currentPos = GetPosition(); // Calculate direction on XZ plane glm::vec3 direction = target - currentPos; direction.y = 0.0f; // Ignore Y component direction = glm::normalize(direction); // Calculate the angle between the forward vector and the direction glm::vec3 forward(0.0f, 0.0f, -1.0f); // Assuming forward is -Z float angle = std::atan2(direction.x, direction.z); // Create a quaternion for rotation around Y-axis m_rotation = glm::angleAxis(angle, glm::vec3(0.0f, 1.0f, 0.0f)); } inline glm::vec3 Player::GetLookAt() const { return m_lookAt; }