mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
Transform Rewrite (#374)
Remove individual Translation / Rotation / Scale components in favor of a combined Transform component
This commit is contained in:
parent
3bc5e4cb1e
commit
474bb5403e
46 changed files with 478 additions and 1386 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -5,4 +5,4 @@ Cargo.lock
|
||||||
.cargo/config
|
.cargo/config
|
||||||
/.idea
|
/.idea
|
||||||
/.vscode
|
/.vscode
|
||||||
/benches/target
|
/benches/target
|
|
@ -7,7 +7,7 @@ use bevy_render::{
|
||||||
pipeline::{DynamicBinding, PipelineSpecialization, RenderPipeline, RenderPipelines},
|
pipeline::{DynamicBinding, PipelineSpecialization, RenderPipeline, RenderPipelines},
|
||||||
render_graph::base::MainPass,
|
render_graph::base::MainPass,
|
||||||
};
|
};
|
||||||
use bevy_transform::prelude::{Rotation, Scale, Transform, Translation};
|
use bevy_transform::prelude::{GlobalTransform, Transform};
|
||||||
|
|
||||||
/// A component bundle for "pbr mesh" entities
|
/// A component bundle for "pbr mesh" entities
|
||||||
#[derive(Bundle)]
|
#[derive(Bundle)]
|
||||||
|
@ -18,9 +18,7 @@ pub struct PbrComponents {
|
||||||
pub draw: Draw,
|
pub draw: Draw,
|
||||||
pub render_pipelines: RenderPipelines,
|
pub render_pipelines: RenderPipelines,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub translation: Translation,
|
pub global_transform: GlobalTransform,
|
||||||
pub rotation: Rotation,
|
|
||||||
pub scale: Scale,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PbrComponents {
|
impl Default for PbrComponents {
|
||||||
|
@ -49,9 +47,7 @@ impl Default for PbrComponents {
|
||||||
main_pass: Default::default(),
|
main_pass: Default::default(),
|
||||||
draw: Default::default(),
|
draw: Default::default(),
|
||||||
transform: Default::default(),
|
transform: Default::default(),
|
||||||
translation: Default::default(),
|
global_transform: Default::default(),
|
||||||
rotation: Default::default(),
|
|
||||||
scale: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,6 +57,5 @@ impl Default for PbrComponents {
|
||||||
pub struct LightComponents {
|
pub struct LightComponents {
|
||||||
pub light: Light,
|
pub light: Light,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub translation: Translation,
|
pub global_transform: GlobalTransform,
|
||||||
pub rotation: Rotation,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use bevy_core::Byteable;
|
use bevy_core::Byteable;
|
||||||
use bevy_math::Mat4;
|
|
||||||
use bevy_property::Properties;
|
use bevy_property::Properties;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::{CameraProjection, PerspectiveProjection},
|
camera::{CameraProjection, PerspectiveProjection},
|
||||||
color::Color,
|
color::Color,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::Translation;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
/// A point light
|
/// A point light
|
||||||
|
@ -37,7 +36,7 @@ pub(crate) struct LightRaw {
|
||||||
unsafe impl Byteable for LightRaw {}
|
unsafe impl Byteable for LightRaw {}
|
||||||
|
|
||||||
impl LightRaw {
|
impl LightRaw {
|
||||||
pub fn from(light: &Light, transform: &Mat4, translation: &Translation) -> LightRaw {
|
pub fn from(light: &Light, global_transform: &GlobalTransform) -> LightRaw {
|
||||||
let perspective = PerspectiveProjection {
|
let perspective = PerspectiveProjection {
|
||||||
fov: light.fov,
|
fov: light.fov,
|
||||||
aspect_ratio: 1.0,
|
aspect_ratio: 1.0,
|
||||||
|
@ -45,8 +44,8 @@ impl LightRaw {
|
||||||
far: light.depth.end,
|
far: light.depth.end,
|
||||||
};
|
};
|
||||||
|
|
||||||
let proj = perspective.get_projection_matrix() * *transform;
|
let proj = perspective.get_projection_matrix() * *global_transform.value();
|
||||||
let (x, y, z) = translation.0.into();
|
let (x, y, z) = global_transform.translation().into();
|
||||||
LightRaw {
|
LightRaw {
|
||||||
proj: proj.to_cols_array_2d(),
|
proj: proj.to_cols_array_2d(),
|
||||||
pos: [x, y, z, 1.0],
|
pos: [x, y, z, 1.0],
|
||||||
|
|
|
@ -80,7 +80,7 @@ pub fn lights_node_system(
|
||||||
render_resource_context: Res<Box<dyn RenderResourceContext>>,
|
render_resource_context: Res<Box<dyn RenderResourceContext>>,
|
||||||
// TODO: this write on RenderResourceBindings will prevent this system from running in parallel with other systems that do the same
|
// TODO: this write on RenderResourceBindings will prevent this system from running in parallel with other systems that do the same
|
||||||
mut render_resource_bindings: ResMut<RenderResourceBindings>,
|
mut render_resource_bindings: ResMut<RenderResourceBindings>,
|
||||||
mut query: Query<(&Light, &Transform, &Translation)>,
|
mut query: Query<(&Light, &GlobalTransform)>,
|
||||||
) {
|
) {
|
||||||
let state = &mut state;
|
let state = &mut state;
|
||||||
let render_resource_context = &**render_resource_context;
|
let render_resource_context = &**render_resource_context;
|
||||||
|
@ -132,14 +132,12 @@ pub fn lights_node_system(
|
||||||
data[0..light_count_size].copy_from_slice([light_count as u32, 0, 0, 0].as_bytes());
|
data[0..light_count_size].copy_from_slice([light_count as u32, 0, 0, 0].as_bytes());
|
||||||
|
|
||||||
// light array
|
// light array
|
||||||
for ((light, transform, translation), slot) in query
|
for ((light, global_transform), slot) in query
|
||||||
.iter()
|
.iter()
|
||||||
.iter()
|
.iter()
|
||||||
.zip(data[light_count_size..current_light_uniform_size].chunks_exact_mut(size))
|
.zip(data[light_count_size..current_light_uniform_size].chunks_exact_mut(size))
|
||||||
{
|
{
|
||||||
slot.copy_from_slice(
|
slot.copy_from_slice(LightRaw::from(&light, &global_transform).as_bytes());
|
||||||
LightRaw::from(&light, &transform.value, &translation).as_bytes(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -24,10 +24,13 @@ use bevy_render::{
|
||||||
render_graph::{base, AssetRenderResourcesNode, RenderGraph, RenderResourcesNode},
|
render_graph::{base, AssetRenderResourcesNode, RenderGraph, RenderResourcesNode},
|
||||||
shader::Shader,
|
shader::Shader,
|
||||||
};
|
};
|
||||||
use bevy_transform::prelude::Transform;
|
use bevy_transform::prelude::GlobalTransform;
|
||||||
|
|
||||||
pub(crate) fn add_pbr_graph(graph: &mut RenderGraph, resources: &Resources) {
|
pub(crate) fn add_pbr_graph(graph: &mut RenderGraph, resources: &Resources) {
|
||||||
graph.add_system_node(node::TRANSFORM, RenderResourcesNode::<Transform>::new(true));
|
graph.add_system_node(
|
||||||
|
node::TRANSFORM,
|
||||||
|
RenderResourcesNode::<GlobalTransform>::new(true),
|
||||||
|
);
|
||||||
graph.add_system_node(
|
graph.add_system_node(
|
||||||
node::STANDARD_MATERIAL,
|
node::STANDARD_MATERIAL,
|
||||||
AssetRenderResourcesNode::<StandardMaterial>::new(true),
|
AssetRenderResourcesNode::<StandardMaterial>::new(true),
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::Draw;
|
||||||
use bevy_core::FloatOrd;
|
use bevy_core::FloatOrd;
|
||||||
use bevy_ecs::{Entity, Query};
|
use bevy_ecs::{Entity, Query};
|
||||||
use bevy_property::Properties;
|
use bevy_property::Properties;
|
||||||
use bevy_transform::prelude::Transform;
|
use bevy_transform::prelude::GlobalTransform;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct VisibleEntity {
|
pub struct VisibleEntity {
|
||||||
|
@ -24,13 +24,13 @@ impl VisibleEntities {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visible_entities_system(
|
pub fn visible_entities_system(
|
||||||
mut camera_query: Query<(&Camera, &Transform, &mut VisibleEntities)>,
|
mut camera_query: Query<(&Camera, &GlobalTransform, &mut VisibleEntities)>,
|
||||||
mut draw_query: Query<(Entity, &Draw)>,
|
mut draw_query: Query<(Entity, &Draw)>,
|
||||||
draw_transform_query: Query<(&Draw, &Transform)>,
|
draw_transform_query: Query<(&Draw, &GlobalTransform)>,
|
||||||
) {
|
) {
|
||||||
for (camera, camera_transform, mut visible_entities) in &mut camera_query.iter() {
|
for (camera, camera_global_transform, mut visible_entities) in &mut camera_query.iter() {
|
||||||
visible_entities.value.clear();
|
visible_entities.value.clear();
|
||||||
let camera_position = camera_transform.value.w_axis().truncate();
|
let camera_position = camera_global_transform.translation();
|
||||||
|
|
||||||
let mut no_transform_order = 0.0;
|
let mut no_transform_order = 0.0;
|
||||||
let mut transparent_entities = Vec::new();
|
let mut transparent_entities = Vec::new();
|
||||||
|
@ -39,18 +39,19 @@ pub fn visible_entities_system(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let order = if let Ok(transform) = draw_transform_query.get::<Transform>(entity) {
|
let order =
|
||||||
let position = transform.value.w_axis().truncate();
|
if let Ok(global_transform) = draw_transform_query.get::<GlobalTransform>(entity) {
|
||||||
// smaller distances are sorted to lower indices by using the distance from the camera
|
let position = global_transform.translation();
|
||||||
FloatOrd(match camera.depth_calculation {
|
// smaller distances are sorted to lower indices by using the distance from the camera
|
||||||
DepthCalculation::ZDifference => camera_position.z() - position.z(),
|
FloatOrd(match camera.depth_calculation {
|
||||||
DepthCalculation::Distance => (camera_position - position).length(),
|
DepthCalculation::ZDifference => camera_position.z() - position.z(),
|
||||||
})
|
DepthCalculation::Distance => (camera_position - position).length(),
|
||||||
} else {
|
})
|
||||||
let order = FloatOrd(no_transform_order);
|
} else {
|
||||||
no_transform_order += 0.1;
|
let order = FloatOrd(no_transform_order);
|
||||||
order
|
no_transform_order += 0.1;
|
||||||
};
|
order
|
||||||
|
};
|
||||||
|
|
||||||
if draw.is_transparent {
|
if draw.is_transparent {
|
||||||
transparent_entities.push(VisibleEntity { entity, order })
|
transparent_entities.push(VisibleEntity { entity, order })
|
||||||
|
|
|
@ -7,7 +7,8 @@ use crate::{
|
||||||
use base::MainPass;
|
use base::MainPass;
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
use bevy_ecs::Bundle;
|
use bevy_ecs::Bundle;
|
||||||
use bevy_transform::components::{Rotation, Scale, Transform, Translation};
|
use bevy_math::Vec3;
|
||||||
|
use bevy_transform::components::{GlobalTransform, Transform};
|
||||||
|
|
||||||
/// A component bundle for "mesh" entities
|
/// A component bundle for "mesh" entities
|
||||||
#[derive(Bundle, Default)]
|
#[derive(Bundle, Default)]
|
||||||
|
@ -17,9 +18,7 @@ pub struct MeshComponents {
|
||||||
pub render_pipelines: RenderPipelines,
|
pub render_pipelines: RenderPipelines,
|
||||||
pub main_pass: MainPass,
|
pub main_pass: MainPass,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub translation: Translation,
|
pub global_transform: GlobalTransform,
|
||||||
pub rotation: Rotation,
|
|
||||||
pub scale: Scale,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A component bundle for "3d camera" entities
|
/// A component bundle for "3d camera" entities
|
||||||
|
@ -29,9 +28,7 @@ pub struct Camera3dComponents {
|
||||||
pub perspective_projection: PerspectiveProjection,
|
pub perspective_projection: PerspectiveProjection,
|
||||||
pub visible_entities: VisibleEntities,
|
pub visible_entities: VisibleEntities,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub translation: Translation,
|
pub global_transform: GlobalTransform,
|
||||||
pub rotation: Rotation,
|
|
||||||
pub scale: Scale,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Camera3dComponents {
|
impl Default for Camera3dComponents {
|
||||||
|
@ -44,9 +41,7 @@ impl Default for Camera3dComponents {
|
||||||
perspective_projection: Default::default(),
|
perspective_projection: Default::default(),
|
||||||
visible_entities: Default::default(),
|
visible_entities: Default::default(),
|
||||||
transform: Default::default(),
|
transform: Default::default(),
|
||||||
translation: Default::default(),
|
global_transform: Default::default(),
|
||||||
rotation: Default::default(),
|
|
||||||
scale: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,9 +53,7 @@ pub struct Camera2dComponents {
|
||||||
pub orthographic_projection: OrthographicProjection,
|
pub orthographic_projection: OrthographicProjection,
|
||||||
pub visible_entities: VisibleEntities,
|
pub visible_entities: VisibleEntities,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub translation: Translation,
|
pub global_transform: GlobalTransform,
|
||||||
pub rotation: Rotation,
|
|
||||||
pub scale: Scale,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Camera2dComponents {
|
impl Default for Camera2dComponents {
|
||||||
|
@ -78,10 +71,8 @@ impl Default for Camera2dComponents {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
visible_entities: Default::default(),
|
visible_entities: Default::default(),
|
||||||
transform: Default::default(),
|
transform: Transform::from_translation(Vec3::new(0.0, 0.0, far - 0.1)),
|
||||||
translation: Translation::new(0.0, 0.0, far - 0.1),
|
global_transform: Default::default(),
|
||||||
rotation: Default::default(),
|
|
||||||
scale: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,18 +73,19 @@ pub fn camera_node_system(
|
||||||
// PERF: this write on RenderResourceAssignments will prevent this system from running in parallel
|
// PERF: this write on RenderResourceAssignments will prevent this system from running in parallel
|
||||||
// with other systems that do the same
|
// with other systems that do the same
|
||||||
mut render_resource_bindings: ResMut<RenderResourceBindings>,
|
mut render_resource_bindings: ResMut<RenderResourceBindings>,
|
||||||
query: Query<(&Camera, &Transform)>,
|
query: Query<(&Camera, &GlobalTransform)>,
|
||||||
) {
|
) {
|
||||||
let render_resource_context = &**render_resource_context;
|
let render_resource_context = &**render_resource_context;
|
||||||
|
|
||||||
let (camera, transform) = if let Some(camera_entity) = active_cameras.get(&state.camera_name) {
|
let (camera, global_transform) =
|
||||||
(
|
if let Some(camera_entity) = active_cameras.get(&state.camera_name) {
|
||||||
query.get::<Camera>(camera_entity).unwrap(),
|
(
|
||||||
query.get::<Transform>(camera_entity).unwrap(),
|
query.get::<Camera>(camera_entity).unwrap(),
|
||||||
)
|
query.get::<GlobalTransform>(camera_entity).unwrap(),
|
||||||
} else {
|
)
|
||||||
return;
|
} else {
|
||||||
};
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let staging_buffer = if let Some(staging_buffer) = state.staging_buffer {
|
let staging_buffer = if let Some(staging_buffer) = state.staging_buffer {
|
||||||
render_resource_context.map_buffer(staging_buffer);
|
render_resource_context.map_buffer(staging_buffer);
|
||||||
|
@ -118,7 +119,7 @@ pub fn camera_node_system(
|
||||||
|
|
||||||
let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>();
|
let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>();
|
||||||
let camera_matrix: [f32; 16] =
|
let camera_matrix: [f32; 16] =
|
||||||
(camera.projection_matrix * transform.value.inverse()).to_cols_array();
|
(camera.projection_matrix * global_transform.value().inverse()).to_cols_array();
|
||||||
|
|
||||||
render_resource_context.write_mapped_buffer(
|
render_resource_context.write_mapped_buffer(
|
||||||
staging_buffer,
|
staging_buffer,
|
||||||
|
|
|
@ -179,14 +179,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderResources for bevy_transform::prelude::Transform {
|
impl RenderResources for bevy_transform::prelude::GlobalTransform {
|
||||||
fn render_resources_len(&self) -> usize {
|
fn render_resources_len(&self) -> usize {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_render_resource(&self, index: usize) -> Option<&dyn RenderResource> {
|
fn get_render_resource(&self, index: usize) -> Option<&dyn RenderResource> {
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
Some(&self.value)
|
Some(self.value())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use bevy_render::{
|
||||||
prelude::Draw,
|
prelude::Draw,
|
||||||
render_graph::base::MainPass,
|
render_graph::base::MainPass,
|
||||||
};
|
};
|
||||||
use bevy_transform::prelude::{Rotation, Scale, Transform, Translation};
|
use bevy_transform::prelude::{GlobalTransform, Transform};
|
||||||
|
|
||||||
#[derive(Bundle)]
|
#[derive(Bundle)]
|
||||||
pub struct SpriteComponents {
|
pub struct SpriteComponents {
|
||||||
|
@ -21,9 +21,7 @@ pub struct SpriteComponents {
|
||||||
pub draw: Draw,
|
pub draw: Draw,
|
||||||
pub render_pipelines: RenderPipelines,
|
pub render_pipelines: RenderPipelines,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub translation: Translation,
|
pub global_transform: GlobalTransform,
|
||||||
pub rotation: Rotation,
|
|
||||||
pub scale: Scale,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SpriteComponents {
|
impl Default for SpriteComponents {
|
||||||
|
@ -56,9 +54,7 @@ impl Default for SpriteComponents {
|
||||||
main_pass: MainPass,
|
main_pass: MainPass,
|
||||||
material: Default::default(),
|
material: Default::default(),
|
||||||
transform: Default::default(),
|
transform: Default::default(),
|
||||||
translation: Default::default(),
|
global_transform: Default::default(),
|
||||||
rotation: Default::default(),
|
|
||||||
scale: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,9 +73,7 @@ pub struct SpriteSheetComponents {
|
||||||
pub main_pass: MainPass,
|
pub main_pass: MainPass,
|
||||||
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub translation: Translation,
|
pub global_transform: GlobalTransform,
|
||||||
pub rotation: Rotation,
|
|
||||||
pub scale: Scale,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SpriteSheetComponents {
|
impl Default for SpriteSheetComponents {
|
||||||
|
@ -112,9 +106,7 @@ impl Default for SpriteSheetComponents {
|
||||||
sprite: Default::default(),
|
sprite: Default::default(),
|
||||||
texture_atlas: Default::default(),
|
texture_atlas: Default::default(),
|
||||||
transform: Default::default(),
|
transform: Default::default(),
|
||||||
translation: Default::default(),
|
global_transform: Default::default(),
|
||||||
rotation: Default::default(),
|
|
||||||
scale: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
119
crates/bevy_transform/src/components/global_transform.rs
Normal file
119
crates/bevy_transform/src/components/global_transform.rs
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
use bevy_math::{Mat3, Mat4, Quat, Vec3};
|
||||||
|
use bevy_property::Properties;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone, Copy, Properties)]
|
||||||
|
pub struct GlobalTransform {
|
||||||
|
value: Mat4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlobalTransform {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn new(value: Mat4) -> Self {
|
||||||
|
GlobalTransform { value }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn identity() -> Self {
|
||||||
|
GlobalTransform {
|
||||||
|
value: Mat4::identity(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_translation(translation: Vec3) -> Self {
|
||||||
|
GlobalTransform::new(Mat4::from_translation(translation))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_rotation(rotation: Quat) -> Self {
|
||||||
|
GlobalTransform::new(Mat4::from_quat(rotation))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make sure scale is positive
|
||||||
|
pub fn from_scale(scale: Vec3) -> Self {
|
||||||
|
GlobalTransform::new(Mat4::from_scale(scale))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_translation(mut self, translation: Vec3) -> Self {
|
||||||
|
self.translate(translation);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_rotation(mut self, rotation: Quat) -> Self {
|
||||||
|
self.rotate(rotation);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_scale(mut self, scale: Vec3) -> Self {
|
||||||
|
self.apply_scale(scale);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> &Mat4 {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value_mut(&mut self) -> &mut Mat4 {
|
||||||
|
&mut self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translation(&self) -> Vec3 {
|
||||||
|
Vec3::from(self.value.w_axis().truncate())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotation(&self) -> Quat {
|
||||||
|
let scale = self.scale();
|
||||||
|
|
||||||
|
Quat::from_rotation_mat3(&Mat3::from_cols(
|
||||||
|
Vec3::from(self.value.x_axis().truncate()) / scale.x(),
|
||||||
|
Vec3::from(self.value.y_axis().truncate()) / scale.y(),
|
||||||
|
Vec3::from(self.value.z_axis().truncate()) / scale.z(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale(&self) -> Vec3 {
|
||||||
|
Vec3::new(
|
||||||
|
self.value.x_axis().truncate().length(),
|
||||||
|
self.value.y_axis().truncate().length(),
|
||||||
|
self.value.z_axis().truncate().length(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_translation(&mut self, translation: Vec3) {
|
||||||
|
*self.value.w_axis_mut() = translation.extend(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_rotation(&mut self, rotation: Quat) {
|
||||||
|
let rotation = rotation * self.rotation().conjugate();
|
||||||
|
rotation.normalize();
|
||||||
|
self.value = Mat4::from_quat(rotation) * self.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_scale(&mut self, scale: Vec3) {
|
||||||
|
let scale = scale / self.scale();
|
||||||
|
self.value = Mat4::from_scale(scale) * self.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translate(&mut self, translation: Vec3) {
|
||||||
|
*self.value.w_axis_mut() += translation.extend(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotate(&mut self, rotation: Quat) {
|
||||||
|
self.value = Mat4::from_quat(rotation) * self.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_scale(&mut self, scale: Vec3) {
|
||||||
|
self.value = Mat4::from_scale(scale) * self.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for GlobalTransform {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::identity()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for GlobalTransform {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.value)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,41 +0,0 @@
|
||||||
use bevy_math::Mat4;
|
|
||||||
use bevy_property::Properties;
|
|
||||||
use std::{
|
|
||||||
fmt,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy, Properties)]
|
|
||||||
pub struct LocalTransform(pub Mat4);
|
|
||||||
|
|
||||||
impl LocalTransform {
|
|
||||||
pub fn identity() -> Self {
|
|
||||||
Self(Mat4::identity())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for LocalTransform {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::identity()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for LocalTransform {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for LocalTransform {
|
|
||||||
type Target = Mat4;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for LocalTransform {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +1,9 @@
|
||||||
mod children;
|
mod children;
|
||||||
mod local_transform;
|
mod global_transform;
|
||||||
mod non_uniform_scale;
|
|
||||||
mod parent;
|
mod parent;
|
||||||
mod rotation;
|
|
||||||
mod scale;
|
|
||||||
mod transform;
|
mod transform;
|
||||||
mod translation;
|
|
||||||
|
|
||||||
pub use children::Children;
|
pub use children::Children;
|
||||||
pub use local_transform::*;
|
pub use global_transform::*;
|
||||||
pub use non_uniform_scale::*;
|
|
||||||
pub use parent::{Parent, PreviousParent};
|
pub use parent::{Parent, PreviousParent};
|
||||||
pub use rotation::*;
|
|
||||||
pub use scale::*;
|
|
||||||
pub use transform::*;
|
pub use transform::*;
|
||||||
pub use translation::*;
|
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
use bevy_math::Vec3;
|
|
||||||
use bevy_property::Properties;
|
|
||||||
use std::{
|
|
||||||
fmt,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy, Properties)]
|
|
||||||
pub struct NonUniformScale(pub Vec3);
|
|
||||||
|
|
||||||
impl NonUniformScale {
|
|
||||||
pub fn new(x: f32, y: f32, z: f32) -> Self {
|
|
||||||
Self(Vec3::new(x, y, z))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for NonUniformScale {
|
|
||||||
fn default() -> Self {
|
|
||||||
NonUniformScale(Vec3::new(1.0, 1.0, 1.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Vec3> for NonUniformScale {
|
|
||||||
fn from(scale: Vec3) -> Self {
|
|
||||||
Self(scale)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Vec3> for NonUniformScale {
|
|
||||||
fn from(scale: &Vec3) -> Self {
|
|
||||||
Self(*scale)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&mut Vec3> for NonUniformScale {
|
|
||||||
fn from(scale: &mut Vec3) -> Self {
|
|
||||||
Self(*scale)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for NonUniformScale {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let (x, y, z) = self.0.into();
|
|
||||||
write!(f, "NonUniformScale({}, {}, {})", x, y, z)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for NonUniformScale {
|
|
||||||
type Target = Vec3;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for NonUniformScale {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
use bevy_math::Quat;
|
|
||||||
use bevy_property::Properties;
|
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy, Properties)]
|
|
||||||
pub struct Rotation(pub Quat);
|
|
||||||
impl Rotation {
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn identity() -> Self {
|
|
||||||
Self(Quat::identity())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_rotation_yxz(yaw: f32, pitch: f32, roll: f32) -> Self {
|
|
||||||
Self(Quat::from_rotation_ypr(yaw, pitch, roll))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_rotation_xyz(x: f32, y: f32, z: f32) -> Self {
|
|
||||||
Self(Quat::from_rotation_ypr(y, x, z))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_rotation_x(x: f32) -> Self {
|
|
||||||
Self(Quat::from_rotation_x(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_rotation_y(y: f32) -> Self {
|
|
||||||
Self(Quat::from_rotation_y(y))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_rotation_z(z: f32) -> Self {
|
|
||||||
Self(Quat::from_rotation_z(z))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Rotation {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::identity()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Quat> for Rotation {
|
|
||||||
fn from(rotation: Quat) -> Self {
|
|
||||||
Self(rotation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Rotation {
|
|
||||||
type Target = Quat;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Rotation {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
use bevy_property::Properties;
|
|
||||||
use std::{
|
|
||||||
fmt,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy, Properties)]
|
|
||||||
pub struct Scale(pub f32);
|
|
||||||
|
|
||||||
impl From<f32> for Scale {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from(scale: f32) -> Self {
|
|
||||||
Self(scale)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Scale {
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn identity() -> Self {
|
|
||||||
Scale(1.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Scale {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::identity()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Scale {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "Scale({})", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Scale {
|
|
||||||
type Target = f32;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Scale {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +1,108 @@
|
||||||
use bevy_math::Mat4;
|
use bevy_math::{Mat3, Mat4, Quat, Vec3};
|
||||||
use bevy_property::Properties;
|
use bevy_property::Properties;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy, Properties)]
|
#[derive(Debug, PartialEq, Clone, Copy, Properties)]
|
||||||
pub struct Transform {
|
pub struct Transform {
|
||||||
pub value: Mat4,
|
value: Mat4,
|
||||||
pub sync: bool, // NOTE: this is hopefully a temporary measure to allow setting the transform directly.
|
|
||||||
// ideally setting the transform automatically propagates back to position / translation / rotation,
|
|
||||||
// but right now they are always considered the source of truth
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Transform {
|
impl Transform {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn new(value: Mat4) -> Self {
|
||||||
|
Transform { value }
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn identity() -> Self {
|
pub fn identity() -> Self {
|
||||||
Transform {
|
Transform {
|
||||||
value: Mat4::identity(),
|
value: Mat4::identity(),
|
||||||
sync: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
pub fn from_translation(translation: Vec3) -> Self {
|
||||||
pub fn new(value: Mat4) -> Self {
|
Transform::new(Mat4::from_translation(translation))
|
||||||
Transform { value, sync: true }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This creates a new `LocalToWorld` transform with the `sync` field set to `false`.
|
pub fn from_rotation(rotation: Quat) -> Self {
|
||||||
/// While `sync` is false, position, rotation, and scale components will not be synced to the transform.
|
Transform::new(Mat4::from_quat(rotation))
|
||||||
/// This is helpful if you want to manually set the transform to a value (ex: Mat4::face_toward)
|
}
|
||||||
#[inline(always)]
|
|
||||||
pub fn new_sync_disabled(value: Mat4) -> Self {
|
// TODO: make sure scale is positive
|
||||||
Transform { value, sync: false }
|
pub fn from_scale(scale: Vec3) -> Self {
|
||||||
|
Transform::new(Mat4::from_scale(scale))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_translation(mut self, translation: Vec3) -> Self {
|
||||||
|
self.translate(translation);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_rotation(mut self, rotation: Quat) -> Self {
|
||||||
|
self.rotate(rotation);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_scale(mut self, scale: Vec3) -> Self {
|
||||||
|
self.apply_scale(scale);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> &Mat4 {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value_mut(&mut self) -> &mut Mat4 {
|
||||||
|
&mut self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translation(&self) -> Vec3 {
|
||||||
|
Vec3::from(self.value.w_axis().truncate())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotation(&self) -> Quat {
|
||||||
|
let scale = self.scale();
|
||||||
|
|
||||||
|
Quat::from_rotation_mat3(&Mat3::from_cols(
|
||||||
|
Vec3::from(self.value.x_axis().truncate()) / scale.x(),
|
||||||
|
Vec3::from(self.value.y_axis().truncate()) / scale.y(),
|
||||||
|
Vec3::from(self.value.z_axis().truncate()) / scale.z(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale(&self) -> Vec3 {
|
||||||
|
Vec3::new(
|
||||||
|
self.value.x_axis().truncate().length(),
|
||||||
|
self.value.y_axis().truncate().length(),
|
||||||
|
self.value.z_axis().truncate().length(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_translation(&mut self, translation: Vec3) {
|
||||||
|
*self.value.w_axis_mut() = translation.extend(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_rotation(&mut self, rotation: Quat) {
|
||||||
|
let rotation = rotation * self.rotation().conjugate();
|
||||||
|
rotation.normalize();
|
||||||
|
self.value = Mat4::from_quat(rotation) * self.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_scale(&mut self, scale: Vec3) {
|
||||||
|
let scale = scale / self.scale();
|
||||||
|
self.value = Mat4::from_scale(scale) * self.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translate(&mut self, translation: Vec3) {
|
||||||
|
*self.value.w_axis_mut() += translation.extend(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotate(&mut self, rotation: Quat) {
|
||||||
|
self.value = Mat4::from_quat(rotation) * self.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_scale(&mut self, scale: Vec3) {
|
||||||
|
self.value = Mat4::from_scale(scale) * self.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
use bevy_math::Vec3;
|
|
||||||
use bevy_property::Properties;
|
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Copy, Clone, Properties)]
|
|
||||||
pub struct Translation(pub Vec3);
|
|
||||||
|
|
||||||
impl Translation {
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn identity() -> Self {
|
|
||||||
Self(Vec3::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn new(x: f32, y: f32, z: f32) -> Self {
|
|
||||||
Self(Vec3::new(x, y, z))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Translation {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::identity()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Vec3> for Translation {
|
|
||||||
fn from(translation: Vec3) -> Self {
|
|
||||||
Self(translation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Translation {
|
|
||||||
type Target = Vec3;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Translation {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::prelude::{Children, LocalTransform, Parent, PreviousParent};
|
use crate::prelude::{Children, Parent, PreviousParent};
|
||||||
use bevy_ecs::{Commands, CommandsInternal, Component, DynamicBundle, Entity, WorldWriter};
|
use bevy_ecs::{Commands, CommandsInternal, Component, DynamicBundle, Entity, WorldWriter};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
|
@ -14,11 +14,7 @@ impl WorldWriter for InsertChildren {
|
||||||
world
|
world
|
||||||
.insert(
|
.insert(
|
||||||
*child,
|
*child,
|
||||||
(
|
(Parent(self.parent), PreviousParent(Some(self.parent))),
|
||||||
Parent(self.parent),
|
|
||||||
PreviousParent(Some(self.parent)),
|
|
||||||
LocalTransform::default(),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -55,11 +51,7 @@ impl WorldWriter for PushChildren {
|
||||||
world
|
world
|
||||||
.insert(
|
.insert(
|
||||||
*child,
|
*child,
|
||||||
(
|
(Parent(self.parent), PreviousParent(Some(self.parent))),
|
||||||
Parent(self.parent),
|
|
||||||
PreviousParent(Some(self.parent)),
|
|
||||||
LocalTransform::default(),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -215,7 +207,7 @@ impl<'a> BuildChildren for ChildBuilder<'a> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::BuildChildren;
|
use super::BuildChildren;
|
||||||
use crate::prelude::{Children, LocalTransform, Parent, PreviousParent};
|
use crate::prelude::{Children, Parent, PreviousParent};
|
||||||
use bevy_ecs::{Commands, Entity, Resources, World};
|
use bevy_ecs::{Commands, Entity, Resources, World};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
|
||||||
|
@ -261,9 +253,6 @@ mod tests {
|
||||||
*world.get::<PreviousParent>(child2).unwrap(),
|
*world.get::<PreviousParent>(child2).unwrap(),
|
||||||
PreviousParent(Some(parent))
|
PreviousParent(Some(parent))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(world.get::<LocalTransform>(child1).is_ok());
|
|
||||||
assert!(world.get::<LocalTransform>(child2).is_ok());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -301,9 +290,6 @@ mod tests {
|
||||||
PreviousParent(Some(parent))
|
PreviousParent(Some(parent))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(world.get::<LocalTransform>(child1).is_ok());
|
|
||||||
assert!(world.get::<LocalTransform>(child2).is_ok());
|
|
||||||
|
|
||||||
commands.insert_children(parent, 1, &entities[3..]);
|
commands.insert_children(parent, 1, &entities[3..]);
|
||||||
commands.apply(&mut world, &mut resources);
|
commands.apply(&mut world, &mut resources);
|
||||||
|
|
||||||
|
@ -322,8 +308,5 @@ mod tests {
|
||||||
*world.get::<PreviousParent>(child4).unwrap(),
|
*world.get::<PreviousParent>(child4).unwrap(),
|
||||||
PreviousParent(Some(parent))
|
PreviousParent(Some(parent))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(world.get::<LocalTransform>(child3).is_ok());
|
|
||||||
assert!(world.get::<LocalTransform>(child4).is_ok());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,7 @@ mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{hierarchy::BuildChildren, transform_systems};
|
use crate::{hierarchy::BuildChildren, transform_systems};
|
||||||
use bevy_ecs::{Resources, Schedule, World};
|
use bevy_ecs::{Resources, Schedule, World};
|
||||||
|
use bevy_math::Vec3;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn correct_children() {
|
fn correct_children() {
|
||||||
|
@ -127,13 +128,13 @@ mod test {
|
||||||
let mut parent = None;
|
let mut parent = None;
|
||||||
let mut children = Vec::new();
|
let mut children = Vec::new();
|
||||||
commands
|
commands
|
||||||
.spawn((Translation::new(1.0, 0.0, 0.0), Transform::identity()))
|
.spawn((Transform::from_translation(Vec3::new(1.0, 0.0, 0.0)),))
|
||||||
.for_current_entity(|entity| parent = Some(entity))
|
.for_current_entity(|entity| parent = Some(entity))
|
||||||
.with_children(|parent| {
|
.with_children(|parent| {
|
||||||
parent
|
parent
|
||||||
.spawn((Translation::new(0.0, 2.0, 0.0), Transform::identity()))
|
.spawn((Transform::from_translation(Vec3::new(0.0, 2.0, 0.0)),))
|
||||||
.for_current_entity(|entity| children.push(entity))
|
.for_current_entity(|entity| children.push(entity))
|
||||||
.spawn((Translation::new(0.0, 0.0, 3.0), Transform::identity()))
|
.spawn((Transform::from_translation(Vec3::new(0.0, 0.0, 3.0)),))
|
||||||
.for_current_entity(|entity| children.push(entity));
|
.for_current_entity(|entity| children.push(entity));
|
||||||
});
|
});
|
||||||
let parent = parent.unwrap();
|
let parent = parent.unwrap();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::prelude::{Children, LocalTransform, Parent, PreviousParent};
|
use crate::prelude::{Children, Parent, PreviousParent};
|
||||||
use bevy_ecs::{Component, DynamicBundle, Entity, WorldBuilder};
|
use bevy_ecs::{Component, DynamicBundle, Entity, WorldBuilder};
|
||||||
|
|
||||||
pub struct WorldChildBuilder<'a, 'b> {
|
pub struct WorldChildBuilder<'a, 'b> {
|
||||||
|
@ -23,11 +23,7 @@ impl<'a, 'b> WorldChildBuilder<'a, 'b> {
|
||||||
.expect("There should always be a parent at this point.");
|
.expect("There should always be a parent at this point.");
|
||||||
self.world_builder
|
self.world_builder
|
||||||
.spawn_as_entity(entity, components)
|
.spawn_as_entity(entity, components)
|
||||||
.with_bundle((
|
.with_bundle((Parent(parent_entity), PreviousParent(Some(parent_entity))));
|
||||||
Parent(parent_entity),
|
|
||||||
PreviousParent(Some(parent_entity)),
|
|
||||||
LocalTransform::default(),
|
|
||||||
));
|
|
||||||
{
|
{
|
||||||
let world = &mut self.world_builder.world;
|
let world = &mut self.world_builder.world;
|
||||||
let mut added = false;
|
let mut added = false;
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
pub mod components;
|
pub mod components;
|
||||||
pub mod hierarchy;
|
pub mod hierarchy;
|
||||||
pub mod local_transform_systems;
|
|
||||||
pub mod transform_propagate_system;
|
pub mod transform_propagate_system;
|
||||||
pub mod transform_systems;
|
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{components::*, hierarchy::*, TransformPlugin};
|
pub use crate::{components::*, hierarchy::*, TransformPlugin};
|
||||||
|
@ -11,16 +9,12 @@ pub mod prelude {
|
||||||
use bevy_app::prelude::*;
|
use bevy_app::prelude::*;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_type_registry::RegisterType;
|
use bevy_type_registry::RegisterType;
|
||||||
use prelude::{
|
use prelude::{Children, Parent, Transform};
|
||||||
Children, LocalTransform, NonUniformScale, Parent, Rotation, Scale, Transform, Translation,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub(crate) fn transform_systems() -> Vec<Box<dyn System>> {
|
pub(crate) fn transform_systems() -> Vec<Box<dyn System>> {
|
||||||
let mut systems = Vec::with_capacity(5);
|
let mut systems = Vec::with_capacity(5);
|
||||||
|
|
||||||
systems.append(&mut hierarchy::hierarchy_maintenance_systems());
|
systems.append(&mut hierarchy::hierarchy_maintenance_systems());
|
||||||
systems.append(&mut local_transform_systems::local_transform_systems());
|
|
||||||
systems.append(&mut transform_systems::transform_systems());
|
|
||||||
systems.push(transform_propagate_system::transform_propagate_system.system());
|
systems.push(transform_propagate_system::transform_propagate_system.system());
|
||||||
|
|
||||||
systems
|
systems
|
||||||
|
@ -33,12 +27,7 @@ impl Plugin for TransformPlugin {
|
||||||
fn build(&self, app: &mut AppBuilder) {
|
fn build(&self, app: &mut AppBuilder) {
|
||||||
app.register_component::<Children>()
|
app.register_component::<Children>()
|
||||||
.register_component::<Parent>()
|
.register_component::<Parent>()
|
||||||
.register_component::<LocalTransform>()
|
|
||||||
.register_component::<Transform>()
|
.register_component::<Transform>()
|
||||||
.register_component::<Translation>()
|
|
||||||
.register_component::<Rotation>()
|
|
||||||
.register_component::<Scale>()
|
|
||||||
.register_component::<NonUniformScale>()
|
|
||||||
// add transform systems to startup so the first update is "correct"
|
// add transform systems to startup so the first update is "correct"
|
||||||
.add_startup_systems(transform_systems())
|
.add_startup_systems(transform_systems())
|
||||||
.add_systems_to_stage(stage::POST_UPDATE, transform_systems());
|
.add_systems_to_stage(stage::POST_UPDATE, transform_systems());
|
||||||
|
|
|
@ -1,365 +0,0 @@
|
||||||
use crate::components::*;
|
|
||||||
use bevy_ecs::prelude::*;
|
|
||||||
use bevy_math::{Mat4, Quat, Vec3};
|
|
||||||
|
|
||||||
// TODO: "on changed" for all of these systems
|
|
||||||
pub fn local_transform_translation_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
Rotation,
|
|
||||||
Without<Scale, Without<NonUniformScale, (&mut LocalTransform, Changed<Translation>)>>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut local, translation) in &mut query.iter() {
|
|
||||||
*local = LocalTransform(Mat4::from_translation(translation.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_transform_rotation_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
Translation,
|
|
||||||
Without<Scale, Without<NonUniformScale, (&mut LocalTransform, Changed<Rotation>)>>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut local, rotation) in &mut query.iter() {
|
|
||||||
*local = LocalTransform(Mat4::from_quat(rotation.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_transform_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
Translation,
|
|
||||||
Without<Rotation, Without<NonUniformScale, (&mut LocalTransform, Changed<Scale>)>>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut local, scale) in &mut query.iter() {
|
|
||||||
*local = LocalTransform(Mat4::from_scale(Vec3::new(scale.0, scale.0, scale.0)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_transform_non_uniform_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
Translation,
|
|
||||||
Without<Rotation, Without<Scale, (&mut LocalTransform, Changed<NonUniformScale>)>>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut local, non_uniform_scale) in &mut query.iter() {
|
|
||||||
*local = LocalTransform(Mat4::from_scale(non_uniform_scale.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_transform_translation_rotation_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
Scale,
|
|
||||||
Without<
|
|
||||||
NonUniformScale,
|
|
||||||
(
|
|
||||||
&mut LocalTransform,
|
|
||||||
Or<(Changed<Translation>, Changed<Rotation>)>,
|
|
||||||
),
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut local, (translation, rotation)) in &mut query.iter() {
|
|
||||||
*local = LocalTransform(Mat4::from_rotation_translation(rotation.0, translation.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_transform_translation_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
Rotation,
|
|
||||||
Without<
|
|
||||||
NonUniformScale,
|
|
||||||
(
|
|
||||||
&mut LocalTransform,
|
|
||||||
Or<(Changed<Translation>, Changed<Scale>)>,
|
|
||||||
),
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut local, (translation, scale)) in &mut query.iter() {
|
|
||||||
*local = LocalTransform(Mat4::from_scale_rotation_translation(
|
|
||||||
Vec3::new(scale.0, scale.0, scale.0),
|
|
||||||
Quat::default(),
|
|
||||||
translation.0,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_transform_translation_non_uniform_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
Rotation,
|
|
||||||
Without<
|
|
||||||
Scale,
|
|
||||||
(
|
|
||||||
&mut LocalTransform,
|
|
||||||
Or<(Changed<Translation>, Changed<NonUniformScale>)>,
|
|
||||||
),
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut local, (translation, non_uniform_scale)) in &mut query.iter() {
|
|
||||||
*local = LocalTransform(Mat4::from_scale_rotation_translation(
|
|
||||||
non_uniform_scale.0,
|
|
||||||
Quat::default(),
|
|
||||||
translation.0,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_transform_rotation_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
Translation,
|
|
||||||
Without<
|
|
||||||
NonUniformScale,
|
|
||||||
(&mut LocalTransform, Or<(Changed<Rotation>, Changed<Scale>)>),
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut local, (rotation, scale)) in &mut query.iter() {
|
|
||||||
*local = LocalTransform(Mat4::from_scale_rotation_translation(
|
|
||||||
Vec3::new(scale.0, scale.0, scale.0),
|
|
||||||
rotation.0,
|
|
||||||
Vec3::default(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_transform_rotation_non_uniform_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
Translation,
|
|
||||||
Without<
|
|
||||||
Scale,
|
|
||||||
(
|
|
||||||
&mut LocalTransform,
|
|
||||||
Or<(Changed<Rotation>, Changed<NonUniformScale>)>,
|
|
||||||
),
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut local, (rotation, non_uniform_scale)) in &mut query.iter() {
|
|
||||||
*local = LocalTransform(Mat4::from_scale_rotation_translation(
|
|
||||||
non_uniform_scale.0,
|
|
||||||
rotation.0,
|
|
||||||
Vec3::default(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_transform_translation_rotation_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
NonUniformScale,
|
|
||||||
(
|
|
||||||
&mut LocalTransform,
|
|
||||||
Or<(Changed<Translation>, Changed<Rotation>, Changed<Scale>)>,
|
|
||||||
),
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut local, (translation, rotation, scale)) in &mut query.iter() {
|
|
||||||
*local = LocalTransform(Mat4::from_scale_rotation_translation(
|
|
||||||
Vec3::new(scale.0, scale.0, scale.0),
|
|
||||||
rotation.0,
|
|
||||||
translation.0,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_transform_translation_rotation_non_uniform_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
Scale,
|
|
||||||
(
|
|
||||||
&mut LocalTransform,
|
|
||||||
Or<(
|
|
||||||
Changed<Translation>,
|
|
||||||
Changed<Rotation>,
|
|
||||||
Changed<NonUniformScale>,
|
|
||||||
)>,
|
|
||||||
),
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut local, (translation, rotation, non_uniform_scale)) in &mut query.iter() {
|
|
||||||
*local = LocalTransform(Mat4::from_scale_rotation_translation(
|
|
||||||
non_uniform_scale.0,
|
|
||||||
rotation.0,
|
|
||||||
translation.0,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn local_transform_systems() -> Vec<Box<dyn System>> {
|
|
||||||
vec![
|
|
||||||
local_transform_translation_system.system(),
|
|
||||||
local_transform_rotation_system.system(),
|
|
||||||
local_transform_scale_system.system(),
|
|
||||||
local_transform_non_uniform_scale_system.system(),
|
|
||||||
local_transform_translation_rotation_system.system(),
|
|
||||||
local_transform_translation_scale_system.system(),
|
|
||||||
local_transform_translation_non_uniform_scale_system.system(),
|
|
||||||
local_transform_rotation_scale_system.system(),
|
|
||||||
local_transform_rotation_non_uniform_scale_system.system(),
|
|
||||||
local_transform_translation_rotation_scale_system.system(),
|
|
||||||
local_transform_translation_rotation_non_uniform_scale_system.system(),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
use bevy_ecs::{Resources, Schedule, World};
|
|
||||||
use bevy_math::{Mat4, Quat, Vec3};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn correct_local_transformation() {
|
|
||||||
let mut world = World::default();
|
|
||||||
let mut resources = Resources::default();
|
|
||||||
|
|
||||||
let mut schedule = Schedule::default();
|
|
||||||
schedule.add_stage("update");
|
|
||||||
for system in local_transform_systems() {
|
|
||||||
schedule.add_system_to_stage("update", system);
|
|
||||||
}
|
|
||||||
|
|
||||||
let local_transform = LocalTransform::identity();
|
|
||||||
let t = Translation::new(1.0, 2.0, 3.0);
|
|
||||||
let r = Rotation(Quat::from_rotation_ypr(1.0, 2.0, 3.0));
|
|
||||||
let s = Scale(2.0);
|
|
||||||
let nus = NonUniformScale::new(1.0, 2.0, 3.0);
|
|
||||||
|
|
||||||
// Add every combination of transform types.
|
|
||||||
let translation = world.spawn((local_transform, t));
|
|
||||||
let rotation = world.spawn((local_transform, r));
|
|
||||||
let scale = world.spawn((local_transform, s));
|
|
||||||
let non_uniform_scale = world.spawn((local_transform, nus));
|
|
||||||
let translation_and_rotation = world.spawn((local_transform, t, r));
|
|
||||||
let translation_and_scale = world.spawn((local_transform, t, s));
|
|
||||||
let translation_and_nus = world.spawn((local_transform, t, nus));
|
|
||||||
let rotation_scale = world.spawn((local_transform, r, s));
|
|
||||||
let rotation_nus = world.spawn((local_transform, r, nus));
|
|
||||||
let translation_rotation_scale = world.spawn((local_transform, t, r, s));
|
|
||||||
let translation_rotation_nus = world.spawn((local_transform, t, r, nus));
|
|
||||||
|
|
||||||
// Run the system
|
|
||||||
schedule.run(&mut world, &mut resources);
|
|
||||||
|
|
||||||
// Verify that each was transformed correctly.
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<LocalTransform>(translation).unwrap().0,
|
|
||||||
Mat4::from_translation(t.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<LocalTransform>(rotation).unwrap().0,
|
|
||||||
Mat4::from_quat(r.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<LocalTransform>(scale).unwrap().0,
|
|
||||||
Mat4::from_scale(Vec3::new(s.0, s.0, s.0))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<LocalTransform>(non_uniform_scale).unwrap().0,
|
|
||||||
Mat4::from_scale(nus.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world
|
|
||||||
.get::<LocalTransform>(translation_and_rotation)
|
|
||||||
.unwrap()
|
|
||||||
.0,
|
|
||||||
Mat4::from_rotation_translation(r.0, t.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world
|
|
||||||
.get::<LocalTransform>(translation_and_scale)
|
|
||||||
.unwrap()
|
|
||||||
.0,
|
|
||||||
Mat4::from_scale_rotation_translation(Vec3::new(s.0, s.0, s.0), Quat::default(), t.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<LocalTransform>(translation_and_nus).unwrap().0,
|
|
||||||
Mat4::from_scale_rotation_translation(nus.0, Quat::default(), t.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<LocalTransform>(rotation_scale).unwrap().0,
|
|
||||||
Mat4::from_scale_rotation_translation(Vec3::new(s.0, s.0, s.0), r.0, Vec3::default())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<LocalTransform>(rotation_nus).unwrap().0,
|
|
||||||
Mat4::from_scale_rotation_translation(nus.0, r.0, Vec3::default())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world
|
|
||||||
.get::<LocalTransform>(translation_rotation_scale)
|
|
||||||
.unwrap()
|
|
||||||
.0,
|
|
||||||
Mat4::from_scale_rotation_translation(Vec3::new(s.0, s.0, s.0), r.0, t.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world
|
|
||||||
.get::<LocalTransform>(translation_rotation_nus)
|
|
||||||
.unwrap()
|
|
||||||
.0,
|
|
||||||
Mat4::from_scale_rotation_translation(nus.0, r.0, t.0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn only_propagates_local_transform_on_change() {
|
|
||||||
let mut world = World::default();
|
|
||||||
let mut resources = Resources::default();
|
|
||||||
|
|
||||||
let mut schedule = Schedule::default();
|
|
||||||
schedule.add_stage("update");
|
|
||||||
for system in local_transform_systems() {
|
|
||||||
schedule.add_system_to_stage("update", system);
|
|
||||||
}
|
|
||||||
|
|
||||||
let local_transform = LocalTransform::identity();
|
|
||||||
let t = Translation::new(1.0, 2.0, 3.0);
|
|
||||||
let r = Rotation(Quat::from_rotation_ypr(1.0, 2.0, 3.0));
|
|
||||||
let s = Scale(2.0);
|
|
||||||
let nus = NonUniformScale::new(1.0, 2.0, 3.0);
|
|
||||||
|
|
||||||
// Add every combination of transform types.
|
|
||||||
world.spawn((local_transform, t));
|
|
||||||
world.spawn((local_transform, r));
|
|
||||||
world.spawn((local_transform, s));
|
|
||||||
world.spawn((local_transform, nus));
|
|
||||||
world.spawn((local_transform, t, r));
|
|
||||||
world.spawn((local_transform, t, s));
|
|
||||||
world.spawn((local_transform, t, nus));
|
|
||||||
world.spawn((local_transform, r, s));
|
|
||||||
world.spawn((local_transform, r, nus));
|
|
||||||
world.spawn((local_transform, t, r, s));
|
|
||||||
world.spawn((local_transform, t, r, nus));
|
|
||||||
|
|
||||||
// Run the system, local transforms should mutate since they are new
|
|
||||||
schedule.run(&mut world, &mut resources);
|
|
||||||
|
|
||||||
// Verify that the local transform is not mutated on the second frame
|
|
||||||
fn assert_no_local_transforms_changed_system(_: Changed<LocalTransform>) {
|
|
||||||
assert!(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
schedule.add_system_to_stage("update", assert_no_local_transforms_changed_system.system());
|
|
||||||
schedule.run(&mut world, &mut resources);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +1,49 @@
|
||||||
use crate::components::*;
|
use crate::components::*;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
use bevy_math::Mat4;
|
||||||
|
|
||||||
pub fn transform_propagate_system(
|
pub fn transform_propagate_system(
|
||||||
mut root_query: Query<
|
mut root_query: Query<Without<Parent, (Option<&Children>, &Transform, &mut GlobalTransform)>>,
|
||||||
Without<Parent, (Option<&Children>, &mut Transform, Option<&LocalTransform>)>,
|
mut transform_query: Query<(&Transform, &mut GlobalTransform, Option<&Children>)>,
|
||||||
>,
|
|
||||||
mut local_transform_query: Query<(&mut Transform, &LocalTransform, Option<&Children>)>,
|
|
||||||
) {
|
) {
|
||||||
for (children, mut transform, local_transform) in &mut root_query.iter() {
|
for (children, transform, mut global_transform) in &mut root_query.iter() {
|
||||||
if let Some(local_transform) = local_transform {
|
*global_transform.value_mut() = *transform.value();
|
||||||
transform.value = local_transform.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(children) = children {
|
if let Some(children) = children {
|
||||||
for child in children.0.iter() {
|
for child in children.0.iter() {
|
||||||
propagate_recursive(*transform, &mut local_transform_query, *child);
|
propagate_recursive(*global_transform.value(), &mut transform_query, *child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn propagate_recursive(
|
fn propagate_recursive(
|
||||||
parent_local_to_world: Transform,
|
parent: Mat4,
|
||||||
local_transform_query: &mut Query<(&mut Transform, &LocalTransform, Option<&Children>)>,
|
transform_query: &mut Query<(&Transform, &mut GlobalTransform, Option<&Children>)>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
) {
|
) {
|
||||||
log::trace!("Updating Transform for {:?}", entity);
|
log::trace!("Updating Transform for {:?}", entity);
|
||||||
let local_transform = {
|
|
||||||
if let Ok(local_transform) = local_transform_query.get::<LocalTransform>(entity) {
|
let global_matrix = {
|
||||||
*local_transform
|
if let (Ok(transform), Ok(mut global_transform)) = (
|
||||||
|
transform_query.get::<Transform>(entity),
|
||||||
|
transform_query.get_mut::<GlobalTransform>(entity),
|
||||||
|
) {
|
||||||
|
*global_transform.value_mut() = parent * *transform.value();
|
||||||
|
*global_transform.value()
|
||||||
} else {
|
} else {
|
||||||
log::warn!(
|
|
||||||
"Entity {:?} is a child in the hierarchy but does not have a LocalTransform",
|
|
||||||
entity
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_transform = Transform {
|
|
||||||
value: parent_local_to_world.value * local_transform.0,
|
|
||||||
sync: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut transform = local_transform_query.get_mut::<Transform>(entity).unwrap();
|
|
||||||
transform.value = new_transform.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect children
|
// Collect children
|
||||||
let children = local_transform_query
|
let children = transform_query
|
||||||
.get::<Children>(entity)
|
.get::<Children>(entity)
|
||||||
.map(|e| e.0.iter().cloned().collect::<Vec<_>>())
|
.map(|e| e.0.iter().cloned().collect::<Vec<_>>())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
for child in children {
|
for child in children {
|
||||||
propagate_recursive(new_transform, local_transform_query, child);
|
propagate_recursive(global_matrix, transform_query, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,20 +66,21 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Root entity
|
// Root entity
|
||||||
let parent = world.spawn((Translation::new(1.0, 0.0, 0.0), Transform::identity()));
|
let parent = world.spawn((
|
||||||
|
Transform::from_translation(Vec3::new(1.0, 0.0, 0.0)),
|
||||||
|
GlobalTransform::identity(),
|
||||||
|
));
|
||||||
let children = world
|
let children = world
|
||||||
.spawn_batch(vec![
|
.spawn_batch(vec![
|
||||||
(
|
(
|
||||||
Translation::new(0.0, 2.0, 0.0),
|
Transform::from_translation(Vec3::new(0.0, 2.0, 0.)),
|
||||||
LocalTransform::identity(),
|
|
||||||
Transform::identity(),
|
|
||||||
Parent(parent),
|
Parent(parent),
|
||||||
|
GlobalTransform::identity(),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Translation::new(0.0, 0.0, 3.0),
|
Transform::from_translation(Vec3::new(0.0, 0.0, 3.)),
|
||||||
LocalTransform::identity(),
|
|
||||||
Transform::identity(),
|
|
||||||
Parent(parent),
|
Parent(parent),
|
||||||
|
GlobalTransform::identity(),
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
.collect::<Vec<Entity>>();
|
.collect::<Vec<Entity>>();
|
||||||
|
@ -103,13 +92,13 @@ mod test {
|
||||||
schedule.run(&mut world, &mut resources);
|
schedule.run(&mut world, &mut resources);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
world.get::<Transform>(children[0]).unwrap().value,
|
*world.get::<GlobalTransform>(children[0]).unwrap().value(),
|
||||||
Mat4::from_translation(Vec3::new(1.0, 0.0, 0.0))
|
Mat4::from_translation(Vec3::new(1.0, 0.0, 0.0))
|
||||||
* Mat4::from_translation(Vec3::new(0.0, 2.0, 0.0))
|
* Mat4::from_translation(Vec3::new(0.0, 2.0, 0.0))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
world.get::<Transform>(children[1]).unwrap().value,
|
*world.get::<GlobalTransform>(children[1]).unwrap().value(),
|
||||||
Mat4::from_translation(Vec3::new(1.0, 0.0, 0.0))
|
Mat4::from_translation(Vec3::new(1.0, 0.0, 0.0))
|
||||||
* Mat4::from_translation(Vec3::new(0.0, 0.0, 3.0))
|
* Mat4::from_translation(Vec3::new(0.0, 0.0, 3.0))
|
||||||
);
|
);
|
||||||
|
@ -130,25 +119,34 @@ mod test {
|
||||||
let mut commands = Commands::default();
|
let mut commands = Commands::default();
|
||||||
let mut children = Vec::new();
|
let mut children = Vec::new();
|
||||||
commands
|
commands
|
||||||
.spawn((Translation::new(1.0, 0.0, 0.0), Transform::identity()))
|
.spawn((
|
||||||
|
Transform::from_translation(Vec3::new(1.0, 0.0, 0.0)),
|
||||||
|
GlobalTransform::identity(),
|
||||||
|
))
|
||||||
.with_children(|parent| {
|
.with_children(|parent| {
|
||||||
parent
|
parent
|
||||||
.spawn((Translation::new(0.0, 2.0, 0.0), Transform::identity()))
|
.spawn((
|
||||||
|
Transform::from_translation(Vec3::new(0.0, 2.0, 0.0)),
|
||||||
|
GlobalTransform::identity(),
|
||||||
|
))
|
||||||
.for_current_entity(|entity| children.push(entity))
|
.for_current_entity(|entity| children.push(entity))
|
||||||
.spawn((Translation::new(0.0, 0.0, 3.0), Transform::identity()))
|
.spawn((
|
||||||
|
Transform::from_translation(Vec3::new(0.0, 0.0, 3.0)),
|
||||||
|
GlobalTransform::identity(),
|
||||||
|
))
|
||||||
.for_current_entity(|entity| children.push(entity));
|
.for_current_entity(|entity| children.push(entity));
|
||||||
});
|
});
|
||||||
commands.apply(&mut world, &mut resources);
|
commands.apply(&mut world, &mut resources);
|
||||||
schedule.run(&mut world, &mut resources);
|
schedule.run(&mut world, &mut resources);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
world.get::<Transform>(children[0]).unwrap().value,
|
*world.get::<GlobalTransform>(children[0]).unwrap().value(),
|
||||||
Mat4::from_translation(Vec3::new(1.0, 0.0, 0.0))
|
Mat4::from_translation(Vec3::new(1.0, 0.0, 0.0))
|
||||||
* Mat4::from_translation(Vec3::new(0.0, 2.0, 0.0))
|
* Mat4::from_translation(Vec3::new(0.0, 2.0, 0.0))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
world.get::<Transform>(children[1]).unwrap().value,
|
*world.get::<GlobalTransform>(children[1]).unwrap().value(),
|
||||||
Mat4::from_translation(Vec3::new(1.0, 0.0, 0.0))
|
Mat4::from_translation(Vec3::new(1.0, 0.0, 0.0))
|
||||||
* Mat4::from_translation(Vec3::new(0.0, 0.0, 3.0))
|
* Mat4::from_translation(Vec3::new(0.0, 0.0, 3.0))
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,433 +0,0 @@
|
||||||
use crate::components::*;
|
|
||||||
use bevy_ecs::prelude::*;
|
|
||||||
use bevy_math::{Mat4, Quat, Vec3};
|
|
||||||
|
|
||||||
// TODO: on changed for all of these systems
|
|
||||||
pub fn transform_translation_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
LocalTransform,
|
|
||||||
Without<
|
|
||||||
Rotation,
|
|
||||||
Without<Scale, Without<NonUniformScale, (&mut Transform, Changed<Translation>)>>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut transform, translation) in &mut query.iter() {
|
|
||||||
if !transform.sync {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*transform = Transform::new(Mat4::from_translation(translation.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transform_rotation_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
LocalTransform,
|
|
||||||
Without<
|
|
||||||
Translation,
|
|
||||||
Without<Scale, Without<NonUniformScale, (&mut Transform, Changed<Rotation>)>>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut transform, rotation) in &mut query.iter() {
|
|
||||||
if !transform.sync {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*transform = Transform::new(Mat4::from_quat(rotation.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transform_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
LocalTransform,
|
|
||||||
Without<
|
|
||||||
Translation,
|
|
||||||
Without<Rotation, Without<NonUniformScale, (&mut Transform, Changed<Scale>)>>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut transform, scale) in &mut query.iter() {
|
|
||||||
if !transform.sync {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*transform = Transform::new(Mat4::from_scale(Vec3::new(scale.0, scale.0, scale.0)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transform_non_uniform_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
LocalTransform,
|
|
||||||
Without<
|
|
||||||
Translation,
|
|
||||||
Without<Rotation, Without<Scale, (&mut Transform, Changed<NonUniformScale>)>>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut transform, non_uniform_scale) in &mut query.iter() {
|
|
||||||
if !transform.sync {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*transform = Transform::new(Mat4::from_scale(non_uniform_scale.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transform_translation_rotation_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
LocalTransform,
|
|
||||||
Without<
|
|
||||||
Scale,
|
|
||||||
Without<
|
|
||||||
NonUniformScale,
|
|
||||||
(
|
|
||||||
&mut Transform,
|
|
||||||
Or<(Changed<Translation>, Changed<Rotation>)>,
|
|
||||||
),
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut transform, (translation, rotation)) in &mut query.iter() {
|
|
||||||
if !transform.sync {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*transform = Transform::new(Mat4::from_rotation_translation(rotation.0, translation.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transform_translation_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
LocalTransform,
|
|
||||||
Without<
|
|
||||||
Rotation,
|
|
||||||
Without<
|
|
||||||
NonUniformScale,
|
|
||||||
(&mut Transform, Or<(Changed<Translation>, Changed<Scale>)>),
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut transform, (translation, scale)) in &mut query.iter() {
|
|
||||||
if !transform.sync {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*transform = Transform::new(Mat4::from_scale_rotation_translation(
|
|
||||||
Vec3::new(scale.0, scale.0, scale.0),
|
|
||||||
Quat::default(),
|
|
||||||
translation.0,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transform_translation_non_uniform_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
LocalTransform,
|
|
||||||
Without<
|
|
||||||
Rotation,
|
|
||||||
Without<
|
|
||||||
Scale,
|
|
||||||
(
|
|
||||||
&mut Transform,
|
|
||||||
Or<(Changed<Translation>, Changed<NonUniformScale>)>,
|
|
||||||
),
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut transform, (translation, non_uniform_scale)) in &mut query.iter() {
|
|
||||||
if !transform.sync {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*transform = Transform::new(Mat4::from_scale_rotation_translation(
|
|
||||||
non_uniform_scale.0,
|
|
||||||
Quat::default(),
|
|
||||||
translation.0,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transform_rotation_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
LocalTransform,
|
|
||||||
Without<
|
|
||||||
Translation,
|
|
||||||
Without<NonUniformScale, (&mut Transform, Or<(Changed<Rotation>, Changed<Scale>)>)>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut transform, (rotation, scale)) in &mut query.iter() {
|
|
||||||
if !transform.sync {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*transform = Transform::new(Mat4::from_scale_rotation_translation(
|
|
||||||
Vec3::new(scale.0, scale.0, scale.0),
|
|
||||||
rotation.0,
|
|
||||||
Vec3::default(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transform_rotation_non_uniform_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
LocalTransform,
|
|
||||||
Without<
|
|
||||||
Translation,
|
|
||||||
Without<
|
|
||||||
Scale,
|
|
||||||
(
|
|
||||||
&mut Transform,
|
|
||||||
Or<(Changed<Rotation>, Changed<NonUniformScale>)>,
|
|
||||||
),
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut transform, (rotation, non_uniform_scale)) in &mut query.iter() {
|
|
||||||
if !transform.sync {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*transform = Transform::new(Mat4::from_scale_rotation_translation(
|
|
||||||
non_uniform_scale.0,
|
|
||||||
rotation.0,
|
|
||||||
Vec3::default(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transform_translation_rotation_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
LocalTransform,
|
|
||||||
Without<
|
|
||||||
NonUniformScale,
|
|
||||||
(
|
|
||||||
&mut Transform,
|
|
||||||
Or<(Changed<Translation>, Changed<Rotation>, Changed<Scale>)>,
|
|
||||||
),
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut transform, (translation, rotation, scale)) in &mut query.iter() {
|
|
||||||
if !transform.sync {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*transform = Transform::new(Mat4::from_scale_rotation_translation(
|
|
||||||
Vec3::new(scale.0, scale.0, scale.0),
|
|
||||||
rotation.0,
|
|
||||||
translation.0,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transform_translation_rotation_non_uniform_scale_system(
|
|
||||||
mut query: Query<
|
|
||||||
Without<
|
|
||||||
LocalTransform,
|
|
||||||
Without<
|
|
||||||
Scale,
|
|
||||||
(
|
|
||||||
&mut Transform,
|
|
||||||
Or<(
|
|
||||||
Changed<Translation>,
|
|
||||||
Changed<Rotation>,
|
|
||||||
Changed<NonUniformScale>,
|
|
||||||
)>,
|
|
||||||
),
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
for (mut transform, (translation, rotation, non_uniform_scale)) in &mut query.iter() {
|
|
||||||
if !transform.sync {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*transform = Transform::new(Mat4::from_scale_rotation_translation(
|
|
||||||
non_uniform_scale.0,
|
|
||||||
rotation.0,
|
|
||||||
translation.0,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transform_systems() -> Vec<Box<dyn System>> {
|
|
||||||
vec![
|
|
||||||
transform_translation_system.system(),
|
|
||||||
transform_rotation_system.system(),
|
|
||||||
transform_scale_system.system(),
|
|
||||||
transform_non_uniform_scale_system.system(),
|
|
||||||
transform_translation_rotation_system.system(),
|
|
||||||
transform_translation_scale_system.system(),
|
|
||||||
transform_translation_non_uniform_scale_system.system(),
|
|
||||||
transform_rotation_scale_system.system(),
|
|
||||||
transform_rotation_non_uniform_scale_system.system(),
|
|
||||||
transform_translation_rotation_scale_system.system(),
|
|
||||||
transform_translation_rotation_non_uniform_scale_system.system(),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
use bevy_ecs::{Resources, Schedule, World};
|
|
||||||
use bevy_math::{Mat4, Quat, Vec3};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn correct_world_transformation() {
|
|
||||||
let mut world = World::default();
|
|
||||||
let mut resources = Resources::default();
|
|
||||||
|
|
||||||
let mut schedule = Schedule::default();
|
|
||||||
schedule.add_stage("update");
|
|
||||||
for system in transform_systems() {
|
|
||||||
schedule.add_system_to_stage("update", system);
|
|
||||||
}
|
|
||||||
|
|
||||||
let transform = Transform::identity();
|
|
||||||
let t = Translation::new(1.0, 2.0, 3.0);
|
|
||||||
let r = Rotation(Quat::from_rotation_ypr(1.0, 2.0, 3.0));
|
|
||||||
let s = Scale(2.0);
|
|
||||||
let nus = NonUniformScale::new(1.0, 2.0, 3.0);
|
|
||||||
|
|
||||||
// Add every combination of transform types.
|
|
||||||
let translation = world.spawn((transform, t));
|
|
||||||
let rotation = world.spawn((transform, r));
|
|
||||||
let scale = world.spawn((transform, s));
|
|
||||||
let non_uniform_scale = world.spawn((transform, nus));
|
|
||||||
let translation_and_rotation = world.spawn((transform, t, r));
|
|
||||||
let translation_and_scale = world.spawn((transform, t, s));
|
|
||||||
let translation_and_nus = world.spawn((transform, t, nus));
|
|
||||||
let rotation_scale = world.spawn((transform, r, s));
|
|
||||||
let rotation_nus = world.spawn((transform, r, nus));
|
|
||||||
let translation_rotation_scale = world.spawn((transform, t, r, s));
|
|
||||||
let translation_rotation_nus = world.spawn((transform, t, r, nus));
|
|
||||||
|
|
||||||
// Run the system
|
|
||||||
schedule.run(&mut world, &mut resources);
|
|
||||||
|
|
||||||
// Verify that each was transformed correctly.
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<Transform>(translation).unwrap().value,
|
|
||||||
Mat4::from_translation(t.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<Transform>(rotation).unwrap().value,
|
|
||||||
Mat4::from_quat(r.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<Transform>(scale).unwrap().value,
|
|
||||||
Mat4::from_scale(Vec3::new(s.0, s.0, s.0))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<Transform>(non_uniform_scale).unwrap().value,
|
|
||||||
Mat4::from_scale(nus.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world
|
|
||||||
.get::<Transform>(translation_and_rotation)
|
|
||||||
.unwrap()
|
|
||||||
.value,
|
|
||||||
Mat4::from_rotation_translation(r.0, t.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<Transform>(translation_and_scale).unwrap().value,
|
|
||||||
Mat4::from_scale_rotation_translation(Vec3::new(s.0, s.0, s.0), Quat::default(), t.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<Transform>(translation_and_nus).unwrap().value,
|
|
||||||
Mat4::from_scale_rotation_translation(nus.0, Quat::default(), t.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<Transform>(rotation_scale).unwrap().value,
|
|
||||||
Mat4::from_scale_rotation_translation(Vec3::new(s.0, s.0, s.0), r.0, Vec3::default())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world.get::<Transform>(rotation_nus).unwrap().value,
|
|
||||||
Mat4::from_scale_rotation_translation(nus.0, r.0, Vec3::default())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world
|
|
||||||
.get::<Transform>(translation_rotation_scale)
|
|
||||||
.unwrap()
|
|
||||||
.value,
|
|
||||||
Mat4::from_scale_rotation_translation(Vec3::new(s.0, s.0, s.0), r.0, t.0)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
world
|
|
||||||
.get::<Transform>(translation_rotation_nus)
|
|
||||||
.unwrap()
|
|
||||||
.value,
|
|
||||||
Mat4::from_scale_rotation_translation(nus.0, r.0, t.0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn only_propagates_transform_on_change() {
|
|
||||||
let mut world = World::default();
|
|
||||||
let mut resources = Resources::default();
|
|
||||||
|
|
||||||
let mut schedule = Schedule::default();
|
|
||||||
schedule.add_stage("update");
|
|
||||||
for system in transform_systems() {
|
|
||||||
schedule.add_system_to_stage("update", system);
|
|
||||||
}
|
|
||||||
|
|
||||||
let transform = Transform::identity();
|
|
||||||
let t = Translation::new(1.0, 2.0, 3.0);
|
|
||||||
let r = Rotation(Quat::from_rotation_ypr(1.0, 2.0, 3.0));
|
|
||||||
let s = Scale(2.0);
|
|
||||||
let nus = NonUniformScale::new(1.0, 2.0, 3.0);
|
|
||||||
|
|
||||||
// Add every combination of transform types.
|
|
||||||
world.spawn((transform, t));
|
|
||||||
world.spawn((transform, r));
|
|
||||||
world.spawn((transform, s));
|
|
||||||
world.spawn((transform, nus));
|
|
||||||
world.spawn((transform, t, r));
|
|
||||||
world.spawn((transform, t, s));
|
|
||||||
world.spawn((transform, t, nus));
|
|
||||||
world.spawn((transform, r, s));
|
|
||||||
world.spawn((transform, r, nus));
|
|
||||||
world.spawn((transform, t, r, s));
|
|
||||||
world.spawn((transform, t, r, nus));
|
|
||||||
|
|
||||||
// Run the system, transforms should mutate since they are new
|
|
||||||
schedule.run(&mut world, &mut resources);
|
|
||||||
|
|
||||||
// Verify that the transform is not mutated on the second frame
|
|
||||||
fn assert_no_transforms_changed_system(_: Changed<Transform>) {
|
|
||||||
assert!(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
schedule.add_system_to_stage("update", assert_no_transforms_changed_system.system());
|
|
||||||
schedule.run(&mut world, &mut resources);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
use bevy_ecs::Bundle;
|
use bevy_ecs::Bundle;
|
||||||
|
use bevy_math::Vec3;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::{Camera, OrthographicProjection, VisibleEntities, WindowOrigin},
|
camera::{Camera, OrthographicProjection, VisibleEntities, WindowOrigin},
|
||||||
draw::Draw,
|
draw::Draw,
|
||||||
|
@ -13,10 +14,7 @@ use bevy_render::{
|
||||||
pipeline::{DynamicBinding, PipelineSpecialization, RenderPipeline, RenderPipelines},
|
pipeline::{DynamicBinding, PipelineSpecialization, RenderPipeline, RenderPipelines},
|
||||||
};
|
};
|
||||||
use bevy_sprite::{ColorMaterial, QUAD_HANDLE};
|
use bevy_sprite::{ColorMaterial, QUAD_HANDLE};
|
||||||
use bevy_transform::{
|
use bevy_transform::prelude::{GlobalTransform, Transform};
|
||||||
components::LocalTransform,
|
|
||||||
prelude::{Rotation, Scale, Transform, Translation},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Bundle, Clone)]
|
#[derive(Bundle, Clone)]
|
||||||
pub struct NodeComponents {
|
pub struct NodeComponents {
|
||||||
|
@ -27,7 +25,7 @@ pub struct NodeComponents {
|
||||||
pub draw: Draw,
|
pub draw: Draw,
|
||||||
pub render_pipelines: RenderPipelines,
|
pub render_pipelines: RenderPipelines,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub local_transform: LocalTransform,
|
pub global_transform: GlobalTransform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NodeComponents {
|
impl Default for NodeComponents {
|
||||||
|
@ -57,7 +55,7 @@ impl Default for NodeComponents {
|
||||||
material: Default::default(),
|
material: Default::default(),
|
||||||
draw: Default::default(),
|
draw: Default::default(),
|
||||||
transform: Default::default(),
|
transform: Default::default(),
|
||||||
local_transform: Default::default(),
|
global_transform: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +71,7 @@ pub struct ImageComponents {
|
||||||
pub draw: Draw,
|
pub draw: Draw,
|
||||||
pub render_pipelines: RenderPipelines,
|
pub render_pipelines: RenderPipelines,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub local_transform: LocalTransform,
|
pub global_transform: GlobalTransform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ImageComponents {
|
impl Default for ImageComponents {
|
||||||
|
@ -105,7 +103,7 @@ impl Default for ImageComponents {
|
||||||
material: Default::default(),
|
material: Default::default(),
|
||||||
draw: Default::default(),
|
draw: Default::default(),
|
||||||
transform: Default::default(),
|
transform: Default::default(),
|
||||||
local_transform: Default::default(),
|
global_transform: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +117,7 @@ pub struct TextComponents {
|
||||||
pub calculated_size: CalculatedSize,
|
pub calculated_size: CalculatedSize,
|
||||||
pub focus_policy: FocusPolicy,
|
pub focus_policy: FocusPolicy,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub local_transform: LocalTransform,
|
pub global_transform: GlobalTransform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TextComponents {
|
impl Default for TextComponents {
|
||||||
|
@ -135,7 +133,7 @@ impl Default for TextComponents {
|
||||||
calculated_size: Default::default(),
|
calculated_size: Default::default(),
|
||||||
style: Default::default(),
|
style: Default::default(),
|
||||||
transform: Default::default(),
|
transform: Default::default(),
|
||||||
local_transform: Default::default(),
|
global_transform: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +150,7 @@ pub struct ButtonComponents {
|
||||||
pub draw: Draw,
|
pub draw: Draw,
|
||||||
pub render_pipelines: RenderPipelines,
|
pub render_pipelines: RenderPipelines,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub local_transform: LocalTransform,
|
pub global_transform: GlobalTransform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ButtonComponents {
|
impl Default for ButtonComponents {
|
||||||
|
@ -185,7 +183,7 @@ impl Default for ButtonComponents {
|
||||||
material: Default::default(),
|
material: Default::default(),
|
||||||
draw: Default::default(),
|
draw: Default::default(),
|
||||||
transform: Default::default(),
|
transform: Default::default(),
|
||||||
local_transform: Default::default(),
|
global_transform: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,9 +194,7 @@ pub struct UiCameraComponents {
|
||||||
pub orthographic_projection: OrthographicProjection,
|
pub orthographic_projection: OrthographicProjection,
|
||||||
pub visible_entities: VisibleEntities,
|
pub visible_entities: VisibleEntities,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
pub translation: Translation,
|
pub global_transform: GlobalTransform,
|
||||||
pub rotation: Rotation,
|
|
||||||
pub scale: Scale,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for UiCameraComponents {
|
impl Default for UiCameraComponents {
|
||||||
|
@ -216,11 +212,9 @@ impl Default for UiCameraComponents {
|
||||||
window_origin: WindowOrigin::BottomLeft,
|
window_origin: WindowOrigin::BottomLeft,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
translation: Translation::new(0.0, 0.0, far - 0.1),
|
|
||||||
visible_entities: Default::default(),
|
visible_entities: Default::default(),
|
||||||
transform: Default::default(),
|
transform: Transform::from_translation(Vec3::new(0.0, 0.0, far - 0.1)),
|
||||||
rotation: Default::default(),
|
global_transform: Default::default(),
|
||||||
scale: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ mod convert;
|
||||||
use crate::{CalculatedSize, Node, Style};
|
use crate::{CalculatedSize, Node, Style};
|
||||||
use bevy_ecs::{Changed, Entity, Query, Res, ResMut, With, Without};
|
use bevy_ecs::{Changed, Entity, Query, Res, ResMut, With, Without};
|
||||||
use bevy_math::Vec2;
|
use bevy_math::Vec2;
|
||||||
use bevy_transform::prelude::{Children, LocalTransform, Parent};
|
use bevy_transform::prelude::{Children, Parent, Transform};
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::HashMap;
|
||||||
use bevy_window::{Window, WindowId, Windows};
|
use bevy_window::{Window, WindowId, Windows};
|
||||||
use stretch::{number::Number, Stretch};
|
use stretch::{number::Number, Stretch};
|
||||||
|
@ -154,7 +154,7 @@ pub fn flex_node_system(
|
||||||
mut node_query: Query<With<Node, (Entity, Changed<Style>, Option<&CalculatedSize>)>>,
|
mut node_query: Query<With<Node, (Entity, Changed<Style>, Option<&CalculatedSize>)>>,
|
||||||
mut changed_size_query: Query<With<Node, (Entity, &Style, Changed<CalculatedSize>)>>,
|
mut changed_size_query: Query<With<Node, (Entity, &Style, Changed<CalculatedSize>)>>,
|
||||||
mut children_query: Query<With<Node, (Entity, Changed<Children>)>>,
|
mut children_query: Query<With<Node, (Entity, Changed<Children>)>>,
|
||||||
mut node_transform_query: Query<(Entity, &mut Node, &mut LocalTransform, Option<&Parent>)>,
|
mut node_transform_query: Query<(Entity, &mut Node, &mut Transform, Option<&Parent>)>,
|
||||||
) {
|
) {
|
||||||
// update window root nodes
|
// update window root nodes
|
||||||
for window in windows.iter() {
|
for window in windows.iter() {
|
||||||
|
@ -190,10 +190,10 @@ pub fn flex_node_system(
|
||||||
// compute layouts
|
// compute layouts
|
||||||
flex_surface.compute_window_layouts();
|
flex_surface.compute_window_layouts();
|
||||||
|
|
||||||
for (entity, mut node, mut local, parent) in &mut node_transform_query.iter() {
|
for (entity, mut node, mut transform, parent) in &mut node_transform_query.iter() {
|
||||||
let layout = flex_surface.get_layout(entity).unwrap();
|
let layout = flex_surface.get_layout(entity).unwrap();
|
||||||
node.size = Vec2::new(layout.size.width, layout.size.height);
|
node.size = Vec2::new(layout.size.width, layout.size.height);
|
||||||
let mut position = local.w_axis();
|
let mut position = transform.translation();
|
||||||
position.set_x(layout.location.x + layout.size.width / 2.0);
|
position.set_x(layout.location.x + layout.size.width / 2.0);
|
||||||
position.set_y(layout.location.y + layout.size.height / 2.0);
|
position.set_y(layout.location.y + layout.size.height / 2.0);
|
||||||
if let Some(parent) = parent {
|
if let Some(parent) = parent {
|
||||||
|
@ -203,6 +203,6 @@ pub fn flex_node_system(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
local.set_w_axis(position);
|
transform.set_translation(position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use bevy_core::FloatOrd;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_input::{mouse::MouseButton, Input};
|
use bevy_input::{mouse::MouseButton, Input};
|
||||||
use bevy_math::Vec2;
|
use bevy_math::Vec2;
|
||||||
use bevy_transform::components::Transform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use bevy_window::CursorMoved;
|
use bevy_window::CursorMoved;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
|
@ -46,7 +46,7 @@ pub fn ui_focus_system(
|
||||||
mut node_query: Query<(
|
mut node_query: Query<(
|
||||||
Entity,
|
Entity,
|
||||||
&Node,
|
&Node,
|
||||||
&Transform,
|
&GlobalTransform,
|
||||||
Option<&mut Interaction>,
|
Option<&mut Interaction>,
|
||||||
Option<&FocusPolicy>,
|
Option<&FocusPolicy>,
|
||||||
)>,
|
)>,
|
||||||
|
@ -56,7 +56,9 @@ pub fn ui_focus_system(
|
||||||
}
|
}
|
||||||
|
|
||||||
if mouse_button_input.just_released(MouseButton::Left) {
|
if mouse_button_input.just_released(MouseButton::Left) {
|
||||||
for (_entity, _node, _transform, interaction, _focus_policy) in &mut node_query.iter() {
|
for (_entity, _node, _global_transform, interaction, _focus_policy) in
|
||||||
|
&mut node_query.iter()
|
||||||
|
{
|
||||||
if let Some(mut interaction) = interaction {
|
if let Some(mut interaction) = interaction {
|
||||||
if *interaction == Interaction::Clicked {
|
if *interaction == Interaction::Clicked {
|
||||||
*interaction = Interaction::None;
|
*interaction = Interaction::None;
|
||||||
|
@ -72,26 +74,28 @@ pub fn ui_focus_system(
|
||||||
let mut query_iter = node_query.iter();
|
let mut query_iter = node_query.iter();
|
||||||
let mut moused_over_z_sorted_nodes = query_iter
|
let mut moused_over_z_sorted_nodes = query_iter
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(entity, node, transform, interaction, focus_policy)| {
|
.filter_map(
|
||||||
let position = transform.value.w_axis();
|
|(entity, node, global_transform, interaction, focus_policy)| {
|
||||||
let ui_position = position.truncate().truncate();
|
let position = global_transform.translation();
|
||||||
let extents = node.size / 2.0;
|
let ui_position = position.truncate();
|
||||||
let min = ui_position - extents;
|
let extents = node.size / 2.0;
|
||||||
let max = ui_position + extents;
|
let min = ui_position - extents;
|
||||||
// if the current cursor position is within the bounds of the node, consider it for clicking
|
let max = ui_position + extents;
|
||||||
if (min.x()..max.x()).contains(&state.cursor_position.x())
|
// if the current cursor position is within the bounds of the node, consider it for clicking
|
||||||
&& (min.y()..max.y()).contains(&state.cursor_position.y())
|
if (min.x()..max.x()).contains(&state.cursor_position.x())
|
||||||
{
|
&& (min.y()..max.y()).contains(&state.cursor_position.y())
|
||||||
Some((entity, focus_policy, interaction, FloatOrd(position.z())))
|
{
|
||||||
} else {
|
Some((entity, focus_policy, interaction, FloatOrd(position.z())))
|
||||||
if let Some(mut interaction) = interaction {
|
} else {
|
||||||
if *interaction == Interaction::Hovered {
|
if let Some(mut interaction) = interaction {
|
||||||
*interaction = Interaction::None;
|
if *interaction == Interaction::Hovered {
|
||||||
|
*interaction = Interaction::None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
None
|
},
|
||||||
}
|
)
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
moused_over_z_sorted_nodes.sort_by_key(|(_, _, _, z)| -*z);
|
moused_over_z_sorted_nodes.sort_by_key(|(_, _, _, z)| -*z);
|
||||||
|
|
|
@ -2,14 +2,14 @@ use super::Node;
|
||||||
use bevy_ecs::{Entity, Query, With, Without};
|
use bevy_ecs::{Entity, Query, With, Without};
|
||||||
use bevy_transform::{
|
use bevy_transform::{
|
||||||
hierarchy,
|
hierarchy,
|
||||||
prelude::{Children, LocalTransform, Parent},
|
prelude::{Children, Parent, Transform},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const UI_Z_STEP: f32 = 0.001;
|
pub const UI_Z_STEP: f32 = 0.001;
|
||||||
|
|
||||||
pub fn ui_z_system(
|
pub fn ui_z_system(
|
||||||
mut root_node_query: Query<With<Node, Without<Parent, Entity>>>,
|
mut root_node_query: Query<With<Node, Without<Parent, Entity>>>,
|
||||||
mut node_query: Query<(Entity, &Node, &mut LocalTransform)>,
|
mut node_query: Query<(Entity, &Node, &mut Transform)>,
|
||||||
children_query: Query<&Children>,
|
children_query: Query<&Children>,
|
||||||
) {
|
) {
|
||||||
let mut current_global_z = 0.0;
|
let mut current_global_z = 0.0;
|
||||||
|
@ -34,12 +34,12 @@ pub fn ui_z_system(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_node_entity(
|
fn update_node_entity(
|
||||||
node_query: &mut Query<(Entity, &Node, &mut LocalTransform)>,
|
node_query: &mut Query<(Entity, &Node, &mut Transform)>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
parent_result: Option<f32>,
|
parent_result: Option<f32>,
|
||||||
previous_result: Option<f32>,
|
previous_result: Option<f32>,
|
||||||
) -> Option<f32> {
|
) -> Option<f32> {
|
||||||
let mut transform = node_query.get_mut::<LocalTransform>(entity).ok()?;
|
let mut transform = node_query.get_mut::<Transform>(entity).ok()?;
|
||||||
let mut z = UI_Z_STEP;
|
let mut z = UI_Z_STEP;
|
||||||
let parent_global_z = parent_result.unwrap();
|
let parent_global_z = parent_result.unwrap();
|
||||||
if let Some(previous_global_z) = previous_result {
|
if let Some(previous_global_z) = previous_result {
|
||||||
|
@ -47,9 +47,9 @@ fn update_node_entity(
|
||||||
};
|
};
|
||||||
let global_z = z + parent_global_z;
|
let global_z = z + parent_global_z;
|
||||||
|
|
||||||
let mut position = transform.w_axis();
|
let mut position = transform.translation();
|
||||||
position.set_z(z);
|
position.set_z(z);
|
||||||
transform.set_w_axis(position);
|
transform.set_translation(position);
|
||||||
|
|
||||||
Some(global_z)
|
Some(global_z)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use bevy_render::{
|
||||||
};
|
};
|
||||||
use bevy_sprite::TextureAtlas;
|
use bevy_sprite::TextureAtlas;
|
||||||
use bevy_text::{DrawableText, Font, FontAtlasSet, TextStyle};
|
use bevy_text::{DrawableText, Font, FontAtlasSet, TextStyle};
|
||||||
use bevy_transform::prelude::Transform;
|
use bevy_transform::prelude::GlobalTransform;
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct Text {
|
pub struct Text {
|
||||||
|
@ -58,11 +58,11 @@ pub fn draw_text_system(
|
||||||
texture_atlases: Res<Assets<TextureAtlas>>,
|
texture_atlases: Res<Assets<TextureAtlas>>,
|
||||||
mut render_resource_bindings: ResMut<RenderResourceBindings>,
|
mut render_resource_bindings: ResMut<RenderResourceBindings>,
|
||||||
mut asset_render_resource_bindings: ResMut<AssetRenderResourceBindings>,
|
mut asset_render_resource_bindings: ResMut<AssetRenderResourceBindings>,
|
||||||
mut query: Query<(&mut Draw, &Text, &Node, &Transform)>,
|
mut query: Query<(&mut Draw, &Text, &Node, &GlobalTransform)>,
|
||||||
) {
|
) {
|
||||||
for (mut draw, text, node, transform) in &mut query.iter() {
|
for (mut draw, text, node, global_transform) in &mut query.iter() {
|
||||||
let position =
|
let position = Vec3::from(global_transform.value().w_axis().truncate())
|
||||||
Vec3::from(transform.value.w_axis().truncate()) - (node.size / 2.0).extend(0.0);
|
- (node.size / 2.0).extend(0.0);
|
||||||
|
|
||||||
let mut drawable_text = DrawableText {
|
let mut drawable_text = DrawableText {
|
||||||
font: fonts.get(&text.font).unwrap(),
|
font: fonts.get(&text.font).unwrap(),
|
||||||
|
|
|
@ -39,7 +39,7 @@ fn setup(
|
||||||
.spawn(Camera2dComponents::default())
|
.spawn(Camera2dComponents::default())
|
||||||
.spawn(SpriteSheetComponents {
|
.spawn(SpriteSheetComponents {
|
||||||
texture_atlas: texture_atlas_handle,
|
texture_atlas: texture_atlas_handle,
|
||||||
scale: Scale(6.0),
|
transform: Transform::from_scale(Vec3::one() * 6.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.with(Timer::from_seconds(0.1, true));
|
.with(Timer::from_seconds(0.1, true));
|
||||||
|
|
|
@ -61,8 +61,8 @@ fn load_atlas(
|
||||||
.spawn(Camera2dComponents::default())
|
.spawn(Camera2dComponents::default())
|
||||||
// draw a sprite from the atlas
|
// draw a sprite from the atlas
|
||||||
.spawn(SpriteSheetComponents {
|
.spawn(SpriteSheetComponents {
|
||||||
scale: Scale(4.0),
|
transform: Transform::from_translation(Vec3::new(150.0, 0.0, 0.0))
|
||||||
translation: Translation(Vec3::new(150.0, 0.0, 0.0)),
|
.with_scale(Vec3::one() * 4.0),
|
||||||
sprite: TextureAtlasSprite::new(vendor_index as u32),
|
sprite: TextureAtlasSprite::new(vendor_index as u32),
|
||||||
texture_atlas: atlas_handle,
|
texture_atlas: atlas_handle,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -70,7 +70,7 @@ fn load_atlas(
|
||||||
// draw the atlas itself
|
// draw the atlas itself
|
||||||
.spawn(SpriteComponents {
|
.spawn(SpriteComponents {
|
||||||
material: materials.add(texture_atlas_texture.into()),
|
material: materials.add(texture_atlas_texture.into()),
|
||||||
translation: Vec3::new(-300.0, 0., 0.0).into(),
|
transform: Transform::from_translation(Vec3::new(-300.0, 0.0, 0.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ fn setup(
|
||||||
.spawn(PbrComponents {
|
.spawn(PbrComponents {
|
||||||
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
|
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
|
||||||
material: materials.add(Color::rgb(0.5, 0.4, 0.3).into()),
|
material: materials.add(Color::rgb(0.5, 0.4, 0.3).into()),
|
||||||
translation: Translation::new(0.0, 1.0, 0.0),
|
transform: Transform::from_translation(Vec3::new(0.0, 1.0, 0.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// sphere
|
// sphere
|
||||||
|
@ -36,17 +36,17 @@ fn setup(
|
||||||
radius: 0.5,
|
radius: 0.5,
|
||||||
})),
|
})),
|
||||||
material: materials.add(Color::rgb(0.1, 0.4, 0.8).into()),
|
material: materials.add(Color::rgb(0.1, 0.4, 0.8).into()),
|
||||||
translation: Translation::new(1.5, 1.5, 1.5),
|
transform: Transform::from_translation(Vec3::new(1.5, 1.5, 1.5)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// light
|
// light
|
||||||
.spawn(LightComponents {
|
.spawn(LightComponents {
|
||||||
translation: Translation::new(4.0, 8.0, 4.0),
|
transform: Transform::from_translation(Vec3::new(4.0, 8.0, 4.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// camera
|
// camera
|
||||||
.spawn(Camera3dComponents {
|
.spawn(Camera3dComponents {
|
||||||
transform: Transform::new_sync_disabled(Mat4::face_toward(
|
transform: Transform::new(Mat4::face_toward(
|
||||||
Vec3::new(-3.0, 5.0, 8.0),
|
Vec3::new(-3.0, 5.0, 8.0),
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 1.0, 0.0),
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
|
|
@ -23,7 +23,7 @@ fn setup(
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
// create a material for the mesh
|
// create a material for the mesh
|
||||||
material: materials.add(Color::rgb(0.5, 0.4, 0.3).into()),
|
material: materials.add(Color::rgb(0.5, 0.4, 0.3).into()),
|
||||||
translation: Translation::new(-1.5, 0.0, 0.0),
|
transform: Transform::from_translation(Vec3::new(-1.5, 0.0, 0.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// mesh
|
// mesh
|
||||||
|
@ -34,17 +34,17 @@ fn setup(
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
// create a material for the mesh
|
// create a material for the mesh
|
||||||
material: materials.add(Color::rgb(0.5, 0.4, 0.3).into()),
|
material: materials.add(Color::rgb(0.5, 0.4, 0.3).into()),
|
||||||
translation: Translation::new(1.5, 0.0, 0.0),
|
transform: Transform::from_translation(Vec3::new(1.5, 0.0, 0.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// light
|
// light
|
||||||
.spawn(LightComponents {
|
.spawn(LightComponents {
|
||||||
translation: Translation::new(4.0, 5.0, 4.0),
|
transform: Transform::from_translation(Vec3::new(4.0, 5.0, 4.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// camera
|
// camera
|
||||||
.spawn(Camera3dComponents {
|
.spawn(Camera3dComponents {
|
||||||
transform: Transform::new_sync_disabled(Mat4::face_toward(
|
transform: Transform::new(Mat4::face_toward(
|
||||||
Vec3::new(-2.0, 2.0, 6.0),
|
Vec3::new(-2.0, 2.0, 6.0),
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 1.0, 0.0),
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
|
|
@ -27,12 +27,12 @@ fn setup(
|
||||||
})
|
})
|
||||||
// light
|
// light
|
||||||
.spawn(LightComponents {
|
.spawn(LightComponents {
|
||||||
translation: Translation::new(4.0, 8.0, 4.0),
|
transform: Transform::from_translation(Vec3::new(4.0, 8.0, 4.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// camera
|
// camera
|
||||||
.spawn(Camera3dComponents {
|
.spawn(Camera3dComponents {
|
||||||
transform: Transform::new_sync_disabled(Mat4::face_toward(
|
transform: Transform::new(Mat4::face_toward(
|
||||||
Vec3::new(-3.0, 3.0, 5.0),
|
Vec3::new(-3.0, 3.0, 5.0),
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 1.0, 0.0),
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
|
|
@ -15,9 +15,9 @@ fn main() {
|
||||||
struct Rotator;
|
struct Rotator;
|
||||||
|
|
||||||
/// rotates the parent, which will result in the child also rotating
|
/// rotates the parent, which will result in the child also rotating
|
||||||
fn rotator_system(time: Res<Time>, mut query: Query<(&Rotator, &mut Rotation)>) {
|
fn rotator_system(time: Res<Time>, mut query: Query<(&Rotator, &mut Transform)>) {
|
||||||
for (_rotator, mut rotation) in &mut query.iter() {
|
for (_rotator, mut transform) in &mut query.iter() {
|
||||||
rotation.0 *= Quat::from_rotation_x(3.0 * time.delta_seconds);
|
transform.rotate(Quat::from_rotation_x(3.0 * time.delta_seconds));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ fn setup(
|
||||||
.spawn(PbrComponents {
|
.spawn(PbrComponents {
|
||||||
mesh: cube_handle,
|
mesh: cube_handle,
|
||||||
material: cube_material_handle,
|
material: cube_material_handle,
|
||||||
translation: Translation::new(0.0, 0.0, 1.0),
|
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 1.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.with(Rotator)
|
.with(Rotator)
|
||||||
|
@ -47,18 +47,18 @@ fn setup(
|
||||||
parent.spawn(PbrComponents {
|
parent.spawn(PbrComponents {
|
||||||
mesh: cube_handle,
|
mesh: cube_handle,
|
||||||
material: cube_material_handle,
|
material: cube_material_handle,
|
||||||
translation: Translation::new(0.0, 0.0, 3.0),
|
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 3.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
// light
|
// light
|
||||||
.spawn(LightComponents {
|
.spawn(LightComponents {
|
||||||
translation: Translation::new(4.0, 5.0, -4.0),
|
transform: Transform::from_translation(Vec3::new(4.0, 5.0, -4.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// camera
|
// camera
|
||||||
.spawn(Camera3dComponents {
|
.spawn(Camera3dComponents {
|
||||||
transform: Transform::new_sync_disabled(Mat4::face_toward(
|
transform: Transform::new(Mat4::face_toward(
|
||||||
Vec3::new(5.0, 10.0, 10.0),
|
Vec3::new(5.0, 10.0, 10.0),
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 1.0, 0.0),
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
|
|
@ -21,11 +21,11 @@ fn main() {
|
||||||
fn move_cubes(
|
fn move_cubes(
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
mut query: Query<(&mut Translation, &Handle<StandardMaterial>)>,
|
mut query: Query<(&mut Transform, &Handle<StandardMaterial>)>,
|
||||||
) {
|
) {
|
||||||
for (mut translation, material_handle) in &mut query.iter() {
|
for (mut transform, material_handle) in &mut query.iter() {
|
||||||
let material = materials.get_mut(&material_handle).unwrap();
|
let material = materials.get_mut(&material_handle).unwrap();
|
||||||
translation.0 += Vec3::new(1.0, 0.0, 0.0) * time.delta_seconds;
|
transform.translate(Vec3::new(1.0, 0.0, 0.0) * time.delta_seconds);
|
||||||
material.albedo =
|
material.albedo =
|
||||||
Color::BLUE * Vec3::splat((3.0 * time.seconds_since_startup as f32).sin());
|
Color::BLUE * Vec3::splat((3.0 * time.seconds_since_startup as f32).sin());
|
||||||
}
|
}
|
||||||
|
@ -39,12 +39,12 @@ fn setup(
|
||||||
commands
|
commands
|
||||||
// light
|
// light
|
||||||
.spawn(LightComponents {
|
.spawn(LightComponents {
|
||||||
translation: Translation::new(4.0, -4.0, 5.0),
|
transform: Transform::from_translation(Vec3::new(4.0, -4.0, 5.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// camera
|
// camera
|
||||||
.spawn(Camera3dComponents {
|
.spawn(Camera3dComponents {
|
||||||
transform: Transform::new_sync_disabled(Mat4::face_toward(
|
transform: Transform::new(Mat4::face_toward(
|
||||||
Vec3::new(0.0, 15.0, 150.0),
|
Vec3::new(0.0, 15.0, 150.0),
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 0.0, 1.0),
|
Vec3::new(0.0, 0.0, 1.0),
|
||||||
|
@ -65,11 +65,11 @@ fn setup(
|
||||||
),
|
),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
translation: Translation::new(
|
transform: Transform::from_translation(Vec3::new(
|
||||||
rng.gen_range(-50.0, 50.0),
|
rng.gen_range(-50.0, 50.0),
|
||||||
rng.gen_range(-50.0, 50.0),
|
rng.gen_range(-50.0, 50.0),
|
||||||
0.0,
|
0.0,
|
||||||
),
|
)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,8 +59,8 @@ fn setup(
|
||||||
.spawn(PbrComponents {
|
.spawn(PbrComponents {
|
||||||
mesh: quad_handle,
|
mesh: quad_handle,
|
||||||
material: material_handle,
|
material: material_handle,
|
||||||
translation: Translation::new(0.0, 0.0, 1.5),
|
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 1.5))
|
||||||
rotation: Rotation(Quat::from_rotation_x(-std::f32::consts::PI / 5.0)),
|
.with_rotation(Quat::from_rotation_x(-std::f32::consts::PI / 5.0)),
|
||||||
draw: Draw {
|
draw: Draw {
|
||||||
is_transparent: true,
|
is_transparent: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -71,8 +71,8 @@ fn setup(
|
||||||
.spawn(PbrComponents {
|
.spawn(PbrComponents {
|
||||||
mesh: quad_handle,
|
mesh: quad_handle,
|
||||||
material: red_material_handle,
|
material: red_material_handle,
|
||||||
translation: Translation::new(0.0, 0.0, 0.0),
|
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0))
|
||||||
rotation: Rotation(Quat::from_rotation_x(-std::f32::consts::PI / 5.0)),
|
.with_rotation(Quat::from_rotation_x(-std::f32::consts::PI / 5.0)),
|
||||||
draw: Draw {
|
draw: Draw {
|
||||||
is_transparent: true,
|
is_transparent: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -83,8 +83,8 @@ fn setup(
|
||||||
.spawn(PbrComponents {
|
.spawn(PbrComponents {
|
||||||
mesh: quad_handle,
|
mesh: quad_handle,
|
||||||
material: blue_material_handle,
|
material: blue_material_handle,
|
||||||
translation: Translation::new(0.0, 0.0, -1.5),
|
transform: Transform::from_translation(Vec3::new(0.0, 0.0, -1.5))
|
||||||
rotation: Rotation(Quat::from_rotation_x(-std::f32::consts::PI / 5.0)),
|
.with_rotation(Quat::from_rotation_x(-std::f32::consts::PI / 5.0)),
|
||||||
draw: Draw {
|
draw: Draw {
|
||||||
is_transparent: true,
|
is_transparent: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -93,7 +93,7 @@ fn setup(
|
||||||
})
|
})
|
||||||
// camera
|
// camera
|
||||||
.spawn(Camera3dComponents {
|
.spawn(Camera3dComponents {
|
||||||
transform: Transform::new_sync_disabled(Mat4::face_toward(
|
transform: Transform::new(Mat4::face_toward(
|
||||||
Vec3::new(3.0, 5.0, 8.0),
|
Vec3::new(3.0, 5.0, 8.0),
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 1.0, 0.0),
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
|
|
@ -19,9 +19,9 @@ fn main() {
|
||||||
struct Rotator;
|
struct Rotator;
|
||||||
|
|
||||||
/// rotates the parent, which will result in the child also rotating
|
/// rotates the parent, which will result in the child also rotating
|
||||||
fn rotator_system(time: Res<Time>, mut query: Query<(&Rotator, &mut Rotation)>) {
|
fn rotator_system(time: Res<Time>, mut query: Query<(&Rotator, &mut Transform)>) {
|
||||||
for (_rotator, mut rotation) in &mut query.iter() {
|
for (_rotator, mut transform) in &mut query.iter() {
|
||||||
rotation.0 *= Quat::from_rotation_x(3.0 * time.delta_seconds);
|
transform.rotate(Quat::from_rotation_x(3.0 * time.delta_seconds));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ fn setup(
|
||||||
shaded: false,
|
shaded: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
translation: Translation::new(0.0, 0.0, 1.0),
|
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 1.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.with(Rotator)
|
.with(Rotator)
|
||||||
|
@ -70,7 +70,7 @@ fn setup(
|
||||||
shaded: false,
|
shaded: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
translation: Translation::new(0.0, 3.0, 0.0),
|
transform: Transform::from_translation(Vec3::new(0.0, 3.0, 0.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.spawn(PbrComponents {
|
.spawn(PbrComponents {
|
||||||
|
@ -79,13 +79,13 @@ fn setup(
|
||||||
shaded: false,
|
shaded: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
translation: Translation::new(0.0, -3.0, 0.0),
|
transform: Transform::from_translation(Vec3::new(0.0, -3.0, 0.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
// camera
|
// camera
|
||||||
.spawn(Camera3dComponents {
|
.spawn(Camera3dComponents {
|
||||||
transform: Transform::new_sync_disabled(Mat4::face_toward(
|
transform: Transform::new(Mat4::face_toward(
|
||||||
Vec3::new(5.0, 10.0, 10.0),
|
Vec3::new(5.0, 10.0, 10.0),
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 1.0, 0.0),
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
|
|
@ -49,31 +49,31 @@ fn setup(
|
||||||
.spawn(PbrComponents {
|
.spawn(PbrComponents {
|
||||||
mesh: monkey_handle,
|
mesh: monkey_handle,
|
||||||
material: material_handle,
|
material: material_handle,
|
||||||
translation: Translation::new(-3.0, 0.0, 0.0),
|
transform: Transform::from_translation(Vec3::new(-3.0, 0.0, 0.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// cube
|
// cube
|
||||||
.spawn(PbrComponents {
|
.spawn(PbrComponents {
|
||||||
mesh: cube_handle,
|
mesh: cube_handle,
|
||||||
material: material_handle,
|
material: material_handle,
|
||||||
translation: Translation::new(0.0, 0.0, 0.0),
|
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// sphere
|
// sphere
|
||||||
.spawn(PbrComponents {
|
.spawn(PbrComponents {
|
||||||
mesh: sphere_handle,
|
mesh: sphere_handle,
|
||||||
material: material_handle,
|
material: material_handle,
|
||||||
translation: Translation::new(3.0, 0.0, 0.0),
|
transform: Transform::from_translation(Vec3::new(3.0, 0.0, 0.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// light
|
// light
|
||||||
.spawn(LightComponents {
|
.spawn(LightComponents {
|
||||||
translation: Translation::new(4.0, 5.0, 4.0),
|
transform: Transform::from_translation(Vec3::new(4.0, 5.0, 4.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// camera
|
// camera
|
||||||
.spawn(Camera3dComponents {
|
.spawn(Camera3dComponents {
|
||||||
transform: Transform::new_sync_disabled(Mat4::face_toward(
|
transform: Transform::new(Mat4::face_toward(
|
||||||
Vec3::new(0.0, 3.0, 10.0),
|
Vec3::new(0.0, 3.0, 10.0),
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 1.0, 0.0),
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
|
|
@ -42,12 +42,12 @@ fn setup(
|
||||||
})
|
})
|
||||||
// light
|
// light
|
||||||
.spawn(LightComponents {
|
.spawn(LightComponents {
|
||||||
translation: Translation::new(4.0, 5.0, 4.0),
|
transform: Transform::from_translation(Vec3::new(4.0, 5.0, 4.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// camera
|
// camera
|
||||||
.spawn(Camera3dComponents {
|
.spawn(Camera3dComponents {
|
||||||
transform: Transform::new_sync_disabled(Mat4::face_toward(
|
transform: Transform::new(Mat4::face_toward(
|
||||||
Vec3::new(2.0, 2.0, 6.0),
|
Vec3::new(2.0, 2.0, 6.0),
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 1.0, 0.0),
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
|
|
@ -15,8 +15,7 @@ fn spawn_system(
|
||||||
commands
|
commands
|
||||||
.spawn(SpriteComponents {
|
.spawn(SpriteComponents {
|
||||||
material,
|
material,
|
||||||
translation: Translation::new(0.0, 0.0, 0.0),
|
transform: Transform::from_scale(Vec3::one() * 0.1),
|
||||||
scale: Scale(0.1),
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.with(Velocity(
|
.with(Velocity(
|
||||||
|
@ -26,7 +25,7 @@ fn spawn_system(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move sprites according to their velocity
|
// Move sprites according to their velocity
|
||||||
fn move_system(pool: Res<ComputeTaskPool>, mut sprites: Query<(&mut Translation, &Velocity)>) {
|
fn move_system(pool: Res<ComputeTaskPool>, mut sprites: Query<(&mut Transform, &Velocity)>) {
|
||||||
// Compute the new location of each sprite in parallel on the
|
// Compute the new location of each sprite in parallel on the
|
||||||
// ComputeTaskPool using batches of 32 sprties
|
// ComputeTaskPool using batches of 32 sprties
|
||||||
//
|
//
|
||||||
|
@ -35,16 +34,19 @@ fn move_system(pool: Res<ComputeTaskPool>, mut sprites: Query<(&mut Translation,
|
||||||
// elements will not typically be faster than just using a normal Iterator.
|
// elements will not typically be faster than just using a normal Iterator.
|
||||||
// See the ParallelIterator documentation for more information on when
|
// See the ParallelIterator documentation for more information on when
|
||||||
// to use or not use ParallelIterator over a normal Iterator.
|
// to use or not use ParallelIterator over a normal Iterator.
|
||||||
sprites.iter().par_iter(32).for_each(&pool, |(mut t, v)| {
|
sprites
|
||||||
t.0 += v.0.extend(0.0);
|
.iter()
|
||||||
});
|
.par_iter(32)
|
||||||
|
.for_each(&pool, |(mut transform, velocity)| {
|
||||||
|
transform.translate(velocity.0.extend(0.0));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bounce sprties outside the window
|
// Bounce sprties outside the window
|
||||||
fn bounce_system(
|
fn bounce_system(
|
||||||
pool: Res<ComputeTaskPool>,
|
pool: Res<ComputeTaskPool>,
|
||||||
windows: Res<Windows>,
|
windows: Res<Windows>,
|
||||||
mut sprites: Query<(&Translation, &mut Velocity)>,
|
mut sprites: Query<(&Transform, &mut Velocity)>,
|
||||||
) {
|
) {
|
||||||
let Window { width, height, .. } = windows.get_primary().expect("No primary window");
|
let Window { width, height, .. } = windows.get_primary().expect("No primary window");
|
||||||
let left = *width as f32 / -2.0;
|
let left = *width as f32 / -2.0;
|
||||||
|
@ -57,7 +59,12 @@ fn bounce_system(
|
||||||
// ParallelIterator, since negating a vector is very inexpensive.
|
// ParallelIterator, since negating a vector is very inexpensive.
|
||||||
.par_iter(32)
|
.par_iter(32)
|
||||||
// Filter out sprites that don't need to be bounced
|
// Filter out sprites that don't need to be bounced
|
||||||
.filter(|(t, _)| !(left < t.x() && t.x() < right && bottom < t.y() && t.y() < top))
|
.filter(|(transform, _)| {
|
||||||
|
!(left < transform.translation().x()
|
||||||
|
&& transform.translation().x() < right
|
||||||
|
&& bottom < transform.translation().y()
|
||||||
|
&& transform.translation().y() < top)
|
||||||
|
})
|
||||||
// For simplicity, just reverse the velocity; don't use realistic bounces
|
// For simplicity, just reverse the velocity; don't use realistic bounces
|
||||||
.for_each(&pool, |(_, mut v)| {
|
.for_each(&pool, |(_, mut v)| {
|
||||||
v.0 = -v.0;
|
v.0 = -v.0;
|
||||||
|
|
|
@ -48,7 +48,7 @@ fn setup(
|
||||||
// paddle
|
// paddle
|
||||||
.spawn(SpriteComponents {
|
.spawn(SpriteComponents {
|
||||||
material: materials.add(Color::rgb(0.2, 0.2, 0.8).into()),
|
material: materials.add(Color::rgb(0.2, 0.2, 0.8).into()),
|
||||||
translation: Translation(Vec3::new(0.0, -215.0, 0.0)),
|
transform: Transform::from_translation(Vec3::new(0.0, -215.0, 0.0)),
|
||||||
sprite: Sprite::new(Vec2::new(120.0, 30.0)),
|
sprite: Sprite::new(Vec2::new(120.0, 30.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
|
@ -57,7 +57,7 @@ fn setup(
|
||||||
// ball
|
// ball
|
||||||
.spawn(SpriteComponents {
|
.spawn(SpriteComponents {
|
||||||
material: materials.add(Color::rgb(0.8, 0.2, 0.2).into()),
|
material: materials.add(Color::rgb(0.8, 0.2, 0.2).into()),
|
||||||
translation: Translation(Vec3::new(0.0, -50.0, 1.0)),
|
transform: Transform::from_translation(Vec3::new(0.0, -50.0, 1.0)),
|
||||||
sprite: Sprite::new(Vec2::new(30.0, 30.0)),
|
sprite: Sprite::new(Vec2::new(30.0, 30.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
|
@ -95,7 +95,7 @@ fn setup(
|
||||||
// left
|
// left
|
||||||
.spawn(SpriteComponents {
|
.spawn(SpriteComponents {
|
||||||
material: wall_material,
|
material: wall_material,
|
||||||
translation: Translation(Vec3::new(-bounds.x() / 2.0, 0.0, 0.0)),
|
transform: Transform::from_translation(Vec3::new(-bounds.x() / 2.0, 0.0, 0.0)),
|
||||||
sprite: Sprite::new(Vec2::new(wall_thickness, bounds.y() + wall_thickness)),
|
sprite: Sprite::new(Vec2::new(wall_thickness, bounds.y() + wall_thickness)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
|
@ -103,7 +103,7 @@ fn setup(
|
||||||
// right
|
// right
|
||||||
.spawn(SpriteComponents {
|
.spawn(SpriteComponents {
|
||||||
material: wall_material,
|
material: wall_material,
|
||||||
translation: Translation(Vec3::new(bounds.x() / 2.0, 0.0, 0.0)),
|
transform: Transform::from_translation(Vec3::new(bounds.x() / 2.0, 0.0, 0.0)),
|
||||||
sprite: Sprite::new(Vec2::new(wall_thickness, bounds.y() + wall_thickness)),
|
sprite: Sprite::new(Vec2::new(wall_thickness, bounds.y() + wall_thickness)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
|
@ -111,7 +111,7 @@ fn setup(
|
||||||
// bottom
|
// bottom
|
||||||
.spawn(SpriteComponents {
|
.spawn(SpriteComponents {
|
||||||
material: wall_material,
|
material: wall_material,
|
||||||
translation: Translation(Vec3::new(0.0, -bounds.y() / 2.0, 0.0)),
|
transform: Transform::from_translation(Vec3::new(0.0, -bounds.y() / 2.0, 0.0)),
|
||||||
sprite: Sprite::new(Vec2::new(bounds.x() + wall_thickness, wall_thickness)),
|
sprite: Sprite::new(Vec2::new(bounds.x() + wall_thickness, wall_thickness)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
|
@ -119,7 +119,7 @@ fn setup(
|
||||||
// top
|
// top
|
||||||
.spawn(SpriteComponents {
|
.spawn(SpriteComponents {
|
||||||
material: wall_material,
|
material: wall_material,
|
||||||
translation: Translation(Vec3::new(0.0, bounds.y() / 2.0, 0.0)),
|
transform: Transform::from_translation(Vec3::new(0.0, bounds.y() / 2.0, 0.0)),
|
||||||
sprite: Sprite::new(Vec2::new(bounds.x() + wall_thickness, wall_thickness)),
|
sprite: Sprite::new(Vec2::new(bounds.x() + wall_thickness, wall_thickness)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
|
@ -147,7 +147,7 @@ fn setup(
|
||||||
.spawn(SpriteComponents {
|
.spawn(SpriteComponents {
|
||||||
material: materials.add(Color::rgb(0.2, 0.2, 0.8).into()),
|
material: materials.add(Color::rgb(0.2, 0.2, 0.8).into()),
|
||||||
sprite: Sprite::new(brick_size),
|
sprite: Sprite::new(brick_size),
|
||||||
translation: Translation(brick_position),
|
transform: Transform::from_translation(brick_position),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.with(Collider::Scorable);
|
.with(Collider::Scorable);
|
||||||
|
@ -158,9 +158,9 @@ fn setup(
|
||||||
fn paddle_movement_system(
|
fn paddle_movement_system(
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
keyboard_input: Res<Input<KeyCode>>,
|
keyboard_input: Res<Input<KeyCode>>,
|
||||||
mut query: Query<(&Paddle, &mut Translation)>,
|
mut query: Query<(&Paddle, &mut Transform)>,
|
||||||
) {
|
) {
|
||||||
for (paddle, mut translation) in &mut query.iter() {
|
for (paddle, mut transform) in &mut query.iter() {
|
||||||
let mut direction = 0.0;
|
let mut direction = 0.0;
|
||||||
if keyboard_input.pressed(KeyCode::Left) {
|
if keyboard_input.pressed(KeyCode::Left) {
|
||||||
direction -= 1.0;
|
direction -= 1.0;
|
||||||
|
@ -170,19 +170,24 @@ fn paddle_movement_system(
|
||||||
direction += 1.0;
|
direction += 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*translation.0.x_mut() += time.delta_seconds * direction * paddle.speed;
|
transform.translate(Vec3::unit_x() * time.delta_seconds * direction * paddle.speed);
|
||||||
|
|
||||||
// bound the paddle within the walls
|
// bound the paddle within the walls
|
||||||
*translation.0.x_mut() = f32::max(-380.0, f32::min(380.0, translation.0.x()));
|
let translation = transform.translation();
|
||||||
|
transform.set_translation(Vec3::new(
|
||||||
|
f32::max(-380.0, f32::min(380.0, translation.x())),
|
||||||
|
translation.y(),
|
||||||
|
translation.z(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ball_movement_system(time: Res<Time>, mut ball_query: Query<(&Ball, &mut Translation)>) {
|
fn ball_movement_system(time: Res<Time>, mut ball_query: Query<(&Ball, &mut Transform)>) {
|
||||||
// clamp the timestep to stop the ball from escaping when the game starts
|
// clamp the timestep to stop the ball from escaping when the game starts
|
||||||
let delta_seconds = f32::min(0.2, time.delta_seconds);
|
let delta_seconds = f32::min(0.2, time.delta_seconds);
|
||||||
|
|
||||||
for (ball, mut translation) in &mut ball_query.iter() {
|
for (ball, mut transform) in &mut ball_query.iter() {
|
||||||
translation.0 += ball.velocity * delta_seconds;
|
transform.translate(ball.velocity * delta_seconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,16 +200,21 @@ fn scoreboard_system(scoreboard: Res<Scoreboard>, mut query: Query<&mut Text>) {
|
||||||
fn ball_collision_system(
|
fn ball_collision_system(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut scoreboard: ResMut<Scoreboard>,
|
mut scoreboard: ResMut<Scoreboard>,
|
||||||
mut ball_query: Query<(&mut Ball, &Translation, &Sprite)>,
|
mut ball_query: Query<(&mut Ball, &Transform, &Sprite)>,
|
||||||
mut collider_query: Query<(Entity, &Collider, &Translation, &Sprite)>,
|
mut collider_query: Query<(Entity, &Collider, &Transform, &Sprite)>,
|
||||||
) {
|
) {
|
||||||
for (mut ball, ball_translation, sprite) in &mut ball_query.iter() {
|
for (mut ball, ball_transform, sprite) in &mut ball_query.iter() {
|
||||||
let ball_size = sprite.size;
|
let ball_size = sprite.size;
|
||||||
let velocity = &mut ball.velocity;
|
let velocity = &mut ball.velocity;
|
||||||
|
|
||||||
// check collision with walls
|
// check collision with walls
|
||||||
for (collider_entity, collider, translation, sprite) in &mut collider_query.iter() {
|
for (collider_entity, collider, transform, sprite) in &mut collider_query.iter() {
|
||||||
let collision = collide(ball_translation.0, ball_size, translation.0, sprite.size);
|
let collision = collide(
|
||||||
|
ball_transform.translation(),
|
||||||
|
ball_size,
|
||||||
|
transform.translation(),
|
||||||
|
sprite.size,
|
||||||
|
);
|
||||||
if let Some(collision) = collision {
|
if let Some(collision) = collision {
|
||||||
// scorable colliders should be despawned and increment the scoreboard on collision
|
// scorable colliders should be despawned and increment the scoreboard on collision
|
||||||
if let Collider::Scorable = *collider {
|
if let Collider::Scorable = *collider {
|
||||||
|
|
|
@ -102,13 +102,13 @@ fn setup(
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)]),
|
)]),
|
||||||
translation: Translation::new(0.0, 0.0, 0.0),
|
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.with(material)
|
.with(material)
|
||||||
// camera
|
// camera
|
||||||
.spawn(Camera3dComponents {
|
.spawn(Camera3dComponents {
|
||||||
transform: Transform::new_sync_disabled(Mat4::face_toward(
|
transform: Transform::new(Mat4::face_toward(
|
||||||
Vec3::new(3.0, 5.0, -8.0),
|
Vec3::new(3.0, 5.0, -8.0),
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 1.0, 0.0),
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
|
|
@ -123,7 +123,7 @@ fn setup(
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)]),
|
)]),
|
||||||
translation: Translation::new(-2.0, 0.0, 0.0),
|
transform: Transform::from_translation(Vec3::new(-2.0, 0.0, 0.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.with(green_material)
|
.with(green_material)
|
||||||
|
@ -149,13 +149,13 @@ fn setup(
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)]),
|
)]),
|
||||||
translation: Translation::new(2.0, 0.0, 0.0),
|
transform: Transform::from_translation(Vec3::new(2.0, 0.0, 0.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.with(blue_material)
|
.with(blue_material)
|
||||||
// camera
|
// camera
|
||||||
.spawn(Camera3dComponents {
|
.spawn(Camera3dComponents {
|
||||||
transform: Transform::new_sync_disabled(Mat4::face_toward(
|
transform: Transform::new(Mat4::face_toward(
|
||||||
Vec3::new(3.0, 5.0, -8.0),
|
Vec3::new(3.0, 5.0, -8.0),
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 1.0, 0.0),
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
|
|
@ -173,12 +173,12 @@ fn setup(
|
||||||
})
|
})
|
||||||
// light
|
// light
|
||||||
.spawn(LightComponents {
|
.spawn(LightComponents {
|
||||||
translation: Translation::new(4.0, 5.0, 4.0),
|
transform: Transform::from_translation(Vec3::new(4.0, 5.0, 4.0)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
// main camera
|
// main camera
|
||||||
.spawn(Camera3dComponents {
|
.spawn(Camera3dComponents {
|
||||||
transform: Transform::new_sync_disabled(Mat4::face_toward(
|
transform: Transform::new(Mat4::face_toward(
|
||||||
Vec3::new(0.0, 0.0, 6.0),
|
Vec3::new(0.0, 0.0, 6.0),
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 1.0, 0.0),
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
@ -192,7 +192,7 @@ fn setup(
|
||||||
window: window_id,
|
window: window_id,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
transform: Transform::new_sync_disabled(Mat4::face_toward(
|
transform: Transform::new(Mat4::face_toward(
|
||||||
Vec3::new(6.0, 0.0, 0.0),
|
Vec3::new(6.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
Vec3::new(0.0, 1.0, 0.0),
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
|
Loading…
Reference in a new issue