# 用Canvas畫一個小城堡 在繪製canvas的時候,因為我們會持續的更新影格,所以可以建立一個 draw()的function,讓要執行的動作都寫在裡面,這樣才能夠不斷的呼叫。 ``` function draw(){ .... } draw() ``` ## 靜態圖像 ### 1.繪製背景網格 ![](https://i.imgur.com/9R5FyHt.png) 網格需要每隔50px畫一條線,所以利用for迴圈找出間隔50px的距離,並畫上線與寫上刻度 ``` // 網格背景 function draw() { ctx.beginPath(); for (var i = 0; i < 10; i++) { let pos = i * 50; //垂直線 ctx.moveTo(pos, 0); ctx.lineTo(pos, 400); //寫刻度 ctx.fillText(pos, pos, 10); //水平線 ctx.moveTo(0, pos); ctx.lineTo(400, pos); //寫刻度 ctx.fillText(pos, 10, pos); } ctx.strokeStyle="rgba(0,0,0,0.1)" ctx.stroke(); } ``` ### 2.繪製內容物 內容物的積木因為都是矩形,所以可以用rect來畫,畫法有兩種,一個是畫單一矩形,另一個是利用bsginPath()開始一個路徑,等全部畫完之後,再一起填塞 ![](https://i.imgur.com/zNOsvvS.png) 單一路徑畫法: ``` // 紅色方塊(一次只畫一塊) ctx.fillStyle = "#e86920"; ctx.fillRect(300, 300, 50, 50); ctx.strokeRect(300, 300, 50, 50); ``` 多重路徑畫法: ``` // 畫多塊之後再一起上色 ctx.beginPath(); ctx.rect(50, 300, 50, 50); ctx.rect(250, 250, 50, 100); ctx.fillStyle = "#fcd92d"; ctx.fill(); ctx.stroke(); ``` 半圓的畫法: 這邊須注意因為圓型的繪圖方向為逆時針,基礎會是一個朝下畫的圓型,若需要改編繪圖方向,則需再最後加上一個參數回`true` ``` // 拱門 從左上角的點開始連 ctx.beginPath(); ctx.moveTo(100, 200); ctx.lineTo(250, 200); ctx.lineTo(250, 250); ctx.lineTo(200, 250); ctx.arc(175, 250, 25, 0, Math.PI, true); ctx.lineTo(100, 250); ctx.closePath(); ctx.fillStyle = "white"; ctx.fill(); ctx.stroke(); ``` 以此類推就可以畫出一個小城堡了~ ![](https://i.imgur.com/E0bCgWO.png) ## 動畫 ### 1.製作車子往前跑 利用setInterVal,每隔300ms就執行一次draw(),並且定義一個time的變數,每執行一次就會+1,就可以把持續更新的數值給車子的X軸,記得要把上一個畫面給清除`ctx.clearRect(0, 0, 400, 400);`,如果不清除上一格畫面的話,車子就會這樣留下軌跡 ![](https://i.imgur.com/G6wjgFA.png) X值越大車子就會越往左,超過440就會永遠消失了。所以為了要讓車子可以不斷地從左方進來,需要限制車子跑的範圍,可以利用餘數的方式`let carx = (time % 440) - 40;`把x軸控制在0~400之間,這樣車子就可以順利跑起來了! ![](https://i.imgur.com/1Gj3vJs.gif) ### 2.抓到滑鼠位置 先在canvas上建立監聽mousemove事件,抓到滑鼠的offsetX與offsetY後,把它存在物件內,方便取得 ``` // 監聽滑鼠位置讓draw()內的程式可以使用 canvas.addEventListener("mousemove", function (evt) { mouse.x = evt.offsetX; mouse.y = evt.offsetY; }); ``` 取得數值之後,我們要讓旗幟的Y軸可以上下移動,需要改變的點有三個,皆為Y軸,所以用剛剛取得的滑鼠Y位置,來變成Y軸移動的範圍,為了讓變動的數值可被控制,所以都/5來減少移動的範圍 `滑鼠移動最大的範圍為0-400,而屋頂距離上方畫布的距離只有150,所以要控制在0-150之內` ![](https://i.imgur.com/jNTRR1K.png) ``` //旗子 ctx.beginPath(); ctx.moveTo(175, 150); ctx.lineTo(175, 100 - mouse.y / 5); ctx.lineTo(200, 110 - (time % 5)- mouse.y / 5); ctx.lineTo(175, 120 - mouse.y / 5); ctx.closePath(); ctx.fillStyle = "hsl("+(mouse.x % 360)+",50%,50%)"; ctx.fill(); ctx.stroke(); ``` - (time % 5 ):是為了上旗子的抖動可以控制在5px左右,因為要持續抖動,所以是用time時間數值去控制 - `ctx.fillStyle = "hsl("+(mouse.x % 360)+",50%,50%)"` 讓旗子在滑鼠左右移動時可以變色 [Codepen範例](https://codepen.io/abbyd0208/pen/jOyzYqm?editors=0010) ###### tags: `Canvas`,`滑鼠互動`