implement jump like in gta 3. Here my implementation: void Player::Update(float deltaTime) { float timestep = CTimer::GetTimeStep(); //deltaTime *= 30; switch (m_state) { case PlayerState::STANDING: HandleStanding(timestep); break; case PlayerState::JUMPING: HandleJumping(timestep); break; case PlayerState::FALLING: HandleFalling(timestep); break; case PlayerState::LANDING: HandleStanding(timestep); break; default: break; } if (isPlayerInAir()) { if (m_state != PlayerState::JUMPING && m_state != PlayerState::FALLING) { SetState(PlayerState::FALLING); std::cout << "Transitioning to FALLING state in Update." << std::endl; } } if (isPlayerInAir() && m_moveSpeed.y > 0.25f) { float airResistance = powf(0.95f, CTimer::GetTimeStep()); m_moveSpeed *= airResistance; std::cout << "Applied air resistance. New m_moveSpeed: " << m_moveSpeed.y << std::endl; } if (isPlayerInAir()) { ApplyGravity(timestep); ApplyAirResistance(timestep); } glm::vec3 newPosition = GetPosition(); newPosition += m_moveSpeed * CTimer::GetTimeStep(); SetPosition(newPosition); //CTimer::Update(); } bool Player::isPlayerInAir() { glm::vec3 playerPosition = GetPosition(); glm::quat playerRotation = GetRotation(); glm::vec3 downDirection(0.0f, -1.0f, 0.0f); float maxFallDistance = 1000.0f; glm::vec3 raycastOrigin = playerPosition + glm::vec3(0.0f, 0.1f, 0.0f); auto fallResult = m_world->PlayerBoxRaycast(raycastOrigin, downDirection, maxFallDistance, m_playerDimensions, playerRotation); if (fallResult.hit) { if (fallResult.distance <= m_groundThreshold) { return false; } } return true; } glm::vec3 Player::GetGroundPos() { glm::vec3 playerPosition = GetPosition(); glm::quat playerRotation = GetRotation(); glm::vec3 downDirection(0.0f, -1.0f, 0.0f); float maxFallDistance = 1000.0f; glm::vec3 raycastOrigin = playerPosition + glm::vec3(0.0f, m_groundThreshold, 0.0f); auto fallResult = m_world->PlayerBoxRaycast(raycastOrigin, downDirection, maxFallDistance, m_playerDimensions, playerRotation); if (fallResult.hit) { return fallResult.hitPoint; } return { 9999.0f, 9999.0f, 9999.0f }; } void Player::ApplyGravity(float dt) { //m_moveSpeed.y -= 9.81 * CTimer::GetTimeStep(); m_moveSpeed.y -= 9.81 * 2.0f * CTimer::GetTimeStep(); } void Player::ApplyAirResistance(float dt) { if (m_fAirResistance > 0.1f) { float f = powf(m_fAirResistance, CTimer::GetTimeStep()); m_moveSpeed *= f; } else { float magnitudeSqr = glm::length2(m_moveSpeed); float f = powf(1.0f / abs(m_fAirResistance * 0.5f * magnitudeSqr + 1.0f), CTimer::GetTimeStep()); m_moveSpeed *= f; } } void Player::ApplyMoveForce(glm::vec3 force) { m_moveSpeed += force * (1.0f / 70.0f); } void Player::Jump() { if (m_state != PlayerState::JUMPING && !isPlayerInAir()) { SetState(PlayerState::JUMPING); ApplyMoveForce(glm::vec3(0.0f, 8.5f, 0.0f)); // Apply jump force on Y-axis std::cout << "Jump initiated!" << std::endl; } } void Player::HandleStanding(float dt) { } void Player::HandleFalling(float dt) { glm::vec3 pos = GetGroundPos(); float dist = glm::distance(pos, m_position); if (dist >= 1000.0f) { std::cout << "Player under map! Hit Pos: "<< pos.x << " " << pos.y << " " << pos.z << std::endl; m_moveSpeed = { 0.0f, 0.0f,0.0f }; SetPosition({ -15.3375, 17.5399 , 69.3102 }); } else { if (dist <= m_groundThreshold) { m_moveSpeed = { 0.0f, 0.0f,0.0f }; SetPosition(pos); } } } void Player::HandleJumping(float dt) { //glm::vec3 pos = GetGroundPos(); //float dist = glm::distance(pos, m_position); if (isPlayerInAir()) { glm::vec3 eulerAngles = glm::eulerAngles(m_rotation); float angleSin = sin(eulerAngles.y); float angleCos = cos(eulerAngles.y); ApplyMoveForce({ -angleSin * 3.0f, 0.05f, 3.0f * angleCos }); std::cout << "Applied move force during jumping." << std::endl; } /*if (dist <= m_groundThreshold) { SetState(PlayerState::STANDING); m_moveSpeed = { 0.0f, 0.0f,0.0f }; SetPosition(pos); } else { }*/ } 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)); } glm::quat Player::GetRotation() const { return m_rotation; } void Player::SetPosition(const glm::vec3& newPosition) { m_position = newPosition; } glm::vec3 Player::GetPosition() const { return m_position; } and here gta 3: update(){ ... 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; } }... } void CPed::SetJump(void) { if (!bInVehicle &&(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()) ped->ApplyMoveForce(0.0f, 0.0f, 8.5f); else ped->ApplyMoveForce(0.0f, 0.0f, 4.5f); if (sq(velocityFromAnim) > ped->m_vecMoveSpeed.MagnitudeSqr2D()) { if (TheCamera.Cams[0].Using3rdPersonMouseCam() && !CCamera::bFreeCam) { 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); } } ped->bIsStanding = false; ped->bIsInTheAir = true; animAssoc->blendDelta = -1000.0f; CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_STD_JUMP_GLIDE); } void CPed::FinishJumpCB(CAnimBlendAssociation *animAssoc, void *arg) { CPed *ped = (CPed*)arg; ped->bResetWalkAnims = true; ped->bIsLanding = false; animAssoc->blendDelta = -1000.0f; }