逐渐旋转物体以面向一点?

问题描述 投票:0回答:2

我正在制作一个javascript游戏,我希望敌方船只能够向指定点旋转。然后可以根据它们的角度计算它们的运动。仅当船舶位于其目标的下方和右侧时,以下旋转代码才有效。如果船在左边,它会旋转到约 0 度并在那里抖动。在右上角,它不断逆时针旋转。 我到底做错了什么?有更好的方法建议吗?

obj.angle %= 360;
// Calculate angle to target point
var targetAngle = Math.atan2(obj.mode.dest.y - obj.y, obj.mode.dest.x - obj.x) * (180 / Math.PI) + 90;
// Get the difference between the current angle and the target angle
var netAngle = Math.abs(obj.angle - targetAngle) % 360;
// Turn in the closest direction to the target
netAngle > 180 ? obj.angle += obj.shipType.turnSpeed : obj.angle -= obj.shipType.turnSpeed;
if(obj.angle < 0) obj.angle += 360;
if(obj.angle > 360) obj.angle -= 360;

我的问题与这个问题非常相似,它更好地解释了它,但不幸的是是在C#中。

编辑:这是工作代码,对于任何可能觉得有用的人:

obj.angle %= 360;
var targetAngle = Math.atan2(obj.mode.dest.y - obj.y, obj.mode.dest.x - obj.x) * (180 / Math.PI) + 90;
targetAngle = (targetAngle + 360) % 360;
if(obj.angle != targetAngle)
{
    var netAngle = (obj.angle - targetAngle + 360) % 360;
    var delta = Math.min(Math.abs(netAngle - 360), netAngle, obj.shipType.turnSpeed);
    var sign  = (netAngle - 180) >= 0 ? 1 : -1;
    obj.angle += sign * delta + 360;
    obj.angle %= 360;
}
javascript jquery canvas rotation
2个回答
3
投票

对代码进行很少的更改,它似乎可以工作:

http://jsfiddle.net/57hAk/11/


1
投票

无需转换为度数即可完成此操作。

步骤是:

  1. 使用
    theta
    计算源向量和目标向量之间的角度
    Math.atan2
  2. theta
    标准化为 0..Tau.
  3. 取源角度和
    theta
    之间的差值,在减法过程中注意 -PI 以下的环绕。

这会产生 -Pi..+Pi 之间的

diff
值。如果为负,则顺时针旋转,否则逆时针旋转。

该公式仅在玩家角度限制在 -Pi..+Pi 范围内时才有效。

这是一个工作示例。

const {PI} = Math;
const TAU = 2 * PI;
const canvas = document.querySelector("canvas");
canvas.width = canvas.height = 240;
const ctx = canvas.getContext("2d");

const player = {
  x: canvas.width / 2,
  y: canvas.height / 2,
  angle: 0,
  radius: 20,
};

const mouse = {x: canvas.width / 2, y: canvas.height / 2};
canvas.addEventListener("mousemove", e => {
  mouse.x = e.offsetX;
  mouse.y = e.offsetY;
});

(function rerender() {
  requestAnimationFrame(rerender);

  let theta = Math.atan2(mouse.y - player.y, mouse.x - player.x);
  theta = theta < 0 ? theta + TAU : theta;
  let diff = player.angle - theta;
  diff = diff < -PI ? diff + TAU : diff;

  if (Math.abs(diff) > 0.02) {
    player.angle -= 0.04 * Math.sign(diff);

    if (player.angle > PI) {
      player.angle -= TAU;
    }
    else if (player.angle < -PI) {
      player.angle += TAU;
    }
  }

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // draw player
  ctx.save();
  ctx.strokeStyle = "black";
  ctx.lineWidth = 8;
  ctx.translate(player.x, player.y);
  ctx.rotate(player.angle);
  ctx.beginPath();
  ctx.arc(0, 0, player.radius, 0, TAU);
  ctx.stroke();
  ctx.beginPath();
  ctx.moveTo(0, 0);
  ctx.lineTo(player.radius * 2, 0);
  ctx.stroke();
  ctx.restore();

  // draw crosshair
  ctx.strokeStyle = "red";
  ctx.lineWidth = 4;
  ctx.beginPath();
  ctx.moveTo(mouse.x - 10, mouse.y);
  ctx.lineTo(mouse.x + 10, mouse.y);
  ctx.stroke();
  ctx.beginPath();
  ctx.moveTo(mouse.x, mouse.y - 10);
  ctx.lineTo(mouse.x, mouse.y + 10);
  ctx.stroke();
})();
canvas {
  border: 2px solid black;
}
<canvas></canvas>

另一种选择:

const theta = Math.atan2(mouse.y - player.y, mouse.x - player.x);
let diff = player.angle - theta;
diff = diff > PI ? diff - TAU : diff;
diff = diff < -PI ? diff + TAU : diff;

这可能可以进一步简化;欢迎发表评论。

相关:旋转一条线看鼠标用线性插值会导致跳跃

© www.soinside.com 2019 - 2024. All rights reserved.