Merge pull request #17 from Ewpratten/player_physics

Merge playerphysics
This commit is contained in:
Evan Pratten 2021-10-01 18:09:35 -07:00 committed by GitHub
commit ae75f99bc2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 206 additions and 71 deletions

View File

@ -16,8 +16,8 @@ serde_json = "1.0.64"
thiserror = "1.0"
chrono = "0.4"
rust-embed = "6.2.0"
raylib = { version = "3.5", git = "https://github.com/ewpratten/raylib-rs", rev = "2399e17d7bf299f34c8e618a9ab140b274639cfb", features = [
"with_serde"
raylib = { version = "3.5", git = "https://github.com/ewpratten/raylib-rs", rev = "2ae949cb3488dd1bb052ece71d61021c8dd6e910", features = [
"serde"
] }
puffin = "0.9"
puffin_http = "0.6"
@ -31,6 +31,7 @@ pkg-version = "1.0"
cfg-if = "1.0"
num-derive = "0.3"
num = "0.4"
tiled = { version ="0.9.5", default-features = false }
[dev-dependencies]
puffin_viewer = "0.6"

View File

@ -1,5 +1,46 @@
{
"name": "Unnamed game",
"base_window_size": [1080, 720],
"sentry_dsn": "https://d5d94e75f08841388287fa0c23606ac7@o398481.ingest.sentry.io/5985679"
"base_window_size": [
1080,
720
],
"sentry_dsn": "https://d5d94e75f08841388287fa0c23606ac7@o398481.ingest.sentry.io/5985679",
"colors": {
"red": [
240,
70,
53,
255
],
"blue": [
101,
75,
250,
255
],
"green": [
61,
227,
161,
255
],
"yellow": [
250,
235,
55,
255
],
"pink": [
240,
246,
227,
255
],
"background": [
20,
20,
20,
255
]
}
}

View File

@ -1,5 +1,7 @@
{
"pixel_scale": 1.0,
"warp_factor": 0.5,
"scanline_darkness": 0.5
"warp_factor": 0.65,
"scanline_darkness": 0.55,
"bloom_samples": 5.0,
"bloom_quality": 2.5
}

View File

@ -1,5 +1,6 @@
/**
* This shader is the last piece of the graphics pipeline. EVERYTHING is passed through it.
* This shader is the last piece of the graphics pipeline. EVERYTHING is passed
* through it.
*/
#version 330
@ -9,6 +10,7 @@ in vec2 fragTexCoord;
// Whole input texture
uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Viewport size
uniform vec2 viewport;
@ -23,6 +25,10 @@ uniform vec2 pixelScale;
uniform float warpFactor;
uniform float scanlineDarkness;
// Bloom parameters
uniform float bloomSamples;
uniform float bloomQuality;
void main() {
// Calculate the distance to merge pixels
float dx = pixelScale.x * (1.0 / viewport.x);
@ -38,20 +44,43 @@ void main() {
// Calculate a UV for this new blocky pixel
vec2 pixelatedUV = vec2(dx * floor(baseUV.x / dx), dy * floor(baseUV.y / dy));
// --- BEGIN CRT SHADER ---
// Warp the UVs of the pixelated texture
vec2 warpedUV = pixelatedUV;
warpedUV.x -= 0.5; warpedUV.x *= 1.0+(dist_center_sq.y * (0.3 * warpFactor)); warpedUV.x += 0.5;
warpedUV.y -= 0.5; warpedUV.y *= 1.0+(dist_center_sq.x * (0.4 * warpFactor)); warpedUV.y += 0.5;
warpedUV.x -= 0.5;
warpedUV.x *= 1.0 + (dist_center_sq.y * (0.3 * warpFactor));
warpedUV.x += 0.5;
warpedUV.y -= 0.5;
warpedUV.y *= 1.0 + (dist_center_sq.x * (0.4 * warpFactor));
warpedUV.y += 0.5;
// If the UV is outside the texture, return black
if (warpedUV.x < 0.0 || warpedUV.x > 1.0 || warpedUV.y < 0.0 || warpedUV.y > 1.0) {
if (warpedUV.x < 0.0 || warpedUV.x > 1.0 || warpedUV.y < 0.0 ||
warpedUV.y > 1.0) {
finalColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
// --- BEGIN BLOOM EFFECT ---
vec2 sizeFactor = vec2(1) / viewport * bloomQuality;
vec4 textureSum = vec4(0);
const int range = 2;
for (int x = -range; x <= range; x++) {
for (int y = -range; y <= range; y++) {
textureSum += texture(texture0, warpedUV + vec2(x, y) * sizeFactor);
}
}
// Determine factor of if we are rendering on a scanline
float scanlineFactor = abs(sin(fragTexCoord.y * viewport.y) * 0.5 * scanlineDarkness);
float scanlineFactor =
abs(sin(fragTexCoord.y * viewport.y) * 0.5 * scanlineDarkness);
// Build the final pixel
finalColor = vec4(mix(texture(texture0, warpedUV).rgb, vec3(0.0), scanlineFactor), 1.0);
vec4 texWithBloom =
((textureSum / (bloomSamples * bloomSamples)) + texture(texture0, warpedUV)) * colDiffuse;
finalColor = vec4(
mix(texWithBloom.rgb, vec3(0.0), scanlineFactor), 1.0);
}

View File

@ -5,12 +5,15 @@ use raylib::math::Vector2;
#[derive(Debug, Clone)]
pub struct MainCharacter {
pub position: Vector2,
pub size: Vector2,
}
impl MainCharacter {
pub fn new(position: Vector2) -> Self {
Self { position }
Self {
position,
size: Vector2::new(60.0, 80.0),
}
}
pub fn apply_force(&mut self, force: Vector2) {

View File

@ -1,3 +1,5 @@
use std::ops::{Div, Sub};
use raylib::prelude::*;
use crate::utilities::non_ref_raylib::HackedRaylibHandle;
@ -9,5 +11,5 @@ pub fn render_character_in_camera_space(
player: &MainCharacter,
) {
raylib.draw_rectangle_v(player.position, Vector2::new(10.0, 20.0), Color::WHITE);
raylib.draw_rectangle_v(player.position.sub(player.size.div(2.0)), player.size, Color::WHITE);
}

View File

@ -1,19 +1,19 @@
use std::cell::RefCell;
use crate::utilities::non_ref_raylib::HackedRaylibHandle;
use crate::{GameConfig, utilities::non_ref_raylib::HackedRaylibHandle};
#[derive(Debug)]
pub struct GameContext {
pub renderer: RefCell<HackedRaylibHandle>
pub renderer: RefCell<HackedRaylibHandle>,
pub config: GameConfig
}
impl GameContext {
/// Construct a new game context.
pub fn new(raylib: RefCell<HackedRaylibHandle>) -> Self {
Self {
renderer: raylib
}
}
}
// impl GameContext {
// /// Construct a new game context.
// pub fn new(raylib: RefCell<HackedRaylibHandle>) -> Self {
// Self {
// renderer: raylib
// }
// }
// }

View File

@ -158,7 +158,10 @@ pub async fn game_begin(game_config: &GameConfig) -> Result<(), Box<dyn std::err
raylib_thread = thread;
// Build the game context
context = Box::new(GameContext::new(RefCell::new(rl.into())));
context = Box::new(GameContext {
renderer: RefCell::new(rl.into()),
config: game_config.clone(),
});
}
// Get the main state machine
@ -183,12 +186,19 @@ pub async fn game_begin(game_config: &GameConfig) -> Result<(), Box<dyn std::err
let mut pixel_shader = ShaderWrapper::new(
None,
Some(StaticGameData::get("shaders/pixelart.fs")).expect("Failed to load pixelart.fs"),
vec!["viewport", "pixelScale", "warpFactor", "scanlineDarkness"],
vec![
"viewport",
"pixelScale",
"warpFactor",
"scanlineDarkness",
"bloomSamples",
"bloomQuality",
],
&mut context.renderer.borrow_mut(),
&raylib_thread,
)?;
info!("Starting the render loop");
while !context.renderer.borrow().window_should_close() {
// Profile the main game loop
puffin::profile_scope!("main_loop");
@ -219,6 +229,8 @@ pub async fn game_begin(game_config: &GameConfig) -> Result<(), Box<dyn std::err
)?;
pixel_shader.set_variable("warpFactor", pixel_shader_config.warp_factor)?;
pixel_shader.set_variable("scanlineDarkness", pixel_shader_config.scanline_darkness)?;
pixel_shader.set_variable("bloomSamples", pixel_shader_config.bloom_samples)?;
pixel_shader.set_variable("bloomQuality", pixel_shader_config.bloom_quality)?;
// Render the game via the pixel shader
render_to_texture(&mut dynamic_texture, || {

View File

@ -1,5 +1,3 @@
use dirty_fsm::{Action, ActionFlag};
use raylib::{color::Color, prelude::RaylibDraw};
use tracing::{debug, trace};
@ -7,6 +5,7 @@ use tracing::{debug, trace};
use crate::{
context::GameContext,
utilities::{non_ref_raylib::HackedRaylibHandle, render_layer::ScreenSpaceRender},
GameConfig,
};
use super::{Scenes, ScreenError};
@ -38,7 +37,7 @@ impl Action<Scenes, ScreenError, GameContext> for FsmErrorScreen {
context: &GameContext,
) -> Result<dirty_fsm::ActionFlag<Scenes>, ScreenError> {
trace!("execute() called on FsmErrorScreen");
self.render_screen_space(&mut context.renderer.borrow_mut());
self.render_screen_space(&mut context.renderer.borrow_mut(), &context.config);
Ok(ActionFlag::Continue)
}
@ -49,7 +48,7 @@ impl Action<Scenes, ScreenError, GameContext> for FsmErrorScreen {
}
impl ScreenSpaceRender for FsmErrorScreen {
fn render_screen_space(&self, raylib: &mut HackedRaylibHandle) {
fn render_screen_space(&self, raylib: &mut HackedRaylibHandle, config: &GameConfig) {
raylib.clear_background(Color::RED);
// Render a warning message

View File

@ -1,4 +1,4 @@
use crate::utilities::render_layer::ScreenSpaceRender;
use crate::{GameConfig, utilities::render_layer::ScreenSpaceRender};
use raylib::prelude::*;
use super::InGameScreen;
@ -6,6 +6,7 @@ impl ScreenSpaceRender for InGameScreen {
fn render_screen_space(
&self,
raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle,
config: &GameConfig
) {
// Calculate the logo position
let screen_size = raylib.get_screen_size();

View File

@ -1,7 +1,11 @@
use dirty_fsm::{Action, ActionFlag};
use raylib::prelude::*;
use crate::{character::MainCharacter, context::GameContext, utilities::render_layer::{FrameUpdate, ScreenSpaceRender, WorldSpaceRender}};
use crate::{
character::MainCharacter,
context::GameContext,
utilities::render_layer::{FrameUpdate, ScreenSpaceRender, WorldSpaceRender},
};
use super::{Scenes, ScreenError};
use tracing::{debug, trace};
@ -13,7 +17,7 @@ mod world;
#[derive(Debug)]
pub struct InGameScreen {
camera: Camera2D,
player: MainCharacter
player: MainCharacter,
}
impl InGameScreen {
@ -26,7 +30,7 @@ impl InGameScreen {
rotation: 0.0,
zoom: 1.0,
},
player: MainCharacter::new(Vector2::zero()),
player: MainCharacter::new(Vector2::new(0.0, -45.0)),
}
}
}
@ -54,10 +58,10 @@ impl Action<Scenes, ScreenError, GameContext> for InGameScreen {
let mut renderer = context.renderer.borrow_mut();
// Update the inputs and checking logic
self.update(&mut renderer, delta);
self.update(&mut renderer, delta, &context.config);
// Wipe the background
renderer.clear_background(Color::BLACK);
renderer.clear_background(context.config.colors.background);
// Render the world
{
@ -65,11 +69,11 @@ impl Action<Scenes, ScreenError, GameContext> for InGameScreen {
let mut raylib_camera_space = renderer.begin_mode2D(self.camera);
// Render in world space
self.render_world_space(&mut raylib_camera_space);
self.render_world_space(&mut raylib_camera_space, &context.config);
}
// Render the HUD
self.render_screen_space(&mut renderer);
self.render_screen_space(&mut renderer, &context.config);
Ok(ActionFlag::Continue)
}

View File

@ -1,14 +1,19 @@
use std::ops::Div;
use super::InGameScreen;
use crate::utilities::{non_ref_raylib::HackedRaylibHandle, render_layer::FrameUpdate};
use crate::{GameConfig, utilities::{non_ref_raylib::HackedRaylibHandle, render_layer::FrameUpdate}};
use chrono::Duration;
use raylib::prelude::*;
impl FrameUpdate for InGameScreen {
fn update(&mut self, raylib: &HackedRaylibHandle, delta_seconds: &Duration) {
fn update(&mut self, raylib: &HackedRaylibHandle, delta_seconds: &Duration,
config: &GameConfig) {
// Set the camera's offset based on screen size
self.camera.offset = raylib.get_screen_size().div(2.0);
self.camera.offset = raylib.get_screen_size().div(Vector2::new(2.0, 1.25));
self.camera.target = Vector2::new(
self.player.position.x,
self.camera.target.y,
);
// Check the only possible keyboard inputs
let is_jump = raylib.is_key_down(KeyboardKey::KEY_SPACE);

View File

@ -1,13 +1,25 @@
use std::ops::Mul;
use super::InGameScreen;
use crate::{
character::render::render_character_in_camera_space,
utilities::{non_ref_raylib::HackedRaylibHandle, render_layer::WorldSpaceRender},
};
use crate::{GameConfig, character::render::render_character_in_camera_space, utilities::{non_ref_raylib::HackedRaylibHandle, render_layer::WorldSpaceRender}};
use raylib::prelude::*;
impl WorldSpaceRender for InGameScreen {
fn render_world_space(&self, raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>) {
fn render_world_space(&self, raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>,
config: &GameConfig) {
// Render the player
render_character_in_camera_space(raylib, &self.player);
// Render the floor as a line
let screen_world_zero = raylib.get_screen_to_world2D(Vector2::zero(), self.camera);
let screen_world_size = raylib.get_screen_to_world2D(raylib.get_screen_size().mul(2.0), self.camera);
raylib.draw_rectangle(
screen_world_zero.x as i32,
0,
screen_world_size.x as i32,
5,
Color::WHITE,
);
}
}

View File

@ -1,18 +1,16 @@
use std::ops::{Div, Sub};
use cfg_if::cfg_if;
use chrono::{DateTime, Utc};
use dirty_fsm::{Action, ActionFlag};
use raylib::prelude::*;
use crate::{
context::GameContext,
utilities::{
use crate::{GameConfig, 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};
@ -66,12 +64,22 @@ impl Action<Scenes, ScreenError, GameContext> for LoadingScreen {
context: &GameContext,
) -> Result<dirty_fsm::ActionFlag<Scenes>, ScreenError> {
trace!("execute() called on LoadingScreen");
self.render_screen_space(&mut context.renderer.borrow_mut());
self.render_screen_space(&mut context.renderer.borrow_mut(), &context.config);
// Check for a quick skip button in debug builds
cfg_if! {
if #[cfg(debug_assertions)] {
let debug_skip_screen = context.renderer.borrow_mut().is_key_pressed(KeyboardKey::KEY_ESCAPE);
} else {
let debug_skip_screen = false;
}
}
// Keep rendering until we pass the loading screen duration
if let Some(start_timestamp) = self.start_timestamp {
let duration = Utc::now().signed_duration_since(start_timestamp);
if duration.num_seconds() >= LOADING_SCREEN_DURATION_SECONDS as i64 {
if duration.num_seconds() >= LOADING_SCREEN_DURATION_SECONDS as i64 || debug_skip_screen
{
info!("LoadingScreen duration reached, moving to next screen");
Ok(ActionFlag::SwitchState(Scenes::MainMenuScreen))
} else {
@ -96,6 +104,7 @@ impl ScreenSpaceRender for LoadingScreen {
fn render_screen_space(
&self,
raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle,
config: &GameConfig
) {
// Calculate the loading screen fade in/out value
// This makes the loading screen fade in/out over the duration of the loading screen
@ -128,7 +137,11 @@ impl ScreenSpaceRender for LoadingScreen {
// Only in debug mode, render a debug message
#[cfg(debug_assertions)]
{
raylib.draw_rectangle_v(Vector2::zero(), Vector2::new(screen_size.x, 40.0), Color::RED);
raylib.draw_rectangle_v(
Vector2::zero(),
Vector2::new(screen_size.x, 40.0),
Color::RED,
);
raylib.draw_text(
"Game in DEBUG MODE. Do not redistribute!",
10,

View File

@ -5,16 +5,13 @@ use dirty_fsm::{Action, ActionFlag};
use pkg_version::pkg_version_major;
use raylib::prelude::*;
use crate::{
context::GameContext,
utilities::{
use crate::{GameConfig, context::GameContext, utilities::{
datastore::{load_texture_from_internal_data, ResourceLoadError},
game_version::get_version_string,
math::interpolate_exp,
non_ref_raylib::HackedRaylibHandle,
render_layer::ScreenSpaceRender,
},
};
}};
use super::{Scenes, ScreenError};
use tracing::{debug, info, trace};
@ -47,7 +44,7 @@ impl Action<Scenes, ScreenError, GameContext> for MainMenuScreen {
context: &GameContext,
) -> Result<dirty_fsm::ActionFlag<Scenes>, ScreenError> {
trace!("execute() called on MainMenuScreen");
self.render_screen_space(&mut context.renderer.borrow_mut());
self.render_screen_space(&mut context.renderer.borrow_mut(), &context.config);
// TODO: TEMP
if context.renderer.borrow_mut().is_key_pressed(KeyboardKey::KEY_SPACE) {
@ -67,6 +64,7 @@ impl ScreenSpaceRender for MainMenuScreen {
fn render_screen_space(
&self,
raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle,
config: &GameConfig
) {
// Render the background
raylib.clear_background(Color::BLACK);

View File

@ -1,6 +1,7 @@
//! Contains the general configuration data for the game
//! This data is immutable, and should only be edited by hand
use raylib::color::Color;
use rust_embed::EmbeddedFile;
/// Defines one of the game's authors
@ -11,12 +12,22 @@ pub struct Author {
pub roles: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColorTheme {
pub red: Color,
pub blue: Color,
pub green: Color,
pub yellow: Color,
pub pink: Color,
pub background: Color,
}
#[derive(Debug, Clone, Deserialize)]
pub struct GameConfig {
pub name: String,
// pub authors: Vec<Author>,
pub base_window_size: (i32, i32),
pub sentry_dsn: String,
pub colors: ColorTheme,
}
impl GameConfig {
@ -31,6 +42,8 @@ pub struct FinalShaderConfig {
pub pixel_scale: f32,
pub warp_factor: f32,
pub scanline_darkness: f32,
pub bloom_samples: f32,
pub bloom_quality: f32,
}
impl FinalShaderConfig {

View File

@ -1,8 +1,8 @@
pub mod discord;
pub mod datastore;
pub mod discord;
pub mod game_config;
pub mod game_version;
pub mod math;
pub mod shaders;
pub mod non_ref_raylib;
pub mod render_layer;
pub mod game_version;
pub mod shaders;

View File

@ -1,15 +1,15 @@
use raylib::{prelude::RaylibMode2D, RaylibHandle};
use crate::utilities::non_ref_raylib::HackedRaylibHandle;
use crate::{GameConfig, context::GameContext, utilities::non_ref_raylib::HackedRaylibHandle};
pub trait FrameUpdate {
fn update(&mut self, raylib: &HackedRaylibHandle, delta_seconds: &chrono::Duration);
fn update(&mut self, raylib: &HackedRaylibHandle, delta_seconds: &chrono::Duration, config: &GameConfig);
}
pub trait ScreenSpaceRender {
fn render_screen_space(&self, raylib: &mut HackedRaylibHandle);
fn render_screen_space(&self, raylib: &mut HackedRaylibHandle, config: &GameConfig);
}
pub trait WorldSpaceRender {
fn render_world_space(&self, raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>);
fn render_world_space(&self, raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>, config: &GameConfig);
}