Skip to content

Commit

Permalink
added: 60 fps limit to player input check
Browse files Browse the repository at this point in the history
  • Loading branch information
micutio committed Oct 16, 2020
1 parent cc6ab64 commit 7a664f0
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 13 deletions.
16 changes: 10 additions & 6 deletions src/core/game_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ impl MessageLog for Vec<(String, Color)> {
/// Results from porcessing an objects action for that turn, in ascending rank.
#[derive(PartialEq, Debug)]
pub enum ObjectProcResult {
NoAction,
NoFeedback,
CheckEnterFOV,
Animate { anim_type: AnimationType },
UpdateFOV,
ReRender,
NoAction, // object did not act and is still pondering its turn
NoFeedback, // action completed, but requires no visual feedback
CheckEnterFOV, // check whether the object has entered the player's FOV
Animate { anim_type: AnimationType }, // play given animation to visualise action
UpdateFOV, // action completed, requires updating FOV
ReRender, // trigger full re-render of the game world
}

/// The game state struct contains all information necessary to represent the current state of the
Expand Down Expand Up @@ -61,6 +61,10 @@ impl GameState {
}
}

pub fn is_players_turn(&self) -> bool {
self.current_obj_index == PLAYER
}

/// Process an object's turn i.e., let it perform as many actions as it has energy for.
// TODO: Implement energy costs for actions.
pub fn process_object(
Expand Down
34 changes: 30 additions & 4 deletions src/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
use std::error::Error;
use std::fs::File;
use std::io::{Read, Write};
use std::thread::{self};
use std::time::{Duration, Instant};

use tcod::colors;

use crate::core::game_objects::GameObjects;
use crate::core::game_state::{GameState, MessageLog};
use crate::core::game_state::{GameState, MessageLog, ObjectProcResult};
use crate::core::world::world_gen::WorldGen;

use crate::core::world::world_gen_organic::OrganicsWorldGenerator;
Expand All @@ -20,6 +22,8 @@ use crate::ui::game_input::{GameInput, PlayerInput};

const SAVEGAME: &str = "data/savegame";

pub const MS_PER_FRAME: Duration = Duration::from_millis(16.0 as u64);

// TODO: Make this changeable via command line flag!
pub const DEBUG_MODE: bool = false;

Expand Down Expand Up @@ -89,20 +93,36 @@ pub fn game_loop(
game_objects: &mut GameObjects,
) {
// use cpuprofiler::PROFILER;

// PROFILER.lock().unwrap().start("./profile.out");

let mut start_time = Instant::now();
while !game_frontend.root.window_closed() {
// ensure that the player action from previous turns is consumed
assert!(game_input.is_action_consumed());

// let the game engine process an object
let process_result = game_state.process_object(game_objects, &game_frontend.fov);
let action_result = game_state.process_object(game_objects, &game_frontend.fov);

// limit frames
if game_state.is_players_turn() {
if let ObjectProcResult::NoAction = action_result {
let elapsed = start_time.elapsed();
println!("time since last inactive: {:#?}", elapsed);
if let Some(slow_down) = MS_PER_FRAME.checked_sub(elapsed) {
println!("sleep for {:#?}", slow_down);
thread::sleep(slow_down);
}
start_time = Instant::now();
}
}

// render action vfx
process_visual_feedback(
game_state,
game_frontend,
game_input,
game_objects,
process_result,
action_result,
);

// once processing is done, check whether we have a new user input
Expand Down Expand Up @@ -140,6 +160,12 @@ pub fn game_loop(
}
None => {}
}

// sync game loop to 60 fps to avoid eating the CPU alive
// if let Some(time_to_next_step) = MS_PER_FRAME.checked_sub(start_time.elapsed()) {
// println!("sleep for {:#?}", time_to_next_step);
// thread::sleep(time_to_next_step);
// }
}
// PROFILER.lock().unwrap().stop();
}
Expand Down
2 changes: 1 addition & 1 deletion src/ui/game_frontend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::ui::game_input::{GameInput, UiAction};
// game window properties
pub const SCREEN_WIDTH: i32 = 80;
pub const SCREEN_HEIGHT: i32 = 50;
const LIMIT_FPS: i32 = 20; // target fps
const LIMIT_FPS: i32 = 60; // target fps

// field of view algorithm parameters
const FOV_ALG: FovAlgorithm = FovAlgorithm::Shadow;
Expand Down
9 changes: 7 additions & 2 deletions src/ui/game_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender, TryRecvError};
use std::sync::{Arc, Mutex};
use std::thread::{self, JoinHandle};
use std::time::{Duration, Instant};

use tcod::input::{self, Event, Key, Mouse};

use crate::core::game_objects::GameObjects;
use crate::core::game_state::GameState;
use crate::entity::action::*;
use crate::game::MS_PER_FRAME;
use crate::player::PLAYER;
use crate::ui::game_frontend::{re_render, FovMap, GameFrontend};
use std::time::Duration;

/// The game input contains fields for
/// - current mouse position
Expand Down Expand Up @@ -347,10 +348,11 @@ fn start_input_proc_thread(
thread::spawn(move || {
let mut mouse_x: i32 = 0;
let mut mouse_y: i32 = 0;

let mut is_paused = false;

loop {
// let start_time = Instant::now();

if !is_paused {
thread::sleep(Duration::from_millis(16));
let _mouse: Mouse = Default::default(); // this is not really used right now
Expand Down Expand Up @@ -402,6 +404,9 @@ fn start_input_proc_thread(
}
_ => {}
}

// // sync game loop to 60 fps to avoid eating the CPU alive
// thread::sleep(MS_PER_FRAME - start_time.elapsed());
}
})
}
Expand Down

0 comments on commit 7a664f0

Please sign in to comment.