sprite working

This commit is contained in:
Back777space
2025-04-06 00:52:18 +02:00
22 changed files with 1424 additions and 79 deletions

View File

@@ -31,8 +31,6 @@ pub(crate) struct AudioAssets {}
#[derive(AssetCollection, Resource, Clone)]
pub(crate) struct GltfAssets {
#[asset(key = "house")]
pub(crate) house: Handle<Gltf>,
#[asset(key = "library", collection(typed, mapped))]
pub(crate) library: HashMap<String, Handle<Gltf>>,
}

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,40 @@
use bevy::{gltf::GltfMesh, math::Vec3A, prelude::*, render::mesh::MeshAabb};
use bevy_rapier3d::prelude::{Collider, RigidBody};
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, 100.0, 0.0).with_scale(Vec3::splat(0.1)),
Interact,
RigidBody::Dynamic,
SceneRoot(asset.clone()),
))
.with_children(|parent| {
parent
.spawn(Collider::cuboid(0.8, 10f32, 0.8))
.insert(Transform::from_xyz(0.0, -5.0, 0.0));
parent
.spawn(Collider::cuboid(1.0, 1.0, 4.5))
// Position the collider relative to the rigid-body.
.insert(Transform::from_xyz(0.0, 4.2, 1.0));
});
//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

@@ -12,10 +12,14 @@ fn spawn_level(
gltf_assets: Res<GltfAssets>
) {
println!("LIBRARY: {:?}", gltf_assets.library);
let jumbo = gltf_assets.library.get("meshes/library/wall.glb").unwrap();
let gltf = models.get(jumbo).unwrap();
let mut x_offset = 0.0;
for mesh_name in ["corner_inside", "corner_outside", "wall", "door", "round_door", "round_hole"] {
let path = format!("meshes/library/space_{}.glb", mesh_name);
let handle = gltf_assets.library.get(&path).expect(&format!("Couldn't find {} in library", mesh_name));
let gltf = models.get(handle).expect(&format!("No model for {}", mesh_name));
// commands.spawn(SceneRoot(gltf.scenes[0].clone()));
let asset = gltf.default_scene.as_ref().unwrap();
commands.spawn(SceneRoot(asset.clone()));
let asset = gltf.default_scene.as_ref().expect(&format!("No scene in {}", mesh_name));
commands.spawn((SceneRoot(asset.clone()), TransformBundle::from_transform(Transform::from_xyz(x_offset, 0.0, 0.0))));
x_offset += 2.0;
}
}

View File

@@ -1,20 +1,23 @@
use asset_loading::ImageAssets;
use bevy::prelude::*;
use bevy::{prelude::*};
use bevy_rapier3d::prelude::*;
mod asset_loading;
mod bevy_plugin;
mod interaction;
mod level_instantiation;
mod main_menu;
mod player;
mod util;
fn main() {
App::new()
.add_plugins((
bevy_plugin::plugin,
asset_loading::plugin,
level_instantiation::map_plugin,
main_menu::plugin,
level_instantiation::map_plugin,
interaction::plugin,
RapierPhysicsPlugin::<NoUserData>::default(),
RapierDebugRenderPlugin::default(),
player::plugin,
@@ -47,16 +50,13 @@ fn setup(
MeshMaterial3d(materials.add(image.king.clone())),
Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
));
commands.spawn((
RigidBody::Fixed,
Collider::cylinder(0.1, 4.0)
));
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,
RigidBody::Fixed,
Collider::cuboid(0.5, 0.5, 0.5),
));
// light

View File

