本文详解JS/HTML5游戏中常用的追踪算法,包括基础的坐标速度分解算法与更自然的视线追踪算法。通过向量计算实现追踪者始终朝向目标移动的效果,提升游戏可玩性,并提供完整代码示例与在线测试工具。
追踪算法概述
本文详细介绍一种在JS/HTML5游戏开发中广泛应用的追踪算法,供开发者参考学习。
追踪算法在动作类游戏中应用极为广泛,从早期的《吃豆人》到现代大型街机机战游戏,追踪效果无处不在。设计优秀的追踪算法能显著提升游戏的可玩性与玩家兴趣。
简单算法实现
简单追踪算法原理
首先介绍一种基础的跟踪算法。如图所示,假设在Canvas坐标系中存在物体A和B,其中物体A负责追踪物体B。物体在二维空间中的运动可分解为X轴和Y轴的分运动,其在X和Y方向的速度分量决定了物体的运行方向与速率。由于速度包含方向与大小,物体A的速度可分解为vx和vy,物体B同理。若物体A要追踪物体B,只需比较两者在X、Y方向的速度即可。设物体A坐标为(x1, y1),速度分量为(vx, vy);物体B坐标为(x2, y2),速度分量为(vx1, vy1)。若A要追踪B,在水平X方向上,若x2大于x1(即B在A右侧),则需将vx设为正值;反之设为负值。垂直Y方向同理处理。

基于上述简单算法原理,我们可以尝试构建一个具体的示例。
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<meta charset="UTF-8">
<title>追踪算法</title>
</head>
<body>
<canvas id="stage"></canvas>
</body>
<script>
window.onload = function () {
var stage = document.querySelector('#stage'),
ctx = stage.getContext('2d');
stage.width = 400;
stage.height = 400;
balls = [];
var ball = {
x: stage.width / 2 - 20,
y: stage.height / 2 - 20,
r: 20,
c: "red"
};
balls.push(ball);
for (var i = 0; i < 30; i++) {
var trace = {
x: Math.ceil(Math.random() * (stage.width - 20) + 10),
y: Math.ceil(Math.random() * (stage.height - 20) + 10),
r: 10,
c: "blue"
};
balls.push(trace);
}
function createBall(x, y, r, c) {
ctx.beginPath();
ctx.fillStyle = c;
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.fill();
}
stage.addEventListener('click', function (event) {
var x = event.clientX - stage.getBoundingClientRect().left;
var y = event.clientY - stage.getBoundingClientRect().top;
balls[0].x = x;
balls[0].y = y;
});
function update() {
ctx.clearRect(0, 0, 400, 400);
ctx.fillStyle = "black";
ctx.rect(0, 0, 400, 400);
ctx.fill();
createBall(balls[0].x, balls[0].y, balls[0].r, balls[0].c);
for (var i = 1, len = balls.length; i < len; i++) {
//简单算法
balls[i].x -= ( balls[0].x>balls[i].x)?-1:1;
balls[i].y -= ( balls[0].y>balls[i].y)?-1:1;
createBall(balls[i].x, balls[i].y, balls[i].r, balls[i].c);
}
requestAnimationFrame(update);
}
update();
};
</script>
</html>
感兴趣的用户可使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试运行上述代码,以观察实际运行效果。
采用该简单算法的方块运动轨迹较为生硬,变向过程突然,视觉效果不够理想。因此,下文将介绍视线追踪算法。
视线追踪算法实现
视线追踪算法
视线追踪算法的核心在于,追踪者始终沿着与目标对象的连线方向移动。如图所示,这种效果类似于猎豹捕食时死死盯住猎物并直线追击的状态。
要实现此效果,意味着在任意时刻,物体A的速度方向必须保持在A与B连接的直线上。那么,如何获取A在x轴和y轴方向上的速度分量呢?
此处可利用向量知识解决问题。向量仅包含方向与大小,无位置概念。假设任意时刻物体A表示为向量v1(x1, y1),物体B表示为向量v2(x2, y2),则由A指向B的向量v3可表示为(x2−x1, y2−y1)。这三个向量的关系如图6-4所示。设向量v3的长度为VLen = √((x2−x1)² + (y2−y1)²),则向量v3标准化后可表示为v4 = ((x2−x1)/VLen, (y2−y1)/VLen)。最终得到的v4在x轴方向的分量即为物体A在该时刻X轴方向的速度分量,v4在Y轴方向的分量即为物体A在该时刻Y轴方向的速度分量。

将上述简单算法按照视线追踪算法的逻辑进行改写:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<meta charset="UTF-8">
<title>追踪算法</title>
</head>
<body>
<canvas id="stage"></canvas>
</body>
<script>
window.onload = function () {
var stage = document.querySelector('#stage'),
ctx = stage.getContext('2d');
stage.width = 400;
stage.height = 400;
balls = [];
var ball = {
x: stage.width / 2 - 20,
y: stage.height / 2 - 20,
r: 20,
c: "red"
};
balls.push(ball);
for (var i = 0; i < 30; i++) {
var trace = {
x: Math.ceil(Math.random() * (stage.width - 20) + 10),
y: Math.ceil(Math.random() * (stage.height - 20) + 10),
r: 10,
c: "blue"
};
balls.push(trace);
}
function createBall(x, y, r, c) {
ctx.beginPath();
ctx.fillStyle = c;
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.fill();
}
stage.addEventListener('click', function (event) {
var x = event.clientX - stage.getBoundingClientRect().left;
var y = event.clientY - stage.getBoundingClientRect().top;
balls[0].x = x;
balls[0].y = y;
});
function update() {
ctx.clearRect(0, 0, 400, 400);
ctx.fillStyle = "black";
ctx.rect(0, 0, 400, 400);
ctx.fill();
createBall(balls[0].x, balls[0].y, balls[0].r, balls[0].c);
for (var i = 1, len = balls.length; i < len; i++) {
//视线追踪算法
var vx = balls[i].x - balls[0].x,
vy = balls[i].y - balls[0].y,
rlen = Math.sqrt(vx * vx + vy * vy),
dx = vx / rlen,
dy = vy / rlen;
balls[i].x -= dx;
balls[i].y -= dy;
createBall(balls[i].x, balls[i].y, balls[i].r, balls[i].c);
}
requestAnimationFrame(update);
}
update();
};
</script>
</html>
使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试运行上述代码,可获得如下运行结果:

相关代码托管于GitHub:https://github.com/krapnikkk/JS-gameMathematics
更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《JavaScript数学运算用法总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript数组操作技巧总结》、《JavaScript排序算法总结》、《JavaScript遍历算法与技巧总结》、《JavaScript查找算法技巧总结》及《JavaScript错误与调试技巧总结》
希望本文所述的算法解析对JavaScript程序设计有所帮助。