Fullscreen and jumping and stuff

This commit is contained in:
Gnarwhal 2024-08-07 05:09:35 +00:00
parent d171be23d9
commit 7f2694ab24
Signed by: Gnarwhal
GPG key ID: 0989A73D8C421174
14 changed files with 347 additions and 35 deletions

2
.gitignore vendored
View file

@ -5,3 +5,5 @@ Cargo.lock
*.dll *.dll
djam_4.*

View file

@ -4,10 +4,6 @@ version = "0.1.0"
authors = ["Gnarwhal <git.aspect893@passmail.net>"] authors = ["Gnarwhal <git.aspect893@passmail.net>"]
edition = "2018" edition = "2018"
[dependencies]
amethyst_window = "0.5.0"
winit = "0.22.2"
[dependencies.serde] [dependencies.serde]
version = "1" version = "1"
features = ["derive"] features = ["derive"]

View file

@ -13,6 +13,7 @@
}, },
actions: { actions: {
ShortHop: [ ShortHop: [
[ScanCode(57)],
[Controller(0, X)], [Controller(0, X)],
[Controller(1, X)], [Controller(1, X)],
[Controller(2, X)], [Controller(2, X)],
@ -22,7 +23,6 @@
], ],
FullHop: [ FullHop: [
[ScanCode(17)], [ScanCode(17)],
[ScanCode(57)],
[Controller(0, A)], [Controller(0, A)],
[Controller(1, A)], [Controller(1, A)],
[Controller(2, A)], [Controller(2, A)],
@ -31,4 +31,4 @@
[Controller(5, A)], [Controller(5, A)],
], ],
} }
) )

BIN
resources/sprites.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

12
resources/sprites.ron Normal file
View file

@ -0,0 +1,12 @@
List((
texture_width: 16,
texture_height: 16,
sprites: [
(
x: 0,
y: 0,
width: 16,
height: 16,
)
],
))

View file

@ -25,7 +25,12 @@
*******************************************************************************/ *******************************************************************************/
pub use self::{ pub use self::{
player::Player physics::Gravity,
physics::Dynamic,
physics::Static,
player::Player,
}; };
mod player; pub mod physics;
pub mod player;

62
src/components/physics.rs Normal file
View file

@ -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<Self>;
}
pub struct Dynamic {
pub velocity: Vector2<f32>,
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<Self>;
}
pub struct Static;
impl Component for Static {
type Storage = DenseVecStorage<Self>;
}

View file

@ -24,18 +24,32 @@
* *
*******************************************************************************/ *******************************************************************************/
use core::default::Default;
use amethyst::{ use amethyst::{
ecs::prelude::{Component, DenseVecStorage}, ecs::prelude::{Component, DenseVecStorage},
}; };
pub struct Player { pub struct Player {
pub id: u32, pub jump_ready: bool,
pub jump_count: usize,
} }
impl Player { 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{ return Player{
id jump_ready: true,
jump_count: 0,
}; };
} }
} }

View file

@ -38,8 +38,9 @@ use amethyst::{
plugins::{RenderFlat2D, RenderToWindow}, plugins::{RenderFlat2D, RenderToWindow},
}, },
utils::application_root_dir, utils::application_root_dir,
window::{DisplayConfig, MonitorIdent},
winit::EventsLoop,
}; };
use amethyst_window::{DisplayConfig, Icon};
use std::path::PathBuf; use std::path::PathBuf;
fn main() -> amethyst::Result<()> { fn main() -> amethyst::Result<()> {
@ -51,8 +52,14 @@ fn main() -> amethyst::Result<()> {
let display_config_path = resources_dir.join("display_config.ron"); let display_config_path = resources_dir.join("display_config.ron");
let binding_path = resources_dir.join("bindings.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)?; let mut display_config = DisplayConfig::load(display_config_path)?;
display_config.icon = Some(PathBuf::from("resources/icon.png")); 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::<systems::PlayerBindings>::new() let input_bundle = InputBundle::<systems::PlayerBindings>::new()
.with_bindings_from_file(binding_path)?; .with_bindings_from_file(binding_path)?;
@ -68,7 +75,9 @@ fn main() -> amethyst::Result<()> {
) )
.with_plugin(RenderFlat2D::default()) .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)?; let mut game = Application::new(resources_dir, states::LevelState, game_data)?;
game.run(); game.run();

View file

@ -27,18 +27,21 @@
use amethyst::{ use amethyst::{
assets::{AssetStorage, Loader, Handle}, assets::{AssetStorage, Loader, Handle},
core::transform::Transform, core::transform::Transform,
ecs::prelude::{Component, DenseVecStorage},
prelude::*, prelude::*,
renderer::{Camera, ImageFormat, SpriteRender, SpriteSheet, SpriteSheetFormat, Texture} renderer::{Camera, ImageFormat, SpriteRender, SpriteSheet, SpriteSheetFormat, Texture}
}; };
use crate::components::Dynamic;
use crate::components::Gravity;
use crate::components::Player; use crate::components::Player;
pub const CAMERA_WIDTH: f32 = 1920.0; pub const CAMERA_WIDTH: f32 = 384.0;
pub const CAMERA_HEIGHT: f32 = 1080.0; pub const CAMERA_HEIGHT: f32 = 216.0;
pub const BLOCK_SIZE: f32 = 16.0;
fn initialize_camera(world: &mut World) { fn initialize_camera(world: &mut World) {
let mut transform = Transform::default(); 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 world
.create_entity() .create_entity()
@ -47,21 +50,57 @@ fn initialize_camera(world: &mut World) {
.build(); .build();
} }
fn initialize_player(world: &mut World) { fn initialize_player(world: &mut World, sprite_sheet_handle: Handle<SpriteSheet>) {
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 world
.create_entity() .create_entity()
.with(Player::new(0)) .with(sprite_render)
.with(Player::default())
.with(Transform::default()) .with(Transform::default())
.with(Dynamic::default())
.with(Gravity)
.with(transform)
.build(); .build();
} }
fn load_sprite_sheet(world: &mut World) -> Handle<SpriteSheet> {
let texture_handle = {
let loader = world.read_resource::<Loader>();
let texture_storage = world.read_resource::<AssetStorage<Texture>>();
loader.load(
"sprites.png",
ImageFormat::default(),
(),
&texture_storage,
)
};
let loader = world.read_resource::<Loader>();
let sprite_sheet_store = world.read_resource::<AssetStorage<SpriteSheet>>();
loader.load(
"sprites.ron",
SpriteSheetFormat(texture_handle),
(),
&sprite_sheet_store,
)
}
pub struct LevelState; pub struct LevelState;
impl SimpleState for LevelState { impl SimpleState for LevelState {
fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) { fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) {
let world = data.world; let world = data.world;
let sprite_sheet_handle = load_sprite_sheet(world);
initialize_camera(world); initialize_camera(world);
initialize_player(world); initialize_player(world, sprite_sheet_handle);
} }
} }

View file

@ -28,4 +28,4 @@ pub use self::{
level::LevelState level::LevelState
}; };
mod level; pub mod level;

