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:
parent
4b9abc5f1e
commit
72992eb4e4
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
42
src/lib.rs
42
src/lib.rs
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue