Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Add examples for Transforms #2441

Closed
wants to merge 34 commits into from
Closed
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
44ea26c
add simple translation example
l4desu-mizu Jul 1, 2021
82a0ebf
add simple rotation example
l4desu-mizu Jul 1, 2021
cf0eff3
add simple scaling example
l4desu-mizu Jul 2, 2021
bbdff6e
add example for all transform types in one scene
l4desu-mizu Jul 3, 2021
0709b0f
add example for local vs global transform
l4desu-mizu Jul 5, 2021
93ae905
add description for newly added examples to examples README.md
l4desu-mizu Jul 16, 2021
ec7a439
use same name for example in Cargo.toml and README.md
l4desu-mizu Jul 16, 2021
d1c14db
update global_vs_local_translation example
l4desu-mizu Jul 16, 2021
4e64689
update transform example
l4desu-mizu Jul 16, 2021
a06060d
add comments to rotation.rs example for a more verbose explanation
l4desu-mizu Jul 18, 2021
2bc355a
improve readability for scaling example
l4desu-mizu Jul 20, 2021
213e2ab
add explanatory notes to translation example
l4desu-mizu Jul 20, 2021
52dc2bb
align entity spawning notation with other examples
l4desu-mizu Jul 25, 2021
1838ff6
fix typos and wording
l4desu-mizu Sep 25, 2021
8aae22d
reduce component complexity by using tuple structs
l4desu-mizu Sep 25, 2021
049ae7b
use unit struct moving to indicate which cubes should be moved in the…
l4desu-mizu Sep 25, 2021
2d4ada5
run cargo fmt
l4desu-mizu Sep 26, 2021
711378f
add a small rotation to scaling example
l4desu-mizu Sep 26, 2021
f8b2a04
add missing import (pi)
l4desu-mizu Sep 26, 2021
43d060e
Merge branch 'main' into transform_examples
l4desu-mizu Sep 26, 2021
a6af682
use App::new()
l4desu-mizu Sep 26, 2021
0b581a0
remove system calls
l4desu-mizu Sep 26, 2021
e06a0bf
simplify example by using inputs
l4desu-mizu Oct 11, 2021
1d5dcca
add start/stop logic
l4desu-mizu Oct 28, 2021
5fa94f5
specify movement toggle directly instead of using colours
l4desu-mizu Oct 28, 2021
24e8c99
add explanational text on screen
l4desu-mizu Oct 17, 2021
7bca2aa
polish comments and explanatory texts
l4desu-mizu Oct 31, 2021
770e57a
Merge branch 'main' into transform_examples
l4desu-mizu Oct 31, 2021
19c92fa
update transforms examples with changes from main
l4desu-mizu Oct 31, 2021
6d088e3
Merge branch 'main' into transform_examples
l4desu-mizu Dec 2, 2021
b9cd0e5
Merge branch 'main' into transform_examples
l4desu-mizu Dec 19, 2021
38ab887
Merge branch 'main' into transform_examples
l4desu-mizu Feb 5, 2022
c9ff37d
Merge branch 'bevyengine:main' into transform_examples
l4desu-mizu Mar 15, 2022
83cd319
rename 3d rotation example
l4desu-mizu Mar 15, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,27 @@ path = "examples/shader/shader_defs.rs"
name = "bevymark"
path = "examples/tools/bevymark.rs"

# Transforms
[[example]]
name = "global_vs_local_translation"
path = "examples/transforms/global_vs_local_translation.rs"

