旋转精灵从光标位置

huangapple go评论63阅读模式
英文:

Rotate a sprite from cursor position

问题

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:

use bevy::math::{Quat, Vec2};

let pos = transform.translation.truncate(); // 玩家位置
let target = event.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(); // 玩家位置
let target = cursor_position; // 鼠标位置
            
let direction = target - pos;
let angle = direction.y.atan2(direction.x); // 计算方向与x轴之间的角度
transform.rotation = Quat::from_rotation_z(angle);

Here is the result:

旋转精灵从光标位置

Here is the repository if you want to try: SpaceGameRust

英文:

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:
https://stackoverflow.com/questions/65370874/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

答案1

得分: 1

你已经接近成功了!主要问题在于你计算的是位置向量和方向向量之间的角度,但你应该计算方向向量和x轴之间的角度:

use bevy::math::{Quat, Vec2, Vec3};

let pos = transform.translation.truncate(); // 玩家位置
let target = Vec2::new(event.position.x, event.position.y); // 光标位置

let direction = target - pos;
let angle = direction.y.atan2(direction.x); // 计算方向与x轴之间的角度
transform.rotation = Quat.from_rotation_z(angle);

atan2 函数用于获取方向向量与x轴之间的角度,这是正确的旋转角度。

英文:

You're almost there! The main issue is that you're calculating the angle between the position vector and the direction vector, but you should calculate the angle between the direction vector and the x-axis:

use bevy::math::{Quat, Vec2, Vec3};

let pos = transform.translation.truncate(); // player position
let target = Vec2::new(event.position.x, event.position.y); // 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);

The atan2 function is used to get the angle between the direction vector and the x-axis, which is the correct angle for rotation

答案2

得分: 1

以下是您要翻译的内容:

需要的是将玩家的正面朝向光标旋转。为了实现这一点,需要一个描述玩家正面方向的向量。

angle = (target - pos).angle_between(pos) 不适用,因为 pos 不描述玩家的朝向。pos 只是玩家的位置。

找到向量 target-pos 相对于 x 轴的角度是有用的,但不足够。从该角度中减去玩家相对于 x 轴的朝向所成的角度,将得到所需的旋转角度。应该根据结果角度围绕通过玩家的 z 轴旋转玩家。

为了获得一个可行的解决方案,需要执行以下操作:

确保目标和玩家的坐标在相同的参考框架中。

atan2 返回一个值在 (-Pi, Pi] 范围内。在获得相对于 x 轴的目标角度时,务必进行转换,使其在 [0, 2*Pi) 范围内。

拥有一个单独的变量来跟踪对象相对于 x 轴的方向。从目标相对于 x 轴的角度中减去这个角度。

关于玩家的朝向是否必须在每次旋转玩家时更新,下面有关于观察结果的信息。

use bevy::math::{Quat, Vec2};
use std::f32::consts::PI;

// 在最开始初始化玩家的朝向。
// 这是相对于 X 轴的角度。
// 重要提示:检查它是什么值(0 度还是 90 度等等)
// 并在此处设置它。
let player_orient = PI/2.0;

...

let pos = transform.translation.truncate(); // 玩家位置
let target = Vec2::new(cursor_position.x - window.width() / 2., cursor_position.y - window.height() / 2.);                // 光标位置
let direction = target - pos; 

// 获取相对于 x 轴的目标角度。 
let mut angle_to_target = direction.y.atan2(direction.x);
// 表示 angle_to_target 在 [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);

// 更新玩家的朝向。
// 始终在 [0, 2*PI) 范围内表示它。
player_orient = (player_orient + angle_to_rotate) % (2.0*PI);

当前系统仅在不更新 player_orient 时才能正常工作,即 player_orient = (player_orient + angle_to_rotate) % (2.0*PI); 被注释掉。同时,angle_to_rotate 必须设置为 angle_to_target - player_orient。否则,会观察到90度的偏移。可能在每帧之前,系统会假定玩家相对于 x 轴为90度,然后计算旋转角度并旋转玩家。

英文:

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 &lt; 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&#39;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.

huangapple
  • 本文由 发表于 2023年5月30日 05:50:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76360493.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定