网页小实验——用canvas生成精灵动画图片

实验目标:借助canvas把一张国际象棋棋子图片转换为一组适用于WebGL渲染的精灵动画图片,不借助其他图片处理工具,不引用其他库只使用原生js实现。

初始图片如下:

一、图片分割

将初始图片分割为六张大小相同的棋子图片

1、html舞台:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>处理棋子图片</title>
 6 </head>
 7 <body>
 8 <canvas id="can_source" style="z-index: 1;top:2px;left:2px;position: absolute"></canvas><!--显示原图的画布-->
 9 <canvas id="can_mask" style="z-index: 10;top:2px;left:2px;position: absolute"></canvas><!--显示操作范围提示的画布-->
10 <canvas id="can_maskbak" style="z-index: 1;top:2px;left:2px;position: absolute"></canvas><!--用来划分区域的背景画布-->
11 </body>
12 <script><!--主体代码-->
13 </script>
14 </html>

这里准备了三张canvas画布,其中can_source是预览原图的画布,称为“源画布”;can_mask是悬浮在can_source上层的透明背景画布,用来绘制切割范围提示,称为“提示画布”;can_maskbak用来圈定切割范围(其实可以不显示它),称为“范围画布”。

2、分割流程:

 1 var can_source=document.getElementById("can_source");
 2     var can_mask=document.getElementById("can_mask");
 3     var can_maskbak=document.getElementById("can_maskbak");
 4     var top_res;
 5     var width=0,height=0;
 6     window.onload=function(){
 7         var img=new Image();
 8         img.src="../../ASSETS/IMAGE/ICON/chesses.jpg";
 9         img.onload=function(){
10             width=img.width;//根据图片尺寸设置画布尺寸
11             height=img.height;
12             can_source.style.width=width+"px";//css尺寸
13             can_source.style.height=height+"px";
14             can_source.width=width;//canvas像素尺寸
15             can_source.height=height;
16             var con_source=can_source.getContext("2d");
17             con_source.drawImage(img,0,0);//显示原图
18 
19             top_res=height+4+"px";
20             can_maskbak.style.left=width+4+"px";//把这个圈定范围的画布放在右边,做对比
21             can_maskbak.style.width=width+"px";
22             can_maskbak.style.height=height+"px";
23             can_maskbak.width=width;
24             can_maskbak.height=height;
25             var con_maskbak=can_maskbak.getContext("2d");
26             con_maskbak.fillStyle="rgba(0,0,0,1)";//填充完全不透明的黑色
27             con_maskbak.fillRect(0,0,width,height);
28 
29             can_mask.style.width=width+"px";
30             can_mask.style.height=height+"px";
31             can_mask.width=width;
32             can_mask.height=height;
33             var con_mask=can_mask.getContext("2d");
34             con_mask.fillStyle="rgba(0,0,0,0)";
35             con_mask.fillRect(0,0,width,height);
36             //下面是具体的操作代码
37             //cutRect(40,10,120,240,256,256);//矩形切割
38             //cutRect(192,10,120,240,256,256);
39             //cutRect(340,10,120,240,256,256);
40             cutRect(33,241,120,240,256,256);
41             cutRect(200,241,120,240,256,256);
42             cutRect(353,241,120,240,256,256);
43         }
44     }

3、具体切割算法:

 1 //从一个画布上下文中剪切一块dataUrl
 2     function cutRect(x,y,wid,hig,wid2,hig2)
 3     {
 4         //将矩形转换为路径,然后用更一般化的路径方法处理区域
 5         var path=[{x:x,y:y},{x:x+wid,y:y},{x:x+wid,y:y+hig},{x:x,y:y+hig}];
 6         var framearea=[x,y,wid,hig];//framearea是操作范围的边界,矩形切割则直接是矩形本身,多边形切割则应是多边形的外切矩形范围
 7         cutPath(path,framearea,wid2,hig2);
 8 
 9     }
10     function cutPath(path,framearea,wid2,hig2)
11     {
12         var len=path.length;
13         var con_mask=can_mask.getContext("2d");
14         con_mask.strokeStyle="rgba(160,197,232,1)";//线框
15         con_mask.beginPath();
16         for(var i=0;i<len;i++)
17         {
18             var point=path[i];
19             if(i==0)
20             {
21                 con_mask.moveTo(point.x,point.y);
22             }
23             else {
24                 con_mask.lineTo(point.x,point.y);
25             }
26 
27         }
28         con_mask.closePath();//在提示画布中绘制提示框
29         con_mask.stroke();
30         //con_mask.Path;
31 
32 
33         var con_maskbak=can_maskbak.getContext("2d");
34         con_maskbak.beginPath();
35         con_maskbak.fillStyle="rgba(0,255,0,1)";
36         con_maskbak.lineWidth=0;
37         for(var i=0;i<len;i++)
38         {
39             var point=path[i];
40             con_maskbak.lineTo(point.x,point.y);
41         }
42         con_maskbak.closePath();
43         con_maskbak.fill();//在范围画布中画出切割的范围(纯绿色)
44 
45         var con_source=can_source.getContext("2d");
46         var data_source=con_source.getImageData(framearea[0],framearea[1],framearea[2],framearea[3]);//获取源画布在操作范围内的像素
47         var data_maskbak=con_maskbak.getImageData(framearea[0],framearea[1],framearea[2],framearea[3]);//获取范围画布在操作范围内的像素
48 
49         var can_temp=document.createElement("canvas");//建立一个暂存canvas作为工具,并不实际显示它。
50         can_temp.width=wid2||framearea[2];//设置暂存画布的尺寸,这里要把长方形的切图保存为正方形!
51         can_temp.height=hig2||framearea[3];
52         var con_temp=can_temp.getContext("2d");
53         con_temp.fillStyle="rgba(255,255,255,1)";
54         con_temp.fillRect(0,0,can_temp.width,can_temp.height);
55         var data_res=con_temp.createImageData(framearea[2],framearea[3]);//建立暂存画布大小的像素数据
56 
57 
58         var len=data_maskbak.data.length;
59         for(var i=0;i<len;i+=4)//对于范围画布的每一个像素
60         {
61             if(data_maskbak.data[i+1]=255)//如果这个像素是绿色
62             {
63                 data_res.data[i]=(data_source.data[i]);//则填充源画布的对应像素
64                 data_res.data[i+1]=(data_source.data[i+1]);
65                 data_res.data[i+2]=(data_source.data[i+2]);
66                 data_res.data[i+3]=(data_source.data[i+3]);
67             }
68             else
69             {
70                 data_res.data[i]=(255);//否则填充完全不透明的白色,注意不透明度通道在rgba表示中是0到1,在data表示中是0到255!
71                 data_res.data[i+1]=(255);
72                 data_res.data[i+2]=(255);
73                 data_res.data[i+3]=(255);
74             }
75         }
76         con_temp.putImageData(data_res,(can_temp.width-framearea[2])/2,(can_temp.height-framearea[3])/2)//把填充完毕的像素数据放置在暂存画布的中间
77         console.log(can_temp.toDataURL());//以dataUrl方式输出暂存画布的数据
78 
79     }

4、切割效果如下:

在控制台里可以找到以文本方式输出的图片数据:

对于小于2MB的图片数据,直接复制dataUrl粘贴到浏览器地址栏回车,即可显示完整图片,之后右键保存;对于大于2MB的图片数据则需把can_temp显示出来,之后右键保存。精灵动画的单帧图片一般较小,所以不考虑需要显示can_temp的情况。

最终获取的一张“兵”图片:

5、改进

其实canvas的path对象本身就有clip方法,可以用这个内置方法简化以上过程。

clip方法的文档:https://www.w3school.com.cn/tags/canvas_clip.asp

二、生成精灵动画

1、html舞台及准备代码:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>建立棋子的动画帧,添加一个图标样式</title>
 6 </head>
 7 <body>
 8     <canvas id="can_back" style="z-index: 1;top:2px;left:2px;position: absolute"></canvas><!--徽章的背景-->
 9     <canvas id="can_back2" style="z-index: 1;top:2px;left:2px;position: absolute"></canvas>
10     <canvas id="can_res" style="z-index: 1;top:2px;left:2px;position: absolute"></canvas><!--显示结果-->
11 </body>
12 <script>
13     var can_back=document.getElementById("can_back");
14     var can_back2=document.getElementById("can_back2");
15     var can_res=document.getElementById("can_res");
16     var width=240,height=360;
17     window.onload=function(){
18         console.log("程序开始")
19         can_back.style.width=width+"px";
20         can_back.width=width;
21         can_back.style.height=height+"px";
22         can_back.height=height;
23         can_back2.style.width=width+"px";
24         can_back2.width=width;
25         can_back2.style.height=height+"px";
26         can_back2.height=height;
27         can_back2.style.left=width+4+"px";
28         can_res.style.top=height+4+"px";
29         var img=new Image();
30         img.src="../../ASSETS/IMAGE/ICON/bing.png";//256*256的图片
31         img.onload=function(){//动画帧生成代码
32         }
33 </script>
34 </html>

 2、在can_back中为棋子添加“徽章”背景

添加后效果如下:

为棋子添加了一个形状和颜色渐变的徽章背景,徽章外为透明色,可以根据棋子所属的势力为徽章设置不同的主色调。算法首先判断can_back的像素点是否在棋子“兵”内,如果在棋子内则原样呈现,否则根据像素的位置计算像素的颜色,一种实现方法如下:

  1 var con_back=can_back.getContext("2d");
  2             con_back.fillStyle="rgba(0,255,0,0)";
  3             con_back.fillRect(0,0,width,height);
  4             con_back.drawImage(img,(width-256)/2,(height-256)/2)
  5 
  6             var data_back=con_back.getImageData(0,0,width,height);
  7             //var len=data_back.length;
  8             var r1=22/19;
  9             var r2=22/51;
 10             var p_light=255;//背景强度
 11             var i_min=0,i_max=0;
 12             //一行一行地处理像素
 13             var data=data_back.data;
 14             for(var i=0;i<360;i++)
 15             {
 16                 var num_w=(Math.pow(110*110-(i-100)*(i-100)*r2*r2,0.5));
 17                 for(var j=0;j<240;j++)//对于这一行里的每一个像素
 18                 {
 19                     var index=(i*240+j)*4;
 20                     if(i<5||i>355)
 21                     {
 22                         data[index]=0;
 23                         data[index+1]=255;
 24                         data[index+2]=0;
 25                         data[index+3]=0;
 26                     }
 27                     else
 28                     {
 29 
 30                         if(i<100)
 31                         {
 32                             if(Math.abs(j-119.5)<((i-5)*r1))
 33                             {
 34                                 if(data[index]+data[index+1]+data[index+2]>600||data[index+3]==0)//不是黑色或者完全透明
 35                                 {
 36                                     var b=127+128*(95-(i-5))/95;//保持红色为主色调
 37                                     var b2=(p_light-b)/2;
 38                                     data[index]=b;
 39                                     data[index+1]=b2;
 40                                     data[index+2]=b2;
 41                                     data[index+3]=255;
 42                                 }
 43                                 else
 44                                 {
 45                                     data[index]=0;
 46                                     data[index+1]=0;
 47                                     data[index+2]=0;
 48                                     data[index+3]=255;
 49                                     if(i_min==0)
 50                                     {
 51                                         i_min=i;
 52                                         i_max=i;
 53                                     }
 54                                     else
 55                                     {
 56                                         if(i>i_max)
 57                                         {
 58                                             i_max=i;
 59                                         }
 60                                     }
 61                                 }
 62                             }
 63                             else
 64                             {
 65                                 data[index]=0;
 66                                 data[index+1]=255;
 67                                 data[index+2]=0;
 68                                 data[index+3]=0;
 69                             }
 70                         }
 71                         else
 72                         {
 73                             //if(Math.abs(j-119.5)<Math.pow((355-i),0.5)*r2)
 74                             if(Math.abs(j-119.5)<num_w)
 75                             {
 76                                 if(data[index]+data[index+1]+data[index+2]>600||data[index+3]==0)//不是黑色
 77                                 {
 78                                     var b=127+128*(255-(355-i))/255;
 79                                     var b2=(p_light-b)/2;
 80                                     data[index]=b;
 81                                     data[index+1]=b2;
 82                                     data[index+2]=b2;
 83                                     data[index+3]=255;
 84                                 }
 85                                 else
 86                                 {
 87                                     data[index]=0;
 88                                     data[index+1]=0;
 89                                     data[index+2]=0;
 90                                     data[index+3]=255;
 91                                     if(i_min==0)
 92                                     {
 93                                         i_min=i;
 94                                         i_max=i;
 95                                     }
 96                                     else
 97                                     {
 98                                         if(i>i_max)
 99                                         {
100                                             i_max=i;
101                                         }
102                                     }
103                                 }
104                             }
105                             else
106                             {
107                                 data[index]=0;
108                                 data[index+1]=255;
109                                 data[index+2]=0;
110                                 data[index+3]=0;
111                             }
112                         }
113                     }
114                 }
115             }
116             con_back.putImageData(data_back,0,0);
View Code

3、在can_back2为徽章中的棋子描边

为后面的环节做准备,给棋子的轮廓描一层rgb(1,1,1)颜色、2px宽度的边

1 var size_border=2;
2             var rgb_border={r:1,g:1,b:1};
3             if(size_border>0)//为前景和背景的边界描边的算法?
4             {//-》为特定的两种颜色边界描边的算法!!!!
5                 console.log("开始描绘边界");
6                 drawBorder(data,240,360,isColorOut,isColorIn,Math.floor(size_border/2),size_border,rgb_border);
7             }//参数:像素数据,宽度,高度,判断像素在描边内测的条件,判断像素在描边外侧的条件,描边的偏移,边宽,描边的颜色
8             var con_back2=can_back2.getContext("2d");
9             con_back2.putImageData(data_back,0,0);

描边函数:

  1 function isColorOut(rgba)
  2     {
  3         if(rgba.r>127)
  4         {
  5             return true;
  6         }
  7         return false;
  8     }
  9     function isColorIn(rgba)
 10     {
 11         if(rgba.r==0&&rgba.g==0&&rgba.b==0)
 12         {
 13             return true;
 14         }
 15         return false;
 16     }
 17     //参数:像素数据,图片的宽度,图片的高度,”外部“的颜色(可以有多种),“内部的颜色”(可以有多种,但不应与arr_rgba1重复!!)
 18     // ,决定把边画在内部还是外部的偏移(默认为0,画在中间?为正表示向内偏),边的宽度,边的颜色(认为完全不透明)
 19     //使用xy的垂直遍历方法,另一种思路是让计算核沿着分界线移动《-绘制的更为平滑
 20     //function drawBorder(data,width,height,arr_rgbaout,arr_rgbain,offset_inout,size_border,rgb_border)
 21     //内外的颜色可能是渐变的!!所以在这里用返回布尔值的函数做参数!!!!而非固定颜色范围
 22     function drawBorder(data,width,height,func_out,func_in,offset_inout,size_border,rgb_border)
 23     {
 24         //首先对于每一行像素
 25         for(var i=0;i<height;i++)
 26         {
 27             var lastRGBA={};
 28             for(var j=0;j<width;j++)
 29             {
 30                 var index=(i*240+j)*4;
 31                 var RGBA={r:data[index],g:data[index+1],b:data[index+2],a:data[index+3]};
 32                 //if(!lastRGBA.r&&lastRGBA.r!=0)//如果是第一个像素
 33                 if(j==0)
 34                 {
 35                     lastRGBA=RGBA;//上一颜色
 36                     continue;
 37                 }
 38                 else
 39                 {
 40                     //if(isRGBAinArr(arr_rgbaout,lastRGBA)&&isRGBAinArr(arr_rgbain,RGBA))//在内外颜色的分界处(左侧)
 41                     if(func_out(lastRGBA)&&func_in(RGBA))//如果上一颜色应该在描边的外侧,同时当前颜色在描边的内侧
 42                     {
 43                         var os_left=Math.floor(size_border/2);//偏右
 44                         var os_right=size_border-os_left;
 45                         var j_left=j-os_left;
 46                         var j_right=j+os_right;
 47                         j_left+=offset_inout;
 48                         j_right+=offset_inout;
 49                         for(var k=j_left;k<j_right;k++)//修正偏右
 50                         {
 51                             if(k>=0&&k<width)
 52                             {
 53                                 var index2=(i*240+k)*4;
 54                                 data[index2]=rgb_border.r;
 55                                 data[index2+1]=rgb_border.g;
 56                                 data[index2+2]=rgb_border.b;
 57                                 data[index2+3]=255;
 58                             }
 59 
 60                         }
 61                     }
 62                     //else if(isRGBAinArr(arr_rgbaout,RGBA)&&isRGBAinArr(arr_rgbain,lastRGBA))//在内外颜色的分界处(右侧)
 63                     else if(func_out(RGBA)&&func_in(lastRGBA))
 64                     {
 65                         var os_right=Math.floor(size_border/2);//偏左
 66                         var os_left=size_border-os_right;
 67                         var j_left=j-os_left;
 68                         var j_right=j+os_right;
 69                         j_left-=offset_inout;
 70                         j_right-=offset_inout;
 71                         for(var k=j_left+1;k<=j_right;k++)//修正偏左
 72                         {
 73                             if(k>=0&&k<width)
 74                             {
 75                                 var index2 = (i * 240 + k) * 4;
 76                                 data[index2] = rgb_border.r;
 77                                 data[index2 + 1] = rgb_border.g;
 78                                 data[index2 + 2] = rgb_border.b;
 79                                 data[index2 + 3] = 255;
 80                             }
 81                         }
 82                     }
 83                 }
 84                 lastRGBA=RGBA;
 85             }
 86 
 87         }
 88         //然后对于每一列像素
 89         for(var i=0;i<width;i++)
 90         {
 91             var lastRGBA={};
 92             for(var j=0;j<height;j++)//对于这一列中的每个像素
 93             {
 94                 var index=(j*240+i)*4;
 95                 var RGBA={r:data[index],g:data[index+1],b:data[index+2],a:data[index+3]};
 96                 //if(!lastRGBA.r&&lastRGBA.r!=0)//如果是第一个像素
 97                 if(j==0)
 98                 {
 99                     lastRGBA=RGBA;
100                     continue;
101                 }
102                 else
103                 {
104                     //if(isRGBAinArr(arr_rgbaout,lastRGBA)&&isRGBAinArr(arr_rgbain,RGBA))//在内外颜色的分界处(左侧)
105                     if(func_out(lastRGBA)&&func_in(RGBA))
106                     {
107                         var os_up=Math.floor(size_border/2);//偏下
108                         var os_down=size_border-os_up;
109                         var j_up=j-os_down;
110                         var j_down=j+os_right;
111                         j_up+=offset_inout;
112                         j_down+=offset_inout;
113                         for(var k=j_up;k<j_down;k++)//不修正偏下
114                         {
115                             if(k>=0&&k<height)
116                             {
117                                 var index2=(k*240+i)*4;
118                                 data[index2]=rgb_border.r;
119                                 data[index2+1]=rgb_border.g;
120                                 data[index2+2]=rgb_border.b;
121                                 data[index2+3]=255;
122                             }
123 
124                         }
125                     }
126                     //else if(isRGBAinArr(arr_rgbaout,RGBA)&&isRGBAinArr(arr_rgbain,lastRGBA))//在内外颜色的分界处(右侧)
127                     else if(func_out(RGBA)&&func_in(lastRGBA))
128                     {//下面应该是忘了改变量名
129                         var os_right=Math.floor(size_border/2);//偏左
130                         var os_left=size_border-os_right;
131                         var j_left=j-os_left;
132                         var j_right=j+os_right;
133                         j_left-=offset_inout;
134                         j_right-=offset_inout;
135                         for(var k=j_left;k<j_right;k++)//修正偏左
136                         {
137                             if(k>=0&&k<height)
138                             {
139                                 var index2 = (k * 240 + i) * 4;
140                                 data[index2] = rgb_border.r;
141                                 data[index2 + 1] = rgb_border.g;
142                                 data[index2 + 2] = rgb_border.b;
143                                 data[index2 + 3] = 255;
144                             }
145                         }
146                     }
147                 }
148                 lastRGBA=RGBA;
149             }
150 
151         }
152     }

这里横竖遍历所有像素,在棋子轮廓内外边界处绘制描边,算法细节可能较难以想象,建议亲自调试实验。使用这种方法绘制的描边可能比较粗糙。

4、为棋子建立不同状态的动画帧

这里以生命值变化为例:

用棋子“填充度”的降低表示棋子生命值的减少,图像生成算法如下:

 1             console.log("开始生成健康状态图片");
 2             /*关于边界,因为纵向体现状态比例,所以最上边和最下边是必然存在的,用最上边和最下边之间的区域分割状态比例
 3             ,然后再根据边框宽度画其他的普通边,考虑到空洞的情况,纵向和横向的普通边数量是不确定的
 4             -》描边的操作应该在前一步进行!!??*/
 5 
 6             i_min+=size_border;
 7             i_max-=size_border;
 8             var i_height=i_max-i_min;
 9             //接下来把它画在1800*1800的图片上(设为2048*2048可能获得更高性能和清晰度,但要求每个单元图片尺寸也必须是2的整数次幂,比如256*256),分为横5竖5最多25个状态
10             /*can_res.style.width=2048+"px";
11             can_res.width=2048;
12             can_res.style.height=2048+"px";
13             can_res.height=2048;*/
14             can_res.style.width=1800+"px";
15             can_res.width=1800;
16             can_res.style.height=1800+"px";
17             can_res.height=1800;
18             var con_res=can_res.getContext("2d");
19             //return;
20             //var data=data_back.data;
21             for(var h=10;h>=0;h--)//健康度状态分十一个阶段递减
22             {
23                 console.log("生成"+h+"/"+10+"的图片")
24                 var int_x=Math.floor((10-h)%5);
25                 var int_y=Math.floor((10-h)/5);
26                 if(h==10)
27                 {
28                     con_res.putImageData(data_back,int_x*360+60,int_y*360);
29                 }
30                 else
31                 {
32                     var i_up=Math.floor(i_max-i_height*((h+1)/10));//i偏低,取像素整体偏上
33                     var i_down=Math.floor(i_max-i_height*((h)/10)+1);
34                     for(var i=i_up;i<i_down;i++)//对于每一行像素
35                     {
36                         var j_left=0,j_right=0;
37                         for(var j=0;j<240;j++)
38                         {
39                             var index=(i*240+j)*4;
40                             if(data[index]==0&&data[index+1]==0&&data[index+2]==0)
41                             {
42                                 if(j_left==0)
43                                 {
44                                     j_left=j;
45                                     data[index]=0;
46                                     data[index+1]=255;
47                                     data[index+2]=0;
48                                     data[index+3]=0;//将像素不透明度设为0
49                                 }
50                                 else
51                                 {
52                                     data[index]=0;
53                                     data[index+1]=255;
54                                     data[index+2]=0;
55                                     data[index+3]=0;
56                                     j_right=j;
57                                 }
58                             }
59                         }
60                         /*if(j_right>0)
61                         {
62                             var index=(i*240+j_right)*4;
63                             data[index]=0;
64                             data[index+1]=0;
65                             data[index+2]=0;
66                             data[index+3]=255;
67                         }*/
68 
69 
70                     }
71                     //描边
72 
73                     con_res.putImageData(data_back,int_x*360+60,int_y*360);
74                     //putImageData时完全透明的rgb通道将被丢弃??!!
75                 }
76 
77 
78             }

5、添加“被破坏”动画帧

实现思路是在棋子上绘制不断增大的透明圆表示棋子的消逝,需要注意的是因为谷歌浏览器无法精确处理半透明计算,所以考虑到以后可能需要绘制半透明的“消逝圆”的情况,先用不透明绿色绘制消逝圆,然后统一把绿色替换为具有精确透明度的颜色。实现代码如下:

 1 //接下来添加5帧栅格式的退出动画
 2             for(var h=1;h<=5;h++)
 3             {
 4                 var int_x=Math.floor((10+h)%5);
 5                 var int_y=Math.floor((10+h)/5);
 6                 con_res.putImageData(data_back,int_x*360+60,int_y*360);
 7                 con_res.fillStyle="rgba(0,255,0,1)";//考虑到对半透明的检查,在show图片时可以先绘制一个绿屏背景!!
 8                 con_res.lineWidth=0;
 9                 for(var i=0;i<4;i++)
10                 {
11                     for(var j=0;j<6;j++)
12                     {
13                         con_res.beginPath();
14                         con_res.arc(int_x*360+60+30+i*60,int_y*360+30+j*60,6*h,0,Math.PI*2);
15                         con_res.fill();//这个方法不能正常呈现a通道
16                     }
17 
18                 }
19             }
20             //将绿幕换成透明
21     
22             var data_res=con_res.getImageData(0,0,1800,1800);//
23             var len=1800*1800*4;
24             var datar=data_res.data;
25             for(var i=0;i<len;i+=4)
26             {//这个循环内加断点会导致运算超时
27                 if(datar[i]==0&&datar[i+1]==255&&datar[i+2]==0)
28                 {
29                     datar[i+1]=0;
30                     datar[i+3]=0;
31                 }
32             }
33             con_res.putImageData(data_res,0,0);

6、使用

经过前面的操作我们得到了棋子“兵”的精灵动画图片:

使用相同方法,我们可以得到其他五种棋子的精灵动画图片,或者添加更多的精灵动画帧。我们可以在Babylon.js之类WebGL引擎中使用这些精灵动画图片创建精灵动画,可以在这里找到Babylon.js的精灵动画文档:旧版文档:https://ljzc002.github.io/BABYLON101/14Sprites%20-%20Babylon.js%20Documentation.htm,新版文档:https://doc.babylonjs.com/divingDeeper/sprites/sprite_map_animations。(4.2版又有了很多新改变,也许要再次开始文档翻译工作了)

 

posted @ 2021-01-30 14:47  ljzc002  阅读(813)  评论(0编辑  收藏  举报