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