View file

@ -25,8 +25,12 @@
*******************************************************************************/ *******************************************************************************/
pub use self::{ pub use self::{
physics::ForceSystem,
physics::CollisionSystem,
player::PlayerSystem, player::PlayerSystem,
player::PlayerBindings, player::PlayerBindings,
}; };
mod player; pub mod physics;
pub mod player;

104
src/systems/physics.rs Normal file
View file

@ -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;
}
}
}
}

View file

@ -27,13 +27,16 @@
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use amethyst::{ use amethyst::{
core::{Transform, SystemDesc}, core::timing::Time,
derive::SystemDesc, derive::SystemDesc,
ecs::{Join, Read, ReadStorage, System, SystemData, World, WriteStorage}, ecs::{Join, Read, System, SystemData, WriteStorage},
input::{InputHandler, BindingTypes, Bindings}, input::{InputHandler, BindingTypes},
}; };
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use crate::components::Dynamic;
use crate::components::Player; use crate::components::Player;
use crate::systems::physics::GRAVITY;
use crate::states::level::BLOCK_SIZE;
#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub enum MovementBindings { pub enum MovementBindings {
@ -58,7 +61,6 @@ impl Display for ActionBindings {
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub struct PlayerBindings; pub struct PlayerBindings;
@ -67,31 +69,94 @@ impl BindingTypes for PlayerBindings {
type Action = ActionBindings; 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)] #[derive(SystemDesc)]
pub struct PlayerSystem; pub struct PlayerSystem;
impl <'s> System<'s> for PlayerSystem { impl <'s> System<'s> for PlayerSystem {
type SystemData = ( type SystemData = (
WriteStorage<'s, Transform>, WriteStorage<'s, Dynamic>,
ReadStorage<'s, Player>, WriteStorage<'s, Player>,
Read<'s, InputHandler<PlayerBindings>>, Read<'s, InputHandler<PlayerBindings>>,
Read<'s, Time>,
); );
fn run(&mut self, (mut transforms, players, input): Self::SystemData) { fn run(&mut self, (mut dynamics, mut players, input, delta_time): Self::SystemData) {
for (transform, _) in (&mut transforms, &players).join() { for (dynamic, player) in (&mut dynamics, &mut players).join() {
let velocity = &mut dynamic.velocity;
let mut movement = 0.0f32; let mut movement = 0.0f32;
for input_id in -1..6 { for input_id in -1..6 {
movement += input movement += input
.axis_value(&MovementBindings::Horizontal(input_id)) .axis_value(&MovementBindings::Horizontal(input_id))
.unwrap_or(0.0); .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 { //////// OLD DEBUGGING STUFF - MAY BE USEFUL LATER ////////
println!("Movement: {}", movement); /*print!("Codes: ");
for code in input.scan_codes_that_are_down() {
print!("{}, ", code);
} }
if input.action_is_down(&ActionBindings::FullHop).unwrap_or(false) { println!();*/
println!("Yump yump!"); ///////////////////////////////////////////////////////////
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);
} }
} }
} }
} }