Transform Rewrite (#374)

Remove individual Translation / Rotation / Scale components in favor of a combined Transform component
This commit is contained in:
Marek Legris 2020-09-14 23:00:32 +02:00 committed by GitHub
parent 3bc5e4cb1e
commit 474bb5403e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 478 additions and 1386 deletions

2
.gitignore vendored
View file

@ -5,4 +5,4 @@ Cargo.lock
.cargo/config .cargo/config
/.idea /.idea
/.vscode /.vscode
/benches/target /benches/target

View file

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

View file

@ -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],

View file

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

View file

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

View file

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

View file

@ -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(),
} }
} }
} }

View file

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

View file

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

View file

@ -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(),
} }
} }
} }

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

View file

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

View file

@ -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::*;

View file

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

View file

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

View file

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

View file

@ -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;
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(),
} }
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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