iT邦幫忙

10

[筆記][HTML][JavaScript]canvas的基本用法(1)-來繪製一些簡單的圖形吧!

大家好啊!又到了每週一次的動頭腦...不對!這禮拜沒有了,哈哈哈,前一陣子啊,小弟我參加了一個活動(在這裡),主要是在九個禮拜的時間,每個禮拜都會出一個主題讓大家練習前端的能力,現在還剩下最後兩週,大家還來得及去報名XD,好啦!以上是題外話,主要是這禮拜的題目非常有趣,他要用canvas去做出一個遊戲,設計稿在這裡,第一次看到真的差點閃尿,不過還是很認命的找資料慢慢畫,既然機會難得,就把這次的學習紀錄起來吧!

首先canvas他是HTML的原生標籤之一,我們可以透過JS把它當作一個白板,在上面繪製各種圖案以及動畫,至於要怎麼做呢?可能需要一點數學公式、三角函數、圓周角定理...欸!等等!先不要按上一頁,其實那一些我也都不太懂,哈哈哈,我們需要做的是跟著感覺走XD,走久了就知道怎麼做是對的了,哈哈,那介紹完後(其實根本沒介紹什麼XD)我們開始實作!

首先,就像其他HTML標籤一樣,想要canvas就先下一個canvas標籤吧!

<canvas id="myCanvas"></canvas>

OK!那我們就完成HTML的建置作業了!接下來就是JavaScript的主場了,首先我們先去找到canvas標籤。

//這一行去抓取canvas的標籤
let canvas = document.getElementById("myCanvas");
//接著指定繪圖方式
let ctx = canvas.getContext("2d");
//讓canvas的高度和寬度等於整個畫面,讓整個視窗都是你的畫布
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;

接著建置作業完成,就可以在上面畫畫了!那我們來看一下怎麼畫吧!

首先是線:

//在繪製任何東西之前,我們都要來個開始,像全天下所有的故事一樣
ctx.beginPath();
//我們用moveTo(x,y)來指定線的起點座標
ctx.moveTo(50,50)
//之後使用lineTo(x,y)來指定與前一個座標相連的點
ctx.lineTo(100,50)
//用stroke()來繪製相連點的線
ctx.stroke()

上方的程式碼應該會出現下圖的結果,也就是一條水平線:
https://ithelp.ithome.com.tw/upload/images/20180723/201069357hPNGy3H23.jpg
可以觀察出來座標的(x,y)是以左到右,由上而下越來越大,就像一般網頁的佈局一樣,這個觀念會用到以後所有的圖形,所以要好好記著哦!

再來我們試著把剛剛的線給圍成一個三角形(上一段的註解我就先拿掉了)!

ctx.beginPath();
ctx.moveTo(50,50)
ctx.lineTo(100,50)
ctx.lineTo(50,100)
//在用lineTo()把線連回原點的位置,圍成三角形
ctx.lineTo(50,50)
/*而除了在連回原點外,也可以使用closePath()
他會把最後一個點及起點座標相連,上下兩行擇一就行了!*/
ctx.closePath()
ctx.stroke()

上方程式碼會呈現出如下的三角形:
https://ithelp.ithome.com.tw/upload/images/20180723/20106935HDb5l4bsW2.jpg
現在的他是黑白的,我們來為他填上色彩和加粗線調寬度吧!

//使用lineWidth指定線條寬度
ctx.lineWidth = 3
//使用strokeStyle指定線條顏色
ctx.strokeStyle = "#0000FF"
//用fillStyle指定填滿色彩
ctx.fillStyle = "#FF0000"
ctx.beginPath()
ctx.moveTo(50,50)
ctx.lineTo(100,50)
ctx.lineTo(50,100)
ctx.closePath()
//用fill()填滿圍起來的範圍
ctx.fill()
ctx.stroke()

我們經過上面的調整,得到的三角形會變成下方的樣子。
https://ithelp.ithome.com.tw/upload/images/20180723/20106935jkihlzWm1o.jpg
順帶一提,如果在沒有圍起來的範圍使用fill()是一點用都沒有的哦!

那線畫完後,我們來學著怎麼畫四角形吧!雖然也可以使用以上的方式處理,但是canvas在四角形部分已經有現成的函數了:

