Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/transforms/transform.rs
6596 views
1
//! Shows multiple transformations of objects.
2
3
use std::f32::consts::PI;
4
5
use bevy::{color::palettes::basic::YELLOW, prelude::*};
6
7
// A struct for additional data of for a moving cube.
8
#[derive(Component)]
9
struct CubeState {
10
start_pos: Vec3,
11
move_speed: f32,
12
turn_speed: f32,
13
}
14
15
// A struct adding information to a scalable entity,
16
// that will be stationary at the center of the scene.
17
#[derive(Component)]
18
struct Center {
19
max_size: f32,
20
min_size: f32,
21
scale_factor: f32,
22
}
23
24
fn main() {
25
App::new()
26
.add_plugins(DefaultPlugins)
27
.add_systems(Startup, setup)
28
.add_systems(
29
Update,
30
(
31
move_cube,
32
rotate_cube,
33
scale_down_sphere_proportional_to_cube_travel_distance,
34
)
35
.chain(),
36
)
37
.run();
38
}
39
40
// Startup system to setup the scene and spawn all relevant entities.
41
fn setup(
42
mut commands: Commands,
43
mut meshes: ResMut<Assets<Mesh>>,
44
mut materials: ResMut<Assets<StandardMaterial>>,
45
) {
46
// Add an object (sphere) for visualizing scaling.
47
commands.spawn((
48
Mesh3d(meshes.add(Sphere::new(3.0).mesh().ico(32).unwrap())),
49
MeshMaterial3d(materials.add(Color::from(YELLOW))),
50
Transform::from_translation(Vec3::ZERO),
51
Center {
52
max_size: 1.0,
53
min_size: 0.1,
54
scale_factor: 0.05,
55
},
56
));
57
58
// Add the cube to visualize rotation and translation.
59
// This cube will circle around the center_sphere
60
// by changing its rotation each frame and moving forward.
61
// Define a start transform for an orbiting cube, that's away from our central object (sphere)
62
// and rotate it so it will be able to move around the sphere and not towards it.
63
let cube_spawn =
64
Transform::from_translation(Vec3::Z * -10.0).with_rotation(Quat::from_rotation_y(PI / 2.));
65
commands.spawn((
66
Mesh3d(meshes.add(Cuboid::default())),
67
MeshMaterial3d(materials.add(Color::WHITE)),
68
cube_spawn,
69
CubeState {
70
start_pos: cube_spawn.translation,
71
move_speed: 2.0,
72
turn_speed: 0.2,
73
},
74
));
75
76
// Spawn a camera looking at the entities to show what's happening in this example.
77
commands.spawn((
78
Camera3d::default(),
79
Transform::from_xyz(0.0, 10.0, 20.0).looking_at(Vec3::ZERO, Vec3::Y),
80
));
81
82
// Add a light source for better 3d visibility.
83
commands.spawn((
84
DirectionalLight::default(),
85
Transform::from_xyz(3.0, 3.0, 3.0).looking_at(Vec3::ZERO, Vec3::Y),
86
));
87
}
88
89
// This system will move the cube forward.
90
fn move_cube(mut cubes: Query<(&mut Transform, &mut CubeState)>, timer: Res<Time>) {
91
for (mut transform, cube) in &mut cubes {
92
// Move the cube forward smoothly at a given move_speed.
93
let forward = transform.forward();
94
transform.translation += forward * cube.move_speed * timer.delta_secs();
95
}
96
}
97
98
// This system will rotate the cube slightly towards the center_sphere.
99
// Due to the forward movement the resulting movement
100
// will be a circular motion around the center_sphere.
101
fn rotate_cube(
102
mut cubes: Query<(&mut Transform, &mut CubeState), Without<Center>>,
103
center_spheres: Query<&Transform, With<Center>>,
104
timer: Res<Time>,
105
) {
106
// Calculate the point to circle around. (The position of the center_sphere)
107
let mut center: Vec3 = Vec3::ZERO;
108
for sphere in &center_spheres {
109
center += sphere.translation;
110
}
111
// Update the rotation of the cube(s).
112
for (mut transform, cube) in &mut cubes {
113
// Calculate the rotation of the cube if it would be looking at the sphere in the center.
114
let look_at_sphere = transform.looking_at(center, *transform.local_y());
115
// Interpolate between the current rotation and the fully turned rotation
116
// when looking at the sphere, with a given turn speed to get a smooth motion.
117
// With higher speed the curvature of the orbit would be smaller.
118
let incremental_turn_weight = cube.turn_speed * timer.delta_secs();
119
let old_rotation = transform.rotation;
120
transform.rotation = old_rotation.lerp(look_at_sphere.rotation, incremental_turn_weight);
121
}
122
}
123
124
// This system will scale down the sphere in the center of the scene
125
// according to the traveling distance of the orbiting cube(s) from their start position(s).
126
fn scale_down_sphere_proportional_to_cube_travel_distance(
127
cubes: Query<(&Transform, &CubeState), Without<Center>>,
128
mut centers: Query<(&mut Transform, &Center)>,
129
) {
130
// First we need to calculate the length of between
131
// the current position of the orbiting cube and the spawn position.
132
let mut distances = 0.0;
133
for (cube_transform, cube_state) in &cubes {
134
distances += (cube_state.start_pos - cube_transform.translation).length();
135
}
136
// Now we use the calculated value to scale the sphere in the center accordingly.
137
for (mut transform, center) in &mut centers {
138
// Calculate the new size from the calculated distances and the centers scale_factor.
139
// Since we want to have the sphere at its max_size at the cubes spawn location we start by
140
// using the max_size as start value and subtract the distances scaled by a scaling factor.
141
let mut new_size: f32 = center.max_size - center.scale_factor * distances;
142
143
// The new size should also not be smaller than the centers min_size.
144
// Therefore the max value out of (new_size, center.min_size) is used.
145
new_size = new_size.max(center.min_size);
146
147
// Now scale the sphere uniformly in all directions using new_size.
148
// Here Vec3:splat is used to create a vector with new_size in x, y and z direction.
149
transform.scale = Vec3::splat(new_size);
150
}
151
}
152
153