zoukankan      html  css  js  c++  java
  • 网页小实验——用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版又有了很多新改变,也许要再次开始文档翻译工作了)

  • 相关阅读:
    稀疏矩阵解题数学库 -- UMFPACK
    国外程序猿整理的C++大全
    SQL实用语句大全
    this 三句话
    ELK 7.4.2 单机安装配置
    简单搭建DNS服务器——bind
    关于博客皮肤
    Golang 实现 array_push
    Golang 发送POST请求,加header头,带参数
    Golang 签名
  • 原文地址:https://www.cnblogs.com/ljzc002/p/14348749.html
Copyright © 2011-2022 走看看