Blender to bevy work, proxies
This commit is contained in:
parent
bb681decf5
commit
52e5fe7692
@ -9,6 +9,8 @@
|
|||||||
- [ ] Figure out how rotation up and down will work, maybe dividing upper and lower body animations
|
- [ ] Figure out how rotation up and down will work, maybe dividing upper and lower body animations
|
||||||
- [ ] Shuffling feet when rotating
|
- [ ] Shuffling feet when rotating
|
||||||
|
|
||||||
|
|
||||||
|
- [ ] Jump not multiplied by deltatime causing super jumps on low fps
|
||||||
- [ ] Perfect movement
|
- [ ] Perfect movement
|
||||||
- [x] ~~Equipping items~~
|
- [x] ~~Equipping items~~
|
||||||
- [x] ~~Replace items in the same slot, drop them~~
|
- [x] ~~Replace items in the same slot, drop them~~
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
use bevy::{ecs::{component::Component, reflect::ReflectComponent}, reflect::Reflect};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct InPlayerHandsParent;
|
4
src/comps/core/markers/proxy/character/mod.rs
Normal file
4
src/comps/core/markers/proxy/character/mod.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub mod player_character;
|
||||||
|
pub mod player_hitbox;
|
||||||
|
pub mod in_player_hands_parent;
|
||||||
|
pub mod player_eye;
|
@ -0,0 +1,6 @@
|
|||||||
|
use bevy::{ecs::{component::Component, reflect::ReflectComponent}, reflect::Reflect};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct PlayerCharacter;
|
6
src/comps/core/markers/proxy/character/player_eye.rs
Normal file
6
src/comps/core/markers/proxy/character/player_eye.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
use bevy::{ecs::{component::Component, reflect::ReflectComponent}, reflect::Reflect};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct PlayerEye;
|
13
src/comps/core/markers/proxy/character/player_hitbox.rs
Normal file
13
src/comps/core/markers/proxy/character/player_hitbox.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
use bevy::{ecs::{component::Component, reflect::ReflectComponent}, reflect::Reflect};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub enum PlayerHitBox {
|
||||||
|
Head,
|
||||||
|
Eyes,
|
||||||
|
#[default]
|
||||||
|
Hands,
|
||||||
|
Thorax,
|
||||||
|
Legs,
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
pub mod character;
|
||||||
|
pub mod plugin;
|
||||||
|
pub mod physics;
|
2
src/comps/core/markers/proxy/physics/mod.rs
Normal file
2
src/comps/core/markers/proxy/physics/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod rapier;
|
||||||
|
pub mod utils;
|
101
src/comps/core/markers/proxy/physics/rapier.rs
Normal file
101
src/comps/core/markers/proxy/physics/rapier.rs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
// use bevy::render::primitives::Aabb;
|
||||||
|
use bevy_rapier3d::geometry::Collider as RapierCollider;
|
||||||
|
use bevy_rapier3d::prelude::{ActiveCollisionTypes, ActiveEvents, ComputedColliderShape};
|
||||||
|
|
||||||
|
use super::utils::*;
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub enum Collider {
|
||||||
|
Ball(f32),
|
||||||
|
Cuboid(Vec3),
|
||||||
|
Capsule(Vec3, Vec3, f32),
|
||||||
|
#[default]
|
||||||
|
Mesh,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub enum AutoAABBCollider {
|
||||||
|
#[default]
|
||||||
|
Cuboid,
|
||||||
|
Ball,
|
||||||
|
Capsule,
|
||||||
|
}
|
||||||
|
|
||||||
|
// replaces all physics stand-ins with the actual rapier types
|
||||||
|
pub fn physics_replace_proxies(
|
||||||
|
meshes: Res<Assets<Mesh>>,
|
||||||
|
mesh_handles: Query<&Handle<Mesh>>,
|
||||||
|
mut proxy_colliders: Query<
|
||||||
|
(Entity, &Collider, &Name, &mut Visibility),
|
||||||
|
(Without<RapierCollider>, Added<Collider>),
|
||||||
|
>,
|
||||||
|
// needed for tri meshes
|
||||||
|
children: Query<&Children>,
|
||||||
|
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
for proxy_colider in proxy_colliders.iter_mut() {
|
||||||
|
let (entity, collider_proxy, name, mut visibility) = proxy_colider;
|
||||||
|
// we hide the collider meshes: perhaps they should be removed altogether once processed ?
|
||||||
|
if name.ends_with("_collider") || name.ends_with("_sensor") {
|
||||||
|
*visibility = Visibility::Hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rapier_collider: RapierCollider;
|
||||||
|
match collider_proxy {
|
||||||
|
Collider::Ball(radius) => {
|
||||||
|
println!("proxy: ball");
|
||||||
|
rapier_collider = RapierCollider::ball(*radius);
|
||||||
|
commands.entity(entity)
|
||||||
|
.insert(rapier_collider)
|
||||||
|
.insert(ActiveEvents::COLLISION_EVENTS) // FIXME: this is just for demo purposes !!!
|
||||||
|
;
|
||||||
|
}
|
||||||
|
Collider::Cuboid(size) => {
|
||||||
|
println!("proxy: cuboid");
|
||||||
|
rapier_collider = RapierCollider::cuboid(size.x, size.y, size.z);
|
||||||
|
commands.entity(entity)
|
||||||
|
.insert(rapier_collider)
|
||||||
|
.insert(ActiveEvents::COLLISION_EVENTS) // FIXME: this is just for demo purposes !!!
|
||||||
|
;
|
||||||
|
}
|
||||||
|
Collider::Capsule(a, b, radius) => {
|
||||||
|
println!("proxy: capsule");
|
||||||
|
rapier_collider = RapierCollider::capsule(*a, *b, *radius);
|
||||||
|
commands.entity(entity)
|
||||||
|
.insert(rapier_collider)
|
||||||
|
.insert(ActiveEvents::COLLISION_EVENTS) // FIXME: this is just for demo purposes !!!
|
||||||
|
;
|
||||||
|
}
|
||||||
|
Collider::Mesh => {
|
||||||
|
println!("proxy: mesh");
|
||||||
|
for (_, collider_mesh) in
|
||||||
|
Mesh::search_in_children(entity, &children, &meshes, &mesh_handles)
|
||||||
|
{
|
||||||
|
rapier_collider = RapierCollider::from_bevy_mesh(
|
||||||
|
collider_mesh,
|
||||||
|
&ComputedColliderShape::TriMesh,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
commands
|
||||||
|
.entity(entity)
|
||||||
|
.insert(rapier_collider)
|
||||||
|
// FIXME: this is just for demo purposes !!!
|
||||||
|
.insert(
|
||||||
|
ActiveCollisionTypes::default()
|
||||||
|
| ActiveCollisionTypes::KINEMATIC_STATIC
|
||||||
|
| ActiveCollisionTypes::STATIC_STATIC
|
||||||
|
| ActiveCollisionTypes::DYNAMIC_STATIC,
|
||||||
|
)
|
||||||
|
.insert(ActiveEvents::COLLISION_EVENTS);
|
||||||
|
// .insert(ActiveEvents::COLLISION_EVENTS)
|
||||||
|
// break;
|
||||||
|
// RapierCollider::convex_hull(points)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
175
src/comps/core/markers/proxy/physics/utils.rs
Normal file
175
src/comps/core/markers/proxy/physics/utils.rs
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy::render::mesh::{MeshVertexAttributeId, PrimitiveTopology, VertexAttributeValues};
|
||||||
|
// TAKEN VERBATIB FROM https://github.com/janhohenheim/foxtrot/blob/src/util/trait_extension.rs
|
||||||
|
|
||||||
|
pub(crate) trait Vec3Ext: Copy {
|
||||||
|
fn is_approx_zero(self) -> bool;
|
||||||
|
fn split(self, up: Vec3) -> SplitVec3;
|
||||||
|
}
|
||||||
|
impl Vec3Ext for Vec3 {
|
||||||
|
#[inline]
|
||||||
|
fn is_approx_zero(self) -> bool {
|
||||||
|
self.length_squared() < 1e-5
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn split(self, up: Vec3) -> SplitVec3 {
|
||||||
|
let vertical = up * self.dot(up);
|
||||||
|
let horizontal = self - vertical;
|
||||||
|
SplitVec3 {
|
||||||
|
vertical,
|
||||||
|
horizontal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub(crate) struct SplitVec3 {
|
||||||
|
pub(crate) vertical: Vec3,
|
||||||
|
pub(crate) horizontal: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait Vec2Ext: Copy {
|
||||||
|
fn is_approx_zero(self) -> bool;
|
||||||
|
fn x0y(self) -> Vec3;
|
||||||
|
}
|
||||||
|
impl Vec2Ext for Vec2 {
|
||||||
|
#[inline]
|
||||||
|
fn is_approx_zero(self) -> bool {
|
||||||
|
self.length_squared() < 1e-5
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn x0y(self) -> Vec3 {
|
||||||
|
Vec3::new(self.x, 0., self.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait MeshExt {
|
||||||
|
fn transform(&mut self, transform: Transform);
|
||||||
|
fn transformed(&self, transform: Transform) -> Mesh;
|
||||||
|
fn read_coords_mut(&mut self, id: impl Into<MeshVertexAttributeId>) -> &mut Vec<[f32; 3]>;
|
||||||
|
fn search_in_children<'a>(
|
||||||
|
parent: Entity,
|
||||||
|
children: &'a Query<&Children>,
|
||||||
|
meshes: &'a Assets<Mesh>,
|
||||||
|
mesh_handles: &'a Query<&Handle<Mesh>>,
|
||||||
|
) -> Vec<(Entity, &'a Mesh)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MeshExt for Mesh {
|
||||||
|
fn transform(&mut self, transform: Transform) {
|
||||||
|
for coords in self.read_coords_mut(Mesh::ATTRIBUTE_POSITION.clone()) {
|
||||||
|
let vec3 = (*coords).into();
|
||||||
|
let transformed = transform.transform_point(vec3);
|
||||||
|
*coords = transformed.into();
|
||||||
|
}
|
||||||
|
for normal in self.read_coords_mut(Mesh::ATTRIBUTE_NORMAL.clone()) {
|
||||||
|
let vec3 = (*normal).into();
|
||||||
|
let transformed = transform.rotation.mul_vec3(vec3);
|
||||||
|
*normal = transformed.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transformed(&self, transform: Transform) -> Mesh {
|
||||||
|
let mut mesh = self.clone();
|
||||||
|
mesh.transform(transform);
|
||||||
|
mesh
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_coords_mut(&mut self, id: impl Into<MeshVertexAttributeId>) -> &mut Vec<[f32; 3]> {
|
||||||
|
// Guaranteed by Bevy for the current usage
|
||||||
|
match self
|
||||||
|
.attribute_mut(id)
|
||||||
|
.expect("Failed to read unknown mesh attribute")
|
||||||
|
{
|
||||||
|
VertexAttributeValues::Float32x3(values) => values,
|
||||||
|
// Guaranteed by Bevy for the current usage
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_in_children<'a>(
|
||||||
|
parent: Entity,
|
||||||
|
children_query: &'a Query<&Children>,
|
||||||
|
meshes: &'a Assets<Mesh>,
|
||||||
|
mesh_handles: &'a Query<&Handle<Mesh>>,
|
||||||
|
) -> Vec<(Entity, &'a Mesh)> {
|
||||||
|
if let Ok(children) = children_query.get(parent) {
|
||||||
|
let mut result: Vec<_> = children
|
||||||
|
.iter()
|
||||||
|
.filter_map(|entity| mesh_handles.get(*entity).ok().map(|mesh| (*entity, mesh)))
|
||||||
|
.map(|(entity, mesh_handle)| {
|
||||||
|
(
|
||||||
|
entity,
|
||||||
|
meshes
|
||||||
|
.get(mesh_handle)
|
||||||
|
.expect("Failed to get mesh from handle"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(|(entity, mesh)| {
|
||||||
|
assert_eq!(mesh.primitive_topology(), PrimitiveTopology::TriangleList);
|
||||||
|
(entity, mesh)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let mut inner_result = children
|
||||||
|
.iter()
|
||||||
|
.flat_map(|entity| {
|
||||||
|
Self::search_in_children(*entity, children_query, meshes, mesh_handles)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
result.append(&mut inner_result);
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait F32Ext: Copy {
|
||||||
|
fn is_approx_zero(self) -> bool;
|
||||||
|
fn squared(self) -> f32;
|
||||||
|
fn lerp(self, other: f32, ratio: f32) -> f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl F32Ext for f32 {
|
||||||
|
#[inline]
|
||||||
|
fn is_approx_zero(self) -> bool {
|
||||||
|
self.abs() < 1e-5
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn squared(self) -> f32 {
|
||||||
|
self * self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn lerp(self, other: f32, ratio: f32) -> f32 {
|
||||||
|
self.mul_add(1. - ratio, other * ratio)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait TransformExt: Copy {
|
||||||
|
fn horizontally_looking_at(self, target: Vec3, up: Vec3) -> Transform;
|
||||||
|
fn lerp(self, other: Transform, ratio: f32) -> Transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TransformExt for Transform {
|
||||||
|
fn horizontally_looking_at(self, target: Vec3, up: Vec3) -> Transform {
|
||||||
|
let direction = target - self.translation;
|
||||||
|
let horizontal_direction = direction - up * direction.dot(up);
|
||||||
|
let look_target = self.translation + horizontal_direction;
|
||||||
|
self.looking_at(look_target, up)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lerp(self, other: Transform, ratio: f32) -> Transform {
|
||||||
|
let translation = self.translation.lerp(other.translation, ratio);
|
||||||
|
let rotation = self.rotation.slerp(other.rotation, ratio);
|
||||||
|
let scale = self.scale.lerp(other.scale, ratio);
|
||||||
|
Transform {
|
||||||
|
translation,
|
||||||
|
rotation,
|
||||||
|
scale,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
src/comps/core/markers/proxy/plugin.rs
Normal file
23
src/comps/core/markers/proxy/plugin.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
use bevy::app::{Plugin, Update};
|
||||||
|
|
||||||
|
use super::{character::{player_hitbox::PlayerHitBox, player_character::PlayerCharacter, player_eye::PlayerEye, in_player_hands_parent::InPlayerHandsParent}, physics::{rapier::{AutoAABBCollider, physics_replace_proxies}, self}};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub struct ProxyComponentsPlugin;
|
||||||
|
|
||||||
|
impl Plugin for ProxyComponentsPlugin {
|
||||||
|
fn build(&self, app: &mut bevy::prelude::App) {
|
||||||
|
// Character
|
||||||
|
app.register_type::<PlayerHitBox>();
|
||||||
|
app.register_type::<PlayerCharacter>();
|
||||||
|
app.register_type::<PlayerEye>();
|
||||||
|
app.register_type::<InPlayerHandsParent>();
|
||||||
|
|
||||||
|
// Physics
|
||||||
|
app
|
||||||
|
.register_type::<AutoAABBCollider>()
|
||||||
|
.register_type::<physics::rapier::Collider>()
|
||||||
|
.add_systems(Update, physics_replace_proxies);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::{prelude::*, gltf::Gltf};
|
||||||
use bevy_rapier3d::prelude::*;
|
use bevy_rapier3d::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -16,7 +16,7 @@ use crate::{
|
|||||||
player_values_state::PlayerValuesState,
|
player_values_state::PlayerValuesState,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup::{equipment::EquipmentChangeEvent, load_state::GameLoadState},
|
setup::{equipment::EquipmentChangeEvent, load_state::GameLoadState, assets::{GltfAsset, GltfAssets}},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::spawn_point::SpawnPoint;
|
use super::spawn_point::SpawnPoint;
|
||||||
@ -41,12 +41,27 @@ pub fn player_spawner(
|
|||||||
mut game_load_state: ResMut<GameLoadState>,
|
mut game_load_state: ResMut<GameLoadState>,
|
||||||
mut equipment_change_event_writer: EventWriter<EquipmentChangeEvent>,
|
mut equipment_change_event_writer: EventWriter<EquipmentChangeEvent>,
|
||||||
player_values_state: Res<PlayerValuesState>,
|
player_values_state: Res<PlayerValuesState>,
|
||||||
|
assets: Res<GltfAssets>,
|
||||||
|
loaded_gltf_assets: Res<Assets<Gltf>>,
|
||||||
) {
|
) {
|
||||||
if game_load_state.player_loaded || !game_load_state.is_everything_except_player_loaded() {
|
if game_load_state.player_loaded || !game_load_state.is_everything_except_player_loaded() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (player_spawn_point_entity, player_spawn_point) in player_sp_query.iter() {
|
for (player_spawn_point_entity, player_spawn_point) in player_sp_query.iter() {
|
||||||
|
let mut plyer_transform = Transform::from_xyz(25.0, 0.0, 25.0).with_scale(Vec3 { x: 3.0, y: 3.0, z: 3.0 });
|
||||||
|
commands.spawn(
|
||||||
|
(
|
||||||
|
SceneBundle {
|
||||||
|
scene: loaded_gltf_assets.get(assets.assets[2].asset.clone()).unwrap().scenes[0].clone(),
|
||||||
|
transform: plyer_transform,
|
||||||
|
visibility: Visibility::Visible,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Name::new("Player component")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
// Spawn hand
|
// Spawn hand
|
||||||
let player_hand = commands
|
let player_hand = commands
|
||||||
.spawn((PlayerHand, Name::new("Player Hand")))
|
.spawn((PlayerHand, Name::new("Player Hand")))
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_gltf_components::ComponentsFromGltfPlugin;
|
use bevy_gltf_components::ComponentsFromGltfPlugin;
|
||||||
use bevy_rapier3d::prelude::*;
|
use bevy_rapier3d::prelude::*;
|
||||||
|
use comps::core::markers::proxy;
|
||||||
use scenes::scene1;
|
use scenes::scene1;
|
||||||
use ui::{editor::plugin::MainEditorUiPlugin, game::plugin::MainGameUIPlugin};
|
use ui::{editor::plugin::MainEditorUiPlugin, game::plugin::MainGameUIPlugin};
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ fn setup_plugins(application: &mut App) {
|
|||||||
.add_plugins(RapierPhysicsPlugin::<NoUserData>::default())
|
.add_plugins(RapierPhysicsPlugin::<NoUserData>::default())
|
||||||
//.add_plugins(bevy_egui::EguiPlugin)
|
//.add_plugins(bevy_egui::EguiPlugin)
|
||||||
//.add_plugins(WorldInspectorPlugin::new())
|
//.add_plugins(WorldInspectorPlugin::new())
|
||||||
|
.add_plugins(proxy::plugin::ProxyComponentsPlugin)
|
||||||
.add_plugins(MainGameUIPlugin)
|
.add_plugins(MainGameUIPlugin)
|
||||||
.add_plugins(MainEditorUiPlugin)
|
.add_plugins(MainEditorUiPlugin)
|
||||||
.add_plugins(RapierDebugRenderPlugin::default());
|
.add_plugins(RapierDebugRenderPlugin::default());
|
||||||
|
Loading…
Reference in New Issue
Block a user