diff --git a/gameengine/packages/quake3/workflows/q3_frame.json b/gameengine/packages/quake3/workflows/q3_frame.json index 799e35352..41bd2e264 100644 --- a/gameengine/packages/quake3/workflows/q3_frame.json +++ b/gameengine/packages/quake3/workflows/q3_frame.json @@ -14,13 +14,15 @@ "typeVersion": 1, "position": [200, 0], "parameters": { - "move_speed": 8.0, - "sprint_multiplier": 2.0, - "crouch_multiplier": 0.4, - "jump_height": 2.0, - "jump_duration": 0.4, - "air_control": 0.5, - "gravity_scale": 0.3, + "move_speed": 4.5, + "sprint_multiplier": 1.5, + "crouch_multiplier": 0.45, + "jump_height": 0.9, + "jump_duration": 0.22, + "air_control": 0.15, + "gravity_scale": 1.6, + "ground_accel": 30.0, + "ground_friction": 24.0, "crouch_height": 0.5, "stand_height": 1.4 } diff --git a/gameengine/src/services/impl/workflow/workflow_generic_steps/workflow_physics_fps_move_step.cpp b/gameengine/src/services/impl/workflow/workflow_generic_steps/workflow_physics_fps_move_step.cpp index 949de4dd9..0d2e71fb7 100644 --- a/gameengine/src/services/impl/workflow/workflow_generic_steps/workflow_physics_fps_move_step.cpp +++ b/gameengine/src/services/impl/workflow/workflow_generic_steps/workflow_physics_fps_move_step.cpp @@ -42,6 +42,11 @@ void WorkflowPhysicsFpsMoveStep::Execute( const float standHeight = getNum("stand_height", 1.6f); const float airControl = getNum("air_control", 0.3f); const float gravityScale = getNum("gravity_scale", 1.0f); + // Acceleration model (CalcFriction-style). Velocity accelerates toward the + // target each frame instead of snapping. Equal accel/friction = modern feel. + const float groundAccel = getNum("ground_accel", 35.0f); + const float groundFriction = getNum("ground_friction", 30.0f); + const float dtMove = context.Get("physics_dt", 1.0f / 60.0f); // Read input state from context (set by input.poll) bool keyW = context.GetBool("input_key_w", false); @@ -100,8 +105,32 @@ void WorkflowPhysicsFpsMoveStep::Execute( } if (grounded) { - // Full ground control - body->setLinearVelocity(btVector3(moveX, currentVel.y(), moveZ)); + // Inertia model: accelerate horizontal velocity toward target instead of + // snap-setting it. When input released, friction decelerates to zero. + float horizX = currentVel.x(); + float horizZ = currentVel.z(); + if (len > 0.001f) { + float diffX = moveX - horizX; + float diffZ = moveZ - horizZ; + float diffLen = std::sqrt(diffX * diffX + diffZ * diffZ); + float maxStep = groundAccel * dtMove; + if (diffLen > maxStep && diffLen > 0.0f) { + float k = maxStep / diffLen; + diffX *= k; + diffZ *= k; + } + horizX += diffX; + horizZ += diffZ; + } else { + float curSpeed = std::sqrt(horizX * horizX + horizZ * horizZ); + if (curSpeed > 0.001f) { + float drop = std::min(curSpeed, groundFriction * dtMove); + float k = (curSpeed - drop) / curSpeed; + horizX *= k; + horizZ *= k; + } + } + body->setLinearVelocity(btVector3(horizX, currentVel.y(), horizZ)); } else { // Air control: blend input with current horizontal velocity (Quake-style) float curX = currentVel.x();