can u help me with gta 3 jump simulation? first of all, gta uses Z as height and my implementation uses Y as height. Use World::PlayerBoxRaycast(const glm::vec3& start, const glm::vec3& direction, float maxDistance, const glm::vec3& playerDimensions, const glm::quat& playerRotation) instead of TestSphereAgainstWorld, also i don't need animations and obstacle detection, pure position and rotation changes. here some gta code: void CPed::SetJump(void) { if (!bInVehicle &&(m_nSurfaceTouched != SURFACE_STEEP_CLIFF || DotProduct(GetForward(), m_vecDamageNormal) >= 0.0f)) { 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 CPhysical::ApplyMoveForce(float jx, float jy, float jz) { m_vecMoveSpeed += CVector(jx, jy, jz)*(1.0f/m_fMass); } void CPed::FinishHitHeadCB(CAnimBlendAssociation animAssoc, void arg) { CPed ped = (CPed)arg; if (animAssoc) { animAssoc->blendDelta = -4.0f; animAssoc->flags |= ASSOC_DELETEFADEDOUT; } if (ped->m_nPedState == PED_JUMP) ped->RestorePreviousState(); ped->bIsLanding = false; } ProcessUpdate() { ... if ((m_nPedStateTimer <= 50.0f / (4.0f * adjustedTs) || m_nPedStateTimer * 0.01f <= forceDir.MagnitudeSqr()) && (m_nCollisionRecords <= 1 || m_nPedStateTimer <= 50.0f / (2.0f * adjustedTs) || m_nPedStateTimer * 1.0f / 250.0f <= Abs(forceDir.z))) { if (m_nCollisionRecords == 1 && m_aCollisionRecords[0] != nil && m_aCollisionRecords[0]->IsBuilding() && m_nPedStateTimer > 50.0f / (2.0f * adjustedTs) && m_nPedStateTimer * 1.0f / 250.0f > Abs(forceDir.z)) { offsetToCheck.x = -forceDir.y; offsetToCheck.z = 0.0f; offsetToCheck.y = forceDir.x; offsetToCheck.Normalise(); CVector posToCheck = GetPosition() + offsetToCheck; // These are either obstacle or ground to land, I don't know which one. float obstacleForFlyingZ, obstacleForFlyingOtherDirZ; CColPoint obstacleForFlying, obstacleForFlyingOtherDir; // Check is there any room for being knocked up in reverse direction of force if (CWorld::ProcessVerticalLine(posToCheck, -20.0f, obstacleForFlying, foundEnt, true, false, false, false, false, false, nil)) { obstacleForFlyingZ = obstacleForFlying.point.z; } else { obstacleForFlyingZ = 500.0f; } posToCheck = GetPosition() - offsetToCheck; // Now check for direction of force this time if (CWorld::ProcessVerticalLine(posToCheck, -20.0f, obstacleForFlyingOtherDir, foundEnt, true, false, false, false, false, false, nil)) { obstacleForFlyingOtherDirZ = obstacleForFlyingOtherDir.point.z; } else { obstacleForFlyingOtherDirZ = 501.0f; } if (obstacleForFlyingZ < obstacleForFlyingOtherDirZ) { offsetToCheck *= -1.0f; } offsetToCheck.z = 1.0f; forceDir = 4.0f * offsetToCheck; forceDir.z = 4.0f; ApplyMoveForce(forceDir); // What was that for?? It pushes player inside of collision sometimes and kills him. #ifdef FIX_BUGS if (!IsPlayer()) #endif GetMatrix().GetPosition() += 0.25f * offsetToCheck; m_fRotationCur = CGeneral::GetRadianAngleBetweenPoints(offsetToCheck.x, offsetToCheck.y, 0.0f, 0.0f); m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); m_fRotationDest = m_fRotationCur; SetHeading(m_fRotationCur); if (m_nPedState != PED_FALL && !bIsPedDieAnimPlaying) { SetFall(1000, ANIM_STD_HIGHIMPACT_BACK, true); } bIsInTheAir = false; } else if (m_vecDamageNormal.z > 0.4f) { forceDir = m_vecDamageNormal; forceDir.z = 0.0f; forceDir.Normalise(); ApplyMoveForce(2.0f * forceDir); } } else if ((CTimer::GetFrameCounter() + m_randomSeed % 256 + 3) & 7) { if (IsPlayer() && m_nPedState != PED_JUMP && pad0->JumpJustDown()) { int16 padWalkX = pad0->GetPedWalkLeftRight(); int16 padWalkY = pad0->GetPedWalkUpDown(); if (Abs(padWalkX) > 0.0f || Abs(padWalkY) > 0.0f) { m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -padWalkX, padWalkY); m_fRotationDest -= TheCamera.Orientation; m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); m_fRotationCur = m_fRotationDest; SetHeading(m_fRotationCur); } SetJump(); m_nPedStateTimer = 0; m_vecHitLastPos = GetPosition(); // Why? forceDir is unused after this point. forceDir = CVector(0.0f, 0.0f, 0.0f); } else if (IsPlayer()) { int16 padWalkX = pad0->GetPedWalkLeftRight(); int16 padWalkY = pad0->GetPedWalkUpDown(); if (Abs(padWalkX) > 0.0f || Abs(padWalkY) > 0.0f) { m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -padWalkX, padWalkY); m_fRotationDest -= TheCamera.Orientation; m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); m_fRotationCur = m_fRotationDest; SetHeading(m_fRotationCur); } CAnimBlendAssociation *jumpAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_JUMP_GLIDE); if (!jumpAssoc) jumpAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_FALL_GLIDE); if (jumpAssoc) { jumpAssoc->blendDelta = -3.0f; jumpAssoc->flags |= ASSOC_DELETEFADEDOUT; } if (m_nPedState == PED_JUMP) m_nPedState = PED_IDLE; } else { CAnimBlendAssociation *jumpAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_JUMP_GLIDE); if (!jumpAssoc) jumpAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_FALL_GLIDE); if (jumpAssoc) { jumpAssoc->blendDelta = -3.0f; jumpAssoc->flags |= ASSOC_DELETEFADEDOUT; } } } else { offsetToCheck = GetPosition(); offsetToCheck.z += 0.5f; if (CWorld::ProcessVerticalLine(offsetToCheck, GetPosition().z - FEET_OFFSET, foundCol, foundEnt, true, true, false, true, false, false, nil)) { GetMatrix().GetPosition().z = FEET_OFFSET + foundCol.point.z; GetMatrix().UpdateRW(); SetLanding(); bIsStanding = true; } } } else if (m_nPedStateTimer < 1001) { m_nPedStateTimer = 0; } } ... if (!bIsStanding && m_vecMoveSpeed.z > 0.25f) { float airResistance = Pow(0.95f, CTimer::GetTimeStep()); m_vecMoveSpeed *= airResistance; } ... ApplyGravity(); ApplyFriction(); ApplyAirResistance(); } and here my code: void Player::ApplyGravity(float dt) { m_moveSpeed.z -= 0.008f * dt; } void Player::ApplyAirResistance(float dt) { if (m_fAirResistance > 0.1f) { float f = powf(m_fAirResistance, dt); m_moveSpeed *= f; } else { float magnitudeSqr = glm::length2(m_moveSpeed); float f = powf(1.0f / abs(m_fAirResistance * 0.5f * magnitudeSqr + 1.0f), dt); m_moveSpeed *= f; } } void Player::ApplyMoveForce(glm::vec3 force) { m_moveSpeed += force * (1.0f / 70.0f); } void Player::Jump() { if (m_state != State::JUMP) { SetState(State::JUMP); } } 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; } std::optional<glm::vec3> Player::isPlayerInAir() { glm::vec3 playerPosition = GetPosition(); glm::vec3 playerDimensions(0.5f, 1.8f, 1.0f); // length, height, width glm::quat playerRotation = GetRotation(); // Vertical raycast (for falling) glm::vec3 downDirection(0.0f, -1.0f, 0.0f); float maxFallDistance = 255.0f; // Adjust as needed glm::vec3 raycastOrigin = playerPosition + glm::vec3(0.0f, 0.1f, 0.0f); // Adjust the Y offset as needed auto fallResult = m_world->PlayerBoxRaycast(raycastOrigin, downDirection, maxFallDistance, playerDimensions, playerRotation); if (fallResult.hit) { float fallDistance = fallResult.distance; // Return a vec3 where: // x = hit (1.0 for true, 0.0 for false) // y = distance to ground // z = y-coordinate of hit point return glm::vec3(1.0f, fallDistance, fallResult.hitPoint.y); } else { //std::cout << "No ground detected within " << maxFallDistance << " units" << std::endl; // Return a vec3 indicating no hit, with a large distance return glm::vec3(0.0f, maxFallDistance + 1.0f, -1.0f); } } void Player::Update(float deltaTime) { bool isStanding = false; auto gravityInfo = isPlayerInAir(); if (gravityInfo) { float groundThreshold = 0.15f; if (m_state == State::JUMP) { if (gravityInfo->y <= groundThreshold) { std::cout << "Standing!" << std::endl; } } else { float maxFallDistance = 255.0f; float groundOffset = 0.01f; if (gravityInfo->y <= groundThreshold) { // Player is grounded or very close to ground glm::vec3 newPosition = GetPosition(); newPosition.y = gravityInfo->z + groundOffset; SetPosition(newPosition); isStanding = true; //std::cout << "Grounded. New position: (" // << newPosition.x << ", " << newPosition.y << ", " << newPosition.z << ")" << std::endl; } else if (gravityInfo->y > maxFallDistance) { // Player is very high, do a raycast from sky glm::vec3 skyPosition = { GetPosition().x, 500.0f, GetPosition().z }; skyPosition.y = 255.0f; // Assuming 255 is the max height auto skyRaycast = m_world->PlayerBoxRaycast(skyPosition, glm::vec3(0.0f, -1.0f, 0.0f), 255.0f, glm::vec3(0.5f, 1.8f, 1.0f), GetRotation()); if (skyRaycast.hit) { glm::vec3 newPosition = GetPosition(); newPosition.y = skyRaycast.hitPoint.y + groundOffset; SetPosition(newPosition); std::cout << "Teleported from sky. New position: (" << newPosition.x << ", " << newPosition.y << ", " << newPosition.z << ")" << std::endl; } } else { // Player is falling //glm::vec3 newPosition = GetPosition(); //newPosition.y -= gravityInfo->y * deltaTime; // Simple falling physics //SetPosition(newPosition); std::cout << "Falling! Distance to ground: " << gravityInfo->y << std::endl; } } } if (!isStanding && m_moveSpeed.y > 0.25f) { float airResistance = powf(0.95f, deltaTime); m_moveSpeed *= airResistance; } ApplyGravity(deltaTime); ApplyAirResistance(deltaTime); }