I don't understand how rotation works in Bevy. I just want to rotate a sprite to follow my cursor position.
What is the piece of code to make it work?
I tried that, but it's not working: Bevy rotation in 2D
use bevy::math::{Quat, Vec2};
let pos = transform.translation.truncate(); // Player position
let target = event.position; // Cursor position
let angle = (target - pos).angle_between(pos); // NaN
transform.rotation = Quat::from_rotation_z(angle);
The above makes an angle = NaN so it is not working.
let pos = transform.translation.truncate(); // Player position
let target = cursor_position; // Cursor position
let direction = target - pos;
let angle = direction.y.atan2(direction.x); // Calculate angle between direction and x-axis
transform.rotation = Quat::from_rotation_z(angle);
Here is the result:
Here is the repository if you want to try: SpaceGameRust
What is needed is to rotate the front of the player towards the cursor. In order to do that the vector that describes the orientation of the front of the player is required, also.
angle = (target - pos).angle_between(pos)
doesn't help because pos
doesn't describe the orientation of the player. pos
is only the position of the player.
Finding the angle of the vector target-pos
with respect to the x-axis is useful but not enough. From that angle, the angle that the orientation of the player makes with respect to the x-axis, should be subtracted. This will give the required angle of rotation. The player should be rotated based on the resulting angle, about the z-axis that passes through the player.
To get a working solution, the following need to be done:
Make sure the coordinates of the target and the player are in the same reference frame.
atan2
returns a value in (-Pi, Pi]. It has to be transformed into a value in [0, 2*Pi). Make sure to do this when getting the angle to the target with respect to the x-axis.
Have a separate variable that keeps track of the object's orientation with respect to the x-axis. Subtract this angle from the angle of the target with respect to the x-axis.
See below for observations about whether the orientation of the player has to be updated each time the player is rotated.
use bevy::math::{Quat, Vec2};
use std::f32::consts::PI;
// Initialize player orientation at the very beginning.
// It is the angle with respect to X-axis.
// IMPORTANT NOTE: Check what value it is (0 degrees or 90 degrees etc)
// and set it here.
let player_orient = PI/2.0;
...
let pos = transform.translation.truncate(); // player position
let target = Vec2::new(cursor_position.x - window.width() / 2., cursor_position.y - window.height() / 2.); // cursor position
let direction = target - pos;
// obtain angle to target with respect to x-axis.
let mut angle_to_target = direction.y.atan2(direction.x);
// represent angle_to_target in [0, 2*PI)
if angle_to_target < 0. {
angle_to_target += 2.0*PI;
}
let angle_to_rotate = angle_to_target - player_orient;
transform.rotation = Quat::from_rotation_z(angle_to_rotate);
// Update the player's orientation.
// Always, represent it in the range [0, 2*PI).
player_orient = (player_orient + angle_to_rotate) % (2.0*PI);
The current system works only if player_orient
is not updated, i.e., player_orient = (player_orient + angle_to_rotate) % (2.0*PI);
is commented out. At the same time, angle_to_rotate
has to be set as angle_to_target - player_orient
. Otherwise, a 90 degree offset is observed. Probably, in each frame, before displaying the player, the system assumes that the player is at 90 degrees with respect to the x-axis and then the angle to rotate is computed and the player is rotated.