1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-03-23 10:29:18 +00:00

more precise and less jittery game loop timing

This commit is contained in:
Alula 2020-10-29 13:22:56 +01:00
parent 4b9abc5f1e
commit 72992eb4e4
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
4 changed files with 51 additions and 48 deletions

View file

@ -36,6 +36,7 @@ use crate::ggez::{Context, GameError, GameResult};
use crate::ggez::conf;
use crate::ggez::vfs::{self, VFS};
pub use crate::ggez::vfs::OpenOptions;
use directories::ProjectDirs;
const CONFIG_NAME: &str = "/conf.toml";
@ -43,9 +44,9 @@ const CONFIG_NAME: &str = "/conf.toml";
#[derive(Debug)]
pub struct Filesystem {
vfs: vfs::OverlayFS,
/*resources_path: path::PathBuf,
//resources_path: path::PathBuf,
user_config_path: path::PathBuf,
user_data_path: path::PathBuf,*/
user_data_path: path::PathBuf,
}
/// Represents a file, either in the filesystem, or in the resources zip file,
@ -112,12 +113,12 @@ impl Filesystem {
// Set up VFS to merge resource path, root path, and zip path.
let mut overlay = vfs::OverlayFS::new();
/*let mut resources_path;
let mut resources_zip_path;
let user_data_path;
let user_config_path;
// let mut resources_path;
// let mut resources_zip_path;
let project_dirs = match ProjectDirs::from("", author, id) {
let project_dirs = match ProjectDirs::from("", "", id) {
Some(dirs) => dirs,
None => {
return Err(GameError::FilesystemError(String::from(
@ -128,7 +129,7 @@ impl Filesystem {
// <game exe root>/resources/
{
/*{
resources_path = root_path.clone();
resources_path.push("resources");
trace!("Resources path: {:?}", resources_path);
@ -147,13 +148,13 @@ impl Filesystem {
} else {
trace!("No resources zip file found");
}
}
}*/
// Per-user data dir,
// ~/.local/share/whatever/
{
user_data_path = project_dirs.data_local_dir();
trace!("User-local data path: {:?}", user_data_path);
log::trace!("User-local data path: {:?}", user_data_path);
let physfs = vfs::PhysicalFS::new(&user_data_path, true);
overlay.push_back(Box::new(physfs));
}
@ -162,15 +163,15 @@ impl Filesystem {
// Save game dir is read-write
{
user_config_path = project_dirs.config_dir();
trace!("User-local configuration path: {:?}", user_config_path);
log::trace!("User-local configuration path: {:?}", user_config_path);
let physfs = vfs::PhysicalFS::new(&user_config_path, false);
overlay.push_back(Box::new(physfs));
}*/
}
let fs = Filesystem {
vfs: overlay,
//user_config_path: user_config_path.to_path_buf(),
//user_data_path: user_data_path.to_path_buf(),
user_config_path: user_config_path.to_path_buf(),
user_data_path: user_data_path.to_path_buf(),
};
Ok(fs)
@ -473,6 +474,8 @@ mod tests {
ofs.push_front(Box::new(physfs));
Filesystem {
vfs: ofs,
user_config_path: path,
user_data_path: path
}
}

View file

@ -18,11 +18,11 @@ use std::time::Instant;
use log::*;
use pretty_env_logger::env_logger::Env;
use winit::event::{ElementState, Event, KeyboardInput, WindowEvent, TouchPhase};
use winit::event::{ElementState, Event, KeyboardInput, TouchPhase, WindowEvent};
use winit::event_loop::ControlFlow;
use crate::builtin_fs::BuiltinFS;
use crate::ggez::{Context, ContextBuilder, filesystem, GameResult, GameError};
use crate::ggez::{Context, ContextBuilder, filesystem, GameError, GameResult};
use crate::ggez::conf::{Backend, WindowMode, WindowSetup};
use crate::ggez::event::{KeyCode, KeyMods};
use crate::ggez::graphics;
@ -73,7 +73,7 @@ struct Game {
ui: UI,
def_matrix: ColumnMatrix4<f32>,
start_time: Instant,
next_tick: u64,
next_tick: u128,
loops: u64,
}
@ -96,23 +96,21 @@ impl Game {
if let Some(scene) = self.scene.as_mut() {
match self.state.timing_mode {
TimingMode::_50Hz | TimingMode::_60Hz => {
while self.start_time.elapsed().as_millis() as u64 > self.next_tick && self.loops < 3 {
self.next_tick += self.state.timing_mode.get_delta() as u64;
while self.start_time.elapsed().as_nanos() >= self.next_tick && self.loops < 3 {
if (self.state.settings.speed - 1.0).abs() < 0.01 {
self.next_tick += self.state.timing_mode.get_delta() as u128;
} else {
self.next_tick += (self.state.timing_mode.get_delta() as f64 / self.state.settings.speed) as u128;
}
self.loops += 1;
}
for _ in 0..self.loops {
scene.tick(&mut self.state, ctx)?;
if self.state.settings.speed_hack {
scene.tick(&mut self.state, ctx)?;
}
}
}
TimingMode::FrameSynchronized => {
scene.tick(&mut self.state, ctx)?;
if self.state.settings.speed_hack {
scene.tick(&mut self.state, ctx)?;
}
}
}
}
@ -156,9 +154,19 @@ impl Game {
KeyCode::X => { state.key_state.set_fire(true) }
KeyCode::A => { state.key_state.set_weapon_prev(true) }
KeyCode::S => { state.key_state.set_weapon_next(true) }
KeyCode::F7 => { state.set_speed(1.0) }
KeyCode::F8 => {
if state.settings.speed > 0.5 {
state.set_speed(state.settings.speed - 0.1);
}
}
KeyCode::F9 => {
if state.settings.speed < 3.0 {
state.set_speed(state.settings.speed + 0.1);
}
}
KeyCode::F10 => { state.settings.debug_outlines = !state.settings.debug_outlines }
KeyCode::F11 => { state.settings.god_mode = !state.settings.god_mode }
KeyCode::F12 => { state.set_speed_hack(!state.settings.speed_hack) }
_ => {}
}
}
@ -238,10 +246,10 @@ pub fn android_main() {
}
static BACKENDS: [Backend; 4] = [
Backend::OpenGL {major: 3, minor: 2},
Backend::OpenGLES { major: 3, minor: 2},
Backend::OpenGLES { major: 3, minor: 0},
Backend::OpenGLES { major: 2, minor: 0}
Backend::OpenGL { major: 3, minor: 2 },
Backend::OpenGLES { major: 3, minor: 2 },
Backend::OpenGLES { major: 3, minor: 0 },
Backend::OpenGLES { major: 2, minor: 0 }
];
fn init_ctx<P: Into<path::PathBuf> + Clone>(event_loop: &winit::event_loop::EventLoopWindowTarget<()>, resource_dir: P) -> GameResult<Context> {
@ -372,7 +380,7 @@ pub fn init() -> GameResult {
match el_state {
ElementState::Pressed => {
let repeat = keyboard::is_key_repeated(ctx);
game.key_down_event( keycode, modifiers.into(), repeat);
game.key_down_event(keycode, modifiers.into(), repeat);
}
ElementState::Released => {
game.key_up_event(keycode, modifiers.into());

View file

@ -75,9 +75,9 @@ impl TitleScene {
static ENGINE_VERSION: &str = "doukutsu-rs 0.1.0";
// asset copyright for freeware version
static COPYRIGHT_PIXEL: &str = "2004.12 Studio Pixel";
// asset copyright for Nicalis, why they've even replaced © with @?
// asset copyright for Nicalis
static COPYRIGHT_NICALIS: &str = "@2011 NICALIS INC.";
static COPYRIGHT_NICALIS_SWITCH: &str = "@2017 NICALIS INC."; // untested?
static COPYRIGHT_NICALIS_SWITCH: &str = "@2017 NICALIS INC.";
static DISCORD_LINK: &str = "https://discord.gg/fbRsNNB";
@ -100,7 +100,6 @@ impl Scene for TitleScene {
} else {
self.option_menu.push_entry(MenuEntry::Disabled("Original textures".to_string()));
}
self.option_menu.push_entry(MenuEntry::Toggle("2x Speed hack".to_string(), state.settings.speed_hack));
self.option_menu.push_entry(MenuEntry::Active("Join our Discord".to_string()));
self.option_menu.push_entry(MenuEntry::Disabled(DISCORD_LINK.to_owned()));
self.option_menu.push_entry(MenuEntry::Active("Back".to_string()));
@ -180,19 +179,12 @@ impl Scene for TitleScene {
*value = state.settings.original_textures;
}
}
MenuSelectionResult::Selected(4, toggle) => {
if let MenuEntry::Toggle(_, value) = toggle {
state.set_speed_hack(!state.settings.speed_hack);
*value = state.settings.speed_hack;
}
}
MenuSelectionResult::Selected(5, _) => {
MenuSelectionResult::Selected(4, _) => {
if let Err(e) = webbrowser::open(DISCORD_LINK) {
log::warn!("Error opening web browser: {}", e);
}
}
MenuSelectionResult::Selected(7, _) | MenuSelectionResult::Canceled => {
MenuSelectionResult::Selected(6, _) | MenuSelectionResult::Canceled => {
self.current_menu = CurrentMenu::MainMenu;
}
_ => {}

View file

@ -31,8 +31,8 @@ pub enum TimingMode {
impl TimingMode {
pub fn get_delta(self) -> usize {
match self {
TimingMode::_50Hz => { 1000 / 50 }
TimingMode::_60Hz => { 1000 / 60 }
TimingMode::_50Hz => { 1000000000 / 50 }
TimingMode::_60Hz => { 1000000000 / 60 }
TimingMode::FrameSynchronized => { 0 }
}
}
@ -40,7 +40,7 @@ impl TimingMode {
pub struct Settings {
pub god_mode: bool,
pub speed_hack: bool,
pub speed: f64,
pub original_textures: bool,
pub enhanced_graphics: bool,
pub debug_outlines: bool,
@ -131,7 +131,7 @@ impl SharedGameState {
sound_manager: SoundManager::new(ctx)?,
settings: Settings {
god_mode: false,
speed_hack: false,
speed: 1.0,
original_textures: false,
enhanced_graphics: true,
debug_outlines: false,
@ -230,10 +230,10 @@ impl SharedGameState {
self.carets.push(Caret::new(x, y, ctype, direct, &self.constants));
}
pub fn set_speed_hack(&mut self, toggle: bool) {
self.settings.speed_hack = toggle;
pub fn set_speed(&mut self, value: f64) {
self.settings.speed = value;
if let Err(err) = self.sound_manager.set_speed(if toggle { 2.0 } else { 1.0 }) {
if let Err(err) = self.sound_manager.set_speed(value as f32) {
log::error!("Error while sending a message to sound manager: {}", err);
}
}