From 7f2694ab248ecdb424eb095a19e855c4666a9a75 Mon Sep 17 00:00:00 2001 From: Gnarwhal Date: Wed, 7 Aug 2024 05:09:35 +0000 Subject: [PATCH] Fullscreen and jumping and stuff --- .gitignore | 2 + Cargo.toml | 4 -- resources/bindings.ron | 4 +- resources/sprites.png | Bin 0 -> 206 bytes resources/sprites.ron | 12 +++++ src/components/mod.rs | 9 +++- src/components/physics.rs | 62 +++++++++++++++++++++++ src/components/player.rs | 20 ++++++-- src/main.rs | 13 ++++- src/states/level.rs | 53 ++++++++++++++++--- src/states/mod.rs | 2 +- src/systems/mod.rs | 6 ++- src/systems/physics.rs | 104 ++++++++++++++++++++++++++++++++++++++ src/systems/player.rs | 91 ++++++++++++++++++++++++++++----- 14 files changed, 347 insertions(+), 35 deletions(-) create mode 100644 resources/sprites.png create mode 100644 resources/sprites.ron create mode 100644 src/components/physics.rs create mode 100644 src/systems/physics.rs diff --git a/.gitignore b/.gitignore index e120e7b..0d410a0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ Cargo.lock *.dll +djam_4.* + diff --git a/Cargo.toml b/Cargo.toml index 5d10895..484276b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,10 +4,6 @@ version = "0.1.0" authors = ["Gnarwhal "] edition = "2018" -[dependencies] -amethyst_window = "0.5.0" -winit = "0.22.2" - [dependencies.serde] version = "1" features = ["derive"] diff --git a/resources/bindings.ron b/resources/bindings.ron index e50aae4..cec0cba 100644 --- a/resources/bindings.ron +++ b/resources/bindings.ron @@ -13,6 +13,7 @@ }, actions: { ShortHop: [ + [ScanCode(57)], [Controller(0, X)], [Controller(1, X)], [Controller(2, X)], @@ -22,7 +23,6 @@ ], FullHop: [ [ScanCode(17)], - [ScanCode(57)], [Controller(0, A)], [Controller(1, A)], [Controller(2, A)], @@ -31,4 +31,4 @@ [Controller(5, A)], ], } -) \ No newline at end of file +) diff --git a/resources/sprites.png b/resources/sprites.png new file mode 100644 index 0000000000000000000000000000000000000000..0ff23dbe8def9ce999f93e6277005e7bbc2cac06 GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1enFxk_^F~q|E=w(N~1_d6Mi;w=kkC9>K)C@LC zeH?${Smi8<*}HGwF6Z1@C|7;#WM0~fYb+N;H!-c~abcJ$z@{L1l3^!Lf`4+pD`RDk xQh?NAQH}nKEbESO{AZFrof_}>F8{z9=5sMZ5?u{te}UF9c)I$ztaD0e0sz};LIeN+ literal 0 HcmV?d00001 diff --git a/resources/sprites.ron b/resources/sprites.ron new file mode 100644 index 0000000..2446c6e --- /dev/null +++ b/resources/sprites.ron @@ -0,0 +1,12 @@ +List(( + texture_width: 16, + texture_height: 16, + sprites: [ + ( + x: 0, + y: 0, + width: 16, + height: 16, + ) + ], +)) \ No newline at end of file diff --git a/src/components/mod.rs b/src/components/mod.rs index 40fd931..cbb88f8 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -25,7 +25,12 @@ *******************************************************************************/ pub use self::{ - player::Player + physics::Gravity, + physics::Dynamic, + physics::Static, + + player::Player, }; -mod player; \ No newline at end of file +pub mod physics; +pub mod player; diff --git a/src/components/physics.rs b/src/components/physics.rs new file mode 100644 index 0000000..8e40312 --- /dev/null +++ b/src/components/physics.rs @@ -0,0 +1,62 @@ +/******************************************************************************* + * + * Copyright (c) 2020 Gnarwhal + * + * ----------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files(the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + *******************************************************************************/ + +use amethyst::{ + core::math::Vector2, + ecs::prelude::{Component, DenseVecStorage} +}; + +pub struct Gravity; + +impl Component for Gravity { + type Storage = DenseVecStorage; +} + +pub struct Dynamic { + pub velocity: Vector2, + pub grounded: bool, + pub friction_coefficient: f32, +} + +impl Default for Dynamic { + fn default() -> Self { + Dynamic { + velocity: Vector2::new(0.0, 0.0), + grounded: false, + friction_coefficient: 1.0, + } + } +} + +impl Component for Dynamic { + type Storage = DenseVecStorage; +} + +pub struct Static; + +impl Component for Static { + type Storage = DenseVecStorage; +} diff --git a/src/components/player.rs b/src/components/player.rs index 8f7e05f..4b1755c 100644 --- a/src/components/player.rs +++ b/src/components/player.rs @@ -24,18 +24,32 @@ * *******************************************************************************/ +use core::default::Default; use amethyst::{ ecs::prelude::{Component, DenseVecStorage}, }; pub struct Player { - pub id: u32, + pub jump_ready: bool, + pub jump_count: usize, } impl Player { - pub fn new(id: u32) -> Player { + pub fn reset_jumps(&mut self, jump_count: usize) { + self.jump_ready = true; + self.jump_count = jump_count; + } + + pub fn trigger_jump(&mut self) { + self.jump_ready = false; + self.jump_count -= 1; + } +} +impl Default for Player { + fn default() -> Player { return Player{ - id + jump_ready: true, + jump_count: 0, }; } } diff --git a/src/main.rs b/src/main.rs index 81d2a48..c34038e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,8 +38,9 @@ use amethyst::{ plugins::{RenderFlat2D, RenderToWindow}, }, utils::application_root_dir, + window::{DisplayConfig, MonitorIdent}, + winit::EventsLoop, }; -use amethyst_window::{DisplayConfig, Icon}; use std::path::PathBuf; fn main() -> amethyst::Result<()> { @@ -51,8 +52,14 @@ fn main() -> amethyst::Result<()> { let display_config_path = resources_dir.join("display_config.ron"); let binding_path = resources_dir.join("bindings.ron"); + let events_loop = EventsLoop::new(); + + let monitor = MonitorIdent::from_primary(&events_loop); + let mut display_config = DisplayConfig::load(display_config_path)?; display_config.icon = Some(PathBuf::from("resources/icon.png")); + display_config.dimensions = Some(monitor.monitor_id(&events_loop).get_dimensions().into()); + display_config.fullscreen = Some(monitor); let input_bundle = InputBundle::::new() .with_bindings_from_file(binding_path)?; @@ -68,7 +75,9 @@ fn main() -> amethyst::Result<()> { ) .with_plugin(RenderFlat2D::default()) )? - .with(systems::PlayerSystem, "player_system", &["input_system"]); + .with(systems::ForceSystem, "force_system", &[]) + .with(systems::PlayerSystem, "player_system", &["force_system", "input_system"]) + .with(systems::CollisionSystem, "physics_system", &["player_system"]); let mut game = Application::new(resources_dir, states::LevelState, game_data)?; game.run(); diff --git a/src/states/level.rs b/src/states/level.rs index df06ebf..69cfa61 100644 --- a/src/states/level.rs +++ b/src/states/level.rs @@ -27,18 +27,21 @@ use amethyst::{ assets::{AssetStorage, Loader, Handle}, core::transform::Transform, - ecs::prelude::{Component, DenseVecStorage}, prelude::*, renderer::{Camera, ImageFormat, SpriteRender, SpriteSheet, SpriteSheetFormat, Texture} }; +use crate::components::Dynamic; +use crate::components::Gravity; use crate::components::Player; -pub const CAMERA_WIDTH: f32 = 1920.0; -pub const CAMERA_HEIGHT: f32 = 1080.0; +pub const CAMERA_WIDTH: f32 = 384.0; +pub const CAMERA_HEIGHT: f32 = 216.0; + +pub const BLOCK_SIZE: f32 = 16.0; fn initialize_camera(world: &mut World) { let mut transform = Transform::default(); - transform.set_translation_xyz(CAMERA_WIDTH * 0.5, CAMERA_HEIGHT * 0.5, 1.0); + transform.set_translation_xyz(0.0, 0.0, 1.0); world .create_entity() @@ -47,21 +50,57 @@ fn initialize_camera(world: &mut World) { .build(); } -fn initialize_player(world: &mut World) { +fn initialize_player(world: &mut World, sprite_sheet_handle: Handle) { + let sprite_render = SpriteRender{ + sprite_sheet: sprite_sheet_handle, + sprite_number: 0, + }; + + let mut transform = Transform::default(); + transform.set_translation_xyz(0.0, 48.0, 0.0); + world .create_entity() - .with(Player::new(0)) + .with(sprite_render) + .with(Player::default()) .with(Transform::default()) + .with(Dynamic::default()) + .with(Gravity) + .with(transform) .build(); } +fn load_sprite_sheet(world: &mut World) -> Handle { + let texture_handle = { + let loader = world.read_resource::(); + let texture_storage = world.read_resource::>(); + loader.load( + "sprites.png", + ImageFormat::default(), + (), + &texture_storage, + ) + }; + + let loader = world.read_resource::(); + let sprite_sheet_store = world.read_resource::>(); + loader.load( + "sprites.ron", + SpriteSheetFormat(texture_handle), + (), + &sprite_sheet_store, + ) +} + pub struct LevelState; impl SimpleState for LevelState { fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) { let world = data.world; + let sprite_sheet_handle = load_sprite_sheet(world); + initialize_camera(world); - initialize_player(world); + initialize_player(world, sprite_sheet_handle); } } \ No newline at end of file diff --git a/src/states/mod.rs b/src/states/mod.rs index c100959..691a39d 100644 --- a/src/states/mod.rs +++ b/src/states/mod.rs @@ -28,4 +28,4 @@ pub use self::{ level::LevelState }; -mod level; \ No newline at end of file +pub mod level; \ No newline at end of file diff --git a/src/systems/mod.rs b/src/systems/mod.rs index 6c962ae..13a209f 100644 --- a/src/systems/mod.rs +++ b/src/systems/mod.rs @@ -25,8 +25,12 @@ *******************************************************************************/ pub use self::{ + physics::ForceSystem, + physics::CollisionSystem, + player::PlayerSystem, player::PlayerBindings, }; -mod player; \ No newline at end of file +pub mod physics; +pub mod player; \ No newline at end of file diff --git a/src/systems/physics.rs b/src/systems/physics.rs new file mode 100644 index 0000000..027af58 --- /dev/null +++ b/src/systems/physics.rs @@ -0,0 +1,104 @@ +/******************************************************************************* + * + * Copyright (c) 2020 Gnarwhal + * + * ----------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files(the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + *******************************************************************************/ + +use amethyst::{ + core::timing::Time, + core::{Transform}, + derive::SystemDesc, + ecs::{Join, Read, ReadStorage, System, SystemData, WriteStorage}, +}; +use crate::components::Dynamic; +use crate::components::Static; +use crate::components::Gravity; +use crate::systems::player::FULL_HOP_TIME; +use crate::systems::player::FULL_HOP_HEIGHT; +use crate::systems::player::MAX_GROUND_SPEED; +use crate::systems::player::MAX_AERIAL_SPEED; +use crate::states::level::CAMERA_HEIGHT; + +pub const FRICTION: f32 = MAX_GROUND_SPEED / 0.25; +pub const AIR_RESISTANCE: f32 = MAX_AERIAL_SPEED / 1.0; + +pub const GRAVITY: f32 = -2.0 * FULL_HOP_HEIGHT / (FULL_HOP_TIME * FULL_HOP_TIME); + +#[derive(SystemDesc)] +pub struct ForceSystem; + +fn apply_resistance(velocity: f32, resistance: f32) -> f32 { + if velocity < 0.0 { + (velocity + resistance).min(0.0) + } else if velocity > 0.0 { + (velocity - resistance).max(0.0) + } else { + 0.0 + } +} + +impl<'s> System<'s> for ForceSystem { + type SystemData = ( + WriteStorage<'s, Dynamic>, + ReadStorage<'s, Gravity>, + Read<'s, Time>, + ); + + fn run(&mut self, (mut dynamics, gravities, delta_time): Self::SystemData) { + for dynamic in (&mut dynamics).join() { + let velocity = &mut dynamic.velocity; + velocity.x = apply_resistance(velocity.x, match dynamic.grounded { true => FRICTION, false => AIR_RESISTANCE, } * dynamic.friction_coefficient * delta_time.delta_seconds()); + } + for (dynamic, _) in (&mut dynamics, &gravities).join() { + dynamic.velocity.y += GRAVITY * delta_time.delta_seconds(); + } + } +} + +#[derive(SystemDesc)] +pub struct CollisionSystem; + +impl<'s> System<'s> for CollisionSystem { + type SystemData = ( + WriteStorage<'s, Transform>, + WriteStorage<'s, Dynamic>, + ReadStorage<'s, Static>, + Read<'s, Time>, + ); + + fn run(&mut self, (mut transforms, mut dynamics, statics, delta_time): Self::SystemData) { + for (transform, dynamic) in (&mut transforms, &mut dynamics).join() { + let translation = transform.translation_mut(); + translation.x += dynamic.velocity.x * delta_time.delta_seconds(); + translation.y += dynamic.velocity.y * delta_time.delta_seconds(); + const FLOOR: f32 = -CAMERA_HEIGHT / 2.0 + 8.0; + if translation.y < FLOOR { + translation.y = FLOOR; + dynamic.velocity.y = 0.0; + dynamic.grounded = true; + } else { + dynamic.grounded = false; + } + } + } +} diff --git a/src/systems/player.rs b/src/systems/player.rs index 1b8a58f..9edd3fb 100644 --- a/src/systems/player.rs +++ b/src/systems/player.rs @@ -27,13 +27,16 @@ use std::fmt::{self, Display}; use amethyst::{ - core::{Transform, SystemDesc}, + core::timing::Time, derive::SystemDesc, - ecs::{Join, Read, ReadStorage, System, SystemData, World, WriteStorage}, - input::{InputHandler, BindingTypes, Bindings}, + ecs::{Join, Read, System, SystemData, WriteStorage}, + input::{InputHandler, BindingTypes}, }; use serde::{Serialize, Deserialize}; +use crate::components::Dynamic; use crate::components::Player; +use crate::systems::physics::GRAVITY; +use crate::states::level::BLOCK_SIZE; #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] pub enum MovementBindings { @@ -58,7 +61,6 @@ impl Display for ActionBindings { } } - #[derive(Debug)] pub struct PlayerBindings; @@ -67,31 +69,94 @@ impl BindingTypes for PlayerBindings { type Action = ActionBindings; } +pub const FULL_HOP_TIME: f32 = 0.35; +pub const SHORT_HOP_HEIGHT: f32 = 1.5 * BLOCK_SIZE; +pub const FULL_HOP_HEIGHT: f32 = 3.25 * BLOCK_SIZE; +pub const AERIAL_HOP_HEIGHT: f32 = 2.25 * BLOCK_SIZE; +const JUMP_COUNT: usize = 2; + +pub const MAX_GROUND_SPEED: f32 = 10.0 * BLOCK_SIZE; +const GROUND_ACCELERATION: f32 = (MAX_GROUND_SPEED * 2.0) / 0.1; + +pub const MAX_AERIAL_SPEED: f32 = 12.0 * BLOCK_SIZE; +const AERIAL_ACCELERATION: f32 = (MAX_AERIAL_SPEED * 2.0) / 0.5; +const AERIAL_JUMP_HORZ_BOOST: f32 = AERIAL_ACCELERATION * 0.3; + #[derive(SystemDesc)] pub struct PlayerSystem; impl <'s> System<'s> for PlayerSystem { type SystemData = ( - WriteStorage<'s, Transform>, - ReadStorage<'s, Player>, + WriteStorage<'s, Dynamic>, + WriteStorage<'s, Player>, Read<'s, InputHandler>, + Read<'s, Time>, ); - fn run(&mut self, (mut transforms, players, input): Self::SystemData) { - for (transform, _) in (&mut transforms, &players).join() { + fn run(&mut self, (mut dynamics, mut players, input, delta_time): Self::SystemData) { + for (dynamic, player) in (&mut dynamics, &mut players).join() { + let velocity = &mut dynamic.velocity; let mut movement = 0.0f32; for input_id in -1..6 { movement += input .axis_value(&MovementBindings::Horizontal(input_id)) .unwrap_or(0.0); + + } + movement.max(-1.0).min(1.0); + if movement != 0.0 { + dynamic.friction_coefficient = 0.0; + } else { + dynamic.friction_coefficient = 1.0; } - if movement != 0.0 { - println!("Movement: {}", movement); + //////// OLD DEBUGGING STUFF - MAY BE USEFUL LATER //////// + /*print!("Codes: "); + for code in input.scan_codes_that_are_down() { + print!("{}, ", code); } - if input.action_is_down(&ActionBindings::FullHop).unwrap_or(false) { - println!("Yump yump!"); + println!();*/ + /////////////////////////////////////////////////////////// + + if dynamic.grounded { + player.reset_jumps(JUMP_COUNT); + + if (movement < 0.0 && velocity.x > -MAX_GROUND_SPEED) + || (movement > 0.0 && velocity.x < MAX_GROUND_SPEED) { + velocity.x += movement * GROUND_ACCELERATION * delta_time.delta_seconds(); + velocity.x = velocity.x.max(-MAX_GROUND_SPEED).min(MAX_GROUND_SPEED); + } + + let SHORT_HOP_SPEED: f32 = (-2.0 * SHORT_HOP_HEIGHT * GRAVITY).sqrt(); + let FULL_HOP_SPEED: f32 = (-2.0 * FULL_HOP_HEIGHT * GRAVITY).sqrt(); + if player.jump_ready { + if input.action_is_down(&ActionBindings::ShortHop).unwrap_or(false) { + velocity.y = SHORT_HOP_SPEED; + player.trigger_jump(); + } else if input.action_is_down(&ActionBindings::FullHop).unwrap_or(false) { + velocity.y = FULL_HOP_SPEED; + player.trigger_jump(); + } + } + velocity.x = velocity.x.max(-MAX_GROUND_SPEED).min(MAX_GROUND_SPEED); + } else { + let AERIAL_HOP_SPEED: f32 = (-2.0 * AERIAL_HOP_HEIGHT * GRAVITY).sqrt(); + if player.jump_ready + && player.jump_count > 0 + && (input.action_is_down(&ActionBindings::ShortHop).unwrap_or(false) + || input.action_is_down(&ActionBindings::FullHop ).unwrap_or(false)) { + velocity.y = AERIAL_HOP_SPEED; + player.trigger_jump(); + velocity.x += movement * AERIAL_JUMP_HORZ_BOOST; + } else { + if !(input.action_is_down(&ActionBindings::ShortHop).unwrap_or(false) + || input.action_is_down(&ActionBindings::FullHop ).unwrap_or(false)) { + player.jump_ready = true; + } + velocity.x += movement * AERIAL_ACCELERATION * delta_time.delta_seconds(); + } + velocity.x = velocity.x.max(-MAX_AERIAL_SPEED).min(MAX_AERIAL_SPEED); } } } -} \ No newline at end of file +}