Initial commit
This commit is contained in:
commit
f55faadbe4
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
3907
Cargo.lock
generated
Normal file
3907
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
Cargo.toml
Normal file
19
Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "experiment"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# Enable a small amount of optimization in debug mode
|
||||||
|
[profile.dev]
|
||||||
|
opt-level = 1
|
||||||
|
|
||||||
|
# Enable high optimizations for dependencies (incl. Bevy), but not for our code:
|
||||||
|
[profile.dev.package."*"]
|
||||||
|
opt-level = 3
|
||||||
|
|
||||||
|
[profile.dev.package.bevy_rapier3d]
|
||||||
|
opt-level = 3
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bevy = { version = "0.11.2", features = ["dynamic_linking"]}
|
||||||
|
bevy_rapier3d = { version = "0.22.0", features = ["debug-render-3d"] }
|
2
rust-toolchain.toml
Normal file
2
rust-toolchain.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
1
src/assets/mod.rs
Normal file
1
src/assets/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
5
src/comps/core/camera.rs
Normal file
5
src/comps/core/camera.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
use bevy::prelude::Component;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct MainCamera;
|
24
src/comps/core/controller.rs
Normal file
24
src/comps/core/controller.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_rapier3d::prelude::*;
|
||||||
|
|
||||||
|
use crate::logic::core::player::player_movement::{PlayerMovementInput, move_player};
|
||||||
|
|
||||||
|
use super::markers::player::Player;
|
||||||
|
|
||||||
|
/// System that captures input and fires events
|
||||||
|
pub fn capture_input(keyboard_input: Res<Input<KeyCode>>, query: Query<(&mut Velocity, &mut ExternalImpulse), With<Player>>, time: Res<Time>) {
|
||||||
|
// Don't allocate on each frame. Instead Check if any of the inputs are being pressed and then allocate.
|
||||||
|
if keyboard_input.any_pressed([KeyCode::A, KeyCode::S, KeyCode::D, KeyCode::W, KeyCode::C, KeyCode::Space]) {
|
||||||
|
let player_movement_input = PlayerMovementInput {
|
||||||
|
up: keyboard_input.pressed(KeyCode::Space),
|
||||||
|
down: keyboard_input.pressed(KeyCode::C),
|
||||||
|
left: keyboard_input.pressed(KeyCode::A),
|
||||||
|
right: keyboard_input.pressed(KeyCode::D),
|
||||||
|
front: keyboard_input.pressed(KeyCode::W),
|
||||||
|
back: keyboard_input.pressed(KeyCode::S),
|
||||||
|
sprint: keyboard_input.pressed(KeyCode::ShiftLeft),
|
||||||
|
};
|
||||||
|
move_player(player_movement_input, query, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
1
src/comps/core/markers/mod.rs
Normal file
1
src/comps/core/markers/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod player;
|
4
src/comps/core/markers/player.rs
Normal file
4
src/comps/core/markers/player.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
use bevy::prelude::Component;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct Player;
|
3
src/comps/core/mod.rs
Normal file
3
src/comps/core/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod camera;
|
||||||
|
pub mod controller;
|
||||||
|
pub mod markers;
|
1
src/comps/mod.rs
Normal file
1
src/comps/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod core;
|
1
src/constants/mod.rs
Normal file
1
src/constants/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod player_values;
|
3
src/constants/player_values.rs
Normal file
3
src/constants/player_values.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
pub const MAX_LINEAR_PLAYER_VELOCITY: f32 = 10.0;
|
||||||
|
pub const PLAYER_ACCELERATION: f32 = 10.0;
|
1
src/logic/core/mod.rs
Normal file
1
src/logic/core/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod player;
|
19
src/logic/core/player/camera_player_sync.rs
Normal file
19
src/logic/core/player/camera_player_sync.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
|
||||||
|
use crate::{comps::core::{markers::player::Player, camera::MainCamera}, utils::rad_deg::radians_from_degrees};
|
||||||
|
|
||||||
|
|
||||||
|
pub fn sync_camera_to_player(
|
||||||
|
player: Query<&Transform, (With<Player>, Without<MainCamera>)>,
|
||||||
|
mut camera: Query<&mut Transform, (With<MainCamera>, Without<Player>)>,
|
||||||
|
) {
|
||||||
|
let Ok(player) = player.get_single() else { return };
|
||||||
|
let Ok(mut camera_transform) = camera.get_single_mut() else { return };
|
||||||
|
|
||||||
|
camera_transform.translation = player.translation;
|
||||||
|
camera_transform.rotation = player.rotation;
|
||||||
|
|
||||||
|
camera_transform.translation.y += 0.5;
|
||||||
|
camera_transform.rotate_x(radians_from_degrees(-15.0)); // Make camera slightly point downward.
|
||||||
|
}
|
3
src/logic/core/player/mod.rs
Normal file
3
src/logic/core/player/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod player_movement;
|
||||||
|
pub mod spawn_player;
|
||||||
|
pub mod camera_player_sync;
|
87
src/logic/core/player/player_movement.rs
Normal file
87
src/logic/core/player/player_movement.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_rapier3d::prelude::*;
|
||||||
|
|
||||||
|
use crate::{comps::core::markers::player::Player, constants::player_values::{MAX_LINEAR_PLAYER_VELOCITY, PLAYER_ACCELERATION}};
|
||||||
|
|
||||||
|
/// Holds all the possible ways a player can be attempting to move at any time.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct PlayerMovementInput {
|
||||||
|
/// Means the player is pressing the space bar key. (JUMP)
|
||||||
|
/// ## DOES NOT MEAN the player should gain upwards velocity
|
||||||
|
pub up: bool,
|
||||||
|
/// Means the player is pressing the control key. (CROUCH)
|
||||||
|
/// ## DOES NOT MEAN the player should gain downards velocity
|
||||||
|
pub down: bool,
|
||||||
|
/// A KEY
|
||||||
|
pub left: bool,
|
||||||
|
/// D KEY
|
||||||
|
pub right: bool,
|
||||||
|
/// W KEY
|
||||||
|
pub front: bool,
|
||||||
|
/// S KEY
|
||||||
|
pub back: bool,
|
||||||
|
// LShift (SPRINTING)
|
||||||
|
pub sprint: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Applies game logic to determine how player should move.
|
||||||
|
pub fn move_player(player_movement_input: PlayerMovementInput, mut query: Query<(&mut Velocity, &mut ExternalImpulse), With<Player>>, time: Res<Time>,) {
|
||||||
|
for (mut player_velocity, mut player_external_force) in &mut query {
|
||||||
|
let crouch_multiplier = if player_movement_input.down {
|
||||||
|
0.25
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
};
|
||||||
|
let sprint_multiplier = if player_movement_input.sprint && !player_movement_input.down {
|
||||||
|
2.5
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
};
|
||||||
|
if player_movement_input.front {
|
||||||
|
player_velocity.linvel.z = apply_movement_acceleration(player_velocity.linvel.z, false, time.delta_seconds(), sprint_multiplier);
|
||||||
|
}
|
||||||
|
if player_movement_input.back {
|
||||||
|
player_velocity.linvel.z = apply_movement_acceleration(player_velocity.linvel.z, true, time.delta_seconds(), 1.0);
|
||||||
|
}
|
||||||
|
if player_movement_input.right {
|
||||||
|
player_velocity.linvel.x = apply_movement_acceleration(player_velocity.linvel.x, true, time.delta_seconds(), 1.0);
|
||||||
|
}
|
||||||
|
if player_movement_input.left {
|
||||||
|
player_velocity.linvel.x = apply_movement_acceleration(player_velocity.linvel.x, false, time.delta_seconds(), 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if player_movement_input.up {
|
||||||
|
player_external_force.impulse = Vec3::new(0.0, 200.0, 0.0);
|
||||||
|
}
|
||||||
|
// When player velocity exceeds max linear velocity then set to max_linear_vel value
|
||||||
|
if player_velocity.linvel.x.abs() > MAX_LINEAR_PLAYER_VELOCITY * crouch_multiplier * sprint_multiplier {
|
||||||
|
let positive = player_velocity.linvel.x.is_sign_positive();
|
||||||
|
if positive { player_velocity.linvel.x = MAX_LINEAR_PLAYER_VELOCITY * crouch_multiplier * sprint_multiplier }
|
||||||
|
else { player_velocity.linvel.x = MAX_LINEAR_PLAYER_VELOCITY * -1.0 * crouch_multiplier }
|
||||||
|
}
|
||||||
|
if player_velocity.linvel.z.abs() > MAX_LINEAR_PLAYER_VELOCITY * crouch_multiplier {
|
||||||
|
let positive = player_velocity.linvel.z.is_sign_positive();
|
||||||
|
if positive { player_velocity.linvel.z = MAX_LINEAR_PLAYER_VELOCITY * crouch_multiplier }
|
||||||
|
else { player_velocity.linvel.z = MAX_LINEAR_PLAYER_VELOCITY * -1.0 * crouch_multiplier }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// currentLinearVelocity + Acceleration * deltaTime
|
||||||
|
fn apply_movement_acceleration(current_linvel: f32, positive: bool, delta_time_secs: f32, multiplier: f32) -> f32 {
|
||||||
|
if positive {
|
||||||
|
if current_linvel.is_sign_positive() {
|
||||||
|
current_linvel + PLAYER_ACCELERATION * delta_time_secs * multiplier
|
||||||
|
} else {
|
||||||
|
// Make it so deacceleration is faster
|
||||||
|
current_linvel + (PLAYER_ACCELERATION * delta_time_secs * 2.0) * multiplier
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if current_linvel.is_sign_negative() {
|
||||||
|
current_linvel - PLAYER_ACCELERATION * delta_time_secs * multiplier
|
||||||
|
} else {
|
||||||
|
// Make it so deacceleration is faster
|
||||||
|
current_linvel - (PLAYER_ACCELERATION * delta_time_secs * 2.0) * multiplier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
src/logic/core/player/spawn_player.rs
Normal file
29
src/logic/core/player/spawn_player.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_rapier3d::prelude::*;
|
||||||
|
|
||||||
|
use crate::comps::core::{markers::player::Player, camera::MainCamera};
|
||||||
|
|
||||||
|
pub fn spawn_player(mut commands: Commands) {
|
||||||
|
commands.spawn(Player)
|
||||||
|
.insert(RigidBody::Dynamic)
|
||||||
|
.insert(GravityScale(1.0))
|
||||||
|
.insert(Collider::capsule_y(2.0, 2.0))
|
||||||
|
.insert(Restitution::coefficient(0.3))
|
||||||
|
.insert(Friction { coefficient: 0.0, ..Default::default() })
|
||||||
|
.insert(TransformBundle::from(Transform::from_xyz(3.0, 5.0, 2.0)))
|
||||||
|
.insert(Velocity::zero())
|
||||||
|
.insert(Damping { linear_damping: 1.0, angular_damping: 1.0 })
|
||||||
|
.insert(LockedAxes::ROTATION_LOCKED_X | LockedAxes::ROTATION_LOCKED_Z)
|
||||||
|
.insert(ColliderMassProperties::Mass(100.0))
|
||||||
|
.insert(ExternalImpulse {
|
||||||
|
impulse: Vec3::ZERO,
|
||||||
|
torque_impulse: Vec3::ZERO,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
commands.spawn(MainCamera)
|
||||||
|
.insert(Camera3dBundle {
|
||||||
|
transform: Transform::from_xyz(0.0, 0.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
}
|
1
src/logic/mod.rs
Normal file
1
src/logic/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod core;
|
32
src/main.rs
Normal file
32
src/main.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_rapier3d::prelude::*;
|
||||||
|
use scenes::scene1;
|
||||||
|
|
||||||
|
mod assets;
|
||||||
|
mod comps;
|
||||||
|
mod scenes;
|
||||||
|
mod setup;
|
||||||
|
mod logic;
|
||||||
|
mod constants;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut application = App::new();
|
||||||
|
|
||||||
|
setup_plugins(&mut application);
|
||||||
|
|
||||||
|
load(&mut application);
|
||||||
|
|
||||||
|
application.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_plugins(application: &mut App) {
|
||||||
|
application
|
||||||
|
.add_plugins(DefaultPlugins)
|
||||||
|
.add_plugins(RapierPhysicsPlugin::<NoUserData>::default()) // Rapier Physics
|
||||||
|
;//.add_plugins(RapierDebugRenderPlugin::default()); // Uncomment this to see physics objects as wireframes
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(application: &mut App) {
|
||||||
|
scene1::init::load_scene(application);
|
||||||
|
}
|
1
src/scenes/mod.rs
Normal file
1
src/scenes/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod scene1;
|
19
src/scenes/scene1/ground.rs
Normal file
19
src/scenes/scene1/ground.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_rapier3d::prelude::*;
|
||||||
|
|
||||||
|
pub fn spawn_ground(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,) {
|
||||||
|
commands
|
||||||
|
.spawn(Collider::cuboid(20.0, 0.1, 20.0))
|
||||||
|
.insert(TransformBundle::from(Transform::from_xyz(0.0, -2.0, 0.0)))
|
||||||
|
.insert(RigidBody::Fixed)
|
||||||
|
.insert(PbrBundle {
|
||||||
|
mesh: meshes.add(shape::Plane::from_size(40.0).into()),
|
||||||
|
material: materials.add(StandardMaterial {
|
||||||
|
base_color: Color::WHITE,
|
||||||
|
perceptual_roughness: 1.0,
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
}
|
20
src/scenes/scene1/init.rs
Normal file
20
src/scenes/scene1/init.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::{logic::core::player::{spawn_player::spawn_player, camera_player_sync::sync_camera_to_player}, comps::core::controller::capture_input};
|
||||||
|
|
||||||
|
use super::{ground::spawn_ground, lighting::setup_lighting, obstacles::spawn_obstacles};
|
||||||
|
|
||||||
|
|
||||||
|
pub fn load_scene(application: &mut App) {
|
||||||
|
// Startup
|
||||||
|
application.add_systems(Startup, spawn_ground);
|
||||||
|
application.add_systems(Startup, spawn_obstacles);
|
||||||
|
application.add_systems(Startup, spawn_player);
|
||||||
|
|
||||||
|
|
||||||
|
// Update
|
||||||
|
application.add_systems(Update, capture_input);
|
||||||
|
application.add_systems(Update, sync_camera_to_player);
|
||||||
|
|
||||||
|
application.add_systems(Startup, setup_lighting);
|
||||||
|
}
|
10
src/scenes/scene1/lighting.rs
Normal file
10
src/scenes/scene1/lighting.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
pub fn setup_lighting(mut commands: Commands) {
|
||||||
|
commands.spawn(SpotLightBundle {
|
||||||
|
spot_light: SpotLight { color: Color::WHITE, intensity: 3000.0, range: 500.0, shadows_enabled: true, ..Default::default() },
|
||||||
|
transform: Transform::from_xyz(20.0, 20.0, 20.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||||
|
visibility: Visibility::Visible,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
}
|
5
src/scenes/scene1/mod.rs
Normal file
5
src/scenes/scene1/mod.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
pub mod init;
|
||||||
|
|
||||||
|
pub mod ground;
|
||||||
|
pub mod lighting;
|
||||||
|
pub mod obstacles;
|
20
src/scenes/scene1/obstacles.rs
Normal file
20
src/scenes/scene1/obstacles.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_rapier3d::prelude::*;
|
||||||
|
|
||||||
|
pub fn spawn_obstacles(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,) {
|
||||||
|
let mesh = shape::Box::new(3.0, 7.0, 3.0).into();
|
||||||
|
commands
|
||||||
|
.spawn(Collider::from_bevy_mesh(&mesh, &Default::default()).unwrap())
|
||||||
|
.insert(RigidBody::Fixed)
|
||||||
|
.insert(PbrBundle {
|
||||||
|
mesh: meshes.add(mesh.into()),
|
||||||
|
material: materials.add(StandardMaterial {
|
||||||
|
base_color: Color::RED,
|
||||||
|
perceptual_roughness: 1.0,
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
transform: Transform::from_xyz(-5.0, 3.5, -10.0),
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
}
|
0
src/setup/mod.rs
Normal file
0
src/setup/mod.rs
Normal file
2
src/utils/mod.rs
Normal file
2
src/utils/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
pub mod rad_deg;
|
7
src/utils/rad_deg.rs
Normal file
7
src/utils/rad_deg.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn radians_from_degrees(degrees: f32) -> f32 {
|
||||||
|
(PI * degrees) / 180.0
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user