Add examples for Transforms (#2441)
# Add Transform Examples - Adding examples for moving/rotating entities (with its own section) to resolve #2400 I've stumbled upon this project and been fiddling around a little. Saw the issue and thought I might just add some examples for the proposed transformations. Mind to check if I got the gist correctly and suggest anything I can improve?
This commit is contained in:
		
							parent
							
								
									6e61fef67d
								
							
						
					
					
						commit
						9dfd4e4b08
					
				
							
								
								
									
										21
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								Cargo.toml
									
									
									
									
									
								
							@ -502,6 +502,27 @@ path = "examples/shader/compute_shader_game_of_life.rs"
 | 
				
			|||||||
name = "bevymark"
 | 
					name = "bevymark"
 | 
				
			||||||
path = "examples/tools/bevymark.rs"
 | 
					path = "examples/tools/bevymark.rs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Transforms
 | 
				
			||||||
 | 
					[[example]]
 | 
				
			||||||
 | 
					name = "global_vs_local_translation"
 | 
				
			||||||
 | 
					path = "examples/transforms/global_vs_local_translation.rs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[example]]
 | 
				
			||||||
 | 
					name = "3d_rotation"
 | 
				
			||||||
 | 
					path = "examples/transforms/3d_rotation.rs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[example]]
 | 
				
			||||||
 | 
					name = "scale"
 | 
				
			||||||
 | 
					path = "examples/transforms/scale.rs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[example]]
 | 
				
			||||||
 | 
					name = "transform"
 | 
				
			||||||
 | 
					path = "examples/transforms/transform.rs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[example]]
 | 
				
			||||||
 | 
					name = "translation"
 | 
				
			||||||
 | 
					path = "examples/transforms/translation.rs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# UI (User Interface)
 | 
					# UI (User Interface)
 | 
				
			||||||
[[example]]
 | 
					[[example]]
 | 
				
			||||||
name = "button"
 | 
					name = "button"
 | 
				
			||||||
 | 
				
			|||||||
@ -52,6 +52,7 @@ git checkout v0.4.0
 | 
				
			|||||||
  - [Shaders](#shaders)
 | 
					  - [Shaders](#shaders)
 | 
				
			||||||
  - [Tests](#tests)
 | 
					  - [Tests](#tests)
 | 
				
			||||||
  - [Tools](#tools)
 | 
					  - [Tools](#tools)
 | 
				
			||||||
 | 
					  - [Transforms](#transforms)
 | 
				
			||||||
  - [UI (User Interface)](#ui-user-interface)
 | 
					  - [UI (User Interface)](#ui-user-interface)
 | 
				
			||||||
  - [Window](#window)
 | 
					  - [Window](#window)
 | 
				
			||||||
- [Platform-Specific Examples](#platform-specific-examples)
 | 
					- [Platform-Specific Examples](#platform-specific-examples)
 | 
				
			||||||
@ -247,6 +248,16 @@ Example | File | Description
 | 
				
			|||||||
--- | --- | ---
 | 
					--- | --- | ---
 | 
				
			||||||
`bevymark` | [`tools/bevymark.rs`](./tools/bevymark.rs) | A heavy sprite rendering workload to benchmark your system with Bevy
 | 
					`bevymark` | [`tools/bevymark.rs`](./tools/bevymark.rs) | A heavy sprite rendering workload to benchmark your system with Bevy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Transforms
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example | File | Description
 | 
				
			||||||
 | 
					--- | --- | ---
 | 
				
			||||||
 | 
					`global_vs_local_translation` | [`transforms/global_vs_local_translation.rs`](./transforms/global_vs_local_translation.rs) | Illustrates the difference between direction of a translation in respect to local object or global object Transform
 | 
				
			||||||
 | 
					`3d_rotation` | [`transforms/3d_rotation.rs`](./transforms/3d_rotation.rs) | Illustrates how to (constantly) rotate an object around an axis
 | 
				
			||||||
 | 
					`scale` | [`transforms/scale.rs`](./transforms/scale.rs) | Illustrates how to scale an object in each direction
 | 
				
			||||||
 | 
					`transform` | [`transforms/transfrom.rs`](./transforms/transform.rs) | Shows multiple transformations of objects
 | 
				
			||||||
 | 
					`translation` | [`transforms/translation.rs`](./transforms/translation.rs) | Illustrates how to move an object along an axis
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## UI (User Interface)
 | 
					## UI (User Interface)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Example | File | Description
 | 
					Example | File | Description
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										57
									
								
								examples/transforms/3d_rotation.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								examples/transforms/3d_rotation.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					use bevy::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::f32::consts::PI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const FULL_TURN: f32 = 2.0 * PI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Define a component to designate a rotation speed to an entity.
 | 
				
			||||||
 | 
					#[derive(Component)]
 | 
				
			||||||
 | 
					struct Rotatable {
 | 
				
			||||||
 | 
					    speed: f32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    App::new()
 | 
				
			||||||
 | 
					        .add_plugins(DefaultPlugins)
 | 
				
			||||||
 | 
					        .add_startup_system(setup)
 | 
				
			||||||
 | 
					        .add_system(rotate_cube)
 | 
				
			||||||
 | 
					        .run();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn setup(
 | 
				
			||||||
 | 
					    mut commands: Commands,
 | 
				
			||||||
 | 
					    mut meshes: ResMut<Assets<Mesh>>,
 | 
				
			||||||
 | 
					    mut materials: ResMut<Assets<StandardMaterial>>,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    // Spawn a cube to rotate.
 | 
				
			||||||
 | 
					    commands
 | 
				
			||||||
 | 
					        .spawn_bundle(PbrBundle {
 | 
				
			||||||
 | 
					            mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
 | 
				
			||||||
 | 
					            material: materials.add(Color::WHITE.into()),
 | 
				
			||||||
 | 
					            transform: Transform::from_translation(Vec3::ZERO),
 | 
				
			||||||
 | 
					            ..Default::default()
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .insert(Rotatable { speed: 0.3 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Spawn a camera looking at the entities to show what's happening in this example.
 | 
				
			||||||
 | 
					    commands.spawn_bundle(PerspectiveCameraBundle {
 | 
				
			||||||
 | 
					        transform: Transform::from_xyz(0.0, 10.0, 20.0).looking_at(Vec3::ZERO, Vec3::Y),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add a light source for better 3d visibility.
 | 
				
			||||||
 | 
					    commands.spawn_bundle(PointLightBundle {
 | 
				
			||||||
 | 
					        transform: Transform::from_translation(Vec3::ONE * 3.0),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This system will rotate any entity in the scene with an assigned Rotatable around its z-axis.
 | 
				
			||||||
 | 
					fn rotate_cube(mut cubes: Query<(&mut Transform, &Rotatable)>, timer: Res<Time>) {
 | 
				
			||||||
 | 
					    for (mut transform, cube) in cubes.iter_mut() {
 | 
				
			||||||
 | 
					        // The speed is taken as a percentage of a full 360 degree turn.
 | 
				
			||||||
 | 
					        // The timers delta_seconds is used to smooth out the movement.
 | 
				
			||||||
 | 
					        let rotation_change = Quat::from_rotation_y(FULL_TURN * cube.speed * timer.delta_seconds());
 | 
				
			||||||
 | 
					        transform.rotate(rotation_change);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										188
									
								
								examples/transforms/global_vs_local_translation.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								examples/transforms/global_vs_local_translation.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,188 @@
 | 
				
			|||||||
 | 
					use bevy::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Define a marker for entities that should be changed via their global transform.
 | 
				
			||||||
 | 
					#[derive(Component)]
 | 
				
			||||||
 | 
					struct ChangeGlobal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Define a marker for entities that should be changed via their local transform.
 | 
				
			||||||
 | 
					#[derive(Component)]
 | 
				
			||||||
 | 
					struct ChangeLocal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Define a marker for entities that should move.
 | 
				
			||||||
 | 
					#[derive(Component)]
 | 
				
			||||||
 | 
					struct Move;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Define a resource for the current movement direction;
 | 
				
			||||||
 | 
					#[derive(Default)]
 | 
				
			||||||
 | 
					struct Direction(Vec3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Define component to decide when an entity should be ignored by the movement systems.
 | 
				
			||||||
 | 
					#[derive(Component)]
 | 
				
			||||||
 | 
					struct ToggledBy(KeyCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    App::new()
 | 
				
			||||||
 | 
					        .add_plugins(DefaultPlugins)
 | 
				
			||||||
 | 
					        .add_startup_system(setup)
 | 
				
			||||||
 | 
					        .init_resource::<Direction>()
 | 
				
			||||||
 | 
					        .add_system(move_cubes_according_to_global_transform)
 | 
				
			||||||
 | 
					        .add_system(move_cubes_according_to_local_transform)
 | 
				
			||||||
 | 
					        .add_system(update_directional_input)
 | 
				
			||||||
 | 
					        .add_system(toggle_movement)
 | 
				
			||||||
 | 
					        .run();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Startup system to setup the scene and spawn all relevant entities.
 | 
				
			||||||
 | 
					fn setup(
 | 
				
			||||||
 | 
					    mut commands: Commands,
 | 
				
			||||||
 | 
					    mut meshes: ResMut<Assets<Mesh>>,
 | 
				
			||||||
 | 
					    mut materials: ResMut<Assets<StandardMaterial>>,
 | 
				
			||||||
 | 
					    asset_server: Res<AssetServer>,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    // To show the difference between a local transform (rotation, scale and position in respect to a given entity)
 | 
				
			||||||
 | 
					    // and global transform (rotation, scale and position in respect to the base coordinate system of the visible scene)
 | 
				
			||||||
 | 
					    // it's helpful to add multiple entities that are attached to each other.
 | 
				
			||||||
 | 
					    // This way we'll see that the transform in respect to an entity's parent is different to the
 | 
				
			||||||
 | 
					    // global transform within the visible scene.
 | 
				
			||||||
 | 
					    // This example focuses on translation only to clearly demonstrate the differences.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Spawn a basic cube to have an entity as reference.
 | 
				
			||||||
 | 
					    let mut main_entity = commands.spawn();
 | 
				
			||||||
 | 
					    main_entity
 | 
				
			||||||
 | 
					        .insert_bundle(PbrBundle {
 | 
				
			||||||
 | 
					            mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
 | 
				
			||||||
 | 
					            material: materials.add(Color::YELLOW.into()),
 | 
				
			||||||
 | 
					            ..Default::default()
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .insert(ChangeGlobal)
 | 
				
			||||||
 | 
					        .insert(Move)
 | 
				
			||||||
 | 
					        .insert(ToggledBy(KeyCode::Key1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Spawn two entities as children above the original main entity.
 | 
				
			||||||
 | 
					    // The red entity spawned here will be changed via its global transform
 | 
				
			||||||
 | 
					    // where the green one will be changed via its local transform.
 | 
				
			||||||
 | 
					    main_entity.with_children(|child_builder| {
 | 
				
			||||||
 | 
					        // also see parenting example
 | 
				
			||||||
 | 
					        child_builder
 | 
				
			||||||
 | 
					            .spawn_bundle(PbrBundle {
 | 
				
			||||||
 | 
					                mesh: meshes.add(Mesh::from(shape::Cube { size: 0.5 })),
 | 
				
			||||||
 | 
					                material: materials.add(Color::RED.into()),
 | 
				
			||||||
 | 
					                transform: Transform::from_translation(Vec3::Y - Vec3::Z),
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .insert(ChangeGlobal)
 | 
				
			||||||
 | 
					            .insert(Move)
 | 
				
			||||||
 | 
					            .insert(ToggledBy(KeyCode::Key2));
 | 
				
			||||||
 | 
					        child_builder
 | 
				
			||||||
 | 
					            .spawn_bundle(PbrBundle {
 | 
				
			||||||
 | 
					                mesh: meshes.add(Mesh::from(shape::Cube { size: 0.5 })),
 | 
				
			||||||
 | 
					                material: materials.add(Color::GREEN.into()),
 | 
				
			||||||
 | 
					                transform: Transform::from_translation(Vec3::Y + Vec3::Z),
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .insert(ChangeLocal)
 | 
				
			||||||
 | 
					            .insert(Move)
 | 
				
			||||||
 | 
					            .insert(ToggledBy(KeyCode::Key3));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Spawn a camera looking at the entities to show what's happening in this example.
 | 
				
			||||||
 | 
					    commands.spawn_bundle(PerspectiveCameraBundle {
 | 
				
			||||||
 | 
					        transform: Transform::from_xyz(0.0, 10.0, 20.0).looking_at(Vec3::ZERO, Vec3::Y),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add a light source for better 3d visibility.
 | 
				
			||||||
 | 
					    commands.spawn_bundle(PointLightBundle {
 | 
				
			||||||
 | 
					        transform: Transform::from_translation(Vec3::splat(3.0)),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add a UI cam and text to explain inputs and what is happening.
 | 
				
			||||||
 | 
					    commands.spawn_bundle(UiCameraBundle::default());
 | 
				
			||||||
 | 
					    commands.spawn_bundle(TextBundle {
 | 
				
			||||||
 | 
					        text: Text::with_section(
 | 
				
			||||||
 | 
					            "Press the arrow keys to move the cubes. Toggle movement for yellow (1), red (2) and green (3) cubes via number keys.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Notice how the green cube will translate further in respect to the yellow in contrast to the red cube.
 | 
				
			||||||
 | 
					This is due to the use of its LocalTransform that is relative to the yellow cubes transform instead of the GlobalTransform as in the case of the red cube.
 | 
				
			||||||
 | 
					The red cube is moved through its GlobalTransform and thus is unaffected by the yellows transform.",
 | 
				
			||||||
 | 
					            TextStyle {
 | 
				
			||||||
 | 
					                font: asset_server.load("fonts/FiraSans-Bold.ttf"),
 | 
				
			||||||
 | 
					                font_size: 22.0,
 | 
				
			||||||
 | 
					                color: Color::WHITE,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            TextAlignment {
 | 
				
			||||||
 | 
					                horizontal: HorizontalAlign::Left,
 | 
				
			||||||
 | 
					                ..Default::default()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        ..Default::default()});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This system will move all cubes that are marked as ChangeGlobal according to their global transform.
 | 
				
			||||||
 | 
					fn move_cubes_according_to_global_transform(
 | 
				
			||||||
 | 
					    mut cubes: Query<&mut GlobalTransform, (With<ChangeGlobal>, With<Move>)>,
 | 
				
			||||||
 | 
					    direction: Res<Direction>,
 | 
				
			||||||
 | 
					    timer: Res<Time>,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    for mut global_transform in cubes.iter_mut() {
 | 
				
			||||||
 | 
					        global_transform.translation += direction.0 * timer.delta_seconds();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This system will move all cubes that are marked as ChangeLocal according to their local transform.
 | 
				
			||||||
 | 
					fn move_cubes_according_to_local_transform(
 | 
				
			||||||
 | 
					    mut cubes: Query<&mut Transform, (With<ChangeLocal>, With<Move>)>,
 | 
				
			||||||
 | 
					    direction: Res<Direction>,
 | 
				
			||||||
 | 
					    timer: Res<Time>,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    for mut transform in cubes.iter_mut() {
 | 
				
			||||||
 | 
					        transform.translation += direction.0 * timer.delta_seconds();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This system updates a resource that defines in which direction the cubes should move.
 | 
				
			||||||
 | 
					// The direction is defined by the input of arrow keys and is only in left/right and up/down direction.
 | 
				
			||||||
 | 
					fn update_directional_input(mut direction: ResMut<Direction>, keyboard_input: Res<Input<KeyCode>>) {
 | 
				
			||||||
 | 
					    let horizontal_movement = Vec3::X
 | 
				
			||||||
 | 
					        * (keyboard_input.pressed(KeyCode::Right) as i32
 | 
				
			||||||
 | 
					            - keyboard_input.pressed(KeyCode::Left) as i32) as f32;
 | 
				
			||||||
 | 
					    let vertical_movement = Vec3::Y
 | 
				
			||||||
 | 
					        * (keyboard_input.pressed(KeyCode::Up) as i32
 | 
				
			||||||
 | 
					            - keyboard_input.pressed(KeyCode::Down) as i32) as f32;
 | 
				
			||||||
 | 
					    direction.0 = horizontal_movement + vertical_movement;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This system enables and disables the movement for each entity if their assigned key is pressed.
 | 
				
			||||||
 | 
					fn toggle_movement(
 | 
				
			||||||
 | 
					    mut commands: Commands,
 | 
				
			||||||
 | 
					    movable_entities: Query<(Entity, &Handle<StandardMaterial>, &ToggledBy), With<Move>>,
 | 
				
			||||||
 | 
					    static_entities: Query<(Entity, &Handle<StandardMaterial>, &ToggledBy), Without<Move>>,
 | 
				
			||||||
 | 
					    mut materials: ResMut<Assets<StandardMaterial>>,
 | 
				
			||||||
 | 
					    keyboard_input: Res<Input<KeyCode>>,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    // Update the currently movable entities and remove their Move component if the assigned key was pressed to disable their movement.
 | 
				
			||||||
 | 
					    // This will also make them transparent so they can be identified as 'disabled' in the scene.
 | 
				
			||||||
 | 
					    for (entity, material_handle, toggled_by) in movable_entities.iter() {
 | 
				
			||||||
 | 
					        if keyboard_input.just_pressed(toggled_by.0) {
 | 
				
			||||||
 | 
					            materials
 | 
				
			||||||
 | 
					                .get_mut(material_handle)
 | 
				
			||||||
 | 
					                .unwrap()
 | 
				
			||||||
 | 
					                .base_color
 | 
				
			||||||
 | 
					                .set_a(0.5);
 | 
				
			||||||
 | 
					            commands.entity(entity).remove::<Move>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // Update the currently non-movable entities and add a Move component if the assigned key was pressed to enable their movement.
 | 
				
			||||||
 | 
					    // This will also make them opaque so they can be identified as 'enabled' in the scene.
 | 
				
			||||||
 | 
					    for (entity, material_handle, toggled_by) in static_entities.iter() {
 | 
				
			||||||
 | 
					        if keyboard_input.just_pressed(toggled_by.0) {
 | 
				
			||||||
 | 
					            materials
 | 
				
			||||||
 | 
					                .get_mut(material_handle)
 | 
				
			||||||
 | 
					                .unwrap()
 | 
				
			||||||
 | 
					                .base_color
 | 
				
			||||||
 | 
					                .set_a(1.0);
 | 
				
			||||||
 | 
					            commands.entity(entity).insert(Move);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										96
									
								
								examples/transforms/scale.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								examples/transforms/scale.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					use bevy::math::Vec3Swizzles;
 | 
				
			||||||
 | 
					use bevy::prelude::*;
 | 
				
			||||||
 | 
					use std::f32::consts::PI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Define a component to keep information for the scaled object.
 | 
				
			||||||
 | 
					#[derive(Component)]
 | 
				
			||||||
 | 
					struct Scaling {
 | 
				
			||||||
 | 
					    scale_direction: Vec3,
 | 
				
			||||||
 | 
					    scale_speed: f32,
 | 
				
			||||||
 | 
					    max_element_size: f32,
 | 
				
			||||||
 | 
					    min_element_size: f32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Implement a simple initialisation.
 | 
				
			||||||
 | 
					impl Scaling {
 | 
				
			||||||
 | 
					    fn new() -> Self {
 | 
				
			||||||
 | 
					        Scaling {
 | 
				
			||||||
 | 
					            scale_direction: Vec3::X,
 | 
				
			||||||
 | 
					            scale_speed: 2.0,
 | 
				
			||||||
 | 
					            max_element_size: 5.0,
 | 
				
			||||||
 | 
					            min_element_size: 1.0,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    App::new()
 | 
				
			||||||
 | 
					        .add_plugins(DefaultPlugins)
 | 
				
			||||||
 | 
					        .add_startup_system(setup)
 | 
				
			||||||
 | 
					        .add_system(change_scale_direction)
 | 
				
			||||||
 | 
					        .add_system(scale_cube)
 | 
				
			||||||
 | 
					        .run();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Startup system to setup the scene and spawn all relevant entities.
 | 
				
			||||||
 | 
					fn setup(
 | 
				
			||||||
 | 
					    mut commands: Commands,
 | 
				
			||||||
 | 
					    mut meshes: ResMut<Assets<Mesh>>,
 | 
				
			||||||
 | 
					    mut materials: ResMut<Assets<StandardMaterial>>,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    // Spawn a cube to scale.
 | 
				
			||||||
 | 
					    commands
 | 
				
			||||||
 | 
					        .spawn_bundle(PbrBundle {
 | 
				
			||||||
 | 
					            mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
 | 
				
			||||||
 | 
					            material: materials.add(Color::WHITE.into()),
 | 
				
			||||||
 | 
					            transform: Transform::from_rotation(Quat::from_rotation_y(PI / 4.0)),
 | 
				
			||||||
 | 
					            ..Default::default()
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .insert(Scaling::new());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Spawn a camera looking at the entities to show what's happening in this example.
 | 
				
			||||||
 | 
					    commands.spawn_bundle(PerspectiveCameraBundle {
 | 
				
			||||||
 | 
					        transform: Transform::from_xyz(0.0, 10.0, 20.0).looking_at(Vec3::ZERO, Vec3::Y),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add a light source for better 3d visibility.
 | 
				
			||||||
 | 
					    commands.spawn_bundle(PointLightBundle {
 | 
				
			||||||
 | 
					        transform: Transform::from_translation(Vec3::ONE * 3.0),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This system will check if a scaled entity went above or below the entities scaling bounds
 | 
				
			||||||
 | 
					// and change the direction of the scaling vector.
 | 
				
			||||||
 | 
					fn change_scale_direction(mut cubes: Query<(&mut Transform, &mut Scaling)>) {
 | 
				
			||||||
 | 
					    for (mut transform, mut cube) in cubes.iter_mut() {
 | 
				
			||||||
 | 
					        // If an entity scaled beyond the maximum of its size in any dimension
 | 
				
			||||||
 | 
					        // the scaling vector is flipped so the scaling is gradually reverted.
 | 
				
			||||||
 | 
					        // Additionally, to ensure the condition does not trigger again we floor the elements to
 | 
				
			||||||
 | 
					        // their next full value, which should be max_element_size at max.
 | 
				
			||||||
 | 
					        if transform.scale.max_element() > cube.max_element_size {
 | 
				
			||||||
 | 
					            cube.scale_direction *= -1.0;
 | 
				
			||||||
 | 
					            transform.scale = transform.scale.floor();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // If an entity scaled beyond the minimum of its size in any dimension
 | 
				
			||||||
 | 
					        // the scaling vector is also flipped.
 | 
				
			||||||
 | 
					        // Additionally the Values are ceiled to be min_element_size at least
 | 
				
			||||||
 | 
					        // and the scale direction is flipped.
 | 
				
			||||||
 | 
					        // This way the entity will change the dimension in which it is scaled any time it
 | 
				
			||||||
 | 
					        // reaches its min_element_size.
 | 
				
			||||||
 | 
					        if transform.scale.min_element() < cube.min_element_size {
 | 
				
			||||||
 | 
					            cube.scale_direction *= -1.0;
 | 
				
			||||||
 | 
					            transform.scale = transform.scale.ceil();
 | 
				
			||||||
 | 
					            cube.scale_direction = cube.scale_direction.zxy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This system will scale any entity with assigned Scaling in each direction
 | 
				
			||||||
 | 
					// by cycling through the directions to scale.
 | 
				
			||||||
 | 
					fn scale_cube(mut cubes: Query<(&mut Transform, &Scaling)>, timer: Res<Time>) {
 | 
				
			||||||
 | 
					    for (mut transform, cube) in cubes.iter_mut() {
 | 
				
			||||||
 | 
					        transform.scale += cube.scale_direction * cube.scale_speed * timer.delta_seconds();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										151
									
								
								examples/transforms/transform.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								examples/transforms/transform.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,151 @@
 | 
				
			|||||||
 | 
					use bevy::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::f32::consts::PI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A struct for additional data of for a moving cube.
 | 
				
			||||||
 | 
					#[derive(Component)]
 | 
				
			||||||
 | 
					struct CubeState {
 | 
				
			||||||
 | 
					    start_pos: Vec3,
 | 
				
			||||||
 | 
					    move_speed: f32,
 | 
				
			||||||
 | 
					    turn_speed: f32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A struct adding information to a scalable entity,
 | 
				
			||||||
 | 
					// that will be stationary at the center of the scene.
 | 
				
			||||||
 | 
					#[derive(Component)]
 | 
				
			||||||
 | 
					struct Center {
 | 
				
			||||||
 | 
					    max_size: f32,
 | 
				
			||||||
 | 
					    min_size: f32,
 | 
				
			||||||
 | 
					    scale_factor: f32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    App::new()
 | 
				
			||||||
 | 
					        .add_plugins(DefaultPlugins)
 | 
				
			||||||
 | 
					        .add_startup_system(setup)
 | 
				
			||||||
 | 
					        .add_system(move_cube)
 | 
				
			||||||
 | 
					        .add_system(rotate_cube)
 | 
				
			||||||
 | 
					        .add_system(scale_down_sphere_proportional_to_cube_travel_distance)
 | 
				
			||||||
 | 
					        .run();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Startup system to setup the scene and spawn all relevant entities.
 | 
				
			||||||
 | 
					fn setup(
 | 
				
			||||||
 | 
					    mut commands: Commands,
 | 
				
			||||||
 | 
					    mut meshes: ResMut<Assets<Mesh>>,
 | 
				
			||||||
 | 
					    mut materials: ResMut<Assets<StandardMaterial>>,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    // Add an object (sphere) for visualizing scaling.
 | 
				
			||||||
 | 
					    commands
 | 
				
			||||||
 | 
					        .spawn_bundle(PbrBundle {
 | 
				
			||||||
 | 
					            mesh: meshes.add(Mesh::from(shape::Icosphere {
 | 
				
			||||||
 | 
					                radius: 3.0,
 | 
				
			||||||
 | 
					                subdivisions: 32,
 | 
				
			||||||
 | 
					            })),
 | 
				
			||||||
 | 
					            material: materials.add(Color::YELLOW.into()),
 | 
				
			||||||
 | 
					            transform: Transform::from_translation(Vec3::ZERO),
 | 
				
			||||||
 | 
					            ..Default::default()
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .insert(Center {
 | 
				
			||||||
 | 
					            max_size: 1.0,
 | 
				
			||||||
 | 
					            min_size: 0.1,
 | 
				
			||||||
 | 
					            scale_factor: 0.05,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add the cube to visualize rotation and translation.
 | 
				
			||||||
 | 
					    // This cube will circle around the center_sphere
 | 
				
			||||||
 | 
					    // by changing its rotation each frame and moving forward.
 | 
				
			||||||
 | 
					    // Define a start transform for an orbiting cube, that's away from our central object (sphere)
 | 
				
			||||||
 | 
					    // and rotate it so it will be able to move around the sphere and not towards it.
 | 
				
			||||||
 | 
					    let angle_90 = PI / 2.0;
 | 
				
			||||||
 | 
					    let mut cube_spawn = Transform::from_translation(Vec3::Z * -10.0);
 | 
				
			||||||
 | 
					    cube_spawn.rotation = Quat::from_rotation_y(angle_90);
 | 
				
			||||||
 | 
					    commands
 | 
				
			||||||
 | 
					        .spawn_bundle(PbrBundle {
 | 
				
			||||||
 | 
					            mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
 | 
				
			||||||
 | 
					            material: materials.add(Color::WHITE.into()),
 | 
				
			||||||
 | 
					            transform: cube_spawn,
 | 
				
			||||||
 | 
					            ..Default::default()
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .insert(CubeState {
 | 
				
			||||||
 | 
					            start_pos: cube_spawn.translation,
 | 
				
			||||||
 | 
					            move_speed: 2.0,
 | 
				
			||||||
 | 
					            turn_speed: 0.2,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Spawn a camera looking at the entities to show what's happening in this example.
 | 
				
			||||||
 | 
					    commands.spawn_bundle(PerspectiveCameraBundle {
 | 
				
			||||||
 | 
					        transform: Transform::from_xyz(0.0, 10.0, 20.0).looking_at(Vec3::ZERO, Vec3::Y),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add a light source for better 3d visibility.
 | 
				
			||||||
 | 
					    commands.spawn_bundle(PointLightBundle {
 | 
				
			||||||
 | 
					        transform: Transform::from_translation(Vec3::ONE * 3.0),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This system will move the cube forward.
 | 
				
			||||||
 | 
					fn move_cube(mut cubes: Query<(&mut Transform, &mut CubeState)>, timer: Res<Time>) {
 | 
				
			||||||
 | 
					    for (mut transform, cube) in cubes.iter_mut() {
 | 
				
			||||||
 | 
					        // Move the cube forward smoothly at a given move_speed.
 | 
				
			||||||
 | 
					        let forward = transform.forward();
 | 
				
			||||||
 | 
					        transform.translation += forward * cube.move_speed * timer.delta_seconds();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This system will rotate the cube slightly towards the center_sphere.
 | 
				
			||||||
 | 
					// Due to the forward movement the resulting movement
 | 
				
			||||||
 | 
					// will be a circular motion around the center_sphere.
 | 
				
			||||||
 | 
					fn rotate_cube(
 | 
				
			||||||
 | 
					    mut cubes: Query<(&mut Transform, &mut CubeState), Without<Center>>,
 | 
				
			||||||
 | 
					    center_spheres: Query<&Transform, With<Center>>,
 | 
				
			||||||
 | 
					    timer: Res<Time>,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    // Calculate the point to circle around. (The position of the center_sphere)
 | 
				
			||||||
 | 
					    let mut center: Vec3 = Vec3::ZERO;
 | 
				
			||||||
 | 
					    for sphere in center_spheres.iter() {
 | 
				
			||||||
 | 
					        center += sphere.translation;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // Update the rotation of the cube(s).
 | 
				
			||||||
 | 
					    for (mut transform, cube) in cubes.iter_mut() {
 | 
				
			||||||
 | 
					        // Calculate the rotation of the cube if it would be looking at the sphere in the center.
 | 
				
			||||||
 | 
					        let look_at_sphere = transform.looking_at(center, transform.local_y());
 | 
				
			||||||
 | 
					        // Interpolate between the current rotation and the fully turned rotation
 | 
				
			||||||
 | 
					        // when looking a the sphere,  with a given turn speed to get a smooth motion.
 | 
				
			||||||
 | 
					        // With higher speed the curvature of the orbit would be smaller.
 | 
				
			||||||
 | 
					        let incremental_turn_weight = cube.turn_speed * timer.delta_seconds();
 | 
				
			||||||
 | 
					        let old_rotation = transform.rotation;
 | 
				
			||||||
 | 
					        transform.rotation = old_rotation.lerp(look_at_sphere.rotation, incremental_turn_weight);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This system will scale down the sphere in the center of the scene
 | 
				
			||||||
 | 
					// according to the traveling distance of the orbiting cube(s) from their start position(s).
 | 
				
			||||||
 | 
					fn scale_down_sphere_proportional_to_cube_travel_distance(
 | 
				
			||||||
 | 
					    cubes: Query<(&Transform, &CubeState), Without<Center>>,
 | 
				
			||||||
 | 
					    mut centers: Query<(&mut Transform, &Center)>,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    // First we need to calculate the length of between
 | 
				
			||||||
 | 
					    // the current position of the orbiting cube and the spawn position.
 | 
				
			||||||
 | 
					    let mut distances = 0.0;
 | 
				
			||||||
 | 
					    for (cube_transform, cube_state) in cubes.iter() {
 | 
				
			||||||
 | 
					        distances += (cube_state.start_pos - cube_transform.translation).length();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // Now we use the calculated value to scale the sphere in the center accordingly.
 | 
				
			||||||
 | 
					    for (mut transform, center) in centers.iter_mut() {
 | 
				
			||||||
 | 
					        // Calculate the new size from the calculated distances and the centers scale_factor.
 | 
				
			||||||
 | 
					        // Since we want to have the sphere at its max_size at the cubes spawn location we start by
 | 
				
			||||||
 | 
					        // using the max_size as start value and subtract the distances scaled by a scaling factor.
 | 
				
			||||||
 | 
					        let mut new_size: f32 = center.max_size - center.scale_factor * distances;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // The new size should also not be smaller than the centers min_size.
 | 
				
			||||||
 | 
					        // Therefore the max value out of (new_size, center.min_size) is used.
 | 
				
			||||||
 | 
					        new_size = new_size.max(center.min_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Now scale the sphere uniformly in all directions using new_size.
 | 
				
			||||||
 | 
					        // Here Vec3:splat is used to create a vector with new_size in x, y and z direction.
 | 
				
			||||||
 | 
					        transform.scale = Vec3::splat(new_size);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										71
									
								
								examples/transforms/translation.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								examples/transforms/translation.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					use bevy::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Define a struct to keep some information about our entity.
 | 
				
			||||||
 | 
					// Here it's an arbitrary movement speed, the spawn location, and a maximum distance from it.
 | 
				
			||||||
 | 
					#[derive(Component)]
 | 
				
			||||||
 | 
					struct Movable {
 | 
				
			||||||
 | 
					    spawn: Vec3,
 | 
				
			||||||
 | 
					    max_distance: f32,
 | 
				
			||||||
 | 
					    speed: f32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Implement a utility function for easier Movable struct creation.
 | 
				
			||||||
 | 
					impl Movable {
 | 
				
			||||||
 | 
					    fn new(spawn: Vec3) -> Self {
 | 
				
			||||||
 | 
					        Movable {
 | 
				
			||||||
 | 
					            spawn,
 | 
				
			||||||
 | 
					            max_distance: 5.0,
 | 
				
			||||||
 | 
					            speed: 2.0,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    App::new()
 | 
				
			||||||
 | 
					        .add_plugins(DefaultPlugins)
 | 
				
			||||||
 | 
					        .add_startup_system(setup)
 | 
				
			||||||
 | 
					        .add_system(move_cube)
 | 
				
			||||||
 | 
					        .run();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Startup system to setup the scene and spawn all relevant entities.
 | 
				
			||||||
 | 
					fn setup(
 | 
				
			||||||
 | 
					    mut commands: Commands,
 | 
				
			||||||
 | 
					    mut meshes: ResMut<Assets<Mesh>>,
 | 
				
			||||||
 | 
					    mut materials: ResMut<Assets<StandardMaterial>>,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    // Add a cube to visualize translation.
 | 
				
			||||||
 | 
					    let entity_spawn = Vec3::ZERO;
 | 
				
			||||||
 | 
					    commands
 | 
				
			||||||
 | 
					        .spawn_bundle(PbrBundle {
 | 
				
			||||||
 | 
					            mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
 | 
				
			||||||
 | 
					            material: materials.add(Color::WHITE.into()),
 | 
				
			||||||
 | 
					            transform: Transform::from_translation(entity_spawn),
 | 
				
			||||||
 | 
					            ..Default::default()
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .insert(Movable::new(entity_spawn));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Spawn a camera looking at the entities to show what's happening in this example.
 | 
				
			||||||
 | 
					    commands.spawn_bundle(PerspectiveCameraBundle {
 | 
				
			||||||
 | 
					        transform: Transform::from_xyz(0.0, 10.0, 20.0).looking_at(entity_spawn, Vec3::Y),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add a light source for better 3d visibility.
 | 
				
			||||||
 | 
					    commands.spawn_bundle(PointLightBundle {
 | 
				
			||||||
 | 
					        transform: Transform::from_translation(Vec3::ONE * 3.0),
 | 
				
			||||||
 | 
					        ..Default::default()
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This system will move all Movable entities with a Transform
 | 
				
			||||||
 | 
					fn move_cube(mut cubes: Query<(&mut Transform, &mut Movable)>, timer: Res<Time>) {
 | 
				
			||||||
 | 
					    for (mut transform, mut cube) in cubes.iter_mut() {
 | 
				
			||||||
 | 
					        // Check if the entity moved too far from its spawn, if so invert the moving direction.
 | 
				
			||||||
 | 
					        if (cube.spawn - transform.translation).length() > cube.max_distance {
 | 
				
			||||||
 | 
					            cube.speed *= -1.0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let direction = transform.local_x();
 | 
				
			||||||
 | 
					        transform.translation += direction * cube.speed * timer.delta_seconds();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user