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的工具软件:

Tiled   Mappy   Tile Studio

posted @ 2012-02-11 23:34  越己  阅读(1377)  评论(0编辑  收藏  举报