canvas遊戲開發學習之六:運用樣式與顏色(二)
線型 Line styles
可以透過一系列屬性來設定線的樣式。
lineWidth = value lineCap = type lineJoin = type miterLimit = value
我會詳細介紹這些屬性,不過透過以下的範例可能會更容易理解。
lineWidth 屬性的例子
這 個屬性設定目前繪線的粗細。屬性值必須為正數。預設值是1.0。線寬是指給定路徑的中心到兩邊的粗細。換句話說就是路徑的兩邊各繪製線寬的一半。因為畫 布的座標並不和像素直接對應,所以需要得到精確的水平或垂直線的時候要特別注意。在下面的範例中,用遞增的寬度繪製了10條直線。最左邊的線寬1.0單位。 而且,最左邊的以及所有寬度為奇數的線並不能精確呈現,這就是因為路徑的定位問題。
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) 的矩形,整個區域的邊界剛好落在像素邊緣上,這樣就可以得到的矩形有著清晰的邊緣。
如 果你想要繪製一條從 (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的效果,端點出加上了等寬且高度為一半線寬的方塊。
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var lineCap = ['butt','round','square']; // Draw guides ctx.strokeStyle = '#09f'; ctx.beginPath(); ctx.moveTo(10,10); ctx.lineTo(140,10); ctx.moveTo(10,140); ctx.lineTo(140,140); ctx.stroke(); // Draw lines ctx.strokeStyle = 'black'; 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属性的制约。
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var lineJoin = ['round','bevel','miter']; 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。
渐变 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,'white'); lineargradient.addColorStop(1,'black');
createLinearGradient
的例子
本例中,我弄了两种不同的渐变。第一种是背景色渐变,你会发现,我给同一位置设置了两种颜色,你也可以用这来实现突变的效果,就像这里从白色到绿色的突 变。一般情况下,色标的定义是无所谓顺序的,但是色标位置重复时,顺序就变得非常重要了。所以,保持色标定义顺序和它理想的顺序一致,结果应该没什么大问题。
第二种渐变,我并不是从 0.0 位置开始定义色标,因为那并不是那么严格的。在 0.5 处设一黑色色标,渐变会默认认为从起点到色标之间都是黑色。你会发现,strokeStyle
和fillStyle属性都可以接受canvasGradient对象。
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); // Create gradients var lingrad = ctx.createLinearGradient(0,0,0,150); lingrad.addColorStop(0, '#00ABEB'); lingrad.addColorStop(0.5, '#fff'); //lingrad.addColorStop(0.5, '#26C000'); //lingrad.addColorStop(1, '#fff'); var lingrad2 = ctx.createLinearGradient(0,50,0,95); lingrad2.addColorStop(0.5, '#000'); lingrad2.addColorStop(1, 'rgba(0,0,0,0)'); // 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)。
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); // Create gradients var radgrad = ctx.createRadialGradient(45,45,10,52,50,30); radgrad.addColorStop(0, '#A7D30C'); radgrad.addColorStop(0.9, '#019F62'); radgrad.addColorStop(1, 'rgba(1,159,98,0)'); var radgrad2 = ctx.createRadialGradient(105,105,20,112,120,50); radgrad2.addColorStop(0, '#FF5F98'); radgrad2.addColorStop(0.75, '#FF0188'); radgrad2.addColorStop(1, 'rgba(255,1,136,0)'); var radgrad3 = ctx.createRadialGradient(95,15,15,102,20,40); radgrad3.addColorStop(0, '#00C9FF'); radgrad3.addColorStop(0.8, '#00B5E2'); radgrad3.addColorStop(1, 'rgba(0,201,255,0)'); var radgrad4 = ctx.createRadialGradient(0,150,50,0,140,90); radgrad4.addColorStop(0, '#F4F201'); radgrad4.addColorStop(0.8, '#E4C700'); radgrad4.addColorStop(1, 'rgba(228,199,0,0)'); // 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 = 'someimage.png'; var ptrn = ctx.createPattern(img,'repeat');
注意:与 drawImage 有点不同,你需要确认 image 对象已经装载完毕,否则图案可能效果不对的。Firefox 目前只支持属性值repeat。如果赋其它值,什么效果都没有的。
createPattern
的例子
这最后的例子,我创建一个图案然后赋给了fillStyle属性。值得一提的是,使用 Image 对象的onloadhandler 来确保设置图案之前图像已经装载完毕。
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); // create new image object to use as pattern var img = new Image(); img.src = 'images/wallpaper.png'; img.onload = function(){ // create pattern var ptrn = ctx.createPattern(img,'repeat'); ctx.fillStyle = ptrn; ctx.fillRect(0,0,150,150); } }
以上就是canvas游戏开发学习之六:运用样式与颜色(二)的内容,更多相关内容请关注PHP中文网(www.php.cn)!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

使用Go語言打造令人驚嘆的遊戲,包括以下步驟:設定項目:使用Git創建一個新專案並創建必要的檔案。編寫遊戲邏輯:在game.go中編寫核心遊戲邏輯,例如猜數字遊戲。編寫入口點:在main.go中建立遊戲的入口點,允許使用者輸入和處理猜測。編譯與運行:編譯和運行遊戲,實戰案例是猜數字遊戲,使用者可以輸入0到99之間的數字並獲得回饋。

在遊戲開發中選擇Java框架時,應考慮專案的特定需求。可供選擇的Java遊戲框架包括:LibGDX:適用於跨平台2D/3D遊戲。 JMonkeyEngine:用於建立複雜3D遊戲。 Slick2D:適用於輕量級2D遊戲。 AndEngine:專門針對Android開發的2D遊戲引擎。 Kryonet:提供網路連線功能。例如,對於2DRPG遊戲,LibGDX因其跨平台支援、輕量級設計和活躍社群而成為理想選擇。

探索Canvas框架:了解常用的Canvas框架有哪些,需要具體程式碼範例引言:Canvas是HTML5中提供的一個繪圖API,透過它我們可以實現豐富的圖形和動畫效果。為了提高繪圖的效率和便利性,許多開發者開發了不同的Canvas框架。本文將介紹一些常用的Canvas框架,並提供具體程式碼範例,以幫助讀者更深入地了解這些框架的使用方法。一、EaselJS框架Ea

在現今的軟體開發領域中,Golang(Go語言)作為一種高效、簡潔、並發性強的程式語言,越來越受到開發者的青睞。其豐富的標準庫和高效的並發特性使它成為遊戲開發領域的一個備受關注的選擇。本文將探討如何利用Golang來實現遊戲開發,並透過具體的程式碼範例來展示其強大的可能性。 1.Golang在遊戲開發中的優勢作為靜態類型語言,Golang正在建構大型遊戲系統

uniapp實現如何使用canvas繪製圖表和動畫效果,需要具體程式碼範例一、引言隨著行動裝置的普及,越來越多的應用程式需要在行動裝置上展示各種圖表和動畫效果。而uniapp作為一款基於Vue.js的跨平台開發框架,提供了使用canvas繪製圖表和動畫效果的能力。本文將介紹uniapp如何使用canvas來實現圖表和動畫效果,並給出具體的程式碼範例。二、canvas

Go框架在遊戲開發中的實戰案例:技術堆疊:Gov1.18、Gin框架、MongoDB架構:Web伺服器(處理HTTP請求)、遊戲伺服器(處理遊戲邏輯和通訊)、MongoDB資料庫(儲存玩家資料)Web伺服器:使用Gin路由處理玩家創建和獲取請求遊戲伺服器:處理遊戲邏輯和玩家通信,使用UNIX套接字進行網絡通信數據庫:使用MongoDB存儲玩家數據,提供創建和獲取玩家信息的功能實戰案例功能:創建玩家、獲取玩家、更新玩家狀態、處理玩家互動結論:Go框架提供了高效

了解JavaScript中的遊戲開發和實體引擎,需要具體程式碼範例近年來,隨著網路的快速發展,Web遊戲成為了人們娛樂生活中的重要組成部分。而作為Web前端開發的主要技術之一,JavaScript在遊戲開發中扮演了舉足輕重的角色。本文將介紹一些關於JavaScript遊戲開發和實體引擎的基本知識,並提供一些具體的程式碼範例。遊戲開發入門在進行遊戲開發前,我們首

C++是一種強大的程式語言,被廣泛應用於遊戲開發領域。如果你對遊戲開發感興趣,並且有一定的程式設計基礎,那麼本文將幫助你入門C++遊戲開發,並從零開始實現自己的遊戲專案。第一步:準備工作在開始之前,確保你已經安裝了一個C++編譯器,例如MicrosoftVisualStudio或Code::Blocks等。這些工具將幫助你編譯和運行你的遊戲專案。第二步:學
