JavaScript Canvas2D实现SpriteSheet角色动画

原创 2017年08月23日 20:01:09

一、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最终显示结果:
这里写图片描述

版权声明:本文为博主原创文章,转载必须声明出处和作者。地址:http://blog.csdn.net/sujun10 作者:弃天笑

cocos2d-x初学笔记08:角色动画Animation

其实这篇所讲的角色的动画Animation在TestCpp项目里面是属于动作Action范围的,咱们现在把它拿出来单独的说一说。         动画Animation其实就是一张张连贯的图片顺序播...
  • jukai7
  • jukai7
  • 2013年02月01日 21:21
  • 1521

3D游戏角色动画

摘要:本文主要描述了3D游戏角色动画的原理及应用,从介绍微软的X文件到最为广泛应用的骨骼蒙皮动画,另外简要的介绍了下渐变动画的原理。 关键词:Role Animation   Skeletal An...

cocos2dx-3.0角色动画

#include "role.h" role::role(void) { } role::~role(void) { } bool role::init() { //一些前置工作 i...
  • hotyin
  • hotyin
  • 2014年10月02日 05:47
  • 407

opengl实现角色动画

  • 2011年11月27日 15:31
  • 2.35MB
  • 下载

基于OpenGL的角色动画实现

我的本科毕设做的是一个BVH文件解析,角色关节也是一个多叉树,层次变换树。孩子节点依赖于结点的变换。上图中的角色以躯干Torso为根节点,脖子和头属于一个子树;左右手臂、左右腿分别属于四个子树,所以上...
  • dizuo
  • dizuo
  • 2012年03月19日 12:57
  • 4466

如何在cocos2d里面使用动画和spritesheet 3.0 & C++版

在游戏编程中,动画可谓必不可少,今天就向大家介绍cocos2d里面如何使Sprite加载动画,同时我们利用了SpriteSheet技术来简化操作及提高效率。 本文是基于大神子龙山人翻译的博客修改...

(译)如何在cocos2d里面使用动画和spritesheet

转自:http://www.cnblogs.com/zilongshanren/archive/2011/04/11/2012770.html   原文链接地址:http://www.rayw...

如何在cocos2d里面使用动画和spritesheet

子龙山人 Learning,Sharing,Improving! (译)如何在cocos2d里面使用动画和spritesheet   免责申明(必读!):本博客提供的所有教程的翻译原稿均来自...
  • artwebs
  • artwebs
  • 2013年05月02日 16:28
  • 619
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JavaScript Canvas2D实现SpriteSheet角色动画
举报原因:
原因补充:

(最多只允许输入30个字)