平滑 'turning' 脚本
Smooth 'turning' script
我正在使用 Javascript 制作 HTML5 Canvas 游戏。
我想让一个物体平滑地转向某个方向。
我将方向存储为变量,并使用弧度。代码是这样工作的:
window.setInterval(loop,25);
var dir = 0;
var targetDir = Math.PI/2;
function loop() {
dir += (targetDir - dir) / 5;
document.getElementById('text').innerHTML = dir; //To display the direction
}
<p id='text'></p>
它大部分时间都有效,但如果方向和目标方向在相反的 left/right 侧,计算机将假定到达目标的最快方法是一路绕行,像这样:
(Image)
有人知道我可以用来使其正常工作的算法吗?
希望有人能给出一个优雅的解决方案,目前还没有,所以这就是我的做法。
我一直觉得这个问题的解决方法很不优雅,就是说,我不知道有没有更好的方法,也没有努力去寻找。下面是两个函数,它们将 return 从函数 Math.atan2(yDif, xDif)
导出的两个角度之间的最短方向,其中 return 是一个范围在 -Math.PI
到 [=14= 之间的角度]
获取最短方向。
// returns true if shortest direction is clockwise else false
function isShortestDirClockwise(ang1, ang2){
if (ang1 < 0) {
if ( (ang2 < 0 && ang1 > ang2) || (ang2 >= 0 && ang1 + Math.PI < ang2) ) {
return false;
}
} else {
if ( (ang2 > 0 && ang1 > ang2) || (ang2 <= 0 && ang1 - Math.PI < ang2) ) {
return false;
}
}
return true;
}
获取最短角度
// returns the shortest angle neg angles are counterClockwise positive are clockwise
function getShortestAngle(ang1, ang2){
var cw = true; // clockwise
var ang;
if (ang1 < 0) {
if( (ang2 < 0 && ang1 > ang2) || (ang2 >= 0 && ang1 + Math.PI < ang2) ) {
cw = false;
}
} else {
if ( (ang2 > 0 && ang1 > ang2) || (ang2 <= 0 && ang1 - Math.PI < ang2) ) {
cw = false;
}
}
if (cw) {
var ang = ang2 - ang1;
if (ang < 0) {
ang = ang2 + Math.PI * 2 - ang1;
}
return ang;
}
var ang = ang1 - ang2;
if (ang < 0) {
ang = ang1 + Math.PI * 2 - ang2;
}
return -ang;
}
因为我讨厌使用这些函数,所以我更喜欢下面稍微复杂但更优雅的解决方案。这会根据一组 3 个点找到最短的角度。中心点,以及我希望找到夹角的两个点,它总是 returns 任何两条线之间的最短角度。
// Warning may return NAN if there is no solution (ie one or both points (p1,p2) are at center)
// Also uses Math.hypot check browser compatibility if you wish to use this function or use Math.sqrt(v1.x * v1.x + v1.y * v1.y) instead
function getAngleBetween(center, p1, p2){
var d;
var ang;
// get vectors from center to both points
var v1 = { x : p1.x - center.x, y : p1.y - center.y};
var v2 = { x : p2.x - center.x, y : p2.y - center.y};
// normalise both vectors
d = Math.hypot(v1.x, v1.y);
v1.x /= d;
v1.y /= d;
d = Math.hypot(v2.x, v2.y);
v2.x /= d;
v2.y /= d;
// cross product gets the angle in range -Math.PI / 2 to Math.PI / 2
ang = Math.asin(v1.x * v2.y - v1.y * v2.x);
// use the cross product of the line perpendicular to the first to find the quadrant
if(-v1.y * v2.y - v1.x * v2.x > 0){
if(ang < 0){
ang = -Math.PI - ang;
}else{
ang = Math.PI - ang;
}
}
return ang;
}
我正在使用 Javascript 制作 HTML5 Canvas 游戏。
我想让一个物体平滑地转向某个方向。
我将方向存储为变量,并使用弧度。代码是这样工作的:
window.setInterval(loop,25);
var dir = 0;
var targetDir = Math.PI/2;
function loop() {
dir += (targetDir - dir) / 5;
document.getElementById('text').innerHTML = dir; //To display the direction
}
<p id='text'></p>
它大部分时间都有效,但如果方向和目标方向在相反的 left/right 侧,计算机将假定到达目标的最快方法是一路绕行,像这样: (Image)
有人知道我可以用来使其正常工作的算法吗?
希望有人能给出一个优雅的解决方案,目前还没有,所以这就是我的做法。
我一直觉得这个问题的解决方法很不优雅,就是说,我不知道有没有更好的方法,也没有努力去寻找。下面是两个函数,它们将 return 从函数 Math.atan2(yDif, xDif)
导出的两个角度之间的最短方向,其中 return 是一个范围在 -Math.PI
到 [=14= 之间的角度]
获取最短方向。
// returns true if shortest direction is clockwise else false
function isShortestDirClockwise(ang1, ang2){
if (ang1 < 0) {
if ( (ang2 < 0 && ang1 > ang2) || (ang2 >= 0 && ang1 + Math.PI < ang2) ) {
return false;
}
} else {
if ( (ang2 > 0 && ang1 > ang2) || (ang2 <= 0 && ang1 - Math.PI < ang2) ) {
return false;
}
}
return true;
}
获取最短角度
// returns the shortest angle neg angles are counterClockwise positive are clockwise
function getShortestAngle(ang1, ang2){
var cw = true; // clockwise
var ang;
if (ang1 < 0) {
if( (ang2 < 0 && ang1 > ang2) || (ang2 >= 0 && ang1 + Math.PI < ang2) ) {
cw = false;
}
} else {
if ( (ang2 > 0 && ang1 > ang2) || (ang2 <= 0 && ang1 - Math.PI < ang2) ) {
cw = false;
}
}
if (cw) {
var ang = ang2 - ang1;
if (ang < 0) {
ang = ang2 + Math.PI * 2 - ang1;
}
return ang;
}
var ang = ang1 - ang2;
if (ang < 0) {
ang = ang1 + Math.PI * 2 - ang2;
}
return -ang;
}
因为我讨厌使用这些函数,所以我更喜欢下面稍微复杂但更优雅的解决方案。这会根据一组 3 个点找到最短的角度。中心点,以及我希望找到夹角的两个点,它总是 returns 任何两条线之间的最短角度。
// Warning may return NAN if there is no solution (ie one or both points (p1,p2) are at center)
// Also uses Math.hypot check browser compatibility if you wish to use this function or use Math.sqrt(v1.x * v1.x + v1.y * v1.y) instead
function getAngleBetween(center, p1, p2){
var d;
var ang;
// get vectors from center to both points
var v1 = { x : p1.x - center.x, y : p1.y - center.y};
var v2 = { x : p2.x - center.x, y : p2.y - center.y};
// normalise both vectors
d = Math.hypot(v1.x, v1.y);
v1.x /= d;
v1.y /= d;
d = Math.hypot(v2.x, v2.y);
v2.x /= d;
v2.y /= d;
// cross product gets the angle in range -Math.PI / 2 to Math.PI / 2
ang = Math.asin(v1.x * v2.y - v1.y * v2.x);
// use the cross product of the line perpendicular to the first to find the quadrant
if(-v1.y * v2.y - v1.x * v2.x > 0){
if(ang < 0){
ang = -Math.PI - ang;
}else{
ang = Math.PI - ang;
}
}
return ang;
}