Blender to bevy work, proxies

This commit is contained in:
Franklin Blanco 2023-11-16 11:47:13 -08:00
parent bb681decf5
commit 52e5fe7692
13 changed files with 360 additions and 2 deletions

View File

@ -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~~

View File

@ -0,0 +1,6 @@
use bevy::{ecs::{component::Component, reflect::ReflectComponent}, reflect::Reflect};
#[derive(Component, Reflect, Default, Debug)]
#[reflect(Component)]
pub struct InPlayerHandsParent;

View File

@ -0,0 +1,4 @@
pub mod player_character;
pub mod player_hitbox;
pub mod in_player_hands_parent;
pub mod player_eye;

View File

@ -0,0 +1,6 @@
use bevy::{ecs::{component::Component, reflect::ReflectComponent}, reflect::Reflect};
#[derive(Component, Reflect, Default, Debug)]
#[reflect(Component)]
pub struct PlayerCharacter;

View File

@ -0,0 +1,6 @@
use bevy::{ecs::{component::Component, reflect::ReflectComponent}, reflect::Reflect};
#[derive(Component, Reflect, Default, Debug)]
#[reflect(Component)]
pub struct PlayerEye;

View 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,
}

View File

@ -0,0 +1,3 @@
pub mod character;
pub mod plugin;
pub mod physics;

View File

@ -0,0 +1,2 @@
pub mod rapier;
pub mod utils;

View 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)
}
}
}
}
}

View 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,
}
}
}

View 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);
}
}

View File

@ -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")))

View File

@ -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());