mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-11-22 11:50:53 +00:00
chore(bevy_gltf_components): Update to Bevy 0.12 (#32)
* chore(bevy_gltf_components): updated code for bevy_main/ v0.12 * refactor(examples): cleanups & tweaks * added compatibility tables
This commit is contained in:
parent
d06aa0042e
commit
c4e83655f3
565
Cargo.lock
generated
565
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
11
Cargo.toml
11
Cargo.toml
@ -10,16 +10,15 @@ members = [
|
|||||||
"crates/bevy_gltf_blueprints",
|
"crates/bevy_gltf_blueprints",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
bevy="0.11"
|
bevy="0.12"
|
||||||
bevy_rapier3d = { version = "0.22.0", features = [ "serde-serialize", "debug-render-3d", "enhanced-determinism"] }
|
bevy_asset_loader = { version = "0.18", features = ["standard_dynamic_assets" ]}
|
||||||
bevy_editor_pls = { version = "0.5.0" }
|
bevy_rapier3d = { version = "0.23.0", features = [ "serde-serialize", "debug-render-3d", "enhanced-determinism"] }
|
||||||
bevy_asset_loader = { version = "0.17.0", features = ["standard_dynamic_assets" ]} #version = "0.16",
|
bevy_editor_pls = { version = "0.6" }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = { version = "0.11", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] }
|
bevy = { version = "0.12", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] }
|
||||||
bevy_gltf_components = { path = "crates/bevy_gltf_components" }
|
bevy_gltf_components = { path = "crates/bevy_gltf_components" }
|
||||||
bevy_gltf_blueprints = { path = "crates/bevy_gltf_blueprints" }
|
bevy_gltf_blueprints = { path = "crates/bevy_gltf_blueprints" }
|
||||||
|
|
||||||
|
@ -128,11 +128,9 @@ you will get a warning **per entity**
|
|||||||
## Limitations / issues
|
## Limitations / issues
|
||||||
- some components have to be defined in ```text``` in Blender, might try using the AppTypeRegistry and some Python code on the Blender side for a nicer UI (although this loses the "fast & easy, no tooling" approach)
|
- some components have to be defined in ```text``` in Blender, might try using the AppTypeRegistry and some Python code on the Blender side for a nicer UI (although this loses the "fast & easy, no tooling" approach)
|
||||||
- Some of `bevy_rapier`/physics code / ways to define colliders could perhaps be done better within Blender (currently it also goes via RON)
|
- Some of `bevy_rapier`/physics code / ways to define colliders could perhaps be done better within Blender (currently it also goes via RON)
|
||||||
- there seem to be some random system ordering issues that I am still investigating (only when replacing proxy components, no breaking bugs, just restarting your Bevy app is enough)
|
|
||||||
|
|
||||||
## Future work
|
## Future work
|
||||||
- I have a number of other tools/ code helpers that I have not yet included here, because they need cleanup/ might make this example too complex
|
- I have a number of other tools/ code helpers that I have not yet included here, because they need cleanup/ might make this example too complex
|
||||||
* simplified animation logic: ie instead of having to manually specify the animations you need from a gltf file, it is integrated with the spawning system above, which creates a ```Animations``` component in all entities that have an ```AnimationPlayer``` and you can simply query for both to easilly control your animations per entity.
|
|
||||||
|
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
({
|
({
|
||||||
"world":File (path: "advanced/models/World.glb#Scene0"),
|
"world":File (path: "advanced/models/World.glb"),
|
||||||
"models": Folder (
|
"models": Folder (
|
||||||
path: "advanced/models/library",
|
path: "advanced/models/library",
|
||||||
),
|
),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
({
|
({
|
||||||
"world":File (path: "animation/models/Level1.glb#Scene0"),
|
"world":File (path: "animation/models/Level1.glb"),
|
||||||
"models": Folder (
|
"models": Folder (
|
||||||
path: "animation/models/library",
|
path: "animation/models/library",
|
||||||
),
|
),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bevy_gltf_blueprints"
|
name = "bevy_gltf_blueprints"
|
||||||
version = "0.2.1"
|
version = "0.3.0"
|
||||||
authors = ["Mark 'kaosat-dev' Moissette"]
|
authors = ["Mark 'kaosat-dev' Moissette"]
|
||||||
description = "Adds the ability to define Blueprints/Prefabs for [Bevy](https://bevyengine.org/) inside gltf files and spawn them in Bevy."
|
description = "Adds the ability to define Blueprints/Prefabs for [Bevy](https://bevyengine.org/) inside gltf files and spawn them in Bevy."
|
||||||
homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow"
|
homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow"
|
||||||
@ -11,8 +11,8 @@ edition = "2021"
|
|||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
bevy = { version = "0.11", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf", "bevy_animation", "animation"] }
|
bevy = { version = "0.12", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf", "bevy_animation", "animation"] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy_gltf_components = "0.1"
|
bevy_gltf_components = "0.2"
|
||||||
bevy = { version = "0.11", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf", "bevy_animation", "animation"] }
|
bevy = { version = "0.12", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf", "bevy_animation", "animation"] }
|
||||||
|
@ -25,8 +25,8 @@ Here's a minimal usage example:
|
|||||||
```toml
|
```toml
|
||||||
# Cargo.toml
|
# Cargo.toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy="0.11"
|
bevy="0.12"
|
||||||
bevy_gltf_blueprints = { version = "0.2"}
|
bevy_gltf_blueprints = { version = "0.3"}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ fn spawn_blueprint(
|
|||||||
Add the following to your `[dependencies]` section in `Cargo.toml`:
|
Add the following to your `[dependencies]` section in `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
bevy_gltf_blueprints = "0.2"
|
bevy_gltf_blueprints = "0.3"
|
||||||
```
|
```
|
||||||
|
|
||||||
Or use `cargo add`:
|
Or use `cargo add`:
|
||||||
@ -246,6 +246,19 @@ https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/example
|
|||||||
https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/animation
|
https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/animation
|
||||||
|
|
||||||
|
|
||||||
|
## Compatible Bevy versions
|
||||||
|
|
||||||
|
The main branch is compatible with the latest Bevy release, while the branch `bevy_main` tries to track the `main` branch of Bevy (PRs updating the tracked commit are welcome).
|
||||||
|
|
||||||
|
Compatibility of `bevy_gltf_blueprints` versions:
|
||||||
|
| `bevy_gltf_blueprints` | `bevy` |
|
||||||
|
| :-- | :-- |
|
||||||
|
| `0.3` | `0.12` |
|
||||||
|
| `0.1 -0.2` | `0.11` |
|
||||||
|
| branch `main` | `0.12` |
|
||||||
|
| branch `bevy_main` | `main` |
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This crate, all its code, contents & assets is Dual-licensed under either of
|
This crate, all its code, contents & assets is Dual-licensed under either of
|
||||||
|
@ -58,14 +58,15 @@ pub(crate) fn spawn_from_blueprints(
|
|||||||
Path::new(&blueprints_config.library_folder).join(Path::new(model_file_name.as_str()));
|
Path::new(&blueprints_config.library_folder).join(Path::new(model_file_name.as_str()));
|
||||||
|
|
||||||
debug!("attempting to spawn {:?}", model_path);
|
debug!("attempting to spawn {:?}", model_path);
|
||||||
let scene: Handle<Gltf> = asset_server.load(model_path);
|
let model_handle: Handle<Gltf> = asset_server.load(model_path);
|
||||||
|
|
||||||
let world = game_world.single_mut();
|
let world = game_world.single_mut();
|
||||||
let world = world.1[0]; // FIXME: dangerous hack because our gltf data have a single child like this, but might not always be the case
|
let world = world.1[0]; // FIXME: dangerous hack because our gltf data have a single child like this, but might not always be the case
|
||||||
|
|
||||||
let gltf = assets_gltf
|
let gltf = assets_gltf
|
||||||
.get(&scene)
|
.get(&model_handle)
|
||||||
.expect("this gltf should have been loaded");
|
.expect("this gltf should have been loaded");
|
||||||
|
|
||||||
// WARNING we work under the assumtion that there is ONLY ONE named scene, and that the first one is the right one
|
// WARNING we work under the assumtion that there is ONLY ONE named scene, and that the first one is the right one
|
||||||
let main_scene_name = gltf
|
let main_scene_name = gltf
|
||||||
.named_scenes
|
.named_scenes
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bevy_gltf_components"
|
name = "bevy_gltf_components"
|
||||||
version = "0.1.3"
|
version = "0.2.0"
|
||||||
authors = ["Mark 'kaosat-dev' Moissette"]
|
authors = ["Mark 'kaosat-dev' Moissette"]
|
||||||
description = "Allows you to define [Bevy](https://bevyengine.org/) components direclty inside gltf files and instanciate the components on the Bevy side."
|
description = "Allows you to define [Bevy](https://bevyengine.org/) components direclty inside gltf files and instanciate the components on the Bevy side."
|
||||||
homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow"
|
homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow"
|
||||||
@ -11,9 +11,9 @@ edition = "2021"
|
|||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
bevy = { version = "0.11", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] }
|
bevy = { version = "0.12", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = { version = "0.11", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] }
|
bevy = { version = "0.12", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] }
|
||||||
serde = "1.0.188"
|
serde = "1.0.188"
|
||||||
ron = "0.8.1"
|
ron = "0.8.1"
|
||||||
|
@ -23,8 +23,8 @@ Here's a minimal usage example:
|
|||||||
```toml
|
```toml
|
||||||
# Cargo.toml
|
# Cargo.toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy="0.11"
|
bevy="0.12"
|
||||||
bevy_gltf_components = { version = "0.1"}
|
bevy_gltf_components = { version = "0.2"}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -88,6 +88,20 @@ Typically , the order of systems should be
|
|||||||
https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/basic
|
https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/basic
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Compatible Bevy versions
|
||||||
|
|
||||||
|
The main branch is compatible with the latest Bevy release, while the branch `bevy_main` tries to track the `main` branch of Bevy (PRs updating the tracked commit are welcome).
|
||||||
|
|
||||||
|
Compatibility of `bevy_gltf_components` versions:
|
||||||
|
| `bevy_gltf_components` | `bevy` |
|
||||||
|
| :-- | :-- |
|
||||||
|
| `0.2` | `0.12` |
|
||||||
|
| `0.1` | `0.11` |
|
||||||
|
| branch `main` | `0.12` |
|
||||||
|
| branch `bevy_main` | `main` |
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This crate, all its code, contents & assets is Dual-licensed under either of
|
This crate, all its code, contents & assets is Dual-licensed under either of
|
||||||
|
@ -5,24 +5,167 @@ use serde::de::DeserializeSeed;
|
|||||||
|
|
||||||
use bevy::ecs::{entity::Entity, reflect::ReflectComponent};
|
use bevy::ecs::{entity::Entity, reflect::ReflectComponent};
|
||||||
use bevy::gltf::{Gltf, GltfExtras};
|
use bevy::gltf::{Gltf, GltfExtras};
|
||||||
use bevy::prelude::{debug, info, warn, Assets, Name, Parent, ResMut};
|
use bevy::reflect::serde::UntypedReflectDeserializer; // ReflectSerializer
|
||||||
use bevy::reflect::serde::UntypedReflectDeserializer;
|
use bevy::reflect::{Reflect, TypeInfo, TypeRegistry};
|
||||||
use bevy::reflect::{Reflect, TypeInfo, TypeRegistryInternal};
|
|
||||||
use bevy::scene::Scene;
|
use bevy::scene::Scene;
|
||||||
use bevy::utils::HashMap;
|
use bevy::utils::HashMap;
|
||||||
|
use bevy::{
|
||||||
|
log::{debug, info, warn},
|
||||||
|
prelude::{Assets, Name, Parent, ResMut},
|
||||||
|
};
|
||||||
|
|
||||||
use super::capitalize_first_letter;
|
use super::capitalize_first_letter;
|
||||||
|
|
||||||
|
pub fn ronstring_to_reflect_component(
|
||||||
|
ron_string: &String,
|
||||||
|
type_registry: &TypeRegistry,
|
||||||
|
) -> Vec<Box<dyn Reflect>> {
|
||||||
|
let lookup: HashMap<String, Value> = ron::from_str(ron_string.as_str()).unwrap();
|
||||||
|
let mut components: Vec<Box<dyn Reflect>> = Vec::new();
|
||||||
|
for (key, value) in lookup.into_iter() {
|
||||||
|
let type_string = key.replace("component: ", "").trim().to_string();
|
||||||
|
let capitalized_type_name = capitalize_first_letter(type_string.as_str());
|
||||||
|
|
||||||
|
let mut parsed_value: String;
|
||||||
|
match value.clone() {
|
||||||
|
Value::String(str) => {
|
||||||
|
parsed_value = str;
|
||||||
|
}
|
||||||
|
_ => parsed_value = ron::to_string(&value).unwrap().to_string(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(type_registration) =
|
||||||
|
type_registry.get_with_short_type_path(capitalized_type_name.as_str())
|
||||||
|
{
|
||||||
|
debug!("TYPE INFO {:?}", type_registration.type_info());
|
||||||
|
match type_registration.type_info() {
|
||||||
|
TypeInfo::TupleStruct(info) => {
|
||||||
|
// we handle tupple strucs with only one field differently, as Blender's custom properties with custom ui (float, int, bool, etc) always give us a tupple struct
|
||||||
|
if info.field_len() == 1 {
|
||||||
|
let field = info
|
||||||
|
.field_at(0)
|
||||||
|
.expect("we should always have at least one field here");
|
||||||
|
let field_name = field.type_path();
|
||||||
|
// TODO: find a way to cast with typeId instead of this matching
|
||||||
|
/*match field.type_id(){
|
||||||
|
TypeId::of::<f32>() => {
|
||||||
|
println!("WE HAVE A f32");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Vec3 => {
|
||||||
|
println!("WE HAVE A VEC3");
|
||||||
|
let bla:Vec3 = ron::from_str(&parsed_value).unwrap();
|
||||||
|
println!("bla {}", bla)
|
||||||
|
}
|
||||||
|
_ =>{}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
let mut formated = parsed_value.clone();
|
||||||
|
match field_name {
|
||||||
|
"f32" => {
|
||||||
|
formated = parsed_value.parse::<f32>().unwrap().to_string();
|
||||||
|
}
|
||||||
|
"f64" => {
|
||||||
|
formated = parsed_value.parse::<f64>().unwrap().to_string();
|
||||||
|
}
|
||||||
|
"u8" => {
|
||||||
|
formated = parsed_value.parse::<u8>().unwrap().to_string();
|
||||||
|
}
|
||||||
|
"u16" => {
|
||||||
|
formated = parsed_value.parse::<u16>().unwrap().to_string();
|
||||||
|
}
|
||||||
|
"u32" => {
|
||||||
|
formated = parsed_value.parse::<u32>().unwrap().to_string();
|
||||||
|
}
|
||||||
|
"u64" => {
|
||||||
|
formated = parsed_value.parse::<u64>().unwrap().to_string();
|
||||||
|
}
|
||||||
|
"u128" => {
|
||||||
|
formated = parsed_value.parse::<u128>().unwrap().to_string();
|
||||||
|
}
|
||||||
|
"glam::Vec2" => {
|
||||||
|
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
||||||
|
formated = format!("(x:{},y:{})", parsed[0], parsed[1]);
|
||||||
|
}
|
||||||
|
"glam::Vec3" => {
|
||||||
|
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
||||||
|
formated =
|
||||||
|
format!("(x:{},y:{},z:{})", parsed[0], parsed[1], parsed[2]);
|
||||||
|
}
|
||||||
|
"bevy_render::color::Color" => {
|
||||||
|
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
||||||
|
if parsed.len() == 3 {
|
||||||
|
formated = format!(
|
||||||
|
"Rgba(red:{},green:{},blue:{}, alpha: 1.0)",
|
||||||
|
parsed[0], parsed[1], parsed[2]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if parsed.len() == 4 {
|
||||||
|
formated = format!(
|
||||||
|
"Rgba(red:{},green:{},blue:{}, alpha:{})",
|
||||||
|
parsed[0], parsed[1], parsed[2], parsed[3]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed_value = format!("({formated})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// println!("parsed value {}",parsed_value);
|
||||||
|
if parsed_value.is_empty() {
|
||||||
|
parsed_value = "()".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
let ron_string = format!(
|
||||||
|
"{{ \"{}\":{} }}",
|
||||||
|
type_registration.type_info().type_path(),
|
||||||
|
parsed_value
|
||||||
|
);
|
||||||
|
|
||||||
|
// usefull to determine what an entity looks like Serialized
|
||||||
|
/*let test_struct = Enemy::default();
|
||||||
|
let serializer = ReflectSerializer::new(&test_struct, &type_registry);
|
||||||
|
let serialized =
|
||||||
|
ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
|
||||||
|
println!("serialized Component {}", serialized);*/
|
||||||
|
|
||||||
|
debug!("component data ron string {}", ron_string);
|
||||||
|
let mut deserializer = ron::Deserializer::from_str(ron_string.as_str()).unwrap();
|
||||||
|
let reflect_deserializer = UntypedReflectDeserializer::new(type_registry);
|
||||||
|
let component = reflect_deserializer.deserialize(&mut deserializer).expect(
|
||||||
|
format!(
|
||||||
|
"failed to deserialize component {} with value: {:?}",
|
||||||
|
key, value
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
|
||||||
|
debug!("component {:?}", component);
|
||||||
|
debug!("real type {:?}", component.get_represented_type_info());
|
||||||
|
|
||||||
|
components.push(component);
|
||||||
|
debug!("found type registration for {}", capitalized_type_name);
|
||||||
|
} else {
|
||||||
|
warn!("no type registration for {}", capitalized_type_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
components
|
||||||
|
}
|
||||||
|
|
||||||
/// main function: injects components into each entity in gltf files that have gltf_extras, using reflection
|
/// main function: injects components into each entity in gltf files that have gltf_extras, using reflection
|
||||||
pub fn gltf_extras_to_components(
|
pub fn gltf_extras_to_components(
|
||||||
gltf: &mut Gltf,
|
gltf: &mut Gltf,
|
||||||
scenes: &mut ResMut<Assets<Scene>>,
|
scenes: &mut ResMut<Assets<Scene>>,
|
||||||
type_registry: impl Deref<Target = TypeRegistryInternal>,
|
type_registry: impl Deref<Target = TypeRegistry>,
|
||||||
gltf_name: &str,
|
|
||||||
) {
|
) {
|
||||||
let mut added_components = 0;
|
let mut added_components = 0;
|
||||||
for (_name, scene) in &gltf.named_scenes {
|
for (_name, scene) in &gltf.named_scenes {
|
||||||
debug!("gltf: {:?} scene name {:?}", gltf_name, _name);
|
debug!("gltf: scene name {:?}", _name);
|
||||||
|
|
||||||
let scene = scenes.get_mut(scene).unwrap();
|
let scene = scenes.get_mut(scene).unwrap();
|
||||||
|
|
||||||
@ -81,16 +224,22 @@ pub fn gltf_extras_to_components(
|
|||||||
}
|
}
|
||||||
for component in components {
|
for component in components {
|
||||||
let mut entity_mut = scene.world.entity_mut(entity);
|
let mut entity_mut = scene.world.entity_mut(entity);
|
||||||
debug!("------adding {} {:?}", component.type_name(), component);
|
debug!(
|
||||||
|
"------adding {} {:?}",
|
||||||
|
component.get_represented_type_info().unwrap().type_path(),
|
||||||
|
component
|
||||||
|
);
|
||||||
|
|
||||||
|
let component_type_path =
|
||||||
|
component.get_represented_type_info().unwrap().type_path();
|
||||||
type_registry
|
type_registry
|
||||||
.get_with_name(component.type_name())
|
.get_with_type_path(component_type_path)
|
||||||
.unwrap() // Component was successfully deserialized, it has to be in the registry
|
.unwrap() // Component was successfully deserialized, it has to be in the registry
|
||||||
.data::<ReflectComponent>()
|
.data::<ReflectComponent>()
|
||||||
.unwrap() // Hopefully, the component deserializer ensures those are components
|
.unwrap() // Hopefully, the component deserializer ensures those are components
|
||||||
.insert(&mut entity_mut, &*component);
|
.insert(&mut entity_mut, &*component);
|
||||||
|
|
||||||
// info!("all components {:?}", scene.world.entity(entity).archetype().components());
|
// debug!("all components {:?}", scene.world.entity(entity).archetype().components());
|
||||||
// scene.world.components().
|
// scene.world.components().
|
||||||
// TODO: how can we insert any additional components "by hand" here ?
|
// TODO: how can we insert any additional components "by hand" here ?
|
||||||
}
|
}
|
||||||
@ -103,142 +252,5 @@ pub fn gltf_extras_to_components(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info!("done extracting gltf_extras /n");
|
info!("done injecting components from gltf_extras /n");
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ronstring_to_reflect_component(
|
|
||||||
ron_string: &String,
|
|
||||||
type_registry: &TypeRegistryInternal,
|
|
||||||
) -> Vec<Box<dyn Reflect>> {
|
|
||||||
let lookup: HashMap<String, Value> = ron::from_str(ron_string.as_str()).unwrap();
|
|
||||||
let mut components: Vec<Box<dyn Reflect>> = Vec::new();
|
|
||||||
for (key, value) in lookup.into_iter() {
|
|
||||||
let type_string = key.replace("component: ", "").trim().to_string();
|
|
||||||
let capitalized_type_name = capitalize_first_letter(type_string.as_str());
|
|
||||||
|
|
||||||
let mut parsed_value: String;
|
|
||||||
match value.clone() {
|
|
||||||
Value::String(str) => {
|
|
||||||
parsed_value = str;
|
|
||||||
}
|
|
||||||
_ => parsed_value = ron::to_string(&value).unwrap().to_string(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(type_registration) =
|
|
||||||
type_registry.get_with_short_name(capitalized_type_name.as_str())
|
|
||||||
{
|
|
||||||
// println!("TYPE INFO {:?}", type_registration.type_info());
|
|
||||||
match type_registration.type_info() {
|
|
||||||
TypeInfo::TupleStruct(info) => {
|
|
||||||
// we handle tupple strucs with only one field differently, as Blender's custom properties with custom ui (float, int, bool, etc) always give us a tupple struct
|
|
||||||
if info.field_len() == 1 {
|
|
||||||
let field = info
|
|
||||||
.field_at(0)
|
|
||||||
.expect("we should always have at least one field here");
|
|
||||||
let field_name = field.type_name();
|
|
||||||
// TODO: find a way to cast with typeId instead of this matching
|
|
||||||
/*match field.type_id(){
|
|
||||||
TypeId::of::<f32>() => {
|
|
||||||
println!("WE HAVE A f32");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vec3 => {
|
|
||||||
println!("WE HAVE A VEC3");
|
|
||||||
let bla:Vec3 = ron::from_str(&parsed_value).unwrap();
|
|
||||||
println!("bla {}", bla)
|
|
||||||
}
|
|
||||||
_ =>{}
|
|
||||||
}*/
|
|
||||||
let mut formated = parsed_value.clone();
|
|
||||||
match field_name {
|
|
||||||
"f32" => {
|
|
||||||
formated = parsed_value.parse::<f32>().unwrap().to_string();
|
|
||||||
}
|
|
||||||
"f64" => {
|
|
||||||
formated = parsed_value.parse::<f64>().unwrap().to_string();
|
|
||||||
}
|
|
||||||
"u8" => {
|
|
||||||
formated = parsed_value.parse::<u8>().unwrap().to_string();
|
|
||||||
}
|
|
||||||
"u16" => {
|
|
||||||
formated = parsed_value.parse::<u16>().unwrap().to_string();
|
|
||||||
}
|
|
||||||
"u32" => {
|
|
||||||
formated = parsed_value.parse::<u32>().unwrap().to_string();
|
|
||||||
}
|
|
||||||
"u64" => {
|
|
||||||
formated = parsed_value.parse::<u64>().unwrap().to_string();
|
|
||||||
}
|
|
||||||
"u128" => {
|
|
||||||
formated = parsed_value.parse::<u128>().unwrap().to_string();
|
|
||||||
}
|
|
||||||
"glam::f32::vec2::Vec2" => {
|
|
||||||
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
|
||||||
formated = format!("(x:{},y:{})", parsed[0], parsed[1]);
|
|
||||||
}
|
|
||||||
"glam::f32::vec3::Vec3" => {
|
|
||||||
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
|
||||||
formated =
|
|
||||||
format!("(x:{},y:{},z:{})", parsed[0], parsed[1], parsed[2]);
|
|
||||||
}
|
|
||||||
"bevy_render::color::Color" => {
|
|
||||||
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
|
||||||
if parsed.len() == 3 {
|
|
||||||
formated = format!(
|
|
||||||
"Rgba(red:{},green:{},blue:{}, alpha: 1.0)",
|
|
||||||
parsed[0], parsed[1], parsed[2]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if parsed.len() == 4 {
|
|
||||||
formated = format!(
|
|
||||||
"Rgba(red:{},green:{},blue:{}, alpha:{})",
|
|
||||||
parsed[0], parsed[1], parsed[2], parsed[3]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
parsed_value = format!("({formated})");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// println!("parsed value {}",parsed_value);
|
|
||||||
if parsed_value.is_empty() {
|
|
||||||
parsed_value = "()".to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
let ron_string = format!(
|
|
||||||
"{{ \"{}\":{} }}",
|
|
||||||
type_registration.type_name(),
|
|
||||||
parsed_value
|
|
||||||
);
|
|
||||||
|
|
||||||
// usefull to determine what an entity looks like Serialized
|
|
||||||
/*let test_struct = TuppleTestStr::default();
|
|
||||||
let serializer = ReflectSerializer::new(&test_struct, &type_registry);
|
|
||||||
let serialized =
|
|
||||||
ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
|
|
||||||
println!("serialized Component {}", serialized);*/
|
|
||||||
|
|
||||||
// println!("component data ron string {}", ron_string);
|
|
||||||
let mut deserializer = ron::Deserializer::from_str(ron_string.as_str()).unwrap();
|
|
||||||
let reflect_deserializer = UntypedReflectDeserializer::new(type_registry);
|
|
||||||
let component = reflect_deserializer.deserialize(&mut deserializer).expect(
|
|
||||||
format!(
|
|
||||||
"failed to deserialize component {} with value: {:?}",
|
|
||||||
key, value
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
);
|
|
||||||
|
|
||||||
components.push(component);
|
|
||||||
debug!("found type registration for {}", capitalized_type_name);
|
|
||||||
} else {
|
|
||||||
warn!("no type registration for {}", capitalized_type_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
components
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use bevy::gltf::Gltf;
|
|||||||
use bevy::utils::HashSet;
|
use bevy::utils::HashSet;
|
||||||
use bevy::{asset::LoadState, prelude::*};
|
use bevy::{asset::LoadState, prelude::*};
|
||||||
|
|
||||||
use super::gltf_extras_to_components;
|
use crate::gltf_extras_to_components;
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
/// component to keep track of gltfs' loading state
|
/// component to keep track of gltfs' loading state
|
||||||
@ -18,7 +18,7 @@ impl GltfLoadingTracker {
|
|||||||
loading_gltfs: HashSet::new(),
|
loading_gltfs: HashSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn add_scene(&mut self, handle: Handle<Gltf>) {
|
pub fn add_gltf(&mut self, handle: Handle<Gltf>) {
|
||||||
self.loading_gltfs.insert(handle);
|
self.loading_gltfs.insert(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,10 +26,14 @@ impl GltfLoadingTracker {
|
|||||||
pub fn track_new_gltf(
|
pub fn track_new_gltf(
|
||||||
mut tracker: ResMut<GltfLoadingTracker>,
|
mut tracker: ResMut<GltfLoadingTracker>,
|
||||||
mut events: EventReader<AssetEvent<Gltf>>,
|
mut events: EventReader<AssetEvent<Gltf>>,
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
) {
|
) {
|
||||||
for event in events.iter() {
|
for event in events.read() {
|
||||||
if let AssetEvent::Created { handle } = event {
|
if let AssetEvent::Added { id } = event {
|
||||||
tracker.add_scene(handle.clone());
|
let handle = asset_server
|
||||||
|
.get_id_handle(*id)
|
||||||
|
.expect("this gltf should have been loaded");
|
||||||
|
tracker.add_gltf(handle.clone());
|
||||||
debug!("gltf created {:?}", handle.clone());
|
debug!("gltf created {:?}", handle.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,36 +42,31 @@ pub fn track_new_gltf(
|
|||||||
|
|
||||||
pub fn process_loaded_scenes(
|
pub fn process_loaded_scenes(
|
||||||
mut gltfs: ResMut<Assets<Gltf>>,
|
mut gltfs: ResMut<Assets<Gltf>>,
|
||||||
mut scenes: ResMut<Assets<Scene>>,
|
|
||||||
mut tracker: ResMut<GltfLoadingTracker>,
|
mut tracker: ResMut<GltfLoadingTracker>,
|
||||||
|
mut scenes: ResMut<Assets<Scene>>,
|
||||||
app_type_registry: Res<AppTypeRegistry>,
|
app_type_registry: Res<AppTypeRegistry>,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
) {
|
) {
|
||||||
let mut loaded_gltfs = Vec::new();
|
let mut loaded_gltfs = Vec::new();
|
||||||
for gltf in &tracker.loading_gltfs {
|
for gltf in &tracker.loading_gltfs {
|
||||||
info!(
|
debug!(
|
||||||
"checking for loaded gltfs {:?}",
|
"checking for loaded gltfs {:?}",
|
||||||
asset_server.get_load_state(gltf)
|
asset_server.get_load_state(gltf)
|
||||||
);
|
);
|
||||||
|
|
||||||
if asset_server.get_load_state(gltf.clone()) == LoadState::Loaded {
|
if let Some(load_state) = asset_server.get_load_state(gltf.clone()) {
|
||||||
|
if load_state == LoadState::Loaded {
|
||||||
debug!("Adding scene to processing list");
|
debug!("Adding scene to processing list");
|
||||||
loaded_gltfs.push(gltf.clone());
|
loaded_gltfs.push(gltf.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let type_registry = app_type_registry.read();
|
let type_registry = app_type_registry.read();
|
||||||
|
|
||||||
for gltf_handle in &loaded_gltfs {
|
for gltf_handle in &loaded_gltfs {
|
||||||
if let Some(gltf) = gltfs.get_mut(gltf_handle) {
|
if let Some(gltf) = gltfs.get_mut(gltf_handle) {
|
||||||
// TODO this is a temporary workaround for library management
|
gltf_extras_to_components(gltf, &mut scenes, &*type_registry);
|
||||||
if let Some(asset_path) = asset_server.get_handle_path(gltf_handle) {
|
|
||||||
let gltf_name = asset_path.path().file_stem().unwrap().to_str().unwrap();
|
|
||||||
gltf_extras_to_components(gltf, &mut scenes, &*type_registry, gltf_name);
|
|
||||||
//gltf_extras_to_prefab_infos(gltf, &mut scenes, &*type_registry, gltf_name);
|
|
||||||
} else {
|
|
||||||
gltf_extras_to_components(gltf, &mut scenes, &*type_registry, "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
tracker.loading_gltfs.remove(gltf_handle);
|
tracker.loading_gltfs.remove(gltf_handle);
|
||||||
tracker.loaded_gltfs.insert(gltf_handle.clone());
|
tracker.loaded_gltfs.insert(gltf_handle.clone());
|
||||||
|
@ -6,7 +6,7 @@ use bevy_asset_loader::prelude::*;
|
|||||||
#[derive(AssetCollection, Resource)]
|
#[derive(AssetCollection, Resource)]
|
||||||
pub struct GameAssets {
|
pub struct GameAssets {
|
||||||
#[asset(key = "world")]
|
#[asset(key = "world")]
|
||||||
pub world: Handle<Scene>,
|
pub world: Handle<Gltf>,
|
||||||
|
|
||||||
#[asset(key = "models", collection(typed, mapped))]
|
#[asset(key = "models", collection(typed, mapped))]
|
||||||
pub models: HashMap<String, Handle<Gltf>>,
|
pub models: HashMap<String, Handle<Gltf>>,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
pub mod camera;
|
pub mod camera;
|
||||||
use bevy_rapier3d::prelude::Velocity;
|
|
||||||
pub use camera::*;
|
pub use camera::*;
|
||||||
|
|
||||||
pub mod lighting;
|
pub mod lighting;
|
||||||
@ -11,61 +10,12 @@ pub use relationships::*;
|
|||||||
pub mod physics;
|
pub mod physics;
|
||||||
pub use physics::*;
|
pub use physics::*;
|
||||||
|
|
||||||
// pub mod blueprints;
|
// pub mod save_load;
|
||||||
// pub use blueprints::*;
|
// pub use save_load::*;
|
||||||
|
|
||||||
pub mod save_load;
|
|
||||||
pub use save_load::*;
|
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_gltf_blueprints::*;
|
use bevy_gltf_blueprints::*;
|
||||||
|
|
||||||
use rand::Rng;
|
|
||||||
|
|
||||||
fn spawn_test(
|
|
||||||
keycode: Res<Input<KeyCode>>,
|
|
||||||
mut commands: Commands,
|
|
||||||
|
|
||||||
mut game_world: Query<(Entity, &Children), With<GameWorldTag>>,
|
|
||||||
) {
|
|
||||||
if keycode.just_pressed(KeyCode::T) {
|
|
||||||
let world = game_world.single_mut();
|
|
||||||
let world = world.1[0];
|
|
||||||
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
let range = 5.5;
|
|
||||||
let x: f32 = rng.gen_range(-range..range);
|
|
||||||
let y: f32 = rng.gen_range(-range..range);
|
|
||||||
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
let range = 0.8;
|
|
||||||
let vel_x: f32 = rng.gen_range(-range..range);
|
|
||||||
let vel_y: f32 = rng.gen_range(2.0..2.5);
|
|
||||||
let vel_z: f32 = rng.gen_range(-range..range);
|
|
||||||
|
|
||||||
let name_index: u64 = rng.gen();
|
|
||||||
|
|
||||||
let new_entity = commands
|
|
||||||
.spawn((
|
|
||||||
BluePrintBundle {
|
|
||||||
blueprint: BlueprintName("Health_Pickup".to_string()),
|
|
||||||
transform: TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
bevy::prelude::Name::from(format!("test{}", name_index)),
|
|
||||||
// BlueprintName("Health_Pickup".to_string()),
|
|
||||||
// SpawnHere,
|
|
||||||
// TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)),
|
|
||||||
Velocity {
|
|
||||||
linvel: Vec3::new(vel_x, vel_y, vel_z),
|
|
||||||
angvel: Vec3::new(0.0, 0.0, 0.0),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
.id();
|
|
||||||
commands.entity(world).add_child(new_entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CorePlugin;
|
pub struct CorePlugin;
|
||||||
impl Plugin for CorePlugin {
|
impl Plugin for CorePlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
@ -73,12 +23,10 @@ impl Plugin for CorePlugin {
|
|||||||
LightingPlugin,
|
LightingPlugin,
|
||||||
CameraPlugin,
|
CameraPlugin,
|
||||||
PhysicsPlugin,
|
PhysicsPlugin,
|
||||||
SaveLoadPlugin,
|
// SaveLoadPlugin,
|
||||||
BlueprintsPlugin {
|
BlueprintsPlugin {
|
||||||
library_folder: "advanced/models/library".into(),
|
library_folder: "advanced/models/library".into(),
|
||||||
},
|
},
|
||||||
))
|
));
|
||||||
// just for testing
|
|
||||||
.add_systems(Update, spawn_test);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,15 @@ use crate::{
|
|||||||
assets::GameAssets,
|
assets::GameAssets,
|
||||||
state::{GameState, InAppRunning},
|
state::{GameState, InAppRunning},
|
||||||
};
|
};
|
||||||
use bevy_gltf_blueprints::GameWorldTag;
|
use bevy_gltf_blueprints::{BluePrintBundle, BlueprintName, GameWorldTag};
|
||||||
|
|
||||||
|
use bevy_rapier3d::prelude::Velocity;
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
pub fn setup_game(
|
pub fn setup_game(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
game_assets: Res<GameAssets>,
|
game_assets: Res<GameAssets>,
|
||||||
|
models: Res<Assets<bevy::gltf::Gltf>>,
|
||||||
mut next_game_state: ResMut<NextState<GameState>>,
|
mut next_game_state: ResMut<NextState<GameState>>,
|
||||||
) {
|
) {
|
||||||
println!("setting up all stuff");
|
println!("setting up all stuff");
|
||||||
@ -20,7 +24,12 @@ pub fn setup_game(
|
|||||||
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
SceneBundle {
|
SceneBundle {
|
||||||
scene: game_assets.world.clone(),
|
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
||||||
|
scene: models
|
||||||
|
.get(game_assets.world.id())
|
||||||
|
.expect("main level should have been loaded")
|
||||||
|
.scenes[0]
|
||||||
|
.clone(),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
bevy::prelude::Name::from("world"),
|
bevy::prelude::Name::from("world"),
|
||||||
@ -30,3 +39,47 @@ pub fn setup_game(
|
|||||||
|
|
||||||
next_game_state.set(GameState::InGame)
|
next_game_state.set(GameState::InGame)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn spawn_test(
|
||||||
|
keycode: Res<Input<KeyCode>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
|
||||||
|
mut game_world: Query<(Entity, &Children), With<GameWorldTag>>,
|
||||||
|
) {
|
||||||
|
if keycode.just_pressed(KeyCode::T) {
|
||||||
|
let world = game_world.single_mut();
|
||||||
|
let world = world.1[0];
|
||||||
|
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let range = 5.5;
|
||||||
|
let x: f32 = rng.gen_range(-range..range);
|
||||||
|
let y: f32 = rng.gen_range(-range..range);
|
||||||
|
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let range = 0.8;
|
||||||
|
let vel_x: f32 = rng.gen_range(-range..range);
|
||||||
|
let vel_y: f32 = rng.gen_range(2.0..2.5);
|
||||||
|
let vel_z: f32 = rng.gen_range(-range..range);
|
||||||
|
|
||||||
|
let name_index: u64 = rng.gen();
|
||||||
|
|
||||||
|
let new_entity = commands
|
||||||
|
.spawn((
|
||||||
|
BluePrintBundle {
|
||||||
|
blueprint: BlueprintName("Health_Pickup".to_string()),
|
||||||
|
transform: TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
bevy::prelude::Name::from(format!("test{}", name_index)),
|
||||||
|
// BlueprintName("Health_Pickup".to_string()),
|
||||||
|
// SpawnHere,
|
||||||
|
// TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)),
|
||||||
|
Velocity {
|
||||||
|
linvel: Vec3::new(vel_x, vel_y, vel_z),
|
||||||
|
angvel: Vec3::new(0.0, 0.0, 0.0),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
.id();
|
||||||
|
commands.entity(world).add_child(new_entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::state::{AppState, GameState, InMainMenu};
|
||||||
core::save_load::{LoadRequest, SaveRequest},
|
|
||||||
state::{AppState, GameState, InMainMenu},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn setup_main_menu(mut commands: Commands) {
|
pub fn setup_main_menu(mut commands: Commands) {
|
||||||
commands.spawn((Camera2dBundle::default(), InMainMenu));
|
commands.spawn((Camera2dBundle::default(), InMainMenu));
|
||||||
@ -97,8 +94,8 @@ pub fn main_menu(
|
|||||||
|
|
||||||
mut next_app_state: ResMut<NextState<AppState>>,
|
mut next_app_state: ResMut<NextState<AppState>>,
|
||||||
// mut next_game_state: ResMut<NextState<GameState>>,
|
// mut next_game_state: ResMut<NextState<GameState>>,
|
||||||
mut save_requested_events: EventWriter<SaveRequest>,
|
// mut save_requested_events: EventWriter<SaveRequest>,
|
||||||
mut load_requested_events: EventWriter<LoadRequest>,
|
// mut load_requested_events: EventWriter<LoadRequest>,
|
||||||
) {
|
) {
|
||||||
if keycode.just_pressed(KeyCode::Return) {
|
if keycode.just_pressed(KeyCode::Return) {
|
||||||
next_app_state.set(AppState::AppLoading);
|
next_app_state.set(AppState::AppLoading);
|
||||||
|
@ -70,7 +70,7 @@ pub fn test_collision_events(
|
|||||||
mut collision_events: EventReader<CollisionEvent>,
|
mut collision_events: EventReader<CollisionEvent>,
|
||||||
mut contact_force_events: EventReader<ContactForceEvent>,
|
mut contact_force_events: EventReader<ContactForceEvent>,
|
||||||
) {
|
) {
|
||||||
for collision_event in collision_events.iter() {
|
for collision_event in collision_events.read() {
|
||||||
println!("collision");
|
println!("collision");
|
||||||
match collision_event {
|
match collision_event {
|
||||||
CollisionEvent::Started(_entity1, _entity2, _) => {
|
CollisionEvent::Started(_entity1, _entity2, _) => {
|
||||||
@ -82,7 +82,7 @@ pub fn test_collision_events(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for contact_force_event in contact_force_events.iter() {
|
for contact_force_event in contact_force_events.read() {
|
||||||
println!("Received contact force event: {:?}", contact_force_event);
|
println!("Received contact force event: {:?}", contact_force_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,6 +103,7 @@ impl Plugin for GamePlugin {
|
|||||||
// insert_dependant_component::<Player, ShouldBeWithPlayer>,
|
// insert_dependant_component::<Player, ShouldBeWithPlayer>,
|
||||||
player_move_demo, //.run_if(in_state(AppState::Running)),
|
player_move_demo, //.run_if(in_state(AppState::Running)),
|
||||||
// test_collision_events
|
// test_collision_events
|
||||||
|
spawn_test,
|
||||||
)
|
)
|
||||||
.run_if(in_state(GameState::InGame)),
|
.run_if(in_state(GameState::InGame)),
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::Player;
|
use super::Player;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use bevy_gltf_blueprints::GltfBlueprintsSet;
|
||||||
|
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
@ -27,11 +28,7 @@ pub fn picking(
|
|||||||
pub struct PickingPlugin;
|
pub struct PickingPlugin;
|
||||||
impl Plugin for PickingPlugin {
|
impl Plugin for PickingPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.register_type::<Pickable>().add_systems(
|
app.register_type::<Pickable>()
|
||||||
Update,
|
.add_systems(Update, (picking.after(GltfBlueprintsSet::AfterSpawn),));
|
||||||
(
|
|
||||||
picking, //.run_if(in_state(AppState::Running)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use bevy::{asset::ChangeWatcher, prelude::*};
|
use bevy::prelude::*;
|
||||||
use bevy_editor_pls::prelude::*;
|
use bevy_editor_pls::prelude::*;
|
||||||
|
|
||||||
mod core;
|
mod core;
|
||||||
@ -19,13 +19,7 @@ use test_components::*;
|
|||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins((
|
.add_plugins((
|
||||||
DefaultPlugins.set(AssetPlugin {
|
DefaultPlugins.set(AssetPlugin::default()),
|
||||||
// This tells the AssetServer to watch for changes to assets.
|
|
||||||
// It enables our scenes to automatically reload in game when we modify their files.
|
|
||||||
// practical in our case to be able to edit the shaders without needing to recompile
|
|
||||||
// watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(50)), : FIXME: breaks scene save/loading
|
|
||||||
..default()
|
|
||||||
}),
|
|
||||||
// editor
|
// editor
|
||||||
EditorPlugin::default(),
|
EditorPlugin::default(),
|
||||||
// our custom plugins
|
// our custom plugins
|
||||||
|
@ -6,7 +6,7 @@ use bevy_asset_loader::prelude::*;
|
|||||||
#[derive(AssetCollection, Resource)]
|
#[derive(AssetCollection, Resource)]
|
||||||
pub struct GameAssets {
|
pub struct GameAssets {
|
||||||
#[asset(key = "world")]
|
#[asset(key = "world")]
|
||||||
pub world: Handle<Scene>,
|
pub world: Handle<Gltf>,
|
||||||
|
|
||||||
#[asset(key = "models", collection(typed, mapped))]
|
#[asset(key = "models", collection(typed, mapped))]
|
||||||
pub models: HashMap<String, Handle<Gltf>>,
|
pub models: HashMap<String, Handle<Gltf>>,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
pub mod camera;
|
pub mod camera;
|
||||||
use bevy_rapier3d::prelude::Velocity;
|
|
||||||
pub use camera::*;
|
pub use camera::*;
|
||||||
|
|
||||||
pub mod lighting;
|
pub mod lighting;
|
||||||
|
@ -17,9 +17,10 @@ use super::{Fox, Player, Robot};
|
|||||||
pub fn setup_game(
|
pub fn setup_game(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
game_assets: Res<GameAssets>,
|
game_assets: Res<GameAssets>,
|
||||||
|
models: Res<Assets<bevy::gltf::Gltf>>,
|
||||||
|
|
||||||
mut next_game_state: ResMut<NextState<GameState>>,
|
mut next_game_state: ResMut<NextState<GameState>>,
|
||||||
) {
|
) {
|
||||||
println!("setting up all stuff");
|
|
||||||
commands.insert_resource(AmbientLight {
|
commands.insert_resource(AmbientLight {
|
||||||
color: Color::WHITE,
|
color: Color::WHITE,
|
||||||
brightness: 0.2,
|
brightness: 0.2,
|
||||||
@ -28,7 +29,12 @@ pub fn setup_game(
|
|||||||
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
SceneBundle {
|
SceneBundle {
|
||||||
scene: game_assets.world.clone(),
|
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
||||||
|
scene: models
|
||||||
|
.get(game_assets.world.id())
|
||||||
|
.expect("main level should have been loaded")
|
||||||
|
.scenes[0]
|
||||||
|
.clone(),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
bevy::prelude::Name::from("world"),
|
bevy::prelude::Name::from("world"),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use bevy::{asset::ChangeWatcher, prelude::*};
|
use bevy::prelude::*;
|
||||||
use bevy_editor_pls::prelude::*;
|
use bevy_editor_pls::prelude::*;
|
||||||
|
|
||||||
mod core;
|
mod core;
|
||||||
@ -19,13 +19,7 @@ use test_components::*;
|
|||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins((
|
.add_plugins((
|
||||||
DefaultPlugins.set(AssetPlugin {
|
DefaultPlugins.set(AssetPlugin::default()),
|
||||||
// This tells the AssetServer to watch for changes to assets.
|
|
||||||
// It enables our scenes to automatically reload in game when we modify their files.
|
|
||||||
// practical in our case to be able to edit the shaders without needing to recompile
|
|
||||||
// watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(50)), : FIXME: breaks scene save/loading
|
|
||||||
..default()
|
|
||||||
}),
|
|
||||||
// editor
|
// editor
|
||||||
EditorPlugin::default(),
|
EditorPlugin::default(),
|
||||||
// our custom plugins
|
// our custom plugins
|
||||||
|
@ -63,7 +63,7 @@ pub fn test_collision_events(
|
|||||||
mut collision_events: EventReader<CollisionEvent>,
|
mut collision_events: EventReader<CollisionEvent>,
|
||||||
mut contact_force_events: EventReader<ContactForceEvent>,
|
mut contact_force_events: EventReader<ContactForceEvent>,
|
||||||
) {
|
) {
|
||||||
for collision_event in collision_events.iter() {
|
for collision_event in collision_events.read() {
|
||||||
println!("collision");
|
println!("collision");
|
||||||
match collision_event {
|
match collision_event {
|
||||||
CollisionEvent::Started(_entity1, _entity2, _) => {
|
CollisionEvent::Started(_entity1, _entity2, _) => {
|
||||||
@ -75,7 +75,7 @@ pub fn test_collision_events(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for contact_force_event in contact_force_events.iter() {
|
for contact_force_event in contact_force_events.read() {
|
||||||
println!("Received contact force event: {:?}", contact_force_event);
|
println!("Received contact force event: {:?}", contact_force_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use bevy::{asset::ChangeWatcher, gltf::Gltf, prelude::*};
|
use bevy::{gltf::Gltf, prelude::*};
|
||||||
use bevy_editor_pls::prelude::*;
|
use bevy_editor_pls::prelude::*;
|
||||||
use bevy_gltf_components::ComponentsFromGltfPlugin;
|
use bevy_gltf_components::ComponentsFromGltfPlugin;
|
||||||
use bevy_rapier3d::prelude::*;
|
use bevy_rapier3d::prelude::*;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
mod core;
|
mod core;
|
||||||
use crate::core::*;
|
use crate::core::*;
|
||||||
@ -28,13 +27,7 @@ enum AppState {
|
|||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins((
|
.add_plugins((
|
||||||
DefaultPlugins.set(AssetPlugin {
|
DefaultPlugins.set(AssetPlugin::default()),
|
||||||
// This tells the AssetServer to watch for changes to assets.
|
|
||||||
// It enables our scenes to automatically reload in game when we modify their files.
|
|
||||||
// practical in our case to be able to edit the shaders without needing to recompile
|
|
||||||
watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(50)),
|
|
||||||
..default()
|
|
||||||
}),
|
|
||||||
// editor
|
// editor
|
||||||
EditorPlugin::default(),
|
EditorPlugin::default(),
|
||||||
// physics
|
// physics
|
||||||
@ -53,33 +46,33 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
struct AssetLoadHelper(Handle<Scene>);
|
pub struct MyGltf(pub Handle<Gltf>);
|
||||||
|
|
||||||
// we preload the data here, but this is for DEMO PURPOSES ONLY !! Please use https://github.com/NiklasEi/bevy_asset_loader or a similar logic to seperate loading / pre processing
|
// we preload the data here, but this is for DEMO PURPOSES ONLY !! Please use https://github.com/NiklasEi/bevy_asset_loader or a similar logic to seperate loading / pre processing
|
||||||
// of assets from the spawning
|
// of assets from the spawning
|
||||||
// AssetLoadHelper is also just for the same purpose, you do not need it in a real scenario
|
// MyGltf is also just for the same purpose, you do not need it in a real scenario
|
||||||
// the states here are also for demo purposes only,
|
// the states here are also for demo purposes only,
|
||||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
let tmp: Handle<Scene> = asset_server.load("basic/models/level1.glb#Scene0");
|
commands.insert_resource(MyGltf(asset_server.load("basic/models/level1.glb")));
|
||||||
commands.insert_resource(AssetLoadHelper(tmp));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_level(
|
fn spawn_level(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
scene_markers: Query<&LoadedMarker>,
|
scene_markers: Query<&LoadedMarker>,
|
||||||
preloaded_scene: Res<AssetLoadHelper>,
|
|
||||||
|
|
||||||
mut asset_event_reader: EventReader<AssetEvent<Gltf>>,
|
mut asset_event_reader: EventReader<AssetEvent<Gltf>>,
|
||||||
mut next_state: ResMut<NextState<AppState>>,
|
mut next_state: ResMut<NextState<AppState>>,
|
||||||
|
models: Res<Assets<bevy::gltf::Gltf>>,
|
||||||
) {
|
) {
|
||||||
if let Some(asset_event) = asset_event_reader.iter().next() {
|
if let Some(asset_event) = asset_event_reader.read().next() {
|
||||||
match asset_event {
|
match asset_event {
|
||||||
AssetEvent::Created { handle: _ } => {
|
AssetEvent::Added { id } => {
|
||||||
info!("GLTF loaded");
|
info!("GLTF loaded/ added {:?}", asset_event);
|
||||||
|
let my_gltf = models.get(*id).unwrap();
|
||||||
if scene_markers.is_empty() {
|
if scene_markers.is_empty() {
|
||||||
info!("spawning scene");
|
info!("spawning scene");
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
SceneBundle {
|
SceneBundle {
|
||||||
scene: preloaded_scene.0.clone(),
|
scene: my_gltf.scenes[0].clone(),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
LoadedMarker,
|
LoadedMarker,
|
||||||
|
Loading…
Reference in New Issue
Block a user