首頁  >  文章  >  web前端  >  canvas遊戲開發學習之六:運用樣式與顏色(二)

canvas遊戲開發學習之六:運用樣式與顏色(二)

黄舟
黄舟原創
2017-01-16 17:56:431239瀏覽

線型 Line styles

可以透過一系列屬性來設定線的樣式。

lineWidth = value
lineCap = type
lineJoin = type
miterLimit = value

我會詳細介紹這些屬性,不過透過以下的範例可能會更容易理解。

lineWidth 屬性的例子

這 個屬性設定目前繪線的粗細。屬性值必須為正數。預設值是1.0。線寬是指給定路徑的中心到兩邊的粗細。換句話說就是路徑的兩邊各繪製線寬的一半。因為畫 布的座標並不和像素直接對應,所以需要得到精確的水平或垂直線的時候要特別注意。在下面的範例中,用遞增的寬度繪製了10條直線。最左邊的線寬1.0單位。 而且,最左邊的以及所有寬度為奇數的線並不能精確呈現,這就是因為路徑的定位問題。

canvas遊戲開發學習之六:運用樣式與顏色(二)

function draw() {  
     var ctx = document.getElementById('canvas').getContext('2d');  
     for (var i = 0; i < 10; i++){  
       ctx.lineWidth = 1+i;  
       ctx.beginPath();  
       ctx.moveTo(5+i*14,5);  
       ctx.lineTo(5+i*14,140);  
       ctx.stroke();  
     }  
  }

想 要獲得精確的線條,必須對線條是如何描繪出來的有所理解。見下圖,用網格來代表 canvas 的座標格,每一格對應螢幕上像素點。在第一個圖中,填滿了 (2,1) 至 (5,5) 的矩形,整個區域的邊界剛好落在像素邊緣上,這樣就可以得到的矩形有著清晰的邊緣。

canvas遊戲開發學習之六:運用樣式與顏色(二)

如 果你想要繪製一條從 (3,1) 到 (3,5),寬度是 1.0 的線條,你會得到像第二幅圖一樣的結果。實際填滿區域(深藍色部分)僅延伸至路徑兩旁各一半像素。而這半個像素又會以近似的方式進行渲染,這意味著那些 像素只是部分著色,結果就是以實際筆觸顏色一半色調的顏色來填充整個區域(淺藍和深藍的部分)。這就是上例中為何寬度為 1.0 的線並不準確的原因。要解決這個問題,你必須對路徑施以更精確的控制。已知粗1.0 的線條會在路徑兩邊各延伸半像素,那麼像第三幅圖那樣繪製從(3.5,1) 到(3.5,5) 的線條,其邊緣正好落在像素邊界,填充出來就是準確的寬為1.0 的線條。對於那些寬度為偶數的線條,每一邊的像素數都是整數,那麼你想要其路徑是落在像素點之間(如那從(3,1) 到(3,5)) 而不是在像素點的中間。同樣,注意到那個例子的垂直線條,其 Y 座標剛好落在網格線上,如果不是的話,端點上同樣會出現半渲染的像素點。雖然開始處理可縮放的2D 圖形時會有點小痛苦,但是及早注意到像素網格與路徑位置之間的關係,可以確保圖形在經過縮放或其它任何變形後都可以保持看上去蠻好:線寬為1.0 的垂線在放大2 倍後,會變成清晰的線寬為2.0,並且出現在它應該出現的位置。

lineCap
屬性的例子

屬性

lineCap的指決定了線段端點顯示的樣子。它可以為下面的三種的其中之一:butt,round和square。預設是butt。
這個範例裡面,我畫了三條直線,分別賦予不同的lineCap值。還有兩條輔助線,為了可以看得更清楚它們之間的差別,三條線的起點終點都落在輔助線上。最左邊的線用了預設的butt。可以注意到它是與輔助線齊平的。中間的是round的效果,端點加上了半徑為一半線寬的半圓。右邊的是square的效果,端點出加上了等寬且高度為一半線寬的方塊。

canvas遊戲開發學習之六:運用樣式與顏色(二)

