我正在制作一个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;
}
对代码进行很少的更改,它似乎可以工作:
无需转换为度数即可完成此操作。
步骤是:
theta
计算源向量和目标向量之间的角度 Math.atan2
。theta
标准化为 0..Tau.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;
这可能可以进一步简化;欢迎发表评论。