最近突发奇想的想实现一个使用由 Canvas 技术实现的塔防游戏,其中游戏玩法主要为怪物从起点出生,在其抵达终点之前,玩家可以通过消耗金币来 摆放/升级 道具来阻止或击败怪物。 而当怪物进入道具的攻击范围时,道具的枪口将对着怪物的方向,并且朝其方向发射子弹。
在实现这个 子弹跟踪算法 前,我们首先需要明白几件事。
好了,在提出了这三个问题后,我们就可以来仔细思考一下这三个问题的答案了。
那么,首先是第一个问题。
子弹的速度是否会因怪物离道具的距离而发生变化?
这个问题其实很简单。
我们仔细想想,在我们周围生活中可以看到过的塔防游戏里,是否有子弹无论是从近到远都是一秒钟到的游戏?
很显然,几乎没有,又或者说很少见。
其次是第二个问题。
子弹需要如何移动?
这里我们可以看看上面那个实例图(下面也画了个草图)。
从图里我们可以得知,怪物在道具的左上角。
也就是说,怪物的 x 值与 y 值均小于 道具的 x值与y值。
又因子弹的初始位置为道具的中心点,所以当我们的子弹想要朝着左上角移动时,子弹的 x 与 y 均 加上负值即可朝着左上角移动。
同理可得 x = 0, y = -1 则朝着正上方移动 x = 0, y = 1 则朝着正下方移动 x = -1, y = 0 则朝着正左方移动 x = 1, y = 0 则朝着正右方移动 x = 1, y = 1 则朝着右下方移动 x = 1, y = -1 则朝着右上方移动 x = -1, y = 1 则朝着左下方移动
最后我们思考一下第三个问题,也是最重要,最困难的问题。
如何取得子弹的移动方向?
上面我们知道了 子弹 的 x 与 y 轴的速度值会影响 子弹发射的方向。
也许聪明的朋友会想到我们去对比 怪物 与 道具的 x与y 的坐标,然后得出 x 或 y 的值是应该为 1,还是 -1 还是0。
这么想其实没错,但也不对。
因为如果我们只是单纯的取 1,-1, 0的话会造成什么影响?
那样的话,子弹就只会朝着 0°,45°,90°,135°等角度移动了。
但很显然,怪物与道具之间的角度绝不会只有这几个固定值。
所以我们这个时候可以用到某个数学定理了。
我们来看看这张图。
这个图里,怪物与道具的位置显然可以构成一个直角三角形。
而在数学里,是可以通过勾股定理来求出直角三角形的斜角边的。
即
不过说到这可能有的朋友会困惑,我们为什么要算斜边?算了斜边对子弹发射角度有什么帮助吗? 这里咱暂时不用急,讲到后面咱就会明白为什么了。
在上面那个图中,我们可以得知 a值 为怪物与道具的 y 轴的 绝对差值, b值为 为怪物与道具的 x 轴的绝对差值。
那么我们就假设怪物的 x 为 10,y 为 10。
道具的 x 为 30, y 为 20。
那么我们就可以得到斜角的边
let x1 = 10,
x2 = 30,
y1 = 10,
y2 = 20,
c = Math.sqrt(Math.pow(Math.abs(x1 - x2), 2) + Math.pow(Math.abs(y1 - y2),2));// 22.360679774997898
复制代码
此时我们得到了斜角边后,我们就可以声明一个值,即子弹的移动速度,这样是为了保证子弹无论离怪物的距离是否远近,速度都是不会变化的。
const speed = 5;
复制代码
这里我们声明子弹的速度的变量,并为其赋值5。其意义为,子弹在每帧移动5像素。
随后我们用我们得到的斜角边除以子弹的速度,就可以得到子弹在多少帧后抵达该斜角边的最末端的位置。
let hy = c / speed;// 4.47213595499958
复制代码
这里我们可以看到,在4.47213595499958 帧以后,我们的子弹将抵达该斜边的最末端的位置。
也就是说,我们只需要用 怪物与道具的 x与y 的绝对差值去除以这个帧数,就可以得到子弹每一帧的 x与y 的移动距离。
(不过在这里我们需要取反,不然的话子弹只会朝着相反的方向移动)
let x = -((x1 - x2) / hy),
y = -((y1 - y2) / hy);
复制代码
最后,整个算法如下。
const speed = 5;
function get_move_speed(m, t) {
let m_x = m.x + m.speed.x,
m_y = m.y + m.speed.y,
abs_x = Math.abs(t.x - m_x),
abs_y = Math.abs(t.y - m_y),
hy = Math.sqrt(Math.pow(abs_x, 2) + Math.pow(abs_y, 2)) / speed,
x = -((t.x - m_x) / hy),
y = -((t.y - m_y) / hy);
// 注意,这里 m 对象的坐标和 t对象的坐标 均是怪物与道具的中心点
return {x,y}
}
复制代码
PS: 最后这里是做了点预判,因为怪物是会移动的,如果不做预判,很容易造成在子弹移动到怪物原来的位置后,怪物已经离开了。 也为了避免被当成标题党,这里也说明一下,如果想要子弹跟着怪物移动的话,其实每过几帧再调用这个方法就行了。
最后的最后,如果大家觉得这篇文章对你有所帮助的话,还请点个赞支持支持一下拉!
(下一期或者下下期更新这个塔防游戏的如何实现~)。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有