function draw() {  
     var ctx = document.getElementById(&#39;canvas&#39;).getContext(&#39;2d&#39;);  
     var lineCap = [&#39;butt&#39;,&#39;round&#39;,&#39;square&#39;];  
      
     // Draw guides  
     ctx.strokeStyle = &#39;#09f&#39;;  
     ctx.beginPath();  
     ctx.moveTo(10,10);  
     ctx.lineTo(140,10);  
     ctx.moveTo(10,140);  
     ctx.lineTo(140,140);  
     ctx.stroke();  
     
     // Draw lines  
     ctx.strokeStyle = &#39;black&#39;;  
     for (var i=0;i<lineCap.length;i++){  
       ctx.lineWidth = 15;  
       ctx.lineCap = lineCap[i];  
       ctx.beginPath();  
       ctx.moveTo(25+i*50,10);  
       ctx.lineTo(25+i*50,140);  
       ctx.stroke();  
     }  
   }

lineJoin
屬性的例子

lineJoin的属性值决定了图形中两线段连接处所显示的样子。它可以是这三种之一:round,bevel和miter。默认是miter。
这里我同样用三条折线来做例子,分别设置不同的lineJoin值。最上面一条是round的效果,边角处被磨圆了,圆的半径等于线宽。中间和最下面一条分别是 bevel 和 miter的效果。当值是miter的时候,线段会在连接处外侧延伸直至交于一点,延伸效果受到下面将要介绍的miterLimit属性的制约。

canvas遊戲開發學習之六:運用樣式與顏色(二)

function draw() {  
      var ctx = document.getElementById(&#39;canvas&#39;).getContext(&#39;2d&#39;);  
      var lineJoin = [&#39;round&#39;,&#39;bevel&#39;,&#39;miter&#39;];  
      ctx.lineWidth = 10;  
      for (var i=0;i<lineJoin.length;i++){  
        ctx.lineJoin = lineJoin[i];  
        ctx.beginPath();  
        ctx.moveTo(-5,5+i*40);  
        ctx.lineTo(35,45+i*40);  
        ctx.lineTo(75,5+i*40);  
        ctx.lineTo(115,45+i*40);  
        ctx.lineTo(155,5+i*40);  
        ctx.stroke();  
     }  
   }

miterLimit
属性的演示例子

就如上一个例子所见的应用miter
的效果,线段的外侧边缘会延伸交汇于一点上。线段直接夹角比较大的,交点不会太远,但当夹角减少时,交点距离会呈指数级增大。miterLimit
属性就是用来设定外延交点与连接点的最大距离,如果交点距离大于此值,连接效果会变成了 bevel。

canvas遊戲開發學習之六:運用樣式與顏色(二)

canvas遊戲開發學習之六:運用樣式與顏色(二)

渐变 Gradients

就好像一般的绘图软件一样,我们可以用线性或者径向的渐变来填充或描边。我们用下面的方法新建一个canvasGradient
对象,并且赋给图形的fillStyle或strokeStyle


属性。

createLinearGradient(x1,y1,x2,y2)
createRadialGradient(x1,y1,r1,x2,y2,r2)


createLinearGradient方法接受 4 个参数,表示渐变的起点 (x1,y1) 与终点 (x2,y2)。createRadialGradient方法接受 6 个参数,前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆。

var lineargradient = ctx.createLinearGradient(0,0,150,150);  
var radialgradient = ctx.createRadialGradient(75,75,0,75,75,100);


创建出canvasGradient对象后,我们就可以用addColorStop方法给它上色了。

addColorStop(position, color)

addColorStop
方法接受 2 个参数,position参数必须是一个 0.0 与 1.0 之间的数值,表示渐变中颜色所在的相对位置。例如,0.5 表示颜色会出现在正中间。color参数必须是一个有效的 CSS 颜色值(如 #FFF, rgba(0,0,0,1),等等)。你可以根据需要添加任意多个色标(color stops)。下面是最简单的线性黑白渐变的例子。

var lineargradient = ctx.createLinearGradient(0,0,150,150);  
 lineargradient.addColorStop(0,&#39;white&#39;);  
 lineargradient.addColorStop(1,&#39;black&#39;);

createLinearGradient
的例子

本例中,我弄了两种不同的渐变。第一种是背景色渐变,你会发现,我给同一位置设置了两种颜色,你也可以用这来实现突变的效果,就像这里从白色到绿色的突 变。一般情况下,色标的定义是无所谓顺序的,但是色标位置重复时,顺序就变得非常重要了。所以,保持色标定义顺序和它理想的顺序一致,结果应该没什么大问题。

canvas遊戲開發學習之六:運用樣式與顏色(二)

第二种渐变,我并不是从 0.0 位置开始定义色标,因为那并不是那么严格的。在 0.5 处设一黑色色标,渐变会默认认为从起点到色标之间都是黑色。你会发现,strokeStyle
和fillStyle属性都可以接受canvasGradient对象。

function draw() {  
   var ctx = document.getElementById(&#39;canvas&#39;).getContext(&#39;2d&#39;);  
   
   // Create gradients  
   var lingrad = ctx.createLinearGradient(0,0,0,150);  
   lingrad.addColorStop(0, &#39;#00ABEB&#39;);  
   lingrad.addColorStop(0.5, &#39;#fff&#39;);  
   //lingrad.addColorStop(0.5, &#39;#26C000&#39;);  
   //lingrad.addColorStop(1, &#39;#fff&#39;);  
   
   var lingrad2 = ctx.createLinearGradient(0,50,0,95);  
   lingrad2.addColorStop(0.5, &#39;#000&#39;);  
   lingrad2.addColorStop(1, &#39;rgba(0,0,0,0)&#39;);  
   
   // assign gradients to fill and stroke styles  
   ctx.fillStyle = lingrad;  
   ctx.strokeStyle = lingrad2;  
     
   // draw shapes  
   ctx.fillRect(10,10,130,130);  
   ctx.strokeRect(50,50,50,50);

createRadialGradient
的例子

这个例子,我定义了 4 个不同的径向渐变。由于可以控制渐变的起始与结束点,所以我们可以实现一些比(如在 Photoshop 中所见的)经典的径向渐变更为复杂的效果。(经典的径向渐变是只有一个中心点,简单地由中心点向外围的圆形扩张)。这里,我让起点稍微偏离终点,这样可以达到一种球状 3D 效果。但最好不要让里圆与外圆部分交叠,那样会产生什么效果就真是不得而知了。4 个径向渐变效果的最后一个色标都是透明色。如果想要两色标直接的过渡柔和一些,只要两个颜色值一致就可以了。代码里面看不出来,是因为我用了两种不同的颜色表示方法,但其实是相同的,#019F62 = rgba(1,159,98,1)。

canvas遊戲開發學習之六:運用樣式與顏色(二)

function draw() {
  var ctx = document.getElementById(&#39;canvas&#39;).getContext(&#39;2d&#39;);

  // Create gradients
  var radgrad = ctx.createRadialGradient(45,45,10,52,50,30);
  radgrad.addColorStop(0, &#39;#A7D30C&#39;);
  radgrad.addColorStop(0.9, &#39;#019F62&#39;);
  radgrad.addColorStop(1, &#39;rgba(1,159,98,0)&#39;);
  
  var radgrad2 = ctx.createRadialGradient(105,105,20,112,120,50);
  radgrad2.addColorStop(0, &#39;#FF5F98&#39;);
  radgrad2.addColorStop(0.75, &#39;#FF0188&#39;);
  radgrad2.addColorStop(1, &#39;rgba(255,1,136,0)&#39;);

  var radgrad3 = ctx.createRadialGradient(95,15,15,102,20,40);
  radgrad3.addColorStop(0, &#39;#00C9FF&#39;);
  radgrad3.addColorStop(0.8, &#39;#00B5E2&#39;);
  radgrad3.addColorStop(1, &#39;rgba(0,201,255,0)&#39;);

  var radgrad4 = ctx.createRadialGradient(0,150,50,0,140,90);
  radgrad4.addColorStop(0, &#39;#F4F201&#39;);
  radgrad4.addColorStop(0.8, &#39;#E4C700&#39;);
  radgrad4.addColorStop(1, &#39;rgba(228,199,0,0)&#39;);
  
  // draw shapes
  ctx.fillStyle = radgrad4;
  ctx.fillRect(0,0,150,150);
  ctx.fillStyle = radgrad3;
  ctx.fillRect(0,0,150,150);
  ctx.fillStyle = radgrad2;
  ctx.fillRect(0,0,150,150);
  ctx.fillStyle = radgrad;
  ctx.fillRect(0,0,150,150);
}

图案 Patterns

上一节的一个例子里面,我用了循环来实现图案的效果。其实,有一个更加简单的方法:createPattern。


createPattern(image,type)

该方法接受两个参数。Image 可以是一个Image对象的引用,或者另一个 canvas 对象。Type 必须是下面的字符串值之一:repeat,repeat-x,repeat-y
和no-repeat。图案的应用跟渐变很类似的,创建出一个 pattern 之后,赋给fillStyle或strokeStyle属性即可。

var img = new Image();  
 img.src = &#39;someimage.png&#39;;  
 var ptrn = ctx.createPattern(img,&#39;repeat&#39;);

注意:与 drawImage 有点不同,你需要确认 image 对象已经装载完毕,否则图案可能效果不对的。Firefox 目前只支持属性值repeat。如果赋其它值,什么效果都没有的。

createPattern
的例子

这最后的例子,我创建一个图案然后赋给了fillStyle属性。值得一提的是,使用 Image 对象的onloadhandler 来确保设置图案之前图像已经装载完毕。

canvas遊戲開發學習之六:運用樣式與顏色(二)

function draw() {
  var ctx = document.getElementById(&#39;canvas&#39;).getContext(&#39;2d&#39;);
  // create new image object to use as pattern
  var img = new Image();
  img.src = &#39;images/wallpaper.png&#39;;
  img.onload = function(){
    // create pattern
    var ptrn = ctx.createPattern(img,&#39;repeat&#39;);
    ctx.fillStyle = ptrn;
    ctx.fillRect(0,0,150,150);
  }
  }

以上就是canvas游戏开发学习之六:运用样式与颜色(二)的内容,更多相关内容请关注PHP中文网(www.php.cn)!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn