fix interp fns and make the loading screen fade

This commit is contained in:
Evan Pratten 2021-09-30 12:18:58 -04:00
parent 772bcf8f3d
commit b2c4124d79
6 changed files with 127 additions and 18 deletions

12
.vscode/tasks.json vendored
View File

@ -33,6 +33,18 @@
"env": {
"RUST_LOG": "debug"
}
},
{
"type": "cargo",
"command": "run",
"problemMatcher": [
"$rustc"
],
"group": "build",
"label": "Rust: Run Game - TRACE",
"env": {
"RUST_LOG": "trace"
}
}
]
}

View File

@ -23,6 +23,7 @@ num-traits = "0.2"
sentry = "0.23"
image = "0.23"
tempfile = "3.2"
approx = "0.5"
[dev-dependencies]
puffin_viewer = "0.6"

View File

@ -89,6 +89,8 @@ use crate::{
extern crate thiserror;
#[macro_use]
extern crate serde;
#[macro_use]
extern crate approx;
mod context;
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
let screen_size = Vector2::new(
context.renderer.borrow().get_screen_width() as f32,
context.renderer.borrow().get_screen_height() as f32,
);
let screen_size = context.renderer.borrow().get_screen_size();
// Update the pixel shader to correctly handle the screen size
pixel_shader.set_variable("viewport", screen_size)?;

View File

@ -1,8 +1,18 @@
use std::ops::{Div, Sub};
use chrono::{DateTime, Utc};
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 tracing::{debug, info, trace};
@ -13,19 +23,24 @@ const LOADING_SCREEN_DURATION_SECONDS: u8 = 3;
#[derive(Debug)]
pub struct LoadingScreen {
start_timestamp: Option<DateTime<Utc>>,
game_logo_texture: Texture2D
game_logo_texture: Texture2D,
game_logo_size: Vector2,
}
impl 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
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 {
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 {
fn render_screen_space(
&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
// 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),
);
}
}

View File

@ -1,6 +1,6 @@
use std::ops::Range;
use num_traits::{Float};
use num_traits::Float;
use raylib::math::Vector2;
/// Rotate a vector by an angle
@ -27,7 +27,9 @@ where
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
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
(mapped_value * (output_range.end - output_range.start)) + output_range.start
@ -45,3 +47,48 @@ where
// Interpolate the value
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));
}
}

View File

@ -1,11 +1,22 @@
use std::{ops::{Deref, DerefMut}};
use raylib::{prelude::RaylibDraw, RaylibHandle};
use std::ops::{Deref, DerefMut};
use raylib::{math::Vector2, prelude::RaylibDraw, RaylibHandle};
#[derive(Debug)]
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 From<RaylibHandle> for HackedRaylibHandle {