[[example]]
name = "rotation"
path = "examples/transforms/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)
[[example]]
name = "button"
Expand Down
11 changes: 11 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ git checkout v0.4.0
- [Shaders](#shaders)
- [Tests](#tests)
- [Tools](#tools)
- [Transforms](#transforms)
- [UI (User Interface)](#ui-user-interface)
- [Window](#window)
- [Platform-Specific Examples](#platform-specific-examples)
Expand Down Expand Up @@ -231,6 +232,16 @@ Example | File | Description
--- | --- | ---
`bevymark` | [`tools/bevymark.rs`](./tools/bevymark.rs) | A heavy 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
`rotation` | [`transforms/rotation.rs`](./transforms/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)

Example | File | Description
Expand Down
136 changes: 136 additions & 0 deletions examples/transforms/global_vs_local_translation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
use bevy::prelude::*;

// Define structs to store state information.
struct Moving;
struct SpawnLocation(Vec3);

// Define a marker for entities that should stop at a distance in respect to their global transform.
struct GlobalStop;
// Define a marker for entities that should stop at a distance in respect to their local transform.
struct LocalStop;

// Define the maximum distance an entity should be able to move away from its spawn.
const MAX_DISTANCE: f32 = 5.0;

fn main() {
App::build()
.add_plugins(DefaultPlugins)
.add_startup_system(setup.system())
.add_system(move_cubes.system())
.add_system(stop_too_far_global_distance.system())
.add_system(stop_too_far_local_distance.system())
.run();
}

// Startup system to setup the scene and spawn all relevant entities.
fn setup(
l4desu-mizu marked this conversation as resolved.
Show resolved Hide resolved
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 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 entities parent is different to the
// global transform within the visible scene.
// This example focuses on translation only to clearly demonstrate the differences.
let main_entity_spawn: Transform = Transform::from_translation(Vec3::ZERO);

// 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()),
transform: main_entity_spawn,
..Default::default()
})
.insert(GlobalStop)
.insert(Moving)
.insert(SpawnLocation(main_entity_spawn.translation));

// Define a spawn point for child entities just above the original entity.
let children_spawn = Transform::from_translation(Vec3::Y);
let global_behaviour_child_mesh = PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 0.5 })),
material: materials.add(Color::RED.into()),
transform: children_spawn,
..Default::default()
};
let local_behaviour_child_mesh = PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 0.5 })),
material: materials.add(Color::GREEN.into()),
transform: children_spawn,
..Default::default()
};

// Spawn two entities as children above the original main entity.
// The red entity spawned here will change its behaviour depending on its global transform
// where the green one will change its behaviour depending on its local transform.
main_entity.with_children(|child_builder| {
// also see parenting example
child_builder
.spawn_bundle(global_behaviour_child_mesh)
.insert(GlobalStop)
.insert(Moving)
.insert(SpawnLocation(children_spawn.translation));
child_builder
.spawn_bundle(local_behaviour_child_mesh)
.insert(LocalStop)
.insert(Moving)
.insert(SpawnLocation(children_spawn.translation));
});

// 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(main_entity_spawn.translation, 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 entities that have an EntityState (all cubes).
// The movement here is restricted to one direction (right in the sense of the cameras view).
fn move_cubes(mut cubes: Query<&mut Transform, With<Moving>>, timer: Res<Time>) {
// Iterate over every entity with an EntityState that is not stopped.
for mut transform in cubes.iter_mut() {
let dir = Vec3::X;
transform.translation += dir * timer.delta_seconds();
}
}

// This system will check all entities with an EntityState and the GlobalStop marker
// and check if their distance to their original spawn in respect to their global transform
// is greater than MAX_DISTANCE. If so, we mark that entity as stopped via its EntityState.
fn stop_too_far_global_distance(
mut commands: Commands,
mut cubes: Query<(Entity, &GlobalTransform, &SpawnLocation), With<GlobalStop>>,
) {
for (entity, global_transform, spawn) in cubes.iter_mut() {
if (global_transform.translation - spawn.0).length() >= MAX_DISTANCE {
commands.entity(entity).remove::<Moving>();
}
}
}

// This system will do essentially the same thing as in stop_too_far_global_distance but
// using the local transform. Thus we'll check the traveling distance with respect to the
// entities parent (in the case of the green cube this would be the yellow cube).
// Since the parent (yellow) cube is also moving the green cube with LocalStop will travel further
// than its red sibling that uses the behaviour tied to GlobalStop.
fn stop_too_far_local_distance(
mut commands: Commands,
mut cubes: Query<(Entity, &Transform, &SpawnLocation), With<LocalStop>>,
) {
for (entity, transform, spawn) in cubes.iter_mut() {
if (transform.translation - spawn.0).length() >= MAX_DISTANCE {
commands.entity(entity).remove::<Moving>();
}
}
}
56 changes: 56 additions & 0 deletions examples/transforms/rotation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use bevy::prelude::*;

use std::f32::consts::PI;

const FULL_TURN: f32 = 2.0 * PI;
l4desu-mizu marked this conversation as resolved.
Show resolved Hide resolved

// Define a component to designate a rotation speed to an entity.
struct Rotatable {
speed: f32,
}

fn main() {
App::build()
.add_plugins(DefaultPlugins)
.add_startup_system(setup.system())
.add_system(rotate_cube.system())
.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);
}
}
94 changes: 94 additions & 0 deletions examples/transforms/scale.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use bevy::math::Vec3Swizzles;
use bevy::prelude::*;

// Define a component to keep information for the scaled object.
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::build()
.add_plugins(DefaultPlugins)
.add_startup_system(setup.system())
.add_system(change_scale_direction.system())
.add_system(scale_cube.system())
.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)),
l4desu-mizu marked this conversation as resolved.
Show resolved Hide resolved
..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();
}
}
Loading