@@ -1,10 +1,11 @@
use bevy::{
input::mouse::AccumulatedMouseMotion, prelude::*,
render::view::RenderLayers, window::PrimaryWindow,
input::mouse::AccumulatedMouseMotion, prelude::*, render::view::RenderLayers, transform, window::{self, PrimaryWindow}
};
use bevy_rapier3d::prelude::*;
use crate::{asset_loading::{FlashlightAssets, ImageAssets}, GameState};
pub mod toolbar;
use crate::{asset_loading::{FlashlightAssets}, GameState};
#[derive(Debug, Component)]
pub struct Player;
@@ -26,7 +27,8 @@ pub struct PlayerInput {
}
pub fn plugin(app: &mut App) {
app.add_systems(OnEnter(GameState::Playing), (init_player, hide_cursor))
app.add_plugins(toolbar::plugin)
.add_systems(OnEnter(GameState::Playing), (init_player, hide_cursor))
.add_systems(
Update,
(move_camera, handle_input).run_if(in_state(GameState::Playing)),
@@ -43,14 +45,17 @@ const STATIC_LAYER: usize = 1;
pub fn init_player(
mut commands: Commands,
flashlights: Res<FlashlightAssets>,
images: Res<ImageAssets>,
window: Query<&Window>,
) {
let window = window.single();
commands
.spawn((
Player,
PlayerAction::default(),
CameraSensitivity::default(),
PlayerInput::default(),
toolbar::Item::none(),
// rapier
RigidBody::Dynamic,
Collider::capsule(Vec3::new(0.0, -0.5, 0.0), Vec3::new(0.0, 0.5, 0.0), 0.5),
@@ -60,7 +65,7 @@ pub fn init_player(
linear_damping: 6.0,
angular_damping: 1.0,
},
GravityScale(3.0),
Transform::from_xyz(0.0, 1.0, 0.0),
))
.with_children(|parent| {
@@ -75,26 +80,30 @@ pub fn init_player(
// camera voor pitslampke
parent.spawn((
Camera3d::default(),
Camera2d::default(),
Camera {
order: 1,
..default()
},
RenderLayers::layer(STATIC_LAYER),
));
// pitslampke
let window_size = Vec2::new(window.resolution.width(), window.resolution.height());
let sprite_size = Vec2::new(101.0, 101.0);
let scale = 2.2;
let world_size = sprite_size * scale;
let offset = 70.0;
let mut transform = Transform::from_translation(
Vec3::new(window_size.x / 2.0 - world_size.x / 2.0 - offset, -window_size.y / 2.0 + world_size.y / 2.0, 0.0)
);
transform.scale = Vec3::new(scale, scale, 1.0);
parent.spawn((
Transform::from_xyz(-3.0, -3.0, 0.0),
Sprite {
image: images.king.clone(),
..default()
},
RenderLayers::layer(STATIC_LAYER),
Sprite::from_image(flashlights.flash_hold_4.clone()),
transform,
RenderLayers::layer(STATIC_LAYER),
));
});
commands.spawn(Sprite::from_image(images.king.clone()));
}
fn hide_cursor(mut windows: Query<&mut Window, With<PrimaryWindow>>) {
@@ -125,11 +134,20 @@ 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 PlayerInput), With<Player>>,
mut query: Query<(&Transform, &mut PlayerInput, &mut PlayerAction), With<Player>>,
) {
for (transform, mut input) in query.iter_mut() {
for (transform, mut input, mut action) in query.iter_mut() {
let forward = transform.forward();
let right = transform.right();
let mut movement_direction = Vec3::ZERO;
@@ -152,31 +170,32 @@ pub fn handle_input(
if keyboard_input.pressed(KeyCode::ShiftLeft) {
movement_direction -= Vec3::Y;
}
if keyboard_input.pressed(KeyCode::KeyE) {
*action = PlayerAction::Interact
}
input.movement_direction = movement_direction.normalize_or_zero();
}
}
pub fn apply_player_movement(
mut player_query: Query<(&PlayerInput, &mut Velocity), With<Player>>,
) {
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;
velocity.linvel.y = -SPEED;
}
}
}
}

21
src/player/toolbar.rs Normal file
View File

@@ -0,0 +1,21 @@
use bevy::prelude::*;
use std::default::Default;
use crate::GameState;
use super::Player;
#[derive(Component, Default, Debug)]
pub struct Item(Option<Entity>);
impl Item {
pub fn none() -> Self {
Default::default()
}
}
pub fn plugin(app: &mut App) {
app.add_systems(Update, show_toolbar.run_if(in_state(GameState::Playing)));
}
fn show_toolbar(player_tool_query: Query<&Item, With<Player>>) {}

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;