Revert "Revert "stuff I did while I was away""
This reverts commit c9159e1ebf.
This commit is contained in:
parent
c9159e1ebf
commit
49258f2276
12 changed files with 298 additions and 239 deletions
|
|
@ -1,3 +0,0 @@
|
||||||
[target.x86_64-unknown-linux-gnu]
|
|
||||||
linker = "clang"
|
|
||||||
rustflags = ["-Clink-arg=-fuse-ld=mold"]
|
|
||||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"rust-analyzer.debug.engine": "vadimcn.vscode-lldb",
|
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"Gamepad",
|
"Gamepad",
|
||||||
"qeury",
|
"qeury",
|
||||||
"Substep",
|
"Substep",
|
||||||
"xpbd"
|
"xpbd"
|
||||||
],
|
],
|
||||||
|
"rust-analyzer.checkOnSave": false
|
||||||
}
|
}
|
||||||
9
.vscode/tasks.json
vendored
9
.vscode/tasks.json
vendored
|
|
@ -48,6 +48,15 @@
|
||||||
"--run",
|
"--run",
|
||||||
"steam-run cargo fmt --all"
|
"steam-run cargo fmt --all"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "generate docs",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "nix-shell",
|
||||||
|
"args": [
|
||||||
|
"--run",
|
||||||
|
"cargo doc"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -1209,7 +1209,8 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_xpbd_3d"
|
name = "bevy_xpbd_3d"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
source = "git+https://git.opencodebox.com/MikolajG/bevy_xpbd?branch=reflect-serialize#489e53505abda9649a9ee6e9de6e03a7d5801e28"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0425ea7361b9b27c2a382e0663deb42f41147eee60fb2b3d5fa7e42d363ea848"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"bevy_math",
|
"bevy_math",
|
||||||
|
|
@ -1226,9 +1227,9 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_xpbd_derive"
|
name = "bevy_xpbd_derive"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://git.opencodebox.com/MikolajG/bevy_xpbd?branch=reflect-serialize#489e53505abda9649a9ee6e9de6e03a7d5801e28"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e1ef1d5e328abe1b76df974245f78e17fd17867583883d5e77444c6a8223a64"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.55",
|
"syn 2.0.55",
|
||||||
]
|
]
|
||||||
|
|
@ -3706,9 +3707,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.114"
|
version = "1.0.117"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
|
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
|
|
@ -4185,6 +4186,7 @@ dependencies = [
|
||||||
"embed-resource",
|
"embed-resource",
|
||||||
"image",
|
"image",
|
||||||
"rand",
|
"rand",
|
||||||
|
"serde_json",
|
||||||
"webbrowser",
|
"webbrowser",
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -68,11 +68,12 @@ bevy_asset_loader = { version = "0.20" }
|
||||||
rand = { version = "0.8.3" }
|
rand = { version = "0.8.3" }
|
||||||
webbrowser = { version = "0.8", features = ["hardened"] }
|
webbrowser = { version = "0.8", features = ["hardened"] }
|
||||||
bevy_editor_pls = "0.8.1"
|
bevy_editor_pls = "0.8.1"
|
||||||
bevy_xpbd_3d = {git = "https://git.opencodebox.com/MikolajG/bevy_xpbd", branch = "reflect-serialize"}
|
bevy_xpbd_3d = "0.4.2"
|
||||||
|
|
||||||
# keep the following in sync with Bevy's dependencies
|
# keep the following in sync with Bevy's dependencies
|
||||||
winit = { version = "0.29", default-features = false }
|
winit = { version = "0.29", default-features = false }
|
||||||
image = { version = "0.24", default-features = false }
|
image = { version = "0.24", default-features = false }
|
||||||
|
serde_json = "1.0.117"
|
||||||
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
|
||||||
36
src/config_utils.rs
Normal file
36
src/config_utils.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
Trouble in Terror Town: Community Edition
|
||||||
|
Copyright (C) 2024 Mikolaj Wojciech Gorski
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License 3.0 as published by
|
||||||
|
the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License 3.0 for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License 3.0
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/gpl-3.0.html>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::fs::*;
|
||||||
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
struct CharacterControllerConfig {
|
||||||
|
movement_acceleration: f32,
|
||||||
|
air_control_factor: f32,
|
||||||
|
movement_dampening_factor: f32,
|
||||||
|
jump_impulse: f32,
|
||||||
|
gravity: [f32; 3],
|
||||||
|
max_slope_angle: f32,
|
||||||
|
axis_speed_limit: f32,
|
||||||
|
max_acceleration: f32,
|
||||||
|
friction: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -79,7 +79,7 @@ fn setup(
|
||||||
commands,
|
commands,
|
||||||
meshes,
|
meshes,
|
||||||
materials,
|
materials,
|
||||||
0.5,
|
0.7,
|
||||||
CharacterControllerBundle::new(Collider::capsule(1.0, 0.5), CharacterController::default()),
|
CharacterControllerBundle::new(Collider::capsule(1.0, 0.5), CharacterController::default()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +105,9 @@ fn spawn_map(
|
||||||
RigidBody::Static,
|
RigidBody::Static,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
||||||
|
is_map_spawned.0 = true;
|
||||||
|
|
||||||
println!("map spawned!");
|
println!("map spawned!");
|
||||||
|
|
||||||
is_map_spawned.0 = true
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ fn main() {
|
||||||
.insert_resource(ClearColor(Color::rgb(0.4, 0.4, 0.4)))
|
.insert_resource(ClearColor(Color::rgb(0.4, 0.4, 0.4)))
|
||||||
.add_plugins(DefaultPlugins.set(WindowPlugin {
|
.add_plugins(DefaultPlugins.set(WindowPlugin {
|
||||||
primary_window: Some(Window {
|
primary_window: Some(Window {
|
||||||
title: "Trouble in Terror Town: Source Crossed".to_string(), // ToDo
|
title: "Trouble in Terror Town: Community Edition".to_string(), // ToDo
|
||||||
// Bind to canvas included in `index.html`
|
// Bind to canvas included in `index.html`
|
||||||
canvas: Some("#bevy".to_owned()),
|
canvas: Some("#bevy".to_owned()),
|
||||||
// Tells wasm not to override default event handling, like F5 and Ctrl+R
|
// Tells wasm not to override default event handling, like F5 and Ctrl+R
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ pub struct CharacterControllerPlugin;
|
||||||
impl Plugin for CharacterControllerPlugin {
|
impl Plugin for CharacterControllerPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(Update, move_character);
|
app.add_systems(Update, move_character);
|
||||||
app.add_systems(FixedUpdate, (apply_gravity, update_grounded, dampen_movement,));
|
app.add_systems(FixedUpdate, (apply_gravity, update_grounded, dampen_movement));
|
||||||
app.add_systems(SubstepSchedule, kinematic_controller_collisions.in_set(SubstepSet::SolveUserConstraints));
|
app.add_systems(SubstepSchedule, collide_and_slide.in_set(SubstepSet::SolveUserConstraints));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,10 +52,12 @@ pub struct CharacterController {
|
||||||
pub air_control_factor: Scalar,
|
pub air_control_factor: Scalar,
|
||||||
pub movement_dampening_factor: Scalar,
|
pub movement_dampening_factor: Scalar,
|
||||||
pub jump_impulse: Scalar,
|
pub jump_impulse: Scalar,
|
||||||
|
/// direction in which gravity pulls the character look at [`new_fall_velocity`]
|
||||||
pub gravity: Vector,
|
pub gravity: Vector,
|
||||||
pub max_slope_angle: Scalar,
|
pub max_slope_angle: Scalar,
|
||||||
pub axis_speed_limit: f32,
|
pub axis_speed_limit: f32,
|
||||||
pub max_acceleration: f32,
|
pub max_acceleration: f32,
|
||||||
|
/// value used for holding current calculated friction, do not change on spawn
|
||||||
pub friction: f32,
|
pub friction: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,7 +67,7 @@ impl Default for CharacterController {
|
||||||
movement_acceleration: 20.0,
|
movement_acceleration: 20.0,
|
||||||
air_control_factor: 0.5,
|
air_control_factor: 0.5,
|
||||||
movement_dampening_factor: 0.95,
|
movement_dampening_factor: 0.95,
|
||||||
jump_impulse: 4.0,
|
jump_impulse: 6.0,
|
||||||
gravity: Vector::NEG_Y * 9.81 * 2.0,
|
gravity: Vector::NEG_Y * 9.81 * 2.0,
|
||||||
max_slope_angle: (45.0 as Scalar).to_radians(),
|
max_slope_angle: (45.0 as Scalar).to_radians(),
|
||||||
axis_speed_limit: 6668.5,
|
axis_speed_limit: 6668.5,
|
||||||
|
|
@ -141,212 +143,38 @@ fn get_lateral_acceleration(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// function "borrowed" from UE
|
/// project a point on a plane
|
||||||
fn point_plane_project(point: Vec3, plane_base: Vec3, plane_normal: Vec3) -> Vec3 {
|
fn point_plane_project(point: Vec3, plane_base: Vec3, plane_normal: Vec3) -> Vec3 {
|
||||||
let projection = point - plane_normal * plane_normal.dot(point - plane_base);
|
point - plane_normal * plane_normal.dot(point - plane_base)
|
||||||
projection
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// function "borrowed" from UE
|
/// calculating gravity, later you'll have to pass custom terminal velocity
|
||||||
fn new_fall_velocity(initial_velocity: LinearVelocity, gravity: Vec3, delta_time: f32, speed_limit: f32)
|
fn new_fall_velocity(initial_velocity: LinearVelocity, gravity: Vec3, delta_time: f32, speed_limit: f32)
|
||||||
-> Vec3 {
|
-> Vec3 {
|
||||||
|
|
||||||
let mut result: Vec3 = Vec3 { x: initial_velocity.x, y: initial_velocity.y, z: initial_velocity.z };
|
let mut result: Vec3 = Vec3 { x: initial_velocity.x, y: initial_velocity.y, z: initial_velocity.z };
|
||||||
let terminal_velocity: f32 = 50.0;
|
let terminal_velocity: f32 = 50.0;
|
||||||
|
|
||||||
if delta_time > 0.0
|
// Apply gravity.
|
||||||
{
|
result += gravity * delta_time;
|
||||||
|
|
||||||
// Apply gravity.
|
// Don't exceed terminal velocity.
|
||||||
result += gravity * delta_time;
|
let terminal_limit: f32 = f32::abs(terminal_velocity); //FMath::Abs(GetPhysicsVolume()->TerminalVelocity);
|
||||||
|
if result.length_squared() > (terminal_limit * terminal_limit)
|
||||||
|
{
|
||||||
|
let gravity_dir: Vec3 = gravity.normalize();
|
||||||
|
|
||||||
|
if result.y > terminal_limit || gravity_dir.y > terminal_limit
|
||||||
// Don't exceed terminal velocity.
|
|
||||||
let terminal_limit: f32 = f32::abs(terminal_velocity); //FMath::Abs(GetPhysicsVolume()->TerminalVelocity);
|
|
||||||
if result.length_squared() > (terminal_limit * terminal_limit)
|
|
||||||
{
|
{
|
||||||
let gravity_dir: Vec3 = gravity.normalize();
|
result = point_plane_project(result, Vec3::ZERO, gravity_dir) + gravity_dir * terminal_limit;
|
||||||
|
}
|
||||||
if result.y > terminal_limit || gravity_dir.y > terminal_limit
|
}
|
||||||
{
|
|
||||||
result = point_plane_project(result, Vec3::ZERO, gravity_dir) + gravity_dir * terminal_limit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.z = f32::clamp(result.z, -speed_limit, speed_limit);
|
result.z = f32::clamp(result.z, -speed_limit, speed_limit);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_gravity(
|
|
||||||
time: Res<Time>,
|
|
||||||
mut controllers: Query<(&CharacterController, &mut LinearVelocity)>,
|
|
||||||
) {
|
|
||||||
// Precision is adjusted so that the example works with
|
|
||||||
// both the `f32` and `f64` features. Otherwise you don't need this.
|
|
||||||
let delta_time = time.delta_seconds_f64().adjust_precision();
|
|
||||||
|
|
||||||
for (character_controller, mut linear_velocity) in &mut controllers {
|
|
||||||
|
|
||||||
let mut fall_acceleration: Vec3 = get_lateral_acceleration(character_controller, delta_time, linear_velocity.0);
|
|
||||||
fall_acceleration.y = 0.0;
|
|
||||||
let has_limited_air_control: bool = false;
|
|
||||||
|
|
||||||
|
|
||||||
// Ugly fix for mismatch types, find a proper solution later
|
|
||||||
let new_velocity: Vec3 = new_fall_velocity(linear_velocity.clone(), character_controller.gravity, delta_time, character_controller.axis_speed_limit);
|
|
||||||
linear_velocity.x = new_velocity.x;
|
|
||||||
linear_velocity.y = new_velocity.y;
|
|
||||||
linear_velocity.z = new_velocity.z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn move_character(
|
|
||||||
time: Res<Time>,
|
|
||||||
mut movement_event_reader: EventReader<MovementAction>,
|
|
||||||
mut query: Query<(
|
|
||||||
&mut LinearVelocity,
|
|
||||||
&CharacterController,
|
|
||||||
Has<Grounded>,
|
|
||||||
&Rotation,
|
|
||||||
&ShapeHits,
|
|
||||||
&Transform,
|
|
||||||
)>,
|
|
||||||
) {
|
|
||||||
let delta_time = time.delta_seconds_f64().adjust_precision();
|
|
||||||
|
|
||||||
for event in movement_event_reader.read() {
|
|
||||||
for (
|
|
||||||
mut velocity,
|
|
||||||
character_controller,
|
|
||||||
is_grounded,
|
|
||||||
rotation,
|
|
||||||
shape_hits,
|
|
||||||
character_transform,
|
|
||||||
) in &mut query
|
|
||||||
{
|
|
||||||
character_controller.friction = f32::max(0.0f, character_controller.friction);
|
|
||||||
let forward = character_transform.forward().xyz().normalize();
|
|
||||||
|
|
||||||
match event {
|
|
||||||
MovementAction::Move(direction) => {
|
|
||||||
if is_grounded {
|
|
||||||
velocity.x = f32::clamp(velocity.x, -character_controller.axis_speed_limit, character_controller.axis_speed_limit);
|
|
||||||
velocity.y = f32::clamp(velocity.y, -character_controller.axis_speed_limit, character_controller.axis_speed_limit);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MovementAction::Jump => {
|
|
||||||
if is_grounded {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn update_grounded(
|
|
||||||
mut commands: Commands,
|
|
||||||
mut query: Query<(Entity, &CharacterController, &Rotation, &ShapeHits)>,
|
|
||||||
) {
|
|
||||||
for (entity, character_controller, rotation, hits) in &mut query {
|
|
||||||
let is_grounded = hits.iter().any(|hit| {
|
|
||||||
let angle = rotation.rotate(-hit.normal2).angle_between(Vector::Y).abs();
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"slope angle: {} / {}",
|
|
||||||
angle, character_controller.max_slope_angle
|
|
||||||
);
|
|
||||||
|
|
||||||
angle <= character_controller.max_slope_angle
|
|
||||||
});
|
|
||||||
|
|
||||||
//println!("is grounded: {}", is_grounded);
|
|
||||||
|
|
||||||
if is_grounded {
|
|
||||||
commands.entity(entity).insert(Grounded);
|
|
||||||
} else {
|
|
||||||
commands.entity(entity).remove::<Grounded>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
fn kinematic_controller_collisions(
|
|
||||||
collisions: Res<Collisions>,
|
|
||||||
collider_parents: Query<&ColliderParent, Without<Sensor>>,
|
|
||||||
mut character_controllers: Query<
|
|
||||||
(
|
|
||||||
&RigidBody,
|
|
||||||
&mut Position,
|
|
||||||
&Rotation,
|
|
||||||
&mut LinearVelocity,
|
|
||||||
&CharacterController,
|
|
||||||
)
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
// Iterate through collisions and move the kinematic body to resolve penetration
|
|
||||||
for contacts in collisions.iter() {
|
|
||||||
// If the collision didn't happen during this substep, skip the collision
|
|
||||||
if !contacts.during_current_substep {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the rigid body entities of the colliders (colliders could be children)
|
|
||||||
let Ok([collider_parent1, collider_parent2]) =
|
|
||||||
collider_parents.get_many([contacts.entity1, contacts.entity2])
|
|
||||||
else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the body of the character controller and whether it is the first
|
|
||||||
// or second entity in the collision.
|
|
||||||
let is_first: bool;
|
|
||||||
let (rb, mut position, rotation, mut linear_velocity, character_controller) =
|
|
||||||
if let Ok(character) = character_controllers.get_mut(collider_parent1.get()) {
|
|
||||||
is_first = true;
|
|
||||||
character
|
|
||||||
} else if let Ok(character) = character_controllers.get_mut(collider_parent2.get()) {
|
|
||||||
is_first = false;
|
|
||||||
character
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This system only handles collision response for kinematic character controllers
|
|
||||||
if !rb.is_kinematic() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate through contact manifolds and their contacts.
|
|
||||||
// Each contact in a single manifold shares the same contact normal.
|
|
||||||
for manifold in contacts.manifolds.iter() {
|
|
||||||
let normal = if is_first {
|
|
||||||
-manifold.global_normal1(rotation)
|
|
||||||
} else {
|
|
||||||
-manifold.global_normal2(rotation)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Solve each penetrating contact in the manifold
|
|
||||||
for contact in manifold.contacts.iter().filter(|c| c.penetration > 0.0) {
|
|
||||||
position.0 += normal * contact.penetration;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the slope isn't too steep to walk on but the character
|
|
||||||
// is falling, reset vertical velocity.
|
|
||||||
if normal.angle_between(Vector::Y).abs() <= character_controller.max_slope_angle
|
|
||||||
&& linear_velocity.y < 0.0
|
|
||||||
{
|
|
||||||
linear_velocity.y = linear_velocity.y.max(0.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fn move_character(
|
// fn move_character(
|
||||||
// time: Res<Time>,
|
// time: Res<Time>,
|
||||||
// mut movement_event_reader: EventReader<MovementAction>,
|
// mut movement_event_reader: EventReader<MovementAction>,
|
||||||
|
|
@ -371,47 +199,21 @@ fn kinematic_controller_collisions(
|
||||||
// character_transform,
|
// character_transform,
|
||||||
// ) in &mut query
|
// ) in &mut query
|
||||||
// {
|
// {
|
||||||
|
// character_controller.friction = f32::max(0.0f, character_controller.friction);
|
||||||
|
// let forward = character_transform.forward().xyz().normalize();
|
||||||
|
|
||||||
// match event {
|
// match event {
|
||||||
// MovementAction::Move(direction) => {
|
// MovementAction::Move(direction) => {
|
||||||
// // Get the forward direction of the character in the local coordinate system
|
|
||||||
// let forward = character_transform.forward().xyz().normalize();
|
|
||||||
|
|
||||||
// // Calculate the movement in the local coordinate system
|
|
||||||
// let local_movement = forward
|
|
||||||
// * direction.y
|
|
||||||
// * character_controller.movement_acceleration
|
|
||||||
// * delta_time
|
|
||||||
// + character_transform
|
|
||||||
// .rotation
|
|
||||||
// .mul_vec3(Vec3::new(direction.x, 0.0, 0.0))
|
|
||||||
// * character_controller.movement_acceleration
|
|
||||||
// * delta_time;
|
|
||||||
|
|
||||||
// if is_grounded {
|
// if is_grounded {
|
||||||
// let mut slope_factor = 1.0;
|
// velocity.x = f32::clamp(velocity.x, -character_controller.axis_speed_limit, character_controller.axis_speed_limit);
|
||||||
// for hit in shape_hits.iter() {
|
// velocity.y = f32::clamp(velocity.y, -character_controller.axis_speed_limit, character_controller.axis_speed_limit);
|
||||||
// let angle =
|
|
||||||
// rotation.rotate(-hit.normal2).angle_between(Vector::Y).abs();
|
|
||||||
// if angle <= character_controller.max_slope_angle {
|
|
||||||
// slope_factor *=
|
|
||||||
// (angle / character_controller.max_slope_angle).cos();
|
|
||||||
|
|
||||||
// // Update linear velocity
|
|
||||||
// velocity.x += local_movement.x * slope_factor;
|
|
||||||
// velocity.z += local_movement.z * slope_factor;
|
|
||||||
// } else {
|
|
||||||
// velocity.x = 0.0;
|
|
||||||
// velocity.z = 0.0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
// } else {
|
||||||
// velocity.x += local_movement.x * character_controller.air_control_factor;
|
|
||||||
// velocity.z += local_movement.z * character_controller.air_control_factor;
|
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// MovementAction::Jump => {
|
// MovementAction::Jump => {
|
||||||
// if is_grounded {
|
// if is_grounded {
|
||||||
// velocity.y = character_controller.jump_impulse;
|
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
@ -419,6 +221,184 @@ fn kinematic_controller_collisions(
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
fn apply_gravity(
|
||||||
|
time: Res<Time>,
|
||||||
|
mut controllers: Query<(&CharacterController, &mut LinearVelocity)>,
|
||||||
|
) {
|
||||||
|
let delta_time = time.delta_seconds_f64().adjust_precision();
|
||||||
|
|
||||||
|
for (character_controller, mut linear_velocity) in &mut controllers {
|
||||||
|
let new_velocity = new_fall_velocity(
|
||||||
|
*linear_velocity,
|
||||||
|
character_controller.gravity,
|
||||||
|
delta_time,
|
||||||
|
character_controller.axis_speed_limit,
|
||||||
|
);
|
||||||
|
linear_velocity.0 = new_velocity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_grounded(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut query: Query<(Entity, &CharacterController, &Rotation, &ShapeHits)>,
|
||||||
|
) {
|
||||||
|
for (entity, character_controller, rotation, hits) in &mut query {
|
||||||
|
let is_grounded = hits.iter().any(|hit| {
|
||||||
|
let angle = rotation.rotate(-hit.normal2).angle_between(Vector::Y).abs();
|
||||||
|
angle <= character_controller.max_slope_angle
|
||||||
|
});
|
||||||
|
|
||||||
|
if is_grounded {
|
||||||
|
commands.entity(entity).insert(Grounded);
|
||||||
|
} else {
|
||||||
|
commands.entity(entity).remove::<Grounded>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
fn collide_and_slide(
|
||||||
|
collisions: Res<Collisions>,
|
||||||
|
collider_parents: Query<&ColliderParent, Without<Sensor>>,
|
||||||
|
mut character_controllers: Query<
|
||||||
|
(
|
||||||
|
&RigidBody,
|
||||||
|
&mut Position,
|
||||||
|
&Rotation,
|
||||||
|
&mut LinearVelocity,
|
||||||
|
&CharacterController,
|
||||||
|
)
|
||||||
|
>,
|
||||||
|
) {
|
||||||
|
for contacts in collisions.iter() {
|
||||||
|
if !contacts.during_current_substep {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Ok([collider_parent1, collider_parent2]) =
|
||||||
|
collider_parents.get_many([contacts.entity1, contacts.entity2])
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_first: bool;
|
||||||
|
let (rb, mut position, rotation, mut linear_velocity, character_controller) =
|
||||||
|
if let Ok(character) = character_controllers.get_mut(collider_parent1.get()) {
|
||||||
|
is_first = true;
|
||||||
|
character
|
||||||
|
} else if let Ok(character) = character_controllers.get_mut(collider_parent2.get()) {
|
||||||
|
is_first = false;
|
||||||
|
character
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This system only handles collision response for kinematic character controllers
|
||||||
|
if !rb.is_kinematic() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through contact manifolds and their contacts.
|
||||||
|
// Each contact in a single manifold shares the same contact normal.
|
||||||
|
for manifold in contacts.manifolds.iter() {
|
||||||
|
// Determine the normal of the collision based on which entity the character is
|
||||||
|
let normal = if is_first {
|
||||||
|
-manifold.global_normal1(rotation)
|
||||||
|
} else {
|
||||||
|
-manifold.global_normal2(rotation)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Resolve penetration by moving the position out of the collision
|
||||||
|
for contact in manifold.contacts.iter().filter(|c| c.penetration > 0.0) {
|
||||||
|
position.0 += normal * contact.penetration;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the slope isn't too steep to walk on but the character is falling, reset vertical velocity.
|
||||||
|
if normal.angle_between(Vector::Y).abs() <= character_controller.max_slope_angle
|
||||||
|
&& linear_velocity.y < 0.0
|
||||||
|
{
|
||||||
|
// Stop downward velocity to prevent sliding down walkable slopes
|
||||||
|
linear_velocity.y = linear_velocity.y.max(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn move_character(
|
||||||
|
time: Res<Time>,
|
||||||
|
mut movement_event_reader: EventReader<MovementAction>,
|
||||||
|
mut query: Query<(
|
||||||
|
&mut LinearVelocity,
|
||||||
|
&CharacterController,
|
||||||
|
Has<Grounded>,
|
||||||
|
&Rotation,
|
||||||
|
&ShapeHits,
|
||||||
|
&Transform,
|
||||||
|
)>,
|
||||||
|
) {
|
||||||
|
let delta_time = time.delta_seconds_f64().adjust_precision();
|
||||||
|
|
||||||
|
for event in movement_event_reader.read() {
|
||||||
|
for (
|
||||||
|
mut velocity,
|
||||||
|
character_controller,
|
||||||
|
is_grounded,
|
||||||
|
rotation,
|
||||||
|
shape_hits,
|
||||||
|
character_transform,
|
||||||
|
) in &mut query
|
||||||
|
{
|
||||||
|
match event {
|
||||||
|
MovementAction::Move(direction) => {
|
||||||
|
// Get the forward direction of the character in the local coordinate system
|
||||||
|
let forward = character_transform.forward().xyz().normalize();
|
||||||
|
|
||||||
|
// Calculate the movement in the local coordinate system
|
||||||
|
let local_movement = forward
|
||||||
|
* direction.y
|
||||||
|
* character_controller.movement_acceleration
|
||||||
|
* delta_time
|
||||||
|
+ character_transform
|
||||||
|
.rotation
|
||||||
|
.mul_vec3(Vec3::new(direction.x, 0.0, 0.0))
|
||||||
|
* character_controller.movement_acceleration
|
||||||
|
* delta_time;
|
||||||
|
|
||||||
|
if is_grounded {
|
||||||
|
let mut slope_factor = 1.0;
|
||||||
|
for hit in shape_hits.iter() {
|
||||||
|
let angle =
|
||||||
|
rotation.rotate(-hit.normal2).angle_between(Vector::Y).abs();
|
||||||
|
if angle <= character_controller.max_slope_angle {
|
||||||
|
slope_factor *=
|
||||||
|
(angle / character_controller.max_slope_angle).cos();
|
||||||
|
|
||||||
|
// Update linear velocity
|
||||||
|
velocity.x += local_movement.x * slope_factor;
|
||||||
|
velocity.z += local_movement.z * slope_factor;
|
||||||
|
} else {
|
||||||
|
velocity.x = 0.0;
|
||||||
|
velocity.z = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
velocity.x += local_movement.x * character_controller.air_control_factor;
|
||||||
|
velocity.z += local_movement.z * character_controller.air_control_factor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MovementAction::Jump => {
|
||||||
|
if is_grounded {
|
||||||
|
velocity.y = character_controller.jump_impulse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn dampen_movement(mut qeury: Query<(&mut LinearVelocity, &CharacterController)>) {
|
fn dampen_movement(mut qeury: Query<(&mut LinearVelocity, &CharacterController)>) {
|
||||||
for (mut velocity, character_controller) in &mut qeury {
|
for (mut velocity, character_controller) in &mut qeury {
|
||||||
// We could use `LinearDamping`, but we don't want to dampen movement along the Y axis
|
// We could use `LinearDamping`, but we don't want to dampen movement along the Y axis
|
||||||
|
|
@ -448,6 +428,12 @@ pub fn spawn_player(
|
||||||
parent.spawn((
|
parent.spawn((
|
||||||
PlayerCamera::default(),
|
PlayerCamera::default(),
|
||||||
Camera3dBundle {
|
Camera3dBundle {
|
||||||
|
projection: PerspectiveProjection {
|
||||||
|
// We must specify the FOV in radians.
|
||||||
|
// Rust can convert degrees to radians for us.
|
||||||
|
fov: 90.0_f32.to_radians(),
|
||||||
|
..default()
|
||||||
|
}.into(),
|
||||||
transform: Transform::from_xyz(0., camera_hight, 0.),
|
transform: Transform::from_xyz(0., camera_hight, 0.),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -82,13 +82,13 @@ fn rotate_camera(
|
||||||
camera.rotation_limit_top,
|
camera.rotation_limit_top,
|
||||||
);
|
);
|
||||||
let x_rotation = Quat::from_axis_angle(Vec3::X, camera.rotation.x);
|
let x_rotation = Quat::from_axis_angle(Vec3::X, camera.rotation.x);
|
||||||
info!("{}", x_rotation);
|
//info!("{}", x_rotation);
|
||||||
|
|
||||||
transform.rotation = x_rotation;
|
transform.rotation = x_rotation;
|
||||||
|
|
||||||
camera.rotation.y -= event.delta.x * camera.mouse_gain;
|
camera.rotation.y -= event.delta.x * camera.mouse_gain;
|
||||||
let y_rotation = Quat::from_axis_angle(Vec3::Y, camera.rotation.y);
|
let y_rotation = Quat::from_axis_angle(Vec3::Y, camera.rotation.y);
|
||||||
info!("{}", y_rotation);
|
//info!("{}", y_rotation);
|
||||||
|
|
||||||
rotatable.rotation = y_rotation;
|
rotatable.rotation = y_rotation;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
mod gun_framework;
|
||||||
25
src/weapon_framework/gun_framework.rs
Normal file
25
src/weapon_framework/gun_framework.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
enum GunType {
|
||||||
|
MachineGun,
|
||||||
|
SMG,
|
||||||
|
Pistol,
|
||||||
|
Rifle,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct GunStats {
|
||||||
|
gun_type: GunType,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GunUtils {
|
||||||
|
fn shoot(&mut self);
|
||||||
|
fn reload(&mut self);
|
||||||
|
fn get_ammo_count(&self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GunBase {
|
||||||
|
gun_stats: GunStats,
|
||||||
|
gun_utils: dyn GunUtils,
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue