JavaScript 中使用 canvas 元素平移和滚动背景图像

Posted by cl9000 on May 19, 2020

万物皆有其美,但并非人人都能发现。——<安迪.沃霍尔>

用纯JavaScript创建一个简单的2D游戏。作为第一步,展示如何使用canvas元素对背景图像进行动画处理(平移或滚动)。

简单的2D游戏有两种常见方案:

  • 整个关卡都有巨大的背景图片。所有活动都具有相同的背景图像,但是视口的位置在变化
  • 随着播放器的前进,有一个小图像一直在滚动(通常从右向左滚动)

在背景图像内平移视口

演示代码如下(不支持请访问演示地址查看):

演示地址 http://cl9000.gitee.io/web-code/15_canvas元素平移滚动背景/

这个怎么运作

我们有一个函数,在游戏绘制的每一帧中都会调用该函数。在这种方法中,我们计算视口的位置。对于这个基本示例,我选择从经过的时间中得出位置。因此,相机采取椭圆形路径。

1
2
3
4
5
6
7
function draw(delta) {
totalSeconds += delta;
var x = -1 * (img.width - canvas.width) / 2 * (1 + Math.cos(totalSeconds / Math.PI));
var y = -1 * (img.height - canvas.height) / 2 * (1 + -Math.sin(totalSeconds / Math.PI));

context.drawImage(img, x, y);
}

无限滚动背景图像

演示代码如下(不支持请访问演示地址查看):

演示地址 http://cl9000.gitee.io/web-code/15_canvas元素平移滚动背景/

这个怎么运作

背景位置也从经过的时间(恒定速度)中得出。

  • 我们计算需要多少图像才能覆盖视口: Math.ceil(canvas.width / img.width) + 1
  • 我们计算当前的X位置:totalSeconds * vx % img.width。请在这里注意模运算符。
  • 我们存储当前的上下文状态并转换画布以使绘图更容易。
  • 我们绘制图像-一个接一个地绘制。
  • 我们恢复上下文的状态。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function draw(delta) {
totalSeconds += delta;

var vx = 100; // the background scrolls with a speed of 100 pixels/sec
var numImages = Math.ceil(canvas.width / img.width) + 1;
var xpos = totalSeconds * vx % img.width;

context.save();
context.translate(-xpos, 0);
for (var i = 0; i < numImages; i++) {
context.drawImage(img, i * img.width, 0);
}
context.restore();
}

所有调用我们draw()函数的代码

在这些示例中使用的设置代码。

  • 用了一些基本的requestAnimationFramepolyfill
  • 仅在成功加载图像(加载)后才开始动画。
  • 一些启动/停止逻辑和按钮
  • loop()在动画运行时,每一帧都会调用该函数。在这里我们需要requestAnimationFrame()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
(function() {
window.requestAnimationFrame = window.requestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.mozRequestAnimationFrame
|| function(callback) { window.setTimeout(callback, 1000 / 60); };
var canvas = document.getElementById('bg');
var context = canvas.getContext('2d');
var looping = false;
var totalSeconds = 0;
var img = new Image();
img.onload = imageLoaded;
img.src = 'IMG_SOURCE';
function imageLoaded() {
draw(0);
var btn = document.getElementById('btnStart');
btn.addEventListener('click', function() {
startStop();
});
}
var lastFrameTime = 0;
function startStop() {
looping = !looping;
if (looping) {
lastFrameTime = Date.now();
requestAnimationFrame(loop);
}
}
function loop() {
if (!looping) {
return;
}
requestAnimationFrame(loop);
var now = Date.now();
var deltaSeconds = (now - lastFrameTime) / 1000;
lastFrameTime = now;
draw(deltaSeconds);
}
function draw(delta) {
/* Here happens some magic. */
}
}());

参考

关注【公众号】,了解更多。



支付宝打赏 微信打赏

赞赏一下 坚持原创技术分享,您的支持将鼓励我继续创作!