網頁小實驗——用canvas生成精靈動畫圖片

ljzc002發表於2021-01-30

實驗目標:藉助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的畫素點是否在棋子“兵”內,如果在棋子內則原樣呈現,否則根據畫素的位置計算畫素的顏色,一種實現方法如下:

網頁小實驗——用canvas生成精靈動畫圖片
  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版又有了很多新改變,也許要再次開始文件翻譯工作了)

 

相關文章