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
|
||||
- [ ] Shuffling feet when rotating
|
||||
|
||||
|
||||
- [ ] Jump not multiplied by deltatime causing super jumps on low fps
|
||||
- [ ] Perfect movement
|
||||
- [x] ~~Equipping items~~
|
||||
- [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;
|
|
@ -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;
|
|
@ -0,0 +1,6 @@
|
|||
use bevy::{ecs::{component::Component, reflect::ReflectComponent}, reflect::Reflect};
|
||||
|
||||
|
||||
#[derive(Component, Reflect, Default, Debug)]
|
||||
#[reflect(Component)]
|
||||
pub struct PlayerEye;
|
|
@ -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;
|
|
@ -0,0 +1,2 @@
|
|||
pub mod rapier;
|
||||
pub mod utils;
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 crate::{
|
||||
|
@ -16,7 +16,7 @@ use crate::{
|
|||
player_values_state::PlayerValuesState,
|
||||
},
|
||||
},
|
||||
setup::{equipment::EquipmentChangeEvent, load_state::GameLoadState},
|
||||
setup::{equipment::EquipmentChangeEvent, load_state::GameLoadState, assets::{GltfAsset, GltfAssets}},
|
||||
};
|
||||
|
||||
use super::spawn_point::SpawnPoint;
|
||||
|
@ -41,12 +41,27 @@ pub fn player_spawner(
|
|||
mut game_load_state: ResMut<GameLoadState>,
|
||||
mut equipment_change_event_writer: EventWriter<EquipmentChangeEvent>,
|
||||
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() {
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
let player_hand = commands
|
||||
.spawn((PlayerHand, Name::new("Player Hand")))
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy_gltf_components::ComponentsFromGltfPlugin;
|
||||
use bevy_rapier3d::prelude::*;
|
||||
use comps::core::markers::proxy;
|
||||
use scenes::scene1;
|
||||
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(bevy_egui::EguiPlugin)
|
||||
//.add_plugins(WorldInspectorPlugin::new())
|
||||
.add_plugins(proxy::plugin::ProxyComponentsPlugin)
|
||||
.add_plugins(MainGameUIPlugin)
|
||||
.add_plugins(MainEditorUiPlugin)
|
||||
.add_plugins(RapierDebugRenderPlugin::default());
|
||||
|
|
Loading…
Reference in New Issue