void BotSetCommand (gedict_t* self) { extern float last_frame_time; float msec_since_last = (last_frame_time - self->fb.last_cmd_sent) * 1000; int cmd_msec = (int)msec_since_last; int weapon_script_impulse = 0; int impulse = 0; qbool jumping; qbool firing; vec3_t direction; BotPerformRocketJump (self); if (cmd_msec) { self->fb.cmd_msec_lost += (msec_since_last - cmd_msec); if (self->fb.cmd_msec_lost >= 1) { self->fb.cmd_msec_lost -= 1; cmd_msec += 1; } } else if (self->fb.cmd_msec_last) { // Probably re-sending after blocked(), re-use old number cmd_msec = self->fb.cmd_msec_last; } else { cmd_msec = 12; } //G_sprint(self, PRINT_HIGH, "Movement length @ %f: %d\n", last_frame_time, cmd_msec); // dir_move_ is the direction we want to move in, but need to take inertia into effect // ... as rough guide (and save doubling physics calculations), scale command > VectorNormalize (self->fb.dir_move_); VectorScale (self->fb.dir_move_, sv_maxspeed, self->fb.last_cmd_direction); trap_makevectors (self->fb.desired_angle); // During intermission, always do nothing and leave humans to change level if (intermission_running) { self->fb.firing = self->fb.jumping = false; } else if (teamplay && deathmatch == 1 && !self->fb.firing) { // Weaponscripts if (self->s.v.weapon != IT_SHOTGUN && self->s.v.weapon != IT_AXE) { weapon_script_impulse = (self->s.v.ammo_shells ? 2 : 1); } } impulse = self->fb.botchose ? self->fb.next_impulse : self->fb.firing ? self->fb.desired_weapon_impulse : weapon_script_impulse; if (self->fb.firing && BotUsingCorrectWeapon (self)) { impulse = 0; // we already have the requested weapon } jumping = self->fb.jumping || self->fb.waterjumping; firing = self->fb.firing; self->fb.waterjumping = false; if (self->fb.dbg_countdown > 0) { jumping = firing = false; VectorClear (direction); --self->fb.dbg_countdown; } else { if (jumping && ((int)self->s.v.flags & FL_ONGROUND)) { BestJumpingDirection (self); } else { ApplyPhysics (self); } if (self->s.v.waterlevel <= 1) { vec3_t hor; VectorCopy (self->fb.dir_move_, hor); hor[2] = 0; VectorNormalize (hor); VectorScale (hor, 800, hor); direction[0] = DotProduct (g_globalvars.v_forward, hor); direction[1] = DotProduct (g_globalvars.v_right, hor); direction[2] = 0; } else { direction[0] = DotProduct (g_globalvars.v_forward, self->fb.dir_move_) * 800; direction[1] = DotProduct (g_globalvars.v_right, self->fb.dir_move_) * 800; direction[2] = DotProduct (g_globalvars.v_up, self->fb.dir_move_) * 800; } #ifdef DEBUG_MOVEMENT if (self->fb.debug_path) { G_bprint (PRINT_HIGH, " : final direction sent [%4.1f %4.1f %4.1f]\n", PASSVEC3 (self->fb.dir_move_)); } #endif } self->fb.desired_angle[2] = 0; if (ISDEAD (self)) { firing = false; jumping = BotRequestRespawn (self); VectorClear (direction); impulse = 0; } else if (self->fb.min_move_time > g_globalvars.time) { VectorClear (direction); } // Keep bots on spawns before match start if (match_in_progress != 2 && cvar(FB_CVAR_FREEZE_PREWAR)) { jumping = firing = false; VectorClear(direction); impulse = 0; } trap_SetBotCMD ( NUM_FOR_EDICT (self), cmd_msec, PASSVEC3(self->fb.desired_angle), PASSVEC3(direction), (firing ? 1 : 0) | (jumping ? 2 : 0), impulse ); self->fb.next_impulse = 0; self->fb.botchose = false; self->fb.last_cmd_sent = last_frame_time; self->fb.cmd_msec_last = cmd_msec; VectorClear (self->fb.obstruction_normal); if (self->s.v.button0 && !firing) { // Stopped firing, randomise next time self->fb.last_rndaim_time = 0; } self->fb.prev_look_object = self->fb.look_object; VectorCopy (self->s.v.velocity, self->fb.prev_velocity); }
int main() { // Initialization //-------------------------------------------------------------------------------------- int screenWidth = 800; int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [physics] example - basic rigidbody"); InitPhysics(3); // Initialize physics system with maximum physic objects // Object initialization Transform player = (Transform){(Vector2){(screenWidth - OBJECT_SIZE) / 2, (screenHeight - OBJECT_SIZE) / 2}, 0.0f, (Vector2){OBJECT_SIZE, OBJECT_SIZE}}; AddCollider(PLAYER_INDEX, (Collider){true, COLLIDER_RECTANGLE, (Rectangle){player.position.x, player.position.y, player.scale.x, player.scale.y}, 0}); AddRigidbody(PLAYER_INDEX, (Rigidbody){true, 1.0f, (Vector2){0, 0}, (Vector2){0, 0}, false, false, true, 0.5f, 1.0f}); // Floor initialization // NOTE: floor doesn't need a rigidbody because it's a static physic object, just a collider to collide with other dynamic colliders (with rigidbody) Transform floor = (Transform){(Vector2){0, screenHeight * 0.8f}, 0.0f, (Vector2){screenWidth, screenHeight * 0.2f}}; AddCollider(PLAYER_INDEX + 1, (Collider){true, COLLIDER_RECTANGLE, (Rectangle){floor.position.x, floor.position.y, floor.scale.x, floor.scale.y}, 0}); // Object properties initialization float moveSpeed = 6.0f; float jumpForce = 5.0f; bool physicsDebug = false; SetTargetFPS(60); //-------------------------------------------------------------------------------------- // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- // Update object physics // NOTE: all physics detections and reactions are calculated in ApplyPhysics() function (You will live happier :D) ApplyPhysics(PLAYER_INDEX, &player.position); // Check jump button input if (IsKeyDown(KEY_SPACE) && GetRigidbody(PLAYER_INDEX).isGrounded) { // Reset object Y velocity to avoid double jumping cases but keep the same X velocity that it already has SetRigidbodyVelocity(PLAYER_INDEX, (Vector2){GetRigidbody(PLAYER_INDEX).velocity.x, 0}); // Add jumping force in Y axis AddRigidbodyForce(PLAYER_INDEX, (Vector2){0, jumpForce}); } // Check movement buttons input if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) { // Set rigidbody velocity in X based on moveSpeed value and apply the same Y velocity that it already has SetRigidbodyVelocity(PLAYER_INDEX, (Vector2){moveSpeed, GetRigidbody(PLAYER_INDEX).velocity.y}); } else if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) { // Set rigidbody velocity in X based on moveSpeed negative value and apply the same Y velocity that it already has SetRigidbodyVelocity(PLAYER_INDEX, (Vector2){-moveSpeed, GetRigidbody(PLAYER_INDEX).velocity.y}); } // Check debug mode toggle button input if (IsKeyPressed(KEY_P)) physicsDebug = !physicsDebug; //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- BeginDrawing(); ClearBackground(RAYWHITE); // Draw information DrawText("Use LEFT / RIGHT to MOVE and SPACE to JUMP", (screenWidth - MeasureText("Use LEFT / RIGHT to MOVE and SPACE to JUMP", 20)) / 2, screenHeight * 0.20f, 20, LIGHTGRAY); DrawText("Use P to switch DEBUG MODE", (screenWidth - MeasureText("Use P to switch DEBUG MODE", 20)) / 2, screenHeight * 0.3f, 20, LIGHTGRAY); // Check if debug mode is enabled if (physicsDebug) { // Draw every internal physics stored collider if it is active for (int i = 0; i < 2; i++) { if (GetCollider(i).enabled) { DrawRectangleLines(GetCollider(i).bounds.x, GetCollider(i).bounds.y, GetCollider(i).bounds.width, GetCollider(i).bounds.height, GREEN); } } } else { // Draw player and floor DrawRectangleRec((Rectangle){player.position.x, player.position.y, player.scale.x, player.scale.y}, GRAY); DrawRectangleRec((Rectangle){floor.position.x, floor.position.y, floor.scale.x, floor.scale.y}, BLACK); } EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- UnloadPhysics(); // Unload physic objects CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; }