fix interp fns and make the loading screen fade
This commit is contained in:
parent
772bcf8f3d
commit
b2c4124d79
12
.vscode/tasks.json
vendored
12
.vscode/tasks.json
vendored
@ -33,6 +33,18 @@
|
|||||||
"env": {
|
"env": {
|
||||||
"RUST_LOG": "debug"
|
"RUST_LOG": "debug"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "cargo",
|
||||||
|
"command": "run",
|
||||||
|
"problemMatcher": [
|
||||||
|
"$rustc"
|
||||||
|
],
|
||||||
|
"group": "build",
|
||||||
|
"label": "Rust: Run Game - TRACE",
|
||||||
|
"env": {
|
||||||
|
"RUST_LOG": "trace"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ num-traits = "0.2"
|
|||||||
sentry = "0.23"
|
sentry = "0.23"
|
||||||
image = "0.23"
|
image = "0.23"
|
||||||
tempfile = "3.2"
|
tempfile = "3.2"
|
||||||
|
approx = "0.5"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
puffin_viewer = "0.6"
|
puffin_viewer = "0.6"
|
||||||
|
@ -89,6 +89,8 @@ use crate::{
|
|||||||
extern crate thiserror;
|
extern crate thiserror;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate approx;
|
||||||
|
|
||||||
mod context;
|
mod context;
|
||||||
mod discord_rpc;
|
mod discord_rpc;
|
||||||
@ -191,10 +193,7 @@ pub async fn game_begin(game_config: &GameConfig) -> Result<(), Box<dyn std::err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the screen size once to work with in render code
|
// Fetch the screen size once to work with in render code
|
||||||
let screen_size = Vector2::new(
|
let screen_size = context.renderer.borrow().get_screen_size();
|
||||||
context.renderer.borrow().get_screen_width() as f32,
|
|
||||||
context.renderer.borrow().get_screen_height() as f32,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update the pixel shader to correctly handle the screen size
|
// Update the pixel shader to correctly handle the screen size
|
||||||
pixel_shader.set_variable("viewport", screen_size)?;
|
pixel_shader.set_variable("viewport", screen_size)?;
|
||||||
|
@ -1,8 +1,18 @@
|
|||||||
|
use std::ops::{Div, Sub};
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use dirty_fsm::{Action, ActionFlag};
|
use dirty_fsm::{Action, ActionFlag};
|
||||||
use raylib::{RaylibThread, texture::Texture2D};
|
use raylib::prelude::*;
|
||||||
|
|
||||||
use crate::{context::GameContext, utilities::{datastore::{ResourceLoadError, load_texture_from_internal_data}, non_ref_raylib::HackedRaylibHandle, render_layer::ScreenSpaceRender}};
|
use crate::{
|
||||||
|
context::GameContext,
|
||||||
|
utilities::{
|
||||||
|
datastore::{load_texture_from_internal_data, ResourceLoadError},
|
||||||
|
math::interpolate_exp,
|
||||||
|
non_ref_raylib::HackedRaylibHandle,
|
||||||
|
render_layer::ScreenSpaceRender,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{Scenes, ScreenError};
|
use super::{Scenes, ScreenError};
|
||||||
use tracing::{debug, info, trace};
|
use tracing::{debug, info, trace};
|
||||||
@ -13,19 +23,24 @@ const LOADING_SCREEN_DURATION_SECONDS: u8 = 3;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LoadingScreen {
|
pub struct LoadingScreen {
|
||||||
start_timestamp: Option<DateTime<Utc>>,
|
start_timestamp: Option<DateTime<Utc>>,
|
||||||
game_logo_texture: Texture2D
|
game_logo_texture: Texture2D,
|
||||||
|
game_logo_size: Vector2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LoadingScreen {
|
impl LoadingScreen {
|
||||||
/// Construct a new `LoadingScreen`
|
/// Construct a new `LoadingScreen`
|
||||||
pub fn new(raylib_handle: &mut HackedRaylibHandle, thread: &RaylibThread) -> Result<Self, ResourceLoadError> {
|
pub fn new(
|
||||||
|
raylib_handle: &mut HackedRaylibHandle,
|
||||||
|
thread: &RaylibThread,
|
||||||
|
) -> Result<Self, ResourceLoadError> {
|
||||||
// Load the game logo asset
|
// Load the game logo asset
|
||||||
let game_logo = load_texture_from_internal_data(raylib_handle, thread, "logos/game-logo.png")?;
|
let game_logo =
|
||||||
|
load_texture_from_internal_data(raylib_handle, thread, "logos/game-logo.png")?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
start_timestamp: None,
|
start_timestamp: None,
|
||||||
game_logo_texture: game_logo
|
game_logo_size: Vector2::new(game_logo.width as f32, game_logo.height as f32),
|
||||||
|
game_logo_texture: game_logo,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,10 +95,34 @@ impl Action<Scenes, ScreenError, GameContext> for LoadingScreen {
|
|||||||
impl ScreenSpaceRender for LoadingScreen {
|
impl ScreenSpaceRender for LoadingScreen {
|
||||||
fn render_screen_space(
|
fn render_screen_space(
|
||||||
&self,
|
&self,
|
||||||
_raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle,
|
raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Calculate the loading screen fade in/out value
|
// Calculate the loading screen fade in/out value
|
||||||
// This makes the loading screen fade in/out over the duration of the loading screen
|
// This makes the loading screen fade in/out over the duration of the loading screen
|
||||||
|
let cur_time = Utc::now();
|
||||||
|
let time_since_start =
|
||||||
|
cur_time.signed_duration_since(self.start_timestamp.unwrap_or(cur_time));
|
||||||
|
let fade_percentage = interpolate_exp(
|
||||||
|
time_since_start.num_milliseconds() as f32,
|
||||||
|
0.0..(LOADING_SCREEN_DURATION_SECONDS as f32 * 1000.0),
|
||||||
|
0.0..1.0,
|
||||||
|
8.0,
|
||||||
|
);
|
||||||
|
trace!("Loading screen fade at {:.2}%", fade_percentage);
|
||||||
|
|
||||||
|
// Render the background
|
||||||
|
raylib.clear_background(Color::WHITE);
|
||||||
|
|
||||||
|
// Calculate the logo position
|
||||||
|
let screen_size = raylib.get_screen_size();
|
||||||
|
|
||||||
|
// Render the game logo
|
||||||
|
raylib.draw_texture_ex(
|
||||||
|
&self.game_logo_texture,
|
||||||
|
screen_size.div(2.0).sub(self.game_logo_size.div(2.0)),
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
Color::WHITE.fade(fade_percentage),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use num_traits::{Float};
|
use num_traits::Float;
|
||||||
use raylib::math::Vector2;
|
use raylib::math::Vector2;
|
||||||
|
|
||||||
/// Rotate a vector by an angle
|
/// Rotate a vector by an angle
|
||||||
@ -27,7 +27,9 @@ where
|
|||||||
let normalized_value = (value - input_range.start) / (input_range.end - input_range.start);
|
let normalized_value = (value - input_range.start) / (input_range.end - input_range.start);
|
||||||
|
|
||||||
// Map the value along an exponential curve as defined by the exponent
|
// Map the value along an exponential curve as defined by the exponent
|
||||||
let mapped_value = ((normalized_value - T::one()).powf(exp) * -T::one()) + T::one();
|
let mapped_value = (-T::one())
|
||||||
|
.mul((normalized_value.mul(T::one().add(T::one())) - T::one()).powf(exp))
|
||||||
|
.add(T::one());
|
||||||
|
|
||||||
// Return the value mapped to the output range
|
// Return the value mapped to the output range
|
||||||
(mapped_value * (output_range.end - output_range.start)) + output_range.start
|
(mapped_value * (output_range.end - output_range.start)) + output_range.start
|
||||||
@ -45,3 +47,48 @@ where
|
|||||||
// Interpolate the value
|
// Interpolate the value
|
||||||
interpolate_exp_unchecked(clamped_value, input_range, output_range, exp)
|
interpolate_exp_unchecked(clamped_value, input_range, output_range, exp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rotate_vector() {
|
||||||
|
let vector = Vector2 { x: 1.0, y: 0.0 };
|
||||||
|
let angle_rad = 90.0.to_radians();
|
||||||
|
let expected_vector = Vector2 { x: 0.0, y: 1.0 };
|
||||||
|
let actual_vector = rotate_vector(vector, angle_rad);
|
||||||
|
assert!(relative_eq!(
|
||||||
|
actual_vector.x,
|
||||||
|
expected_vector.x,
|
||||||
|
epsilon = f32::EPSILON
|
||||||
|
));
|
||||||
|
assert!(relative_eq!(
|
||||||
|
actual_vector.y,
|
||||||
|
expected_vector.y,
|
||||||
|
epsilon = f32::EPSILON
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_interpolate_exp_head() {
|
||||||
|
let input_range = 0.0..1.0;
|
||||||
|
let output_range = 0.0..1.0;
|
||||||
|
let exp = 8.0;
|
||||||
|
let value = 0.043;
|
||||||
|
let expected_value = 0.513;
|
||||||
|
let actual_value = interpolate_exp(value, input_range, output_range, exp);
|
||||||
|
assert!(relative_eq!(actual_value, expected_value, epsilon = 0.001));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_interpolate_exp_tail() {
|
||||||
|
let input_range = 0.0..1.0;
|
||||||
|
let output_range = 0.0..1.0;
|
||||||
|
let exp = 8.0;
|
||||||
|
let value = 0.957;
|
||||||
|
let expected_value = 0.513;
|
||||||
|
let actual_value = interpolate_exp(value, input_range, output_range, exp);
|
||||||
|
assert!(relative_eq!(actual_value, expected_value, epsilon = 0.001));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,11 +1,22 @@
|
|||||||
use std::{ops::{Deref, DerefMut}};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use raylib::{prelude::RaylibDraw, RaylibHandle};
|
|
||||||
|
|
||||||
|
use raylib::{math::Vector2, prelude::RaylibDraw, RaylibHandle};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HackedRaylibHandle(RaylibHandle);
|
pub struct HackedRaylibHandle(RaylibHandle);
|
||||||
|
|
||||||
|
impl HackedRaylibHandle {
|
||||||
|
|
||||||
|
/// Get the screen size as a vector
|
||||||
|
#[inline]
|
||||||
|
pub fn get_screen_size(&self) -> Vector2 {
|
||||||
|
Vector2::new(
|
||||||
|
self.get_screen_width() as f32,
|
||||||
|
self.get_screen_height() as f32,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RaylibDraw for HackedRaylibHandle {}
|
impl RaylibDraw for HackedRaylibHandle {}
|
||||||
|
|
||||||
impl From<RaylibHandle> for HackedRaylibHandle {
|
impl From<RaylibHandle> for HackedRaylibHandle {
|
||||||
|
Reference in New Issue
Block a user