大家好啊!又到了每週一次的動頭腦...不對!這禮拜沒有了,哈哈哈,前一陣子啊,小弟我參加了一個活動(在這裡),主要是在九個禮拜的時間,每個禮拜都會出一個主題讓大家練習前端的能力,現在還剩下最後兩週,大家還來得及去報名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()
上方的程式碼應該會出現下圖的結果,也就是一條水平線:
可以觀察出來座標的(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()
上方程式碼會呈現出如下的三角形:
現在的他是黑白的,我們來為他填上色彩和加粗線調寬度吧!
//使用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()
我們經過上面的調整,得到的三角形會變成下方的樣子。
順帶一提,如果在沒有圍起來的範圍使用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()
就可以直接指定坐標及寬高,不需要再指定四個點來用線連起來!現在我們會得到下方的四角形:
這邊我再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()
的角度概念吧!
上方右邊的圖,簡單說明了arc()
的起點角度及終點角度(真的很簡單XD),所以如果我要畫一個,像月亮那樣左半邊的圓,起點就從90度開始,到上方的270度ctx.arc(50,50,25,Math.PI/2,Math.PI*1.5)
就會出現一個左半圓了!
講到這裡,感覺應該要實作畫出一些東西,當作文章的結尾才算完整,那我們來畫一顆神奇寶貝球吧!
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()
成品如下:
用上面的技巧就可以畫出一些簡單的圖形了,下一次我們再來實作關於動畫的部分,到時候整個網頁就會自己動起來了哦!
那關於這篇文章因為也打得滿晚的,怕會有一些地方沒有注意到或是有問題的,再麻煩各位大大留言告訴我,我一定會馬上修正的!另外如果有解釋不清楚的地方也歡迎留言問我!小弟會盡力找出解答的!謝謝大家觀看
看到這個就想到以前選修一堂OpenGL的課程
感覺很無聊所以都沒在聽課...
最後考試時畫出一個房子就過了
哈哈,那個感覺難很多,
而且我下一篇就是想畫個房子XD
怎麼把梗破得那麼突然,哈哈哈。
這麼剛好
畫個台灣地圖吧,這我比較感興趣
這太難了吧
哈哈哈,我也覺得困難
感覺要算好多點和圓弧
不然我把房子進階成街道好了XD
這禮拜還要研究視差滾動
是指這個可怕的東西嗎?
看起來很難@@
會想問台灣地圖是因為最近想做策略遊戲,
正在煩惱那個地圖到底是怎麼畫出來的,
而且還會變色...
哈哈哈,對,天賦樹,很酷,也蠻好奇 Google Map 怎麼用 canvas 畫出地圖。
給小魚大大,自己規劃遊戲感覺很厲害!
說不定我可以試著挑戰看看
給fysh711426大大,這應該需要加上資料庫來處理了吧,哈哈哈,話說我其實不曉得googleMap是不是用canvas畫的
理解canvas運作後可以用three.js進行比較複雜的偽3D創作
像天賦樹、GoogleMap這種
或許可創造一塊平板(plane)材質貼圖上去
設定攝影機從上帝視角(俯視)看下來
針對滑鼠的動作(點擊、Hover)去判斷座標或物件
給予回應的資訊
偷懶的做法XD
用開發工具檢查了一下,google map看起來是用canvas畫出來的...
如果是做遊戲,要看他怎麼呈現,也許不用canvas也做的出來。例如十幾年前做的小玩意:http://www.fillano.idv.tw/game.htm
(點一下「網頁遊戲測試 V0.12」就會跑出來)
給joneshong大大,其實我對於canvas只有很基本的概念而已,不過還是希望之後能做一個非常動態的互動式網頁XD,您說的three.js我在找資料也曾經看過,當初只留下,哇賽!太神了吧!之類的印象,哈哈哈,不知道有沒有辦法走到那一步
給fillano大大,哇那也太厲害了吧!畫那些地圖,計算移動距離,縮放那些計算我一想到頭就昏了,哈哈,話說那個頁面是大大自己開發的嗎?我有點進去感覺超厲害的啊!之前我也有看過類似的畫面,不過他是用canvas做的,在這裡:https://codepen.io/straker/pen/yasit,要是能做到這個程度,此生就無憾了XD
神Q超人小魚
我不知道你們知不知道這個網站
https://js1k.com/
裡面都是JS的作品
不少是做成遊戲
而且都有給Source
給你們參考看看
除了圖,其他都是自己做的XD...地圖是用一塊一塊圖拼起來的,z-index隨著視角方向的深度會有不同,原理很簡單。
不過剛剛看了一下 A* 演算法的實做似乎有點bug,走的路線有點怪...指定的起點終點跟test39一樣時,路線不太一樣,年久失修...
這個程度只要用2D Canvas就能做得出來,我很久以前用SDL也做過一個。
給Homura大大
哇!我不知道有這個網頁!感謝大大分享!看以後我有沒機會做出什麼有趣的東西XD
給fillano大大
我覺得興趣使然的遊戲製作師真的很厲害XD,而且大大的遊戲幾乎都用到演算法,感覺要很細心和經過一連串的頭痛才做得出來,不過還是覺得大大做的費拉諾蘭世界最厲害,哈哈,讓我也很心動想馬上做出一個XD,看這個系列,我可以把canvas研究到什麼程度吧
給joneshong
哈哈,在這個領域上真的是大大沒錯啊!我在canvas動畫的資歷還只有兩個禮拜XD,不過真的很酷!以後還想做出更多有趣的東西!
其實上禮拜在做那個題目的時候,我也想過用three.js來做,但是最後想想如果原生的東西都沒摸過,我怕會搞不清楚哪個是套件的內容,就像我一開始就ASP.NET卻不曉得HTML一樣,之後有機會會在試著做看看,我有把他加入圓夢清單裡面XD
想問一下另外像這種歪來歪去的地圖是怎麼做出來的呢?
想做到點擊下去該區域會變色,
還會顯示該區域的資訊等等的...
給小魚大大
哈哈,我現在再加緊產生第二篇文章,說不定能達成你一點點的需求
雖然我還是用Web的canvas,不是用C#或C++
Web我也可以學學,
不過要像上面整個區域變色可以嗎?
還是要使用多邊形??
感覺有點麻煩...
也許可以試試看吧...
提供一種思路...
以現有建模軟體(3DMax,Maya,AutoCAD...)建立好這種不規則模型
再搭配three.js+OBJLoader
將模型畫在canvas的3D上..
將近兩年前的大學畢業專題是做類似功能...請參考
費拉諾蘭世界超強的!!!
three.js 也好厲害,完全就是遊戲引擎的感覺了。
做遊戲也是我的夢想,大學有跑去旁邊的遊戲設計系,修過幾堂 Unity 的課,不過後來被現實妥協了,沒有繼續往遊戲發展,哈哈哈。