我正在制作的人工智能非常简单,但是对于它正在做的事情来说,它可能有点效率太低了。下图显示了各种算术运算和数学运算之间的速度差异。sin,cos,特别是atan都是低效的。它在C++中进行了测试,但仍应符合JavaScript的要求。
能用更有效的数学达到同样的结果吗?

海图源
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
let targetX = 50;
let targetY = 50;
let obstacleX = 150;
let obstacleY = 50;
let aiX = 250;
let aiY = 51;
function loop() {
// Distance between the vector points
let disTargetX = targetX - aiX;
let disTargetY = targetY - aiY;
let disObstacleX = obstacleX - aiX;
let disObstacleY = obstacleY - aiY;
// Moves to target by default
const angleTarget = Math.atan2(disTargetY, disTargetX);
let moveAngle = angleTarget;
// If near obstacle, adjust course and try to avoid it
if (Math.sqrt(disObstacleX * disObstacleX + disObstacleY * disObstacleY) < 60) {
const angleObstacle = Math.atan2(disObstacleY, disObstacleX);
moveAngle += angleTarget - angleObstacle;
}
// Move the vector to desired location
aiX += Math.cos(moveAngle);
aiY += Math.sin(moveAngle);
//Drawing
ctx.clearRect(0, 0, 600, 200);
ctx.beginPath();
ctx.fillStyle = "teal";
ctx.arc(aiX, aiY, 10, 0, Math.PI * 2, true);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "purple";
ctx.arc(obstacleX, obstacleY, 10, 0, Math.PI * 2, true);
ctx.fill();
ctx.rect(targetX - 20, targetY - 20,40,40);
ctx.stroke();
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);<canvas id="canvas" width="600" height="200"></canvas>发布于 2019-01-03 17:09:59
您可能知道这一点,但是在JavaScript中表示浮点数很难避免舍入错误。
你确定你的数学计算是正确的吗?具体来说,当从angleObstacle中减去moveAngle时,真的应该添加angleTarget吗?我试图对其进行更改,以便在发生这种情况时不会添加angleTarget。它似乎允许绿色圆圈避免与障碍物圆圈相撞。我不知道为什么速度会变..。可能是因为随弧tan或其他sin函数的指数变化。
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const targetX = 50;
const targetY = 50;
const obstacleX = 150;
const obstacleY = 50;
let aiX = 250;
let aiY = 51;
function loop() {
// Distance between the vector points
const disTargetX = targetX - aiX;
const disTargetY = targetY - aiY;
const disObstacleX = obstacleX - aiX;
const disObstacleY = obstacleY - aiY;
// Moves to target by default
const angleTarget = Math.atan2(disTargetY, disTargetX);
let moveAngle = angleTarget;
// If near obstacle, adjust course and try to avoid it
if (Math.sqrt(disObstacleX * disObstacleX + disObstacleY * disObstacleY) < 60) {
const angleObstacle = Math.atan2(disObstacleY, disObstacleX);
moveAngle += /*angleTarget -*/angleObstacle;
}
// Move the vector to desired location
aiX += Math.cos(moveAngle);
aiY += Math.sin(moveAngle);
//Drawing
ctx.clearRect(0, 0, 600, 200);
ctx.beginPath();
ctx.fillStyle = "teal";
ctx.arc(aiX, aiY, 10, 0, Math.PI * 2, true);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "purple";
ctx.arc(obstacleX, obstacleY, 10, 0, Math.PI * 2, true);
ctx.fill();
ctx.rect(targetX - 20, targetY - 20,40,40);
ctx.stroke();
if (aiX > 50) {
requestAnimationFrame(loop);
}
}
requestAnimationFrame(loop);<canvas id="canvas" width="600" height="200"></canvas>在上面的代码片段中,您会注意到对于函数中没有重新分配的变量的许多声明,let已经被const取代了,例如targetX、targetY、obstacleX、obstacleY、disTargetX、disTargetY。这样就避免了任何无意的重新分配。
此外,原始代码将永远循环。我在上面的代码段中添加了一个条件,即aiX > 50,它需要为true才能再次调用该函数(通过requestAnimationFrame)。这避免了不必要的处理。
发布于 2018-11-08 10:48:06
AFAIK,三角函数在(非基于图的)动态运动中是不可避免的.根据您想要完成的任务,网格或基于图形的移动可能是一种选择,尽管图遍历和路径查找可能是它自己的蠕虫。
一个更简单的解决方案可能是预先计算几百个值的正弦/余弦/arctangent,并将它们存储在TypedArray中,在这里您可以直接查找它们。既然你没有做科学计算,这可能就足够了。不过,您可能希望运行一些基准测试来比较这两种解决方案。
https://codereview.stackexchange.com/questions/207037
复制相似问题