ctx.beginPath()
//沿用寬度及色彩設定
ctx.lineWidth = 3;
ctx.strokeStyle = "#0000FF"
ctx.fillStyle = "#FF0000"
/*使用rect(x,y,w,h)繪製四角形
x,y一樣是座標,w和h是四邊形的寬和高*/
ctx.rect(50,50,80,100);
ctx.fill()
ctx.stroke()

使用rect()就可以直接指定坐標及寬高,不需要再指定四個點來用線連起來!現在我們會得到下方的四角形:
https://ithelp.ithome.com.tw/upload/images/20180723/20106935Nigtcz3PHy.jpg
這邊我再PS一下,使用rect()來畫四角形的話,如果沒有接著stroke()就不會有框線,沒有fill()就不會填滿,感覺在說廢話,哈哈,不過他們並不是必要的,只是和線不一樣的是stroke()fill()可以擇一使用。然後是關於座標,他會以四角形的左上角去對齊指定的座標!

最後我們來畫圓吧!這邊用的是arc()來處理:

ctx.beginPath()
//沿用寬度及色彩設定
ctx.lineWidth = 3;
ctx.strokeStyle = "#0000FF"
ctx.fillStyle = "#FF0000"
/*使用arc(x,y,r,s,e)畫一個圓
x,y是圓心的座標,r是半徑,s和e是起點和終點的角度*/
ctx.arc(50,50,25,0,Math.PI*2)
ctx.fill()
ctx.stroke()

arc()的第4和5的參數是指從幾度開始的角度,在上方的程式碼中從0度開始,繪製出360度的圓,因為Math.PI是代表180度,乘上2就變成360度,所以從0度開始繪製360度就是一個完整的圓了!所以如果要半圓就把arc()內改成ctx.arc(50,50,25,0,Math.PI),就是一個半圓弧形了!我們先看一下目前的圓形及arc()的角度概念吧!
https://ithelp.ithome.com.tw/upload/images/20180724/2010693504414fOrmj.jpg
上方右邊的圖,簡單說明了arc()的起點角度及終點角度(真的很簡單XD),所以如果我要畫一個,像月亮那樣左半邊的圓,起點就從90度開始,到上方的270度ctx.arc(50,50,25,Math.PI/2,Math.PI*1.5)就會出現一個左半圓了!
https://ithelp.ithome.com.tw/upload/images/20180724/20106935RbxidrZWdU.jpg

講到這裡,感覺應該要實作畫出一些東西,當作文章的結尾才算完整,那我們來畫一顆神奇寶貝球吧!

let canvas = document.getElementById("myCanvas")
let ctx = canvas.getContext("2d")

canvas.height = window.innerHeight
canvas.width = window.innerWidth;

//畫一個下半圓,指定顏色為白色
ctx.beginPath()
ctx.lineWidth = 3;
ctx.fillStyle = "#FFFFFF"
ctx.arc(100,100,50,0,Math.PI)
ctx.fill()
ctx.stroke()

//畫一個上半圓,指定顏色為紅色
ctx.beginPath()
ctx.fillStyle = "#FF0000"
ctx.arc(100,100,50,Math.PI,Math.PI*2)
ctx.fill()
ctx.stroke()

//畫中間的線和圈圈,指定顏色為白色
ctx.beginPath()
ctx.fillStyle = "#FFFFFF"
//從圓的左邊開始
ctx.moveTo(50,100)
//連到中間後接著一個上半圓
ctx.arc(100,100,10,Math.PI,Math.PI*2)
//繞過去後再畫一條直線到圓的右邊
ctx.lineTo(150,100)
//最後沿著線繞回來畫一個下半圓
ctx.arc(100,100,10,0,Math.PI*2)
ctx.fill()
ctx.stroke()

//畫一個圓形,中間的那個圈圈按鈕
ctx.beginPath()
ctx.arc(100,100,5,0,Math.PI*2)
ctx.stroke()

成品如下:
https://ithelp.ithome.com.tw/upload/images/20180724/20106935im9rOvFVWL.jpg
用上面的技巧就可以畫出一些簡單的圖形了,下一次我們再來實作關於動畫的部分,到時候整個網頁就會自己動起來了哦!

那關於這篇文章因為也打得滿晚的,怕會有一些地方沒有注意到或是有問題的,再麻煩各位大大留言告訴我,我一定會馬上修正的!另外如果有解釋不清楚的地方也歡迎留言問我!小弟會盡力找出解答的!謝謝大家觀看/images/emoticon/emoticon41.gif


1 則留言

3
Homura
iT邦研究生 4 級 ‧ 2018-07-24 15:35:22

看到這個就想到以前選修一堂OpenGL的課程
感覺很無聊所以都沒在聽課...
最後考試時畫出一個房子就過了/images/emoticon/emoticon06.gif

看更多先前的回應...收起先前的回應...

哈哈,那個感覺難很多,
而且我下一篇就是想畫個房子XD
怎麼把梗破得那麼突然,哈哈哈。

Homura iT邦研究生 4 級‧ 2018-07-25 00:01:54 檢舉

這麼剛好/images/emoticon/emoticon06.gif

小魚 iT邦好手 1 級‧ 2018-07-25 00:24:35 檢舉

畫個台灣地圖吧,這我比較感興趣
/images/emoticon/emoticon39.gif

Homura iT邦研究生 4 級‧ 2018-07-25 08:42:31 檢舉

這太難了吧/images/emoticon/emoticon02.gif

哈哈哈,我也覺得困難
感覺要算好多點和圓弧/images/emoticon/emoticon13.gif
不然我把房子進階成街道好了XD
這禮拜還要研究視差滾動/images/emoticon/emoticon02.gif

fysh711426 iT邦研究生 5 級‧ 2018-07-25 12:40:45 檢舉

是指這個可怕的東西嗎?/images/emoticon/emoticon17.gif
https://ithelp.ithome.com.tw/upload/images/20180725/20106935GgpmDnXMdA.jpg

Homura iT邦研究生 4 級‧ 2018-07-25 17:54:59 檢舉

看起來很難@@

小魚 iT邦好手 1 級‧ 2018-07-26 00:51:06 檢舉

會想問台灣地圖是因為最近想做策略遊戲,
正在煩惱那個地圖到底是怎麼畫出來的,
而且還會變色...

fysh711426 iT邦研究生 5 級‧ 2018-07-26 18:31:13 檢舉

哈哈哈,對,天賦樹,很酷,也蠻好奇 Google Map 怎麼用 canvas 畫出地圖。

小魚大大,自己規劃遊戲感覺很厲害!
說不定我可以試著挑戰看看/images/emoticon/emoticon06.gif
fysh711426大大,這應該需要加上資料庫來處理了吧,哈哈哈,話說我其實不曉得googleMap是不是用canvas畫的/images/emoticon/emoticon20.gif

理解canvas運作後可以用three.js進行比較複雜的偽3D創作

像天賦樹、GoogleMap這種
或許可創造一塊平板(plane)材質貼圖上去
設定攝影機從上帝視角(俯視)看下來
針對滑鼠的動作(點擊、Hover)去判斷座標或物件
給予回應的資訊

偷懶的做法XD

fillano iT邦超人 1 級‧ 2018-07-30 11:15:31 檢舉

用開發工具檢查了一下,google map看起來是用canvas畫出來的...

fillano iT邦超人 1 級‧ 2018-07-30 11:19:46 檢舉

如果是做遊戲,要看他怎麼呈現,也許不用canvas也做的出來。例如十幾年前做的小玩意:http://www.fillano.idv.tw/game.htm
(點一下「網頁遊戲測試 V0.12」就會跑出來)

joneshong大大,其實我對於canvas只有很基本的概念而已,不過還是希望之後能做一個非常動態的互動式網頁XD,您說的three.js我在找資料也曾經看過,當初只留下,哇賽!太神了吧!之類的印象,哈哈哈,不知道有沒有辦法走到那一步/images/emoticon/emoticon46.gif

fillano大大,哇那也太厲害了吧!畫那些地圖,計算移動距離,縮放那些計算我一想到頭就昏了,哈哈,話說那個頁面是大大自己開發的嗎?我有點進去感覺超厲害的啊!之前我也有看過類似的畫面,不過他是用canvas做的,在這裡:https://codepen.io/straker/pen/yasit,要是能做到這個程度,此生就無憾了XD

Homura iT邦研究生 4 級‧ 2018-07-30 14:14:06 檢舉

神Q超人小魚
我不知道你們知不知道這個網站
https://js1k.com/
裡面都是JS的作品
不少是做成遊戲
而且都有給Source
給你們參考看看

fillano iT邦超人 1 級‧ 2018-07-30 14:24:37 檢舉

除了圖,其他都是自己做的XD...地圖是用一塊一塊圖拼起來的,z-index隨著視角方向的深度會有不同,原理很簡單。

不過剛剛看了一下 A* 演算法的實做似乎有點bug,走的路線有點怪...指定的起點終點跟test39一樣時,路線不太一樣,年久失修...

這個程度只要用2D Canvas就能做得出來,我很久以前用SDL也做過一個。

傳統使用CPU進行這種圖片運算相當耗資源,而HTML5中的canvas是革命性的技術,能透過webgl使用GPU進行這種影像圖片的處理,效能是平方級的差距...如影片

大大什麼的承擔不起,只是最近剛好有接觸three.JS,我反而覺得比canvas好理解,以場景(sence)為畫布基底,設置一個攝影機(camera)為視角,把想要的元素(box.cube.light)加進去,靜態的就這樣而已很簡單,要做互動、動態的就在運行update的funtion就好了!分享幾個我覺得有趣的官方demo12

看大大分享的文章您應該有底子,寫過一兩次就會慢慢上手啦!

Homura大大
哇!我不知道有這個網頁!感謝大大分享!看以後我有沒機會做出什麼有趣的東西XD

fillano大大
我覺得興趣使然的遊戲製作師真的很厲害XD,而且大大的遊戲幾乎都用到演算法,感覺要很細心和經過一連串的頭痛才做得出來,不過還是覺得大大做的費拉諾蘭世界最厲害,哈哈,讓我也很心動想馬上做出一個XD,看這個系列,我可以把canvas研究到什麼程度吧/images/emoticon/emoticon13.gif

joneshong
哈哈,在這個領域上真的是大大沒錯啊!我在canvas動畫的資歷還只有兩個禮拜XD,不過真的很酷!以後還想做出更多有趣的東西!
其實上禮拜在做那個題目的時候,我也想過用three.js來做,但是最後想想如果原生的東西都沒摸過,我怕會搞不清楚哪個是套件的內容,就像我一開始就ASP.NET卻不曉得HTML一樣/images/emoticon/emoticon20.gif,之後有機會會在試著做看看,我有把他加入圓夢清單裡面XD

小魚 iT邦好手 1 級‧ 2018-07-31 08:14:30 檢舉

fillano joneshong Homura
感謝大大們的分享,
我最近在做單機的部分,
不知道有沒有關於單機遊戲的資源呢?
什麼語言都可以,
C++或C#尤佳,
感恩~

小魚 iT邦好手 1 級‧ 2018-07-31 08:18:15 檢舉

想問一下另外像這種歪來歪去的地圖是怎麼做出來的呢?
想做到點擊下去該區域會變色,
還會顯示該區域的資訊等等的...

https://ithelp.ithome.com.tw/upload/images/20180731/20105694Um1cunfchc.jpg

小魚大大
哈哈,我現在再加緊產生第二篇文章,說不定能達成你一點點的需求/images/emoticon/emoticon13.gif
雖然我還是用Web的canvas,不是用C#或C++/images/emoticon/emoticon70.gif

小魚 iT邦好手 1 級‧ 2018-07-31 11:55:05 檢舉

Web我也可以學學,
不過要像上面整個區域變色可以嗎?
還是要使用多邊形??
感覺有點麻煩...
也許可以試試看吧...

提供一種思路...
以現有建模軟體(3DMax,Maya,AutoCAD...)建立好這種不規則模型
再搭配three.js+OBJLoader
將模型畫在canvas的3D上..

將近兩年前的大學畢業專題是做類似功能...請參考

小魚大大
可以啊!我越來越覺得網頁什麼都做得到了XD,不過手刻原生是真的很麻煩沒有錯,要有超級耐心才辦得到了/images/emoticon/emoticon46.gif
fillano大大的那個網頁幾乎都手刻,開F12看原始碼,感覺就超級厲害!/images/emoticon/emoticon13.gif

joneshong大大
我之前大學也有看過學長姐的專題做模型展示屋,看來那也是用差不多的原理去畫成的,沒想到我現在才懂/images/emoticon/emoticon20.gif
發現我們同是臺南人!/images/emoticon/emoticon37.gif

fysh711426 iT邦研究生 5 級‧ 2018-08-05 11:28:18 檢舉

費拉諾蘭世界超強的!!!
three.js 也好厲害,完全就是遊戲引擎的感覺了。

做遊戲也是我的夢想,大學有跑去旁邊的遊戲設計系,修過幾堂 Unity 的課,不過後來被現實妥協了,沒有繼續往遊戲發展,哈哈哈。
/images/emoticon/emoticon02.gif

我要留言

立即登入留言