player texture and animation
This commit is contained in:
parent
f1c341fdbc
commit
6ef9655a2b
2
.gitignore
vendored
2
.gitignore
vendored
@ -8,3 +8,5 @@ Cargo.lock
|
|||||||
|
|
||||||
# These are backup files generated by rustfmt
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
|
||||||
|
/*.gif
|
||||||
|
BIN
game/assets/character/player_run.png
Normal file
BIN
game/assets/character/player_run.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 138 KiB |
@ -41,6 +41,13 @@
|
|||||||
20,
|
20,
|
||||||
20,
|
20,
|
||||||
255
|
255
|
||||||
|
],
|
||||||
|
"white": [
|
||||||
|
188,
|
||||||
|
188,
|
||||||
|
188,
|
||||||
|
188
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"animation_fps": 15
|
||||||
}
|
}
|
||||||
|
35
game/src/character/collisions.rs
Normal file
35
game/src/character/collisions.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use raylib::math::{Rectangle, Vector2};
|
||||||
|
|
||||||
|
use super::MainCharacter;
|
||||||
|
|
||||||
|
const GRAVITY_PPS: f32 = 2.0;
|
||||||
|
|
||||||
|
pub fn modify_player_based_on_forces(player: &mut MainCharacter) -> Result<(), ()> {
|
||||||
|
// Convert the player to a rectangle
|
||||||
|
let predicted_player_position = player.position + player.velocity;
|
||||||
|
let player_rect = Rectangle::new(
|
||||||
|
predicted_player_position.x - (player.size.x / 2.0),
|
||||||
|
predicted_player_position.y - (player.size.x / 2.0),
|
||||||
|
player.size.x,
|
||||||
|
player.size.y,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Calculate a generic "floor" to always collide with
|
||||||
|
let floor_rect = Rectangle::new(f32::MIN, 0.0, f32::MAX, 1.0);
|
||||||
|
|
||||||
|
// If the player is colliding, only apply the x force
|
||||||
|
if (floor_rect.check_collision_recs(&player_rect) || player_rect.y + player_rect.height > floor_rect.y)
|
||||||
|
&& player.velocity.y > 0.0
|
||||||
|
{
|
||||||
|
player.velocity.y = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Error out if colliding in the X direction
|
||||||
|
|
||||||
|
// Apply the force
|
||||||
|
player.position += player.velocity;
|
||||||
|
|
||||||
|
// Apply gravity
|
||||||
|
player.velocity.y += GRAVITY_PPS;
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -1,22 +1,62 @@
|
|||||||
|
pub mod collisions;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
|
|
||||||
use raylib::math::Vector2;
|
use chrono::{DateTime, Utc};
|
||||||
|
use raylib::{math::Vector2, texture::Texture2D};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
use crate::utilities::anim_render::AnimatedSpriteSheet;
|
||||||
|
|
||||||
|
use self::collisions::modify_player_based_on_forces;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub enum CharacterState {
|
||||||
|
#[default]
|
||||||
|
Running,
|
||||||
|
Jumping,
|
||||||
|
Dashing,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct MainCharacter {
|
pub struct MainCharacter {
|
||||||
pub position: Vector2,
|
pub position: Vector2,
|
||||||
|
pub velocity: Vector2,
|
||||||
pub size: Vector2,
|
pub size: Vector2,
|
||||||
|
pub sprite_sheet: AnimatedSpriteSheet,
|
||||||
|
pub current_state: CharacterState,
|
||||||
|
pub state_set_timestamp: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MainCharacter {
|
impl MainCharacter {
|
||||||
pub fn new(position: Vector2) -> Self {
|
pub fn new(position: Vector2, sprite_sheet: Texture2D) -> Self {
|
||||||
Self {
|
Self {
|
||||||
position,
|
position,
|
||||||
size: Vector2::new(60.0, 80.0),
|
velocity: Vector2::new(20.0, 0.0),
|
||||||
|
size: Vector2::new(100.0, 130.0),
|
||||||
|
sprite_sheet: AnimatedSpriteSheet::new(
|
||||||
|
sprite_sheet,
|
||||||
|
Vector2::new(300.0, 300.0),
|
||||||
|
3,
|
||||||
|
8,
|
||||||
|
6,
|
||||||
|
),
|
||||||
|
current_state: CharacterState::default(),
|
||||||
|
state_set_timestamp: Utc::now(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_force(&mut self, force: Vector2) {
|
pub fn apply_force(&mut self, force: Vector2) -> Option<()> {
|
||||||
self.position += force;
|
self.velocity = force;
|
||||||
|
modify_player_based_on_forces(self).unwrap();
|
||||||
|
// self.position = calculate_player_collisions(&self).unwrap();
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_gravity(&mut self) {
|
||||||
|
modify_player_based_on_forces(self).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_state(&mut self, state: CharacterState) {
|
||||||
|
self.current_state = state;
|
||||||
|
self.state_set_timestamp = Utc::now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,33 @@
|
|||||||
use std::ops::{Div, Sub};
|
use std::ops::{Div, Sub};
|
||||||
|
|
||||||
|
use chrono::Utc;
|
||||||
use raylib::prelude::*;
|
use raylib::prelude::*;
|
||||||
|
use tracing::log::trace;
|
||||||
|
|
||||||
use crate::utilities::non_ref_raylib::HackedRaylibHandle;
|
use crate::{utilities::non_ref_raylib::HackedRaylibHandle, GameConfig};
|
||||||
|
|
||||||
use super::MainCharacter;
|
use super::MainCharacter;
|
||||||
|
|
||||||
pub fn render_character_in_camera_space(
|
pub fn render_character_in_camera_space(
|
||||||
raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>,
|
raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>,
|
||||||
player: &MainCharacter,
|
player: &MainCharacter,
|
||||||
|
config: &GameConfig,
|
||||||
) {
|
) {
|
||||||
|
// Calculate the time since the start of the state
|
||||||
|
let time_since_state_change = Utc::now() - player.state_set_timestamp;
|
||||||
|
|
||||||
raylib.draw_rectangle_v(player.position.sub(player.size.div(2.0)), player.size, Color::WHITE);
|
// Calculate the number of frames since state change
|
||||||
|
let frames_since_state_change = ((time_since_state_change.num_milliseconds() as f64 / 1000.0) * config.animation_fps as f64) as f32;
|
||||||
|
|
||||||
|
trace!(
|
||||||
|
"Rendering player frame: {} ({})",
|
||||||
|
frames_since_state_change % player.sprite_sheet.sprite_count as f32,
|
||||||
|
frames_since_state_change
|
||||||
|
);
|
||||||
|
player.sprite_sheet.render(
|
||||||
|
raylib,
|
||||||
|
player.position.sub(player.size.div(2.0)),
|
||||||
|
Some(Vector2::new(player.size.y, player.size.y)),
|
||||||
|
Some((frames_since_state_change % player.sprite_sheet.sprite_count as f32).floor() as usize),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -10,5 +10,8 @@ impl ScreenSpaceRender for InGameScreen {
|
|||||||
) {
|
) {
|
||||||
// Calculate the logo position
|
// Calculate the logo position
|
||||||
let screen_size = raylib.get_screen_size();
|
let screen_size = raylib.get_screen_size();
|
||||||
|
|
||||||
|
// Draw a thin glow box around the screen
|
||||||
|
raylib.draw_rectangle_lines(0, 0, screen_size.x as i32, screen_size.y as i32, config.colors.red);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
use dirty_fsm::{Action, ActionFlag};
|
use dirty_fsm::{Action, ActionFlag};
|
||||||
use raylib::prelude::*;
|
use raylib::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{character::{CharacterState, MainCharacter}, context::GameContext, utilities::render_layer::{FrameUpdate, ScreenSpaceRender, WorldSpaceRender}};
|
||||||
character::MainCharacter,
|
|
||||||
context::GameContext,
|
|
||||||
utilities::render_layer::{FrameUpdate, ScreenSpaceRender, WorldSpaceRender},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{Scenes, ScreenError};
|
use super::{Scenes, ScreenError};
|
||||||
use tracing::{debug, trace};
|
use tracing::{debug, trace};
|
||||||
@ -22,7 +18,7 @@ pub struct InGameScreen {
|
|||||||
|
|
||||||
impl InGameScreen {
|
impl InGameScreen {
|
||||||
/// Construct a new `InGameScreen`
|
/// Construct a new `InGameScreen`
|
||||||
pub fn new() -> Self {
|
pub fn new(player_sprite_sheet: Texture2D) -> Self {
|
||||||
Self {
|
Self {
|
||||||
camera: Camera2D {
|
camera: Camera2D {
|
||||||
offset: Vector2::zero(),
|
offset: Vector2::zero(),
|
||||||
@ -30,7 +26,7 @@ impl InGameScreen {
|
|||||||
rotation: 0.0,
|
rotation: 0.0,
|
||||||
zoom: 1.0,
|
zoom: 1.0,
|
||||||
},
|
},
|
||||||
player: MainCharacter::new(Vector2::new(0.0, -45.0)),
|
player: MainCharacter::new(Vector2::new(0.0, -80.0), player_sprite_sheet),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,6 +40,9 @@ impl Action<Scenes, ScreenError, GameContext> for InGameScreen {
|
|||||||
fn on_first_run(&mut self, _context: &GameContext) -> Result<(), ScreenError> {
|
fn on_first_run(&mut self, _context: &GameContext) -> Result<(), ScreenError> {
|
||||||
debug!("Running InGameScreen for the first time");
|
debug!("Running InGameScreen for the first time");
|
||||||
|
|
||||||
|
// Set the player to running
|
||||||
|
self.player.set_state(CharacterState::Running);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,27 +1,32 @@
|
|||||||
use std::ops::Div;
|
use std::ops::Div;
|
||||||
|
|
||||||
use super::InGameScreen;
|
use super::InGameScreen;
|
||||||
use crate::{GameConfig, utilities::{non_ref_raylib::HackedRaylibHandle, render_layer::FrameUpdate}};
|
use crate::{
|
||||||
|
utilities::{non_ref_raylib::HackedRaylibHandle, render_layer::FrameUpdate},
|
||||||
|
GameConfig,
|
||||||
|
};
|
||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
use raylib::prelude::*;
|
use raylib::prelude::*;
|
||||||
|
|
||||||
impl FrameUpdate for InGameScreen {
|
impl FrameUpdate for InGameScreen {
|
||||||
fn update(&mut self, raylib: &HackedRaylibHandle, delta_seconds: &Duration,
|
fn update(
|
||||||
config: &GameConfig) {
|
&mut self,
|
||||||
|
raylib: &HackedRaylibHandle,
|
||||||
|
delta_seconds: &Duration,
|
||||||
|
config: &GameConfig,
|
||||||
|
) {
|
||||||
// Set the camera's offset based on screen size
|
// Set the camera's offset based on screen size
|
||||||
self.camera.offset = raylib.get_screen_size().div(Vector2::new(2.0, 1.25));
|
self.camera.offset = raylib.get_screen_size().div(Vector2::new(2.0, 1.05));
|
||||||
self.camera.target = Vector2::new(
|
self.camera.target = Vector2::new(self.player.position.x, self.camera.target.y);
|
||||||
self.player.position.x,
|
|
||||||
self.camera.target.y,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check the only possible keyboard inputs
|
// Check the only possible keyboard inputs
|
||||||
let is_jump = raylib.is_key_down(KeyboardKey::KEY_SPACE);
|
let is_jump = raylib.is_key_pressed(KeyboardKey::KEY_SPACE);
|
||||||
let is_dash = raylib.is_key_down(KeyboardKey::KEY_LEFT_SHIFT);
|
let is_dash = raylib.is_key_down(KeyboardKey::KEY_LEFT_SHIFT);
|
||||||
let is_pause = raylib.is_key_down(KeyboardKey::KEY_ESCAPE);
|
let is_pause = raylib.is_key_down(KeyboardKey::KEY_ESCAPE);
|
||||||
|
|
||||||
if is_jump {
|
if is_jump {
|
||||||
self.player.apply_force(Vector2::new(0.0, -1.0));
|
self.player.apply_force(Vector2::new(0.0, -30.0));
|
||||||
}
|
}
|
||||||
|
self.player.update_gravity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,33 @@
|
|||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
|
|
||||||
use super::InGameScreen;
|
use super::InGameScreen;
|
||||||
use crate::{GameConfig, character::render::render_character_in_camera_space, utilities::{non_ref_raylib::HackedRaylibHandle, render_layer::WorldSpaceRender}};
|
use crate::{
|
||||||
|
character::render::render_character_in_camera_space,
|
||||||
|
utilities::{non_ref_raylib::HackedRaylibHandle, render_layer::WorldSpaceRender},
|
||||||
|
GameConfig,
|
||||||
|
};
|
||||||
use raylib::prelude::*;
|
use raylib::prelude::*;
|
||||||
|
|
||||||
impl WorldSpaceRender for InGameScreen {
|
impl WorldSpaceRender for InGameScreen {
|
||||||
fn render_world_space(&self, raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>,
|
fn render_world_space(
|
||||||
config: &GameConfig) {
|
&self,
|
||||||
|
raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>,
|
||||||
|
config: &GameConfig,
|
||||||
|
) {
|
||||||
// Render the player
|
// Render the player
|
||||||
render_character_in_camera_space(raylib, &self.player);
|
render_character_in_camera_space(raylib, &self.player, &config);
|
||||||
|
|
||||||
// Render the floor as a line
|
// Render the floor as a line
|
||||||
let screen_world_zero = raylib.get_screen_to_world2D(Vector2::zero(), self.camera);
|
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);
|
let screen_world_size =
|
||||||
|
raylib.get_screen_to_world2D(raylib.get_screen_size().mul(2.0), self.camera);
|
||||||
|
|
||||||
raylib.draw_rectangle(
|
raylib.draw_rectangle(
|
||||||
screen_world_zero.x as i32,
|
screen_world_zero.x as i32,
|
||||||
0,
|
0,
|
||||||
screen_world_size.x as i32,
|
screen_world_size.x as i32,
|
||||||
5,
|
5,
|
||||||
Color::WHITE,
|
config.colors.white,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,13 @@ use self::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
context::GameContext,
|
context::GameContext,
|
||||||
utilities::{datastore::ResourceLoadError, non_ref_raylib::HackedRaylibHandle},
|
utilities::{
|
||||||
|
datastore::{load_texture_from_internal_data, ResourceLoadError},
|
||||||
|
non_ref_raylib::HackedRaylibHandle,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use dirty_fsm::StateMachine;
|
use dirty_fsm::StateMachine;
|
||||||
use raylib::RaylibThread;
|
use raylib::{texture::Texture2D, RaylibThread};
|
||||||
|
|
||||||
pub mod fsm_error_screen;
|
pub mod fsm_error_screen;
|
||||||
pub mod ingame_scene;
|
pub mod ingame_scene;
|
||||||
@ -40,6 +43,11 @@ pub fn build_screen_state_machine(
|
|||||||
StateMachine<Scenes, ScreenError, GameContext>,
|
StateMachine<Scenes, ScreenError, GameContext>,
|
||||||
ScreenError,
|
ScreenError,
|
||||||
> {
|
> {
|
||||||
|
// Load the various textures needed by the states
|
||||||
|
let player_sprite_sheet =
|
||||||
|
load_texture_from_internal_data(raylib_handle, thread, "character/player_run.png").unwrap();
|
||||||
|
|
||||||
|
// Set up the state machine
|
||||||
let mut machine = StateMachine::new();
|
let mut machine = StateMachine::new();
|
||||||
machine.add_action(Scenes::FsmErrorScreen, FsmErrorScreen::new())?;
|
machine.add_action(Scenes::FsmErrorScreen, FsmErrorScreen::new())?;
|
||||||
machine.add_action(
|
machine.add_action(
|
||||||
@ -47,6 +55,6 @@ pub fn build_screen_state_machine(
|
|||||||
LoadingScreen::new(raylib_handle, thread)?,
|
LoadingScreen::new(raylib_handle, thread)?,
|
||||||
)?;
|
)?;
|
||||||
machine.add_action(Scenes::MainMenuScreen, MainMenuScreen::new())?;
|
machine.add_action(Scenes::MainMenuScreen, MainMenuScreen::new())?;
|
||||||
machine.add_action(Scenes::InGameScene, InGameScreen::new())?;
|
machine.add_action(Scenes::InGameScene, InGameScreen::new(player_sprite_sheet))?;
|
||||||
Ok(machine)
|
Ok(machine)
|
||||||
}
|
}
|
||||||
|
104
game/src/utilities/anim_render.rs
Normal file
104
game/src/utilities/anim_render.rs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
use raylib::{
|
||||||
|
color::Color,
|
||||||
|
math::{Rectangle, Vector2},
|
||||||
|
prelude::RaylibDraw,
|
||||||
|
texture::Texture2D,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AnimatedSpriteSheet {
|
||||||
|
texture: Texture2D,
|
||||||
|
sprite_size: Vector2,
|
||||||
|
sheet_width: usize,
|
||||||
|
pub sprite_count: usize,
|
||||||
|
default_sprite_id: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnimatedSpriteSheet {
|
||||||
|
/// Construct a new AnimatedSpriteSheet
|
||||||
|
pub fn new(
|
||||||
|
texture: Texture2D,
|
||||||
|
sprite_size: Vector2,
|
||||||
|
sheet_width: usize,
|
||||||
|
sprite_count: usize,
|
||||||
|
default_sprite_id: usize,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
texture,
|
||||||
|
sprite_size,
|
||||||
|
sheet_width,
|
||||||
|
sprite_count,
|
||||||
|
default_sprite_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render<T>(
|
||||||
|
&self,
|
||||||
|
raylib: &mut T,
|
||||||
|
position: Vector2,
|
||||||
|
scaled_size: Option<Vector2>,
|
||||||
|
sprite_id: Option<usize>,
|
||||||
|
) where
|
||||||
|
T: RaylibDraw,
|
||||||
|
{
|
||||||
|
let sprite_id = sprite_id.unwrap_or(self.default_sprite_id);
|
||||||
|
let sprite_id = if sprite_id >= self.sprite_count {
|
||||||
|
self.default_sprite_id
|
||||||
|
} else {
|
||||||
|
sprite_id
|
||||||
|
};
|
||||||
|
|
||||||
|
let sprite_rect = Rectangle::new(
|
||||||
|
(sprite_id % self.sheet_width) as f32 * self.sprite_size.x,
|
||||||
|
(sprite_id / self.sheet_width) as f32 * self.sprite_size.y,
|
||||||
|
self.sprite_size.x,
|
||||||
|
self.sprite_size.y,
|
||||||
|
);
|
||||||
|
|
||||||
|
let scaled_size = scaled_size.unwrap_or(self.sprite_size);
|
||||||
|
|
||||||
|
raylib.draw_texture_pro(
|
||||||
|
&self.texture,
|
||||||
|
sprite_rect,
|
||||||
|
Rectangle::new(position.x, position.y, scaled_size.x, scaled_size.y),
|
||||||
|
Vector2::zero(),
|
||||||
|
0.0,
|
||||||
|
Color::WHITE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// {
|
||||||
|
// let sprite_id = match sprite_id {
|
||||||
|
// Some(id) => {
|
||||||
|
// if id >= self.sprite_count {
|
||||||
|
// self.default_sprite_id
|
||||||
|
// } else {
|
||||||
|
// id
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// None => self.default_sprite_id,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// let sprite_x = sprite_id % self.sheet_width;
|
||||||
|
// let sprite_y = sprite_id / self.sheet_width;
|
||||||
|
|
||||||
|
// raylib.draw_texture_pro(
|
||||||
|
// &self.texture,
|
||||||
|
// Rectangle {
|
||||||
|
// x: sprite_x as f32,
|
||||||
|
// y: sprite_y as f32,
|
||||||
|
// width: self.sprite_size.x,
|
||||||
|
// height: self.sprite_size.y,
|
||||||
|
// },
|
||||||
|
// Rectangle {
|
||||||
|
// x: position.x,
|
||||||
|
// y: position.y,
|
||||||
|
// width: self.sprite_size.x,
|
||||||
|
// height: self.sprite_size.y,
|
||||||
|
// },
|
||||||
|
// Vector2::zero(),
|
||||||
|
// 0.0,
|
||||||
|
// Color::WHITE,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
}
|
@ -20,6 +20,7 @@ pub struct ColorTheme {
|
|||||||
pub yellow: Color,
|
pub yellow: Color,
|
||||||
pub pink: Color,
|
pub pink: Color,
|
||||||
pub background: Color,
|
pub background: Color,
|
||||||
|
pub white: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
@ -28,6 +29,7 @@ pub struct GameConfig {
|
|||||||
pub base_window_size: (i32, i32),
|
pub base_window_size: (i32, i32),
|
||||||
pub sentry_dsn: String,
|
pub sentry_dsn: String,
|
||||||
pub colors: ColorTheme,
|
pub colors: ColorTheme,
|
||||||
|
pub animation_fps: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameConfig {
|
impl GameConfig {
|
||||||
|
@ -6,3 +6,4 @@ pub mod math;
|
|||||||
pub mod non_ref_raylib;
|
pub mod non_ref_raylib;
|
||||||
pub mod render_layer;
|
pub mod render_layer;
|
||||||
pub mod shaders;
|
pub mod shaders;
|
||||||
|
pub mod anim_render;
|
||||||
|
Reference in New Issue
Block a user