Home  >  Article  >  Web Front-end  >  Canvas Game Development Learning Part 6: Using Styles and Colors (2)

Canvas Game Development Learning Part 6: Using Styles and Colors (2)

黄舟
黄舟Original
2017-01-16 17:56:431239browse

Line styles

The line style can be set through a series of properties.

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

I will explain these properties in detail, but it may be easier to understand through the following examples.

Example of lineWidth property

This property sets the thickness of the currently drawn line. Property value must be positive. The default value is 1.0. Line width refers to the thickness of a given path from the center to the sides. In other words, draw half the line width on each side of the path. Because canvas coordinates do not correspond directly to pixels, special attention must be paid when obtaining precise horizontal or vertical lines. In the example below, 10 lines are drawn with increasing width. The leftmost line has a width of 1.0 units. Moreover, the leftmost and all lines with odd widths cannot be rendered accurately because of the positioning problem of the path.

Canvas Game Development Learning Part 6: Using Styles and Colors (2)

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();  
     }  
  }

To obtain accurate lines, you must have an understanding of how lines are drawn. As shown in the figure below, a grid is used to represent the coordinate grid of the canvas. Each grid corresponds to a pixel on the screen. In the first picture, the rectangle from (2,1) to (5,5) is filled, and the boundary of the entire area falls exactly on the edge of the pixel, so that the resulting rectangle has clear edges.

Canvas Game Development Learning Part 6: Using Styles and Colors (2)

If you want to draw a line from (3,1) to (3,5) with a width of 1.0, you will get something like the second picture result. The actual fill area (dark blue) only extends to half the pixels on either side of the path. These half pixels are rendered in an approximate manner, which means that those pixels are only partially colored, resulting in the entire area (the light blue and dark blue parts) being filled with half a tone of the actual stroke color. This is why the line with a width of 1.0 in the example above is not accurate. To solve this problem, you must exert more precise control over the path. It is known that a line with a thickness of 1.0 will extend half a pixel on both sides of the path, then draw a line from (3.5,1) to (3.5,5) like the third picture, and its edge will fall exactly on the pixel boundary, and the filling will be accurate A line with a width of 1.0. For lines with an even width, the number of pixels on each side is an integer, then you want the path to fall between the pixels (such as from (3,1) to (3,5)) rather than within the pixels point in the middle. Also, notice that the vertical line in that example has its Y coordinate exactly falling on the grid line. If it doesn't, there will also be half-rendered pixels at the endpoints. Although working with scalable 2D graphics can be a bit of a pain at first, early attention to the relationship between the pixel grid and path position can ensure that the graphics will keep looking good after being scaled or otherwise deformed: line width After magnifying 2 times, the vertical line with a width of 1.0 will become a clear line with a width of 2.0 and appear where it should appear.

lineCap
Example of properties

Properties

The pointer of lineCap determines how the endpoints of the line segment are displayed. It can be one of three types: butt, round, and square. The default is butt.
In this example, I drew three straight lines and assigned them different lineCap values. There are also two auxiliary lines. In order to see the difference between them more clearly, the starting points and end points of the three lines all fall on the auxiliary lines. The leftmost line uses the default button. Notice that it is flush with the guide line. The middle one is the round effect, with a semicircle with a radius of half the line width added to the endpoint. The one on the right is the effect of a square, with a square of equal width and half the line width added to the endpoint.

Canvas Game Development Learning Part 6: Using Styles and Colors (2)

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
Example of attributes

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

Canvas Game Development Learning Part 6: Using Styles and Colors (2)

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 Game Development Learning Part 6: Using Styles and Colors (2)

Canvas Game Development Learning Part 6: Using Styles and Colors (2)

渐变 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 Game Development Learning Part 6: Using Styles and Colors (2)

第二种渐变,我并不是从 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 Game Development Learning Part 6: Using Styles and Colors (2)

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 Game Development Learning Part 6: Using Styles and Colors (2)

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)!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn