gltf prefabs

This commit is contained in:
2024-11-24 00:05:07 -05:00
parent 953650e394
commit 358b88e7fe
8 changed files with 150 additions and 26 deletions

View File

@@ -1,7 +1,10 @@
use asset_loader::create_asset_loader; use asset_loader::create_asset_loader;
use bevy::{gltf::GltfMesh, prelude::*}; use bevy::{
gltf::{GltfMesh, GltfNode},
prelude::*,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use shared::{identifiers::ResourceIdentifier, prefab_defination::*}; use shared::{component_defination::ComponentDefination, identifiers::ResourceIdentifier, prefab_defination::*};
use crate::{ use crate::{
buildings::{ buildings::{
@@ -29,7 +32,7 @@ pub struct BuildingAsset {
pub health: u32, pub health: u32,
pub building_type: BuildingType, pub building_type: BuildingType,
pub children: Option<Vec<PrefabDefination>>, pub components: Option<Vec<ComponentDefination>>,
} }
impl BuildingAsset { impl BuildingAsset {
@@ -40,31 +43,79 @@ impl BuildingAsset {
gltf: &Gltf, gltf: &Gltf,
commands: &mut Commands, commands: &mut Commands,
meshes: &Assets<GltfMesh>, meshes: &Assets<GltfMesh>,
nodes: &Assets<GltfNode>,
) -> Option<Entity> { ) -> Option<Entity> {
let keys: Vec<_> = gltf.named_meshes.keys().collect(); let base_node = &gltf.named_nodes[&self.base_mesh_path.clone().into_boxed_str()];
info!("{keys:#?}"); if let Some(node) = nodes.get(base_node.id()) {
let mesh_handle = &gltf.named_meshes[&self.base_mesh_path.clone().into_boxed_str()]; if let Some(mesh_handle) = &node.mesh {
if let Some(gltf_mesh) = meshes.get(mesh_handle.id()) { if let Some(gltf_mesh) = meshes.get(mesh_handle.id()) {
let (mesh, mat) = gltf_mesh.unpack(); let (mesh, mat) = gltf_mesh.unpack();
let mut entity = commands.spawn(( let mut entity = commands.spawn((
PbrBundle { PbrBundle {
mesh, mesh,
material: mat, material: mat,
transform: Transform::from_translation(pos) transform: Transform::from_translation(pos).with_rotation(rot),
.with_rotation(Quat::from_rotation_arc(Vec3::NEG_Z, Vec3::Y) * rot),
..Default::default() ..Default::default()
}, },
Building, Building,
)); ));
if let Some(children) = &self.children {
entity.with_children(|b| { entity.with_children(|b| {
for child in children { for child in &node.children {
child.spawn_recursive(gltf, b, meshes); self.process_node(child, meshes, b, &node.name);
} }
}); });
if let Some(component) = self.get_component_def(&format!("/{0}", &node.name)) {
component.apply(&mut entity);
} }
return Some(entity.id()); return Some(entity.id());
} }
}
}
return None;
}
fn process_node(
&self,
node: &GltfNode,
meshes: &Assets<GltfMesh>,
commands: &mut ChildBuilder,
parent: &String,
) -> Option<Entity> {
let path = format!("{0}/{1}", parent, node.name);
if let Some(mesh) = &node.mesh {
if let Some(gltf_mesh) = meshes.get(mesh.id()) {
let (mesh, mat) = gltf_mesh.unpack();
let mut entity = commands.spawn((
PbrBundle {
mesh,
material: mat,
transform: node.transform,
..Default::default()
},
Building,
));
entity.with_children(|b| {
for child in &node.children {
self.process_node(child, meshes, b, &path);
}
});
if let Some(component) = self.get_component_def(&path) {
component.apply(&mut entity);
}
return Some(entity.id());
}
}
return None;
}
fn get_component_def(&self, path: &String) -> Option<&ComponentDefination> {
if let Some(components) = &self.components {
for c in components {
if c.path.eq(path) {
return Some(c);
}
}
}
return None; return None;
} }
} }

View File

@@ -1,6 +1,11 @@
use std::f32::consts::E; use std::f32::consts::E;
use bevy::{ecs::world::CommandQueue, gltf::GltfMesh, prelude::*, window::PrimaryWindow}; use bevy::{
ecs::world::CommandQueue,
gltf::{GltfMesh, GltfNode},
prelude::*,
window::PrimaryWindow,
};
use bevy_asset_loader::loading_state::{ use bevy_asset_loader::loading_state::{
config::{ConfigureLoadingState, LoadingStateConfig}, config::{ConfigureLoadingState, LoadingStateConfig},
LoadingStateAppExt, LoadingStateAppExt,
@@ -123,6 +128,7 @@ fn process_build_queue(
building_assets: Res<Assets<BuildingAsset>>, building_assets: Res<Assets<BuildingAsset>>,
gltf_assets: Res<Assets<Gltf>>, gltf_assets: Res<Assets<Gltf>>,
gltf_meshes: Res<Assets<GltfMesh>>, gltf_meshes: Res<Assets<GltfMesh>>,
gltf_nodes: Res<Assets<GltfNode>>,
mut building_map: ResMut<BuildingMap>, mut building_map: ResMut<BuildingMap>,
heightmap: Res<Map>, heightmap: Res<Map>,
) { ) {
@@ -132,7 +138,14 @@ fn process_build_queue(
let h = heightmap.sample_height(&item.pos); let h = heightmap.sample_height(&item.pos);
println!("Spawning {} at {}", building.name, item.pos); println!("Spawning {} at {}", building.name, item.pos);
if let Some(gltf) = gltf_assets.get(building.prefab.id()) { if let Some(gltf) = gltf_assets.get(building.prefab.id()) {
let e = building.spawn(item.pos.to_world(h), Quat::IDENTITY, gltf, &mut commands, &gltf_meshes); let e = building.spawn(
item.pos.to_world(h),
Quat::IDENTITY,
gltf,
&mut commands,
&gltf_meshes,
&gltf_nodes,
);
if let Some(b) = e { if let Some(b) = e {
building_map.add_building(BuildingEntry::new(item.pos, b)); building_map.add_building(BuildingEntry::new(item.pos, b));
} }

View File

@@ -15,6 +15,7 @@ use bevy_rapier3d::geometry::Collider;
use bevy_rapier3d::plugin::{NoUserData, RapierPhysicsPlugin}; use bevy_rapier3d::plugin::{NoUserData, RapierPhysicsPlugin};
use buildings::BuildingPugin; use buildings::BuildingPugin;
use iyes_perf_ui::prelude::*; use iyes_perf_ui::prelude::*;
use shared::animation_plugin::SimpleAnimationPlugin;
use shared::sets::GameplaySet; use shared::sets::GameplaySet;
use shared::states::{GameplayState, MenuState}; use shared::states::{GameplayState, MenuState};
use shared::{despawn::DespawnPuglin, states::AssetLoadState}; use shared::{despawn::DespawnPuglin, states::AssetLoadState};
@@ -38,6 +39,7 @@ impl Plugin for PhosGamePlugin {
MapInitPlugin, MapInitPlugin,
RenderDistancePlugin, RenderDistancePlugin,
BuildingPugin, BuildingPugin,
SimpleAnimationPlugin,
// BuildUiPlugin, // BuildUiPlugin,
UnitsPlugin, UnitsPlugin,
DespawnPuglin, DespawnPuglin,

View File

@@ -0,0 +1,18 @@
use bevy::prelude::*;
use crate::prefab_defination::RotationAnimation;
pub struct SimpleAnimationPlugin;
impl Plugin for SimpleAnimationPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, rotate);
}
}
fn rotate(mut query: Query<(&mut Transform, &RotationAnimation)>, time: Res<Time>) {
for (mut transform, rot) in query.iter_mut() {
let cur_rot = transform.rotation;
transform.rotation = cur_rot * Quat::from_axis_angle(rot.axis, rot.speed.to_radians() * time.elapsed_seconds());
}
}

View File

@@ -0,0 +1,20 @@
use bevy::{
ecs::system::EntityCommands, math::{Quat, Vec3}, prelude::*
};
use serde::{Deserialize, Serialize};
use crate::prefab_defination::AnimationComponent;
#[derive(Serialize, Deserialize, Debug)]
pub struct ComponentDefination {
pub path: String,
pub animations: Vec<AnimationComponent>,
}
impl ComponentDefination {
pub fn apply(&self, commands: &mut EntityCommands){
for c in &self.animations {
c.apply(commands);
}
}
}

View File

@@ -10,6 +10,8 @@ pub mod sets;
pub mod states; pub mod states;
pub mod tags; pub mod tags;
pub mod prefab_defination; pub mod prefab_defination;
pub mod component_defination;
pub mod animation_plugin;
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub enum Tier { pub enum Tier {

View File

@@ -1,4 +1,5 @@
use bevy::{ use bevy::{
ecs::system::{EntityCommand, EntityCommands},
gltf::{Gltf, GltfMesh}, gltf::{Gltf, GltfMesh},
math::{Quat, Vec3}, math::{Quat, Vec3},
prelude::*, prelude::*,
@@ -57,6 +58,23 @@ impl UnpackGltfMesh for GltfMesh {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub enum AnimationComponent { pub enum AnimationComponent {
Rotation, Rotation(RotationAnimation),
Slider, Slider,
} }
#[derive(Serialize, Deserialize, Debug, Component, Clone, Copy)]
pub struct RotationAnimation {
pub axis: Vec3,
pub speed: f32,
}
impl AnimationComponent {
pub fn apply(&self, commands: &mut EntityCommands) {
match self {
AnimationComponent::Rotation(comp) => {
commands.insert(comp.clone());
}
AnimationComponent::Slider => todo!(),
};
}
}