计算角度差2D游戏的JS函数
Posted
技术标签:
【中文标题】计算角度差2D游戏的JS函数【英文标题】:JS function to calculate angle difference 2D gaming 【发布时间】:2017-07-11 17:28:56 【问题描述】:我编写了一些代码只是为了弄清楚如何计算 2D 游戏 AI 的角度差。我添加了一张图片(示例问题),我正在编写的函数接受角度 A 和 B 的输入,并且应该返回一个方向!返回值应该在 -pi 到 +pi 之间,或者在 -180 到 180 度之间。
顺便说一句,代码主要是:|但在某些时候它失败了。代码可以完全复制到 .html 文件中并运行以进行测试。
example problem pic
代码:
<!DOCTYPE html>
<html style="width:100%;">
<head>
<meta charset="utf-8">
<title>Angle</title>
<style type="text/css">
body
height: 600px;
background-color: #EEEEEE;
#main
text-align: center;
/*border: 1px solid #000000;*/
</style>
</head>
<body>
<center>
<h3>Canvas</h3>
<canvas id="main" >
Your browser does not support the HTML5 canvas tag.
</canvas>
</center>
<script type="text/javascript">
window.onload=function()
"use strict";
var canvas = document.getElementById('main');
var ctx = canvas.getContext('2d');
var font_size = 18;
ctx.font = font_size + 'px Courier New'; // Courier New / Lucida Console
var clearCanvas = function(c)
if (c)
c.updateFill();
ctx.fillRect(0, 0, canvas.width, canvas.height);
else
ctx.clearRect(0, 0, canvas.width, canvas.height);
;
// math extras
Math.M_PI_DB_180 = 0.01745329251994;
Math.M_180_DB_PI = 57.2957795130823;
Math.M_2PI = 6.28318530717959;
Math.M_PI = 3.14159265358979;
Math.M_PI_DB_2 = 1.57079632679489;
Math.DEG2RAD = function(d) return (d * Math.M_PI_DB_180); ;
Math.RAD2DEG = function(r) return (r * Math.M_180_DB_PI); ;
Math._fmod_precesion = 1000000;
Math.fmod = function(a, b)
return (Math.round(a * Math._fmod_precesion) % Math.round(b * Math._fmod_precesion)) / Math._fmod_precesion;
;
Math.roundp = function(value, precision)
var p = Math.pow(10, precision);
return Math.round(value * p) / p;
;
Math.wrapDegree = function(value)
if (value > 360) value = Math.fmod(value, 360);
if (value < -360) value = Math.fmod(value, 360);
if (value < 0) value += 360;
return value;
;
Math.wrapRadian = function(value)
if (value > Math.M_2PI) value = Math.fmod(value, Math.M_2PI);
if (value < -Math.M_2PI) value = Math.fmod(value, Math.M_2PI);
if (value < 0) value += Math.M_2PI;
return value;
;
// gives -179.9 to 179.9
Math.angleDifference = function(a1, a2)
var diff = a1 - a2;
if (diff > Math.M_PI) diff = -(Math.M_2PI - diff);
if (diff < -Math.M_PI) diff = (Math.M_2PI + diff);
if (diff > -0.01 && diff < 0.01) diff = 0; // fix
return diff;
;
Math.angleWithinFOV = function(angle, fov)
var half = fov / 2;
return angle < half && angle > -half;
;
// vector 2D class
var vec2 = function(x, y)
this.x = function() return this._x; ;
this.y = function() return this._y; ;
this.set = function(x, y)
this._x = typeof x == 'number' ? x : 0;
this._y = typeof y == 'number' ? y : 0;
;
this.set(x, y);
// extras
this.add = function(v) this._x += v.x(); this._y += v.y(); ;
this.sub = function(v) this._x -= v.x(); this._y -= v.y(); ;
this.mul = function(v) this._x *= v.x(); this._y *= v.y(); ;
this.lengthMath = function()
return Math.sqrt( Math.pow(this._x, 2) + Math.pow(this._y, 2) );
;
this.normalizedCopy = function()
var len = this.lengthMath();
return len != 0 ? new vec2( this._x / len, this._y / len ) : null;
;
this.clone = function() return new vec2(this._x, this._y); ;
this.next = function(angle, distance)
return new vec2( this._x + (distance * Math.sin(angle)), this._y + (distance * Math.cos(angle)) );
;
this.slopeAngle = function(v)
return Math.wrapRadian( Math.atan2( this._x - v.x(), this._y - v.y() ) + Math.M_PI );
;
;
// color class (updateFill, updateStroke) (colorFill, colorStroke)
var ccolor = function(c)
this._color = c||'#000000';
this.updateFill = function(draw)
ctx.fillStyle = this._color;
if(draw)ctx.fill();
;
this.updateStroke = function(draw)
ctx.strokeStyle = this._color;
if(draw)ctx.stroke();
;
;
// draw fuunctions
var _text = function(v, t, c)
c.updateFill();
ctx.fillText(t, v.x(), v.y() + font_size - (font_size * 0.4));
;
var _line = function(v1, v2, c)
ctx.moveTo(v1.x(), v1.y());
ctx.lineTo(v2.x(), v2.y());
c.updateStroke(true);
;
var _circle = function(v, radius, c, shouldFill)
ctx.beginPath();
ctx.arc(v.x(), v.y(), radius, 0, Math.M_2PI);
if (shouldFill)
c.updateFill(true);
else
c.updateStroke(true);
;
var _viewcone = function(v, radius, c, r1, r2)
ctx.beginPath();
ctx.arc(v.x(), v.y(), radius, r1, r2);
c.updateStroke(true);
;
// mouse move store
var _mousePos = new vec2();
canvas.addEventListener('mousemove', function(e)
var rect = canvas.getBoundingClientRect();
_mousePos.set(e.clientX - rect.left, e.clientY - rect.top);
);
// colors
var _red = new ccolor('#FF0000');
var _green = new ccolor('#00FF00');
var _blue = new ccolor('#0000FF');
var _black = new ccolor('#000000');
var _white = new ccolor('#FFFFFF');
// game vars
var LOOP_INT = 1000 / 60; // 16.6666
var AI_BODY_RADIUS = 50;
var TEST_SPEED = LOOP_INT / 800;
var timer_id = 0;
var text_position = new vec2(5, 5);
var AI_VIEW_CONE = Math.DEG2RAD(120);
var ai_position = new vec2(300, 260);
var ai_angle = Math.DEG2RAD(225);
//var test_angle = 0; // rad
// main loop
var MAIN_LOOP = function()
clearCanvas(_white);
// test
//test_angle += LOOP_INT / 300;
//test_angle = Math.wrapRadian(test_angle + (LOOP_INT / 300));
//_text( text_position, 'ANGLE: ' + (Math.round(test_angle * 100) / 100), _blue );
var target_angle = ai_position.slopeAngle(_mousePos);
var angle_diff = Math.angleDifference(target_angle, ai_angle);
// within FOV
//if ( Math.angleWithinFOV(angle_diff, AI_VIEW_CONE) )
if (angle_diff > 0) ai_angle += TEST_SPEED;
if (angle_diff < 0) ai_angle -= TEST_SPEED;
//
var txt = 'ANGLE DIFF: ' + Math.roundp(Math.RAD2DEG(angle_diff), 2);
_text( text_position, txt, _blue );
// AI
_line(ai_position, ai_position.next(ai_angle, AI_BODY_RADIUS), _red);
// cone
var aa = Math.M_PI_DB_2 - ai_angle;
var vc = AI_VIEW_CONE / 2;
_viewcone(ai_position, AI_BODY_RADIUS, _red, aa - vc, aa + vc);
_line(ai_position, ai_position.next(ai_angle - vc, AI_BODY_RADIUS), _red);
_line(ai_position, ai_position.next(ai_angle + vc, AI_BODY_RADIUS), _red);
// target angle
_line( ai_position, ai_position.next( target_angle, AI_BODY_RADIUS ), _blue );
// cursor
_circle( _mousePos, 5, _green, true );
//requestAnimationFrame(MAIN_LOOP);
;
// srart up
timer_id = setInterval(MAIN_LOOP, LOOP_INT);
;
</script>
</body>
</html>
【问题讨论】:
【参考方案1】:要使用度数计算 2 个角度之间的差异,您可以使用:
var diffA = targetA - sourceA;
diffA = (a + 180) % 360 - 180;
【讨论】:
这是用于游戏的,它需要浮点值高精度 如果targetA
和 sourceA
是浮点数,那么你应该很好。
我刚试了下,问题依旧,试着把线拉到10点左右,然后在7-5点左右移动鼠标
也许您可以更具体地说明您的问题是什么?
否则,我们甚至不知道从哪里开始。以上是关于计算角度差2D游戏的JS函数的主要内容,如果未能解决你的问题,请参考以下文章