This commit is contained in:
Back777space
2025-04-05 22:06:08 +02:00
parent 4dd5b14ea1
commit 2f42713a9d
7 changed files with 410 additions and 124 deletions

View File

@@ -30,8 +30,8 @@ pub(crate) struct AudioAssets {}
#[derive(AssetCollection, Resource, Clone)]
pub(crate) struct GltfAssets {
#[asset(key = "wall")]
pub(crate) wall: Handle<Gltf>,
// #[asset(key = "wall")]
// pub(crate) wall: Handle<Gltf>,
}
#[derive(AssetCollection, Resource, Clone)]

View File

@@ -11,7 +11,7 @@ fn spawn_level(
models: Res<Assets<Gltf>>,
gltf_assets: Res<GltfAssets>
) {
let gltf = models.get(&gltf_assets.wall).unwrap();
// let gltf = models.get(&gltf_assets.wall).unwrap();
commands.spawn(SceneRoot(gltf.scenes[0].clone()));
// commands.spawn(SceneRoot(gltf.scenes[0].clone()));
}

View File

@@ -1,11 +1,11 @@
use asset_loading::ImageAssets;
use bevy::prelude::*;
use bevy_rapier3d::prelude::*;
mod asset_loading;
mod bevy_plugin;
mod level_instantiation;
mod main_menu;
mod physics;
mod player;
fn main() {
@@ -13,10 +13,11 @@ fn main() {
.add_plugins((
bevy_plugin::plugin,
asset_loading::plugin,
physics::plugin,
level_instantiation::map_plugin,
player::plugin,
main_menu::plugin,
RapierPhysicsPlugin::<NoUserData>::default(),
RapierDebugRenderPlugin::default(),
))
.init_state::<GameState>()
.add_systems(OnEnter(GameState::Playing), setup)
@@ -49,11 +50,17 @@ fn setup(
MeshMaterial3d(materials.add(Color::WHITE)),
Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
));
commands.spawn((
RigidBody::Fixed,
Collider::cylinder(0.1, 4.0)
));
// cube
commands.spawn((
Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
Transform::from_xyz(3.0, 0.5, 0.0),
RigidBody::Fixed,
Collider::cuboid(0.5, 0.5, 0.5),
));
// light
commands.spawn((

View File

@@ -1,72 +0,0 @@
use bevy::prelude::*;
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
pub struct Velocity(pub Vec3);
/// The actual position of the player in the physics simulation.
/// This is separate from the `Transform`, which is merely a visual representation.
///
/// If you want to make sure that this component is always initialized
/// with the same value as the `Transform`'s translation, you can
/// use a [component lifecycle hook](https://docs.rs/bevy/0.14.0/bevy/ecs/component/struct.ComponentHooks.html)
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
pub struct PhysicalTranslation(pub Vec3);
/// The value [`PhysicalTranslation`] had in the last fixed timestep.
/// Used for interpolation in the `interpolate_rendered_transform` system.
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
pub struct PreviousPhysicalTranslation(pub Vec3);
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
pub struct AccumulatedInput(pub Vec3);
pub fn plugin(app: &mut App) {
app.add_systems(
RunFixedMainLoop,
interpolate_rendered_transform.in_set(RunFixedMainLoopSystem::AfterFixedMainLoop),
)
.add_systems(FixedUpdate, step);
}
pub fn interpolate_rendered_transform(
fixed_time: Res<Time<Fixed>>,
mut query: Query<(
&mut Transform,
&PhysicalTranslation,
&PreviousPhysicalTranslation,
)>,
) {
for (mut transform, current_physical_translation, previous_physical_translation) in
query.iter_mut()
{
let previous = previous_physical_translation.0;
let current = current_physical_translation.0;
// The overstep fraction is a value between 0 and 1 that tells us how far we are between two fixed timesteps.
let alpha = fixed_time.overstep_fraction();
let rendered_translation = previous.lerp(current, alpha);
transform.translation = rendered_translation;
}
}
pub fn step(
fixed_time: Res<Time<Fixed>>,
mut query: Query<(
&mut PhysicalTranslation,
&mut PreviousPhysicalTranslation,
&mut AccumulatedInput,
&Velocity,
)>,
) {
for (
mut current_physical_translation,
mut previous_physical_translation,
mut input,
velocity,
) in query.iter_mut()
{
previous_physical_translation.0 = current_physical_translation.0;
current_physical_translation.0 += velocity.0 * fixed_time.delta_secs();
input.0 = Vec3::ZERO;
}
}

View File

@@ -1,11 +1,10 @@
use crate::{
GameState,
physics::{AccumulatedInput, PhysicalTranslation, PreviousPhysicalTranslation, Velocity},
};
use bevy::{
input::mouse::AccumulatedMouseMotion, pbr::NotShadowCaster, prelude::*,
render::view::RenderLayers, window::PrimaryWindow,
};
use bevy_rapier3d::prelude::*;
use crate::GameState;
#[derive(Debug, Component)]
pub struct Player;
@@ -21,24 +20,24 @@ impl Default for CameraSensitivity {
#[derive(Debug, Component)]
struct WorldModelCamera;
#[derive(Debug, Component, Default)]
pub struct PlayerInput {
movement_direction: Vec3,
}
pub fn plugin(app: &mut App) {
app.add_systems(OnEnter(GameState::Playing), (init_player, hide_cursor))
.add_systems(Update, move_camera.run_if(in_state(GameState::Playing)))
.add_systems(
RunFixedMainLoop,
handle_input
.in_set(RunFixedMainLoopSystem::BeforeFixedMainLoop)
.run_if(in_state(GameState::Playing)),
Update,
(move_camera, handle_input).run_if(in_state(GameState::Playing)),
)
.add_systems(
FixedUpdate,
apply_player_movement.run_if(in_state(GameState::Playing)),
);
}
/// Used implicitly by all entities without a `RenderLayers` component.
/// Our world model camera and all objects other than the player are on this layer.
/// The light source belongs to both layers.
// const DEFAULT_RENDER_LAYER: usize = 0;
/// Used by the view model camera and the player's arm.
/// The light source belongs to both layers.
/// used by the view model camera and the player's arm.
const STATIC_LAYER: usize = 1;
pub fn init_player(
@@ -53,12 +52,23 @@ pub fn init_player(
.spawn((
Player,
CameraSensitivity::default(),
PlayerInput::default(),
// rapier
RigidBody::Dynamic,
Collider::capsule(Vec3::new(0.0, -0.5, 0.0), Vec3::new(0.0, 0.5, 0.0), 0.5),
Velocity::zero(),
LockedAxes::ROTATION_LOCKED,
Damping {
linear_damping: 6.0,
angular_damping: 1.0,
},
Transform::from_xyz(0.0, 1.0, 0.0),
GlobalTransform::default(),
Visibility::default(),
AccumulatedInput::default(),
Velocity::default(),
PhysicalTranslation(Vec3::new(0.0, 1.0, 0.0)),
PreviousPhysicalTranslation(Vec3::new(0.0, 1.0, 0.0)),
InheritedVisibility::default(),
ViewVisibility::default(),
))
.with_children(|parent| {
parent.spawn((
@@ -68,11 +78,14 @@ pub fn init_player(
fov: 90.0_f32.to_radians(),
..default()
}),
Transform::default(),
GlobalTransform::default(),
Visibility::default(),
InheritedVisibility::default(),
ViewVisibility::default(),
));
// we use a second layer ("framebuffer") to draw the player's arm on
// there also a second camera that only views this buffer
// this makes it easy because the second camera doesn't move with the player
// camera voor pitslampke
parent.spawn((
Camera3d::default(),
Camera {
@@ -84,19 +97,29 @@ pub fn init_player(
..default()
}),
RenderLayers::layer(STATIC_LAYER),
Transform::default(),
GlobalTransform::default(),
Visibility::default(),
InheritedVisibility::default(),
ViewVisibility::default(),
));
// pitslampke
parent.spawn((
Mesh3d(arm),
MeshMaterial3d(arm_material),
Transform::from_xyz(0.2, -0.1, -0.25),
GlobalTransform::default(),
RenderLayers::layer(STATIC_LAYER),
NotShadowCaster,
Visibility::default(),
InheritedVisibility::default(),
ViewVisibility::default(),
));
});
}
fn hide_cursor(mut windows: Query<&mut Window, With<PrimaryWindow>>) {
// Query returns one window typically.
for mut window in windows.iter_mut() {
window.cursor_options.visible = false;
}
@@ -126,35 +149,56 @@ pub fn move_camera(
pub fn handle_input(
keyboard_input: Res<ButtonInput<KeyCode>>,
mut query: Query<(&Transform, &mut AccumulatedInput, &mut Velocity), With<Player>>,
mut query: Query<(&Transform, &mut PlayerInput), With<Player>>,
) {
const SPEED: f32 = 2.0;
for (transform, mut input, mut velocity) in query.iter_mut() {
let forward = transform.forward(); // Forward direction (z axis)
let right = transform.right(); // Right direction (x axis)
for (transform, mut input) in query.iter_mut() {
let forward = transform.forward();
let right = transform.right();
let mut movement_direction = Vec3::ZERO;
if keyboard_input.pressed(KeyCode::KeyW) {
input.x += forward.x;
input.z += forward.z;
movement_direction += Vec3::new(forward.x, 0.0, forward.z).normalize_or_zero();
}
if keyboard_input.pressed(KeyCode::KeyS) {
input.x -= forward.x;
input.z -= forward.z;
movement_direction -= Vec3::new(forward.x, 0.0, forward.z).normalize_or_zero();
}
if keyboard_input.pressed(KeyCode::KeyA) {
input.x -= right.x;
input.z -= right.z;
movement_direction -= Vec3::new(right.x, 0.0, right.z).normalize_or_zero();
}
if keyboard_input.pressed(KeyCode::KeyD) {
input.x += right.x;
input.z += right.z;
movement_direction += Vec3::new(right.x, 0.0, right.z).normalize_or_zero();
}
if keyboard_input.pressed(KeyCode::Space) {
input.y += 1.0;
movement_direction += Vec3::Y;
}
if keyboard_input.pressed(KeyCode::ShiftLeft) {
input.y -= 1.0;
movement_direction -= Vec3::Y;
}
velocity.0 = input.normalize_or_zero() * SPEED;
input.movement_direction = movement_direction.normalize_or_zero();
}
}
pub fn apply_player_movement(
mut player_query: Query<(&PlayerInput, &mut Velocity), With<Player>>,
) {
const SPEED: f32 = 3.0;
const JUMP_FORCE: f32 = 4.0;
for (input, mut velocity) in player_query.iter_mut() {
let horizontal_movement = Vec3::new(
input.movement_direction.x * SPEED,
0.0,
input.movement_direction.z * SPEED,
);
velocity.linvel.x = horizontal_movement.x;
velocity.linvel.z = horizontal_movement.z;
if input.movement_direction.y > 0.0 {
velocity.linvel.y = JUMP_FORCE;
} else if input.movement_direction.y < 0.0 {
velocity.linvel.y = -SPEED;
}
}
}