docs/bevy/examples/2d/rotate_to_cursor.rs 2.2 K · 59 lines · raw · history
| 1 | //! Demonstrates rotating sprites to face the cursor. |
| 2 | |
| 3 | use bevy::prelude::*; |
| 4 | use std::f32::consts::FRAC_PI_2; |
| 5 | |
| 6 | fn main() { |
| 7 | App::new() |
| 8 | .add_plugins(DefaultPlugins) |
| 9 | .add_systems(Startup, setup) |
| 10 | .add_systems(FixedUpdate, player_movement_system) |
| 11 | .run(); |
| 12 | } |
| 13 | |
| 14 | /// Player component |
| 15 | #[derive(Component)] |
| 16 | struct Player; |
| 17 | |
| 18 | /// Add the game's entities to our world and create an orthographic camera for 2D rendering. |
| 19 | /// |
| 20 | /// The Bevy coordinate system is the same for 2D and 3D, in terms of 2D this means that: |
| 21 | /// |
| 22 | /// * `X` axis goes from left to right (`+X` points right) |
| 23 | /// * `Y` axis goes from bottom to top (`+Y` point up) |
| 24 | /// * `Z` axis goes from far to near (`+Z` points towards you, out of the screen) |
| 25 | /// |
| 26 | /// The world origin in this case is at the center of the screen, but the camera could |
| 27 | /// move in which case the world origin would not be the center of the screen |
| 28 | fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { |
| 29 | let ship_handle = asset_server.load("textures/simplespace/ship_C.png"); |
| 30 | |
| 31 | commands.spawn(Camera2d); |
| 32 | |
| 33 | // Player controlled ship |
| 34 | commands.spawn((Sprite::from_image(ship_handle), Player)); |
| 35 | } |
| 36 | |
| 37 | /// Demonstrates applying rotation and movement based on keyboard input. |
| 38 | fn player_movement_system( |
| 39 | mut player: Single<&mut Transform, With<Player>>, |
| 40 | camera_query: Single<(&Camera, &GlobalTransform)>, |
| 41 | window: Single<&Window>, |
| 42 | ) { |
| 43 | let (camera, camera_transform) = *camera_query; |
| 44 | |
| 45 | if let Some(cursor_position) = window.cursor_position() |
| 46 | // Calculate a world position based on the cursor's position. |
| 47 | && let Ok(cursor_world_pos) = camera.viewport_to_world_2d(camera_transform, cursor_position) |
| 48 | { |
| 49 | // The angle an entity needs to rotate to face a point is defined |
| 50 | // by the vector between the two points (Vec2 - Vec2), which we can then |
| 51 | // turn into radians using to_angle. |
| 52 | // |
| 53 | // FRAC_PI_2 is because our sprite's ship is facing "up" so we rotate it an additional 90 degrees |
| 54 | // so that it faces the cursor. |
| 55 | player.rotation = Quat::from_rotation_z( |
| 56 | (cursor_world_pos - player.translation.xy()).to_angle() - FRAC_PI_2, |
| 57 | ); |
| 58 | } |
| 59 | } |