Canvas Bitmap
图片源
两种方式:
1.
<img id="xxx" src="xxx" />
2.
var img = new Image(); img.src = "xxx";
加载
如果想在代码里使用图片,我们必须确保图片加载完了,如下:
img.addEventListener('load', imageLoaded, false);
这种为每张图片创建一个事件侦听器的方式效率上不太好,如果只是一张图片倒是没什么问题。
drawImage
drawImage() 方法被重载了,它有三个版本,下面我按需求进行分解:
现有一张100 * 100的图片,中间我用蓝线框出了一个区域,蓝框的左上角坐标为 (14, 9),蓝框的大小为 72 * 82
需求一:按原大小把图片的画出来
版本:drawImage(img, x, y);
var img = new Image(); img.src = '1.jpg'; img.addEventListener('load', function() { context.drawImage(img, 10, 10); }, false);
需求二:对图片进行缩放
版本:drawImage(img, x, y, width, height);
context.drawImage(img, 10, 10, 50, 50);
可见,图片被缩小到一半大小。
需求三:从图片中取出一部分画到canvas上
版本:drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);
context.drawImage(img, 14, 9, 72, 82, 10, 10, 72, 82);
这个没有缩放,下面我改变 dw 和 dh 的值,就会出现缩放了(缩小一半):
context.drawImage(img, 14, 9, 72, 82, 10, 10, 36, 41);
关于tile
tile 这词是游戏开发中常用的,中文还真不好说,比如下面这张图就是一个tile:
这张图画了坦克运行中的8个状态,连续播放就是一段动画。
下面我简单说说怎么使用tile。比如这里的一个tank,大小是34 * 34,同时我们需要8帧动画,每一帧都会在相同的区域绘制一个tank,原理就是这样,来看代码:
var tile = new Image(); tile.src = 'tile.jpg'; tile.addEventListener('load', function() { var x = 0, tankWidth = 34, tankHeight = 34, totalFrame = 8, curFrame = 0; // 设置一个定时器,这里是每秒24帧的动画 setInterval(function() { x = curFrame * tankWidth; context.drawImage(tile, x, 0, tankWidth, tankHeight, 10, 10, tankWidth, tankHeight); curFrame++; if (curFrame === totalFrame) { curFrame = 1; } }, 1000 / 24); }, false);
图片的transform
还是用tile的图片举例,我们需要tank朝向右边,即旋转90°。
如果你熟悉Flash,肯定知道它有Sprite 和 MovieClip 之类的显示对象,这样添加效果就比较独立,都是一个个的对象,互不影响。但是Canvas不是这样的,一个canvas就是一个“显示对象”,比如你有两个tank,你知道这是两个对象,但是你画到canvas上之后,只不过是canvas的两块像素区域。
如果我们应用了transform,那么整个canvas都会影响(当然应用transform之前绘制的东西不会受影响),就本例来说,我们只需要临时旋转一下tank,只是临时的用一下旋转,用完了要赶紧复原,不然之后的绘制都会受影响。
话不多说,直接看代码:
var tile = new Image(); tile.src = 'tile.jpg'; tile.addEventListener('load', function() { // 第一个tank的信息 var x = 0, y = 0, width = 34, height = 34; // 保存当前的context context.save(); // 重置transform context.setTransform(1, 0, 0, 1, 0, 0); // 接着是旋转部分的代码 // 平移坐标系统,把坐标原点移到tank的中心 context.translate(x + width / 2, y + height / 2); context.rotate(90 * Math.PI / 180); context.drawImage(tile, x, y, width, height, -0.5 * width, -0.5 * height, width, height); // 复原刚才的状态 context.restore(); }, false);
效果如下:
图片的运动
有了tile,我们自然会想着怎么让它动起来,运动不外乎位移,位移说白了就是(x, y)的变化,下面我来分解步骤:
1. 把坐标系统的原点移动到对象的中心,这样可方便transform
2. 坐标原点变为对象中心点的另一个好处是,不再需要操心对象的坐标,只需要考虑translate(x, y)的坐标,因为对象的坐标不再变化了
来看代码:
var tile = new Image(); tile.src = 'tile.jpg'; tile.addEventListener('load', function() { // 第一个tank的信息 var x = 0, y = 0, width = 34, height = 34; // 定义运动的方向,这里定为水平向右运动 var dx = 1, dy = 0; // 运动也是需要动画的 setInterval(function() { // 重绘画布 context.fillStyle = 'lightblue'; context.fillRect(0, 0, canvas.width, canvas.height); // 更新坐标 x += dx; y += dy; context.save(); context.setTransform(1, 0, 0, 1, 0, 0); context.translate(x + width / 2, y + height / 2); context.rotate(90 * Math.PI / 180); context.drawImage(tile, 0, 0, width, height, -0.5 * width, -0.5 * height, width, height); context.restore(); }, 1000 / 24); }, false);
最后奉上三个制作tile的工具软件: