beginning of interaction

This commit is contained in:
LorrensP-2158466
2025-04-05 22:11:24 +02:00
parent 4a9dc86fc0
commit 8fc63fdb50
10 changed files with 3301 additions and 447 deletions

3571
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,3 +6,6 @@ edition = "2024"
[dependencies]
bevy = { version="0.15.3", features = ["jpeg"]}
bevy_asset_loader = { version ="0.22.0", features = ["standard_dynamic_assets"] }
bevy_egui = "0.33.0"
bevy_rapier3d = "0.29.0"
bevy_xpbd_3d = "0.5.0"

Binary file not shown.

View File

@@ -0,0 +1 @@

8
src/interaction/mod.rs Normal file
View File

@@ -0,0 +1,8 @@
use bevy::prelude::*;
mod objects;
mod ui;
pub fn plugin(app: &mut App) {
app.add_plugins((ui::plugin, objects::plugin));
}

View File

@@ -0,0 +1,28 @@
use bevy::prelude::*;
use crate::{GameState, asset_loading::GltfAssets};
pub fn plugin(app: &mut App) {
app.add_systems(OnEnter(GameState::Playing), spawn);
}
#[derive(Component)]
pub struct Interact;
fn spawn(mut commands: Commands, models: Res<Assets<Gltf>>, gltf_assets: Res<GltfAssets>) {
let hammer = gltf_assets
.library
.get("meshes/library/hammer.glb")
.unwrap();
let hammer = models.get(hammer).unwrap();
let asset = hammer.default_scene.as_ref().unwrap();
// hammer
commands.spawn((
Transform::from_xyz(0.0, 1.0, 0.0).with_scale(Vec3::splat(0.1)),
Interact,
SceneRoot(asset.clone()),
));
//tools
}

78
src/interaction/ui.rs Normal file
View File

@@ -0,0 +1,78 @@
use crate::GameState;
use crate::player::{Player, PlayerAction};
use crate::util::{single, single_mut};
use bevy::{prelude::*, window::PrimaryWindow};
use bevy_egui::{EguiContexts, EguiPlugin, egui};
use std::f32::consts::TAU;
use super::objects::Interact;
pub(super) fn plugin(app: &mut App) {
app.add_plugins(EguiPlugin)
.init_resource::<InteractionOpportunity>()
.add_systems(
Update,
(update_interaction_opportunities, display_interaction_prompt)
.chain()
.run_if(in_state(GameState::Playing)),
);
}
#[derive(Debug, Clone, Eq, PartialEq, Resource, Default)]
struct InteractionOpportunity(Option<Entity>);
fn update_interaction_opportunities(
player_query: Query<&GlobalTransform, With<Player>>,
parents: Query<&Parent>,
target_query: Query<
(Entity, &GlobalTransform),
(Without<Player>, Without<Camera>, With<Interact>),
>,
mut interaction_opportunity: ResMut<InteractionOpportunity>,
) {
interaction_opportunity.0 = None;
let player_transform = single!(player_query);
let (target_entity, target_transform) = single!(target_query);
let player_translation = player_transform.translation();
let target_translation = target_transform.translation();
if player_translation.distance(target_translation) <= 2.0 {
interaction_opportunity.0.replace(target_entity);
}
}
fn is_facing_target(
player: Vec3,
target: Vec3,
camera_transform: Transform,
camera: &Camera,
) -> bool {
let camera_to_player = camera_transform.forward();
let player_to_target = target - player;
let angle = camera_to_player.angle_between(player_to_target);
angle < TAU / 8.
}
fn display_interaction_prompt(
interaction_opportunity: Res<InteractionOpportunity>,
mut egui_contexts: EguiContexts,
action: Query<&PlayerAction, With<Player>>,
primary_windows: Query<&Window, With<PrimaryWindow>>,
) {
let Some(opportunity) = interaction_opportunity.0 else {
return;
};
let window = single!(primary_windows);
egui::Window::new("Interaction")
.collapsible(false)
.title_bar(false)
.auto_sized()
.fixed_pos(egui::Pos2::new(window.width() / 2., window.height() / 2.))
.show(egui_contexts.ctx_mut(), |ui| {
ui.label("E: Pick Up");
});
let action = single!(action);
}

View File

@@ -3,20 +3,23 @@ use bevy::prelude::*;
mod asset_loading;
mod bevy_plugin;
mod interaction;
mod level_instantiation;
mod main_menu;
mod physics;
mod player;
mod util;
fn main() {
App::new()
.add_plugins((
bevy_plugin::plugin,
asset_loading::plugin,
main_menu::plugin,
physics::plugin,
level_instantiation::map_plugin,
player::plugin,
main_menu::plugin,
interaction::plugin,
))
.init_state::<GameState>()
.add_systems(OnEnter(GameState::Playing), setup)

View File

@@ -52,6 +52,7 @@ pub fn init_player(
commands
.spawn((
Player,
PlayerAction::default(),
CameraSensitivity::default(),
Transform::from_xyz(0.0, 1.0, 0.0),
Visibility::default(),
@@ -124,37 +125,62 @@ pub fn move_camera(
}
}
#[derive(Component, Debug, Clone, Copy, Eq, PartialEq, Hash, Reflect, Default)]
pub(crate) enum PlayerAction {
#[default]
Move,
Sprint,
Jump,
Interact,
}
pub fn handle_input(
keyboard_input: Res<ButtonInput<KeyCode>>,
mut query: Query<(&Transform, &mut AccumulatedInput, &mut Velocity), With<Player>>,
mut query: Query<
(
&Transform,
&mut AccumulatedInput,
&mut Velocity,
&mut PlayerAction,
),
With<Player>,
>,
) {
const SPEED: f32 = 2.0;
for (transform, mut input, mut velocity) in query.iter_mut() {
for (transform, mut input, mut velocity, mut action) in query.iter_mut() {
let forward = transform.forward(); // Forward direction (z axis)
let right = transform.right(); // Right direction (x axis)
if keyboard_input.pressed(KeyCode::KeyW) {
input.x += forward.x;
input.z += forward.z;
*action = PlayerAction::Move;
}
if keyboard_input.pressed(KeyCode::KeyS) {
input.x -= forward.x;
input.z -= forward.z;
*action = PlayerAction::Move;
}
if keyboard_input.pressed(KeyCode::KeyA) {
input.x -= right.x;
input.z -= right.z;
*action = PlayerAction::Move;
}
if keyboard_input.pressed(KeyCode::KeyD) {
input.x += right.x;
input.z += right.z;
*action = PlayerAction::Move;
}
if keyboard_input.pressed(KeyCode::Space) {
input.y += 1.0;
*action = PlayerAction::Jump;
}
if keyboard_input.pressed(KeyCode::ShiftLeft) {
input.y -= 1.0;
}
if keyboard_input.pressed(KeyCode::KeyE) {
*action = PlayerAction::Interact
}
velocity.0 = input.normalize_or_zero() * SPEED;
}
}

24
src/util.rs Normal file
View File

@@ -0,0 +1,24 @@
macro_rules! single {
($query:expr) => {
match $query.get_single() {
Ok(q) => q,
_ => {
return;
}
}
};
}
macro_rules! single_mut {
($query:expr) => {
match $query.get_single_mut() {
Ok(q) => q,
_ => {
return;
}
}
};
}
pub(crate) use single;
pub(crate) use single_mut;