mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-03-27 04:19:23 +00:00
Implement frame interpolation for smooth 50tps experience
This commit is contained in:
parent
1259de8c44
commit
2542376362
|
@ -275,3 +275,13 @@ impl<T: Num + PartialOrd + Copy + AsPrimitive<f32>> Into<crate::ggez::graphics::
|
|||
pub fn fix9_scale(val: isize, scale: f32) -> f32 {
|
||||
(val as f64 * scale as f64 / 512.0).floor() as f32 / scale
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn lerp_f64(v1: f64, v2: f64, t: f64) -> f64 {
|
||||
v1 * (1.0 - t.fract()) + v2 * t.fract()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn interpolate_fix9_scale(old_val: isize, val: isize, frame_delta: f64, scale: f32) -> f32 {
|
||||
((lerp_f64(old_val as f64, val as f64, frame_delta) * scale as f64 / 512.0).floor() / (scale as f64)) as f32
|
||||
}
|
||||
|
|
13
src/frame.rs
13
src/frame.rs
|
@ -1,14 +1,24 @@
|
|||
use crate::player::Player;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::stage::Stage;
|
||||
use crate::common::interpolate_fix9_scale;
|
||||
|
||||
pub struct Frame {
|
||||
pub x: isize,
|
||||
pub y: isize,
|
||||
pub prev_x: isize,
|
||||
pub prev_y: isize,
|
||||
pub wait: isize,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn xy_interpolated(&self, frame_time: f64, scale: f32) -> (f32, f32) {
|
||||
let x = interpolate_fix9_scale(self.prev_x, self.x, frame_time, scale);
|
||||
let y = interpolate_fix9_scale(self.prev_y, self.y, frame_time, scale);
|
||||
|
||||
(x, y)
|
||||
}
|
||||
|
||||
pub fn immediate_update(&mut self, state: &mut SharedGameState, player: &Player, stage: &Stage) {
|
||||
if (stage.map.width - 1) * 16 < state.canvas_size.0 as usize {
|
||||
self.x = -(((state.canvas_size.0 as isize - ((stage.map.width - 1) * 16) as isize) * 0x200) / 2);
|
||||
|
@ -39,6 +49,9 @@ impl Frame {
|
|||
self.y = max_y;
|
||||
}
|
||||
}
|
||||
|
||||
self.prev_x = self.x;
|
||||
self.prev_y = self.y;
|
||||
}
|
||||
|
||||
pub fn update(&mut self, state: &mut SharedGameState, player: &Player, stage: &Stage) {
|
||||
|
|
22
src/lib.rs
22
src/lib.rs
|
@ -72,6 +72,7 @@ struct Game {
|
|||
state: SharedGameState,
|
||||
ui: UI,
|
||||
def_matrix: ColumnMatrix4<f32>,
|
||||
last_time: Instant,
|
||||
start_time: Instant,
|
||||
next_tick: u128,
|
||||
loops: u64,
|
||||
|
@ -84,6 +85,7 @@ impl Game {
|
|||
ui: UI::new(ctx)?,
|
||||
def_matrix: DrawParam::new().to_matrix(),
|
||||
state: SharedGameState::new(ctx)?,
|
||||
last_time: Instant::now(),
|
||||
start_time: Instant::now(),
|
||||
next_tick: 0,
|
||||
loops: 0,
|
||||
|
@ -118,6 +120,15 @@ impl Game {
|
|||
}
|
||||
|
||||
fn draw(&mut self, ctx: &mut Context) -> GameResult {
|
||||
if self.state.timing_mode != TimingMode::FrameSynchronized {
|
||||
let now = Instant::now();
|
||||
let delta = (now.duration_since(self.last_time).as_nanos() as f64 / 1000000.0).floor()
|
||||
/ (self.state.timing_mode.get_delta_millis() / self.state.settings.speed);
|
||||
self.state.frame_time += delta;
|
||||
self.last_time = now;
|
||||
}
|
||||
self.loops = 0;
|
||||
|
||||
graphics::clear(ctx, [0.0, 0.0, 0.0, 1.0].into());
|
||||
graphics::set_transform(ctx, DrawParam::new()
|
||||
.scale(Vector2::new(self.state.scale, self.state.scale))
|
||||
|
@ -125,6 +136,11 @@ impl Game {
|
|||
graphics::apply_transformations(ctx)?;
|
||||
|
||||
if let Some(scene) = self.scene.as_mut() {
|
||||
if self.state.frame_time.floor() > self.state.prev_frame_time.floor() {
|
||||
self.state.prev_frame_time = self.state.frame_time;
|
||||
scene.draw_tick(&mut self.state, ctx)?;
|
||||
}
|
||||
|
||||
scene.draw(&mut self.state, ctx)?;
|
||||
if self.state.settings.touch_controls {
|
||||
self.state.touch_controls.draw(&self.state.constants, &mut self.state.texture_set, ctx)?;
|
||||
|
@ -136,7 +152,6 @@ impl Game {
|
|||
}
|
||||
|
||||
graphics::present(ctx)?;
|
||||
self.loops = 0;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -333,6 +348,7 @@ pub fn init() -> GameResult {
|
|||
|
||||
if let Some(game) = &mut game {
|
||||
game.loops = 0;
|
||||
game.last_time = Instant::now();
|
||||
}
|
||||
}
|
||||
Event::Suspended => {
|
||||
|
@ -342,6 +358,7 @@ pub fn init() -> GameResult {
|
|||
}
|
||||
if let Some(game) = &mut game {
|
||||
game.loops = 0;
|
||||
game.last_time = Instant::now();
|
||||
}
|
||||
}
|
||||
Event::WindowEvent { event, .. } => {
|
||||
|
@ -419,6 +436,9 @@ pub fn init() -> GameResult {
|
|||
game.state.next_scene = None;
|
||||
|
||||
game.scene.as_mut().unwrap().init(&mut game.state, ctx).unwrap();
|
||||
game.loops = 0;
|
||||
game.state.frame_time = 0.0;
|
||||
game.state.prev_frame_time = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,11 @@ use std::io::Cursor;
|
|||
use bitvec::vec::BitVec;
|
||||
use byteorder::{LE, ReadBytesExt};
|
||||
use itertools::Itertools;
|
||||
use num_traits::abs;
|
||||
|
||||
use crate::bitfield;
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::{Condition, fix9_scale, Rect};
|
||||
use crate::common::{Condition, fix9_scale, interpolate_fix9_scale, Rect};
|
||||
use crate::common::Direction;
|
||||
use crate::common::Flag;
|
||||
use crate::entity::GameEntity;
|
||||
|
@ -75,6 +76,8 @@ pub struct NPC {
|
|||
pub vel_y: isize,
|
||||
pub target_x: isize,
|
||||
pub target_y: isize,
|
||||
pub prev_x: isize,
|
||||
pub prev_y: isize,
|
||||
pub exp: u16,
|
||||
pub size: u8,
|
||||
pub shock: u16,
|
||||
|
@ -118,6 +121,8 @@ impl NPC {
|
|||
vel_y: 0,
|
||||
target_x: 0,
|
||||
target_y: 0,
|
||||
prev_x: 0,
|
||||
prev_y: 0,
|
||||
exp: 0,
|
||||
size: 0,
|
||||
shock: 0,
|
||||
|
@ -230,6 +235,14 @@ impl GameEntity<(&mut Player, &HashMap<u16, RefCell<NPC>>, &mut Stage)> for NPC
|
|||
self.shock -= 1;
|
||||
}
|
||||
|
||||
if abs(self.prev_x - self.x) > 0x1000 {
|
||||
self.prev_x = self.x;
|
||||
}
|
||||
|
||||
if abs(self.prev_y - self.y) > 0x1000 {
|
||||
self.prev_y = self.y;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -239,7 +252,6 @@ impl GameEntity<(&mut Player, &HashMap<u16, RefCell<NPC>>, &mut Stage)> for NPC
|
|||
}
|
||||
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, state.npc_table.get_texture_name(self.npc_type))?;
|
||||
let scale = state.scale;
|
||||
|
||||
let off_x = if self.direction == Direction::Left { self.display_bounds.left } else { self.display_bounds.right } as isize;
|
||||
let shock = if self.shock > 0 {
|
||||
|
@ -247,8 +259,12 @@ impl GameEntity<(&mut Player, &HashMap<u16, RefCell<NPC>>, &mut Stage)> for NPC
|
|||
} else { 0.0 };
|
||||
|
||||
batch.add_rect(
|
||||
fix9_scale(self.x - off_x - frame.x, scale) + shock,
|
||||
fix9_scale(self.y - self.display_bounds.top as isize - frame.y, scale),
|
||||
interpolate_fix9_scale(self.prev_x - off_x - frame.prev_x,
|
||||
self.x - off_x - frame.x,
|
||||
state.frame_time, state.scale) + shock,
|
||||
interpolate_fix9_scale(self.prev_y - self.display_bounds.top as isize - frame.prev_y,
|
||||
self.y - self.display_bounds.top as isize - frame.y,
|
||||
state.frame_time, state.scale),
|
||||
&self.anim_rect,
|
||||
);
|
||||
batch.draw(ctx)?;
|
||||
|
@ -372,6 +388,8 @@ impl NPCMap {
|
|||
vel_y: 0,
|
||||
target_x: 0,
|
||||
target_y: 0,
|
||||
prev_x: 0,
|
||||
prev_y: 0,
|
||||
action_num: 0,
|
||||
anim_num: 0,
|
||||
flag_num: data.flag_num,
|
||||
|
@ -418,6 +436,8 @@ impl NPCMap {
|
|||
vel_y: 0,
|
||||
target_x: 0,
|
||||
target_y: 0,
|
||||
prev_x: 0,
|
||||
prev_y: 0,
|
||||
action_num: 0,
|
||||
anim_num: 0,
|
||||
flag_num: 0,
|
||||
|
|
|
@ -5,7 +5,7 @@ use num_traits::clamp;
|
|||
use num_traits::FromPrimitive;
|
||||
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::{Condition, Direction, Equipment, fix9_scale, Flag, Rect};
|
||||
use crate::common::{Condition, Direction, Equipment, fix9_scale, Flag, interpolate_fix9_scale, Rect};
|
||||
use crate::entity::GameEntity;
|
||||
use crate::frame::Frame;
|
||||
use crate::ggez::{Context, GameResult};
|
||||
|
@ -27,6 +27,8 @@ pub struct Player {
|
|||
pub vel_y: isize,
|
||||
pub target_x: isize,
|
||||
pub target_y: isize,
|
||||
pub prev_x: isize,
|
||||
pub prev_y: isize,
|
||||
pub life: u16,
|
||||
pub max_life: u16,
|
||||
pub cond: Condition,
|
||||
|
@ -72,6 +74,8 @@ impl Player {
|
|||
vel_y: 0,
|
||||
target_x: 0,
|
||||
target_y: 0,
|
||||
prev_x: 0,
|
||||
prev_y: 0,
|
||||
life: constants.my_char.life,
|
||||
max_life: constants.my_char.max_life,
|
||||
cond: Condition(0x80),
|
||||
|
@ -635,8 +639,12 @@ impl GameEntity<()> for Player {
|
|||
{
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "MyChar")?;
|
||||
batch.add_rect(
|
||||
fix9_scale(self.x - self.display_bounds.left as isize - frame.x, state.scale),
|
||||
fix9_scale(self.y - self.display_bounds.top as isize - frame.y, state.scale),
|
||||
interpolate_fix9_scale(self.prev_x - self.display_bounds.left as isize - frame.prev_x,
|
||||
self.x - self.display_bounds.left as isize - frame.x,
|
||||
state.frame_time, state.scale),
|
||||
interpolate_fix9_scale(self.prev_y - self.display_bounds.left as isize - frame.prev_y,
|
||||
self.y - self.display_bounds.left as isize - frame.y,
|
||||
state.frame_time, state.scale),
|
||||
&self.anim_rect,
|
||||
);
|
||||
batch.draw(ctx)?;
|
||||
|
@ -647,15 +655,23 @@ impl GameEntity<()> for Player {
|
|||
match self.direction {
|
||||
Direction::Left => {
|
||||
batch.add_rect(
|
||||
fix9_scale(self.x - self.display_bounds.left as isize - frame.x, state.scale) - 8.0,
|
||||
fix9_scale(self.y - self.display_bounds.top as isize - frame.y, state.scale) + self.weapon_offset_y as f32,
|
||||
interpolate_fix9_scale(self.prev_x - self.display_bounds.left as isize - frame.prev_x,
|
||||
self.x - self.display_bounds.left as isize - frame.x,
|
||||
state.frame_time, state.scale) - 8.0,
|
||||
interpolate_fix9_scale(self.prev_y - self.display_bounds.left as isize - frame.prev_y,
|
||||
self.y - self.display_bounds.left as isize - frame.y,
|
||||
state.frame_time, state.scale) + self.weapon_offset_y as f32,
|
||||
&self.weapon_rect,
|
||||
);
|
||||
}
|
||||
Direction::Right => {
|
||||
batch.add_rect(
|
||||
fix9_scale(self.x - self.display_bounds.left as isize - frame.x, state.scale),
|
||||
fix9_scale(self.y - self.display_bounds.top as isize - frame.y, state.scale) + self.weapon_offset_y as f32,
|
||||
interpolate_fix9_scale(self.prev_x - self.display_bounds.left as isize - frame.prev_x,
|
||||
self.x - self.display_bounds.left as isize - frame.x,
|
||||
state.frame_time, state.scale),
|
||||
interpolate_fix9_scale(self.prev_y - self.display_bounds.left as isize - frame.prev_y,
|
||||
self.y - self.display_bounds.left as isize - frame.y,
|
||||
state.frame_time, state.scale) + self.weapon_offset_y as f32,
|
||||
&self.weapon_rect,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -77,6 +77,8 @@ impl GameScene {
|
|||
frame: Frame {
|
||||
x: 0,
|
||||
y: 0,
|
||||
prev_x: 0,
|
||||
prev_y: 0,
|
||||
wait: 16,
|
||||
},
|
||||
stage_id: id,
|
||||
|
@ -222,6 +224,7 @@ impl GameScene {
|
|||
fn draw_background(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_background_name)?;
|
||||
let scale = state.scale;
|
||||
let (frame_x, frame_y) = self.frame.xy_interpolated(state.frame_time, state.scale);
|
||||
|
||||
match self.stage.data.background_type {
|
||||
BackgroundType::Stationary => {
|
||||
|
@ -237,13 +240,13 @@ impl GameScene {
|
|||
BackgroundType::MoveDistant | BackgroundType::MoveNear => {
|
||||
let (off_x, off_y) = if self.stage.data.background_type == BackgroundType::MoveNear {
|
||||
(
|
||||
self.frame.x as usize % (batch.width() * 0x200),
|
||||
self.frame.y as usize % (batch.height() * 0x200)
|
||||
frame_x % (batch.width() as f32),
|
||||
frame_y % (batch.height() as f32)
|
||||
)
|
||||
} else {
|
||||
(
|
||||
self.frame.x as usize / 2 % (batch.width() * 0x200),
|
||||
self.frame.y as usize / 2 % (batch.height() * 0x200)
|
||||
((frame_x / 2.0 * scale).floor() / scale) % (batch.width() as f32),
|
||||
((frame_y / 2.0 * scale).floor() / scale) % (batch.height() as f32)
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -252,8 +255,8 @@ impl GameScene {
|
|||
|
||||
for y in 0..count_y {
|
||||
for x in 0..count_x {
|
||||
batch.add((x * batch.width()) as f32 - fix9_scale(off_x as isize, scale),
|
||||
(y * batch.height()) as f32 - fix9_scale(off_y as isize, scale));
|
||||
batch.add((x * batch.width()) as f32 - off_x,
|
||||
(y * batch.height()) as f32 - off_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -598,9 +601,9 @@ impl GameScene {
|
|||
for npc_cell in self.npc_map.npcs.values() {
|
||||
let npc = npc_cell.borrow();
|
||||
|
||||
if npc.x < (self.frame.x - npc.display_bounds.width() as isize * 0x200)
|
||||
if npc.x < (self.frame.x - 128 - npc.display_bounds.width() as isize * 0x200)
|
||||
|| npc.x > (self.frame.x + (state.canvas_size.0 as isize + npc.display_bounds.width() as isize) * 0x200)
|
||||
&& npc.y < (self.frame.y - npc.display_bounds.height() as isize * 0x200)
|
||||
&& npc.y < (self.frame.y - 128 - npc.display_bounds.height() as isize * 0x200)
|
||||
|| npc.y > (self.frame.y + (state.canvas_size.1 as isize + npc.display_bounds.height() as isize) * 0x200) {
|
||||
continue;
|
||||
}
|
||||
|
@ -716,6 +719,7 @@ impl GameScene {
|
|||
};
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, tex)?;
|
||||
let mut rect = Rect::<usize>::new(0, 0, 16, 16);
|
||||
let (frame_x, frame_y) = self.frame.xy_interpolated(state.frame_time, state.scale);
|
||||
|
||||
let tile_start_x = clamp(self.frame.x / 0x200 / 16, 0, self.stage.map.width as isize) as usize;
|
||||
let tile_start_y = clamp(self.frame.y / 0x200 / 16, 0, self.stage.map.height as isize) as usize;
|
||||
|
@ -763,8 +767,8 @@ impl GameScene {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
batch.add_rect((x as f32 * 16.0 - 8.0) - fix9_scale(self.frame.x, state.scale),
|
||||
(y as f32 * 16.0 - 8.0) - fix9_scale(self.frame.y, state.scale), &rect);
|
||||
batch.add_rect((x as f32 * 16.0 - 8.0) - frame_x,
|
||||
(y as f32 * 16.0 - 8.0) - frame_y, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1124,6 +1128,24 @@ impl Scene for GameScene {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
self.frame.prev_x = self.frame.x;
|
||||
self.frame.prev_y = self.frame.y;
|
||||
self.player.prev_x = self.player.x;
|
||||
self.player.prev_y = self.player.y;
|
||||
|
||||
for npc_cell in self.npc_map.npcs.values() {
|
||||
let mut npc = npc_cell.borrow_mut();
|
||||
|
||||
if npc.cond.alive() {
|
||||
npc.prev_x = npc.x;
|
||||
npc.prev_y = npc.y;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
state.update_key_trigger();
|
||||
|
||||
|
@ -1182,9 +1204,9 @@ impl Scene for GameScene {
|
|||
if let Some(npc_cell) = self.npc_map.npcs.get(npc_id) {
|
||||
let npc = npc_cell.borrow();
|
||||
|
||||
if npc.x < (self.frame.x - npc.display_bounds.width() as isize * 0x200)
|
||||
if npc.x < (self.frame.x - 128 - npc.display_bounds.width() as isize * 0x200)
|
||||
|| npc.x > (self.frame.x + (state.canvas_size.0 as isize + npc.display_bounds.width() as isize) * 0x200)
|
||||
&& npc.y < (self.frame.y - npc.display_bounds.height() as isize * 0x200)
|
||||
&& npc.y < (self.frame.y - 128 - npc.display_bounds.height() as isize * 0x200)
|
||||
|| npc.y > (self.frame.y + (state.canvas_size.1 as isize + npc.display_bounds.height() as isize) * 0x200) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ pub trait Scene {
|
|||
|
||||
fn tick(&mut self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) }
|
||||
|
||||
fn draw_tick(&mut self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) }
|
||||
|
||||
fn draw(&self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) }
|
||||
|
||||
fn debug_overlay_draw(&mut self, _game_ui: &mut Components, _state: &mut SharedGameState, _ctx: &mut Context, _frame: &mut imgui::Ui) -> GameResult { Ok(()) }
|
||||
|
|
|
@ -92,13 +92,13 @@ impl Scene for TitleScene {
|
|||
self.main_menu.push_entry(MenuEntry::Active("Quit".to_string()));
|
||||
self.main_menu.height = self.main_menu.entries.len() * 14 + 6;
|
||||
|
||||
self.option_menu.push_entry(MenuEntry::Toggle("50 FPS timing".to_string(), state.timing_mode == TimingMode::_50Hz));
|
||||
self.option_menu.push_entry(MenuEntry::Toggle("Original timing (50TPS)".to_string(), state.timing_mode == TimingMode::_50Hz));
|
||||
self.option_menu.push_entry(MenuEntry::Toggle("Linear scaling".to_string(), ctx.filter_mode == FilterMode::Linear));
|
||||
self.option_menu.push_entry(MenuEntry::Toggle("Lighting effects".to_string(), state.settings.lighting_efects));
|
||||
if state.constants.is_cs_plus {
|
||||
self.option_menu.push_entry(MenuEntry::Toggle("Original textures".to_string(), state.settings.original_textures));
|
||||
self.option_menu.push_entry(MenuEntry::Toggle("Freeware textures".to_string(), state.settings.original_textures));
|
||||
} else {
|
||||
self.option_menu.push_entry(MenuEntry::Disabled("Original textures".to_string()));
|
||||
self.option_menu.push_entry(MenuEntry::Disabled("Freeware textures".to_string()));
|
||||
}
|
||||
self.option_menu.push_entry(MenuEntry::Active("Join our Discord".to_string()));
|
||||
self.option_menu.push_entry(MenuEntry::Disabled(DISCORD_LINK.to_owned()));
|
||||
|
|
|
@ -38,6 +38,14 @@ impl TimingMode {
|
|||
TimingMode::FrameSynchronized => { 0 }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_delta_millis(self) -> f64 {
|
||||
match self {
|
||||
TimingMode::_50Hz => { 1000.0 / 50.0 }
|
||||
TimingMode::_60Hz => { 1000.0 / 60.0 }
|
||||
TimingMode::FrameSynchronized => { 0.0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Settings {
|
||||
|
@ -74,6 +82,8 @@ pub struct SharedGameState {
|
|||
pub settings: Settings,
|
||||
pub constants: EngineConstants,
|
||||
pub new_npcs: Vec<NPC>,
|
||||
pub frame_time: f64,
|
||||
pub prev_frame_time: f64,
|
||||
pub scale: f32,
|
||||
pub lightmap_canvas: Canvas,
|
||||
pub canvas_size: (f32, f32),
|
||||
|
@ -112,7 +122,7 @@ impl SharedGameState {
|
|||
.or_else(|_| BMFontRenderer::load("/", "builtin/builtin_font.fnt", ctx))?;
|
||||
|
||||
Ok(SharedGameState {
|
||||
timing_mode: TimingMode::_60Hz,
|
||||
timing_mode: TimingMode::_50Hz,
|
||||
control_flags: ControlFlags(0),
|
||||
game_flags: bitvec::bitvec![0; 8000],
|
||||
fade_state: FadeState::Hidden,
|
||||
|
@ -141,6 +151,8 @@ impl SharedGameState {
|
|||
},
|
||||
constants,
|
||||
new_npcs: Vec::with_capacity(8),
|
||||
frame_time: 0.0,
|
||||
prev_frame_time: 0.0,
|
||||
scale,
|
||||
lightmap_canvas: Canvas::with_window_size(ctx)?,
|
||||
screen_size,
|
||||
|
@ -259,6 +271,8 @@ impl SharedGameState {
|
|||
|
||||
pub fn set_speed(&mut self, value: f64) {
|
||||
self.settings.speed = value;
|
||||
self.frame_time = 0.0;
|
||||
self.prev_frame_time = 0.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