JavaScript Canvas2D实现SpriteSheet角色动画

来源:互联网 发布:ubuntu怎么dakaiexe 编辑:程序博客网 时间:2024/05/16 19:48

一、SpriteSheet

目前市面上H5游戏的图片资源,基本都是采用SpriteSheet打包成图集来使用的。这样可以减少网络加载的次数,从而提升性能。另外的原因就是随着webgl的普及,把多张图片打包成一张纹理,减少纹理的频繁上传,这样也可以提升性能。本文主要是讨论使用Canvas实现的2D序列帧动画的SpriteSheet的解析和动画播放。

二、实现准备

  1. 使用HTML DOM CanvasRenderingContext2D 对象处理。
  2. json配置描述每个动画图片在大图里面占用的位置和大小(这里采用egret的生成的动画数据)
    caiyi_idle.json
{  "res": {    "1_4_1": {      "x": 0,      "y": 0,      "w": 109,      "h": 149    },    "1_4_3": {      "x": 217,      "y": 0,      "w": 102,      "h": 148    },    "1_4_2": {      "x": 320,      "y": 0,      "w": 99,      "h": 150    },    "1_4_0": {      "x": 110,      "y": 0,      "w": 106,      "h": 146    }  },  "mc": {    "caiyi_idle": {      "labels": [{        "end": 4,        "frame": 1,        "name": "1_4"      }],      "frameRate": 5,      "frames": [{        "duration": 1,        "y": -148,        "res": "1_4_0",        "x": -85      },        {          "duration": 1,          "y": -150,          "res": "1_4_1",          "x": -80        },        {          "duration": 1,          "y": -150,          "res": "1_4_2",          "x": -78        },        {          "duration": 1,          "y": -149,          "res": "1_4_3",          "x": -81        }],      "events": []    }  }}

3.动画序列图
caiyi_idle.png
这里写图片描述

4.源码例子下载

5.最终表现效果:
这里写图片描述

6.开发工具:IntelliJ IDEA

三、实现过程原理

  • 获取到 CanvasRenderingContext2D对象
//获取canvas对象var canvas = document.getElementById("canvas2D");//2d渲染对象context = canvas.getContext("2d");
  • 加载json配置和SpriteSheet大图片
xmlRequest = new XMLHttpRequest();xmlRequest.open("GET", "caiyi_idle.json", true);xmlRequest.send(null);

加载到游戏中,转成json对象,里面有对应的数据结构。这个很重要,每一帧显示什么样的图片就靠这个数据了。
这里写图片描述

var imageLoad = new Image();imageLoad.src = "caiyi_idle.png";
  • 使用setTimeout作为动画计时器
    简单实现,实际游戏的话,会比这个复杂一些。
//启动动画setTimeout(tick, 1000 / frameRate);
  • 每次心跳都调用CanvasRenderingContext2D对象的drawImage方法。
    drawImage的语法
drawImage(image, x, y)drawImage(image, x, y, width, height)drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight,          destX, destY, destWidth, destHeight)

参数

image:所要绘制的图像。这必须是表示 <img> 标记或者屏幕外图像的 Image 对象,或者是 Canvas 元素。
x, y:要绘制的图像的左上角的位置。
width, height:图像所应该绘制的尺寸。指定这些参数使得图像可以缩放。
sourceX, sourceY      :图像将要被绘制的区域的左上角。这些整数参数用图像像素来度量。
sourceWidth, sourceHeight:图像所要绘制区域的大小,用图像像素表示。
destX, destY:所要绘制的图像区域的左上角的画布坐标。
destWidth, destHeight:图像区域所要绘制的画布大小。

实现关键代码:

//进行绘图,这里是渲染大的部分图像context.drawImage(image,rect.x,rect.y,rect.w,rect.h,240 + frame.x,200 + frame.y,rect.w,rect.h);

四、完整实现代码

代码中有比较详细的注视。
html代码:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body onload="main()">    <canvas id="canvas2D" width="800" height="600">    Please use!    </canvas>    <script src="MainTest.js"></script></body></html>

js代码

/** * 程序入口 */function main(){    //获取canvas对象    var canvas = document.getElementById("canvas2D");    console.log("canvas:" + canvas);    //2d渲染对象    context = canvas.getContext("2d");    console.log("context:" + context);    //XMLHttpRequest加载json配置文件    xmlRequest = new XMLHttpRequest();    xmlRequest.open("GET", "caiyi_idle.json", true);    xmlRequest.onreadystatechange = onreadystatechange;    xmlRequest.send(null);}//xmlRequestxml的状态改变function onreadystatechange(){    if (xmlRequest.readyState==4)    {        //加载成功,生成json对象        idleConfig = JSON.parse(xmlRequest.responseText);        //加载图片        var imageLoad = new Image();        imageLoad.onload = function (event)        {            //加载完成,初始化json配置图像            image = event.target;            initImage();        }        imageLoad.src = "caiyi_idle.png";    }}function initImage(){    console.log("准备处理SpriteSheet.......");    /** 当前帧 **/    currentFrame = 0;    movieData = idleConfig.mc["caiyi_idle"];    /** 帧频 **/    frameRate = movieData.frameRate;    /** 提取出的动画全部帧数 **/    frames = movieData.frames;    /** 最大帧 **/    maxFrame = frames.length;    //启动动画    setTimeout(tick, 1000 / frameRate);}/** * 动画心跳函数,按照一定的频率定时执行 */function tick(){    //获取帧数据和每帧的位置以及宽高数据    var frame = frames[currentFrame];    var rect = idleConfig.res[frame.res];    //先清掉原来的画布    context.clearRect(0,0,480,240);    //画个背景,设置背景颜色    context.fillStyle = "#003366";    //填充个480 * 240的矩形    context.fillRect(0,0,480,240);    //进行绘图,这里是渲染大图的部分图像,具体看api参数。    context.drawImage(image,rect.x,rect.y,rect.w,rect.h,240 + frame.x,200 + frame.y,rect.w,rect.h);    currentFrame++;    //如果等于最打帧,则重新从0开始    if(currentFrame >= maxFrame)        currentFrame = 0;    //启动动画,循环播放    setTimeout(tick.bind(this), 1000 / frameRate);}

运行mainTest.html最终显示结果:
这里写图片描述

原创粉丝点击