iT邦幫忙

2021 iThome 鐵人賽

DAY 11
0
Modern Web

JavaScript 嗨起來用 JS 做動畫 ε= ᕕ( ᐛ )ᕗ系列 第 11

Day11 - Bmo 眼睛嘴巴動起來

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20210926/20140513sgBHkEVjD5.png
設定 BMO 初始化、更新要更新什麼、畫出 BMO 的方法

class Bmo {
  constructor(ctx, time) {
    // 希望畫布與時間跟遊戲舞台同步
    this.ctxBmo = ctx;
    this.time = time;

    // Bmo 眼睛參數
    this.eyes = {
      right: {
        pos: {x:230, y:130},
        size: 7,
      },
      left: {
        pos: {x:130, y:130},
        size: 7,
      },
    }

    // Bmo 笑容弧度參數
    this.mouth = {
      beginArc: 1/4*Math.PI,
      endArc: 3/4*Math.PI
    }
    this.update();
    this.render();
  };
  
  // 資料更新
  update() {
    // 眼睛隨著滑鼠移動而飄移
    // 滑鼠監聽事件晚點會綁定在遊戲舞台畫布上
    // mouse 的 x y 移動範圍晚點會定義為遊戲舞台畫布 offsetX offsetY
    // 所以 mouse 的 x y 移動範圍將介於 0~遊戲舞台畫布長寬之間
    this.eyes = {
      right: {
        pos: {
          x: 230+mouse.x*0.1,
          y: 130+mouse.y*0.05,
        },
        size: 7,
      },
      left: {
        pos: {
          x: 130+mouse.x*0.1,
          y: 130+mouse.y*0.05
        },
        size: 7,
      },
    };

    // 嘴巴隨著滑鼠移動而歪嘴笑
    this.mouth = {
      beginArc: 1/4*Math.PI+0.001*mouse.x,
      endArc: 3/5*Math.PI+0.001*mouse.x
    };
  };
  
  // 畫面呈現
  render() {
    // 畫 Bmo 身體
    this.ctxBmo.fillStyle = 'hsl(138, 39%, 64%)';
    this.ctxBmo.beginPath();
        this.ctxBmo.fillRect(50,50,300,300);
    this.ctxBmo.closePath();

    // 身體個區塊描邊顏色
    this.ctxBmo.strokeStyle = "rgba(0,50,0,1)";

    // Bmo 臉
    this.ctxBmo.beginPath();
        this.ctxBmo.rect(100,100,200,100);
        this.ctxBmo.fillStyle = 'hsl(108, 48%, 87%)';
        this.ctxBmo.fill();
        this.ctxBmo.stroke();
    this.ctxBmo.closePath();

    // Bmo 左眼
    this.ctxBmo.beginPath();
        this.ctxBmo.arc(this.eyes.left.pos.x,this.eyes.left.pos.y,7,0,2*Math.PI);
        this.ctxBmo.fillStyle = 'hsl(108, 20%, 22%)';
        this.ctxBmo.fill();
        this.ctxBmo.stroke();
    this.ctxBmo.closePath();
        
    // Bmo 右眼
    this.ctxBmo.beginPath();
        this.ctxBmo.arc(this.eyes.right.pos.x,this.eyes.right.pos.y,7,0,2*Math.PI);
        this.ctxBmo.fillStyle = 'hsl(108, 20%, 22%)';
        this.ctxBmo.fill();
        this.ctxBmo.stroke();
    this.ctxBmo.closePath();

    // Bmo mouth
    this.ctxBmo.beginPath();
        this.ctxBmo.arc(200,100,75,this.mouth.beginArc,this.mouth.endArc);
        this.ctxBmo.stroke();
    this.ctxBmo.closePath();

    // bmo btn 左上空白鍵
    this.ctxBmo.beginPath();
        this.ctxBmo.strokeRect(100,225,100,20);
        this.ctxBmo.stroke();
    this.ctxBmo.closePath();

    // bmo btn 左中十字
    // 顏色隨時間改變而變更,並設定改變範圍介於 0~359
    this.ctxBmo.fillStyle = `hsl(${this.time%360},50%,50%)`;
    this.ctxBmo.beginPath();
        this.ctxBmo.fillRect(105,270,40,10);
        this.ctxBmo.fillRect(120,255,10,40);
        this.ctxBmo.fill();
        this.ctxBmo.stroke();
    this.ctxBmo.closePath();

    // bmo btn 左下一一
    this.ctxBmo.beginPath();
        this.ctxBmo.strokeRect(100,310,40,15);
        this.ctxBmo.strokeRect(160,310,40,15);
        this.ctxBmo.stroke();
    this.ctxBmo.closePath();

    // bmo btn 右中三角形
    this.ctxBmo.beginPath();
        this.ctxBmo.moveTo(250,245);
        this.ctxBmo.lineTo(275,270);
        this.ctxBmo.lineTo(225,270);
        this.ctxBmo.closePath();
        this.ctxBmo.stroke();
    this.ctxBmo.closePath();

    // bmo btn 右上圓
    this.ctxBmo.beginPath();
        this.ctxBmo.arc(275,235,10,0,2*Math.PI);
        this.ctxBmo.stroke();
    this.ctxBmo.closePath();

    // bmo btn 右下圓
    this.ctxBmo.beginPath();
        this.ctxBmo.arc(250,305,25,0,2*Math.PI);
        this.ctxBmo.fillStyle = 'hsl(354, 84%, 49%)';
        this.ctxBmo.fill();
        this.ctxBmo.stroke();
    this.ctxBmo.closePath();

    // bmo btn 右右中圓
    this.ctxBmo.beginPath();
        this.ctxBmo.arc(295,280,6,0,2*Math.PI);
        this.ctxBmo.stroke();
    this.ctxBmo.closePath();
  }
};

設定遊戲舞台初始化(包含鋪畫布、請 BMO 上台、更新資料、繪製畫面)

class GameBoard{
  constructor(){
    this.canvas = document.getElementById('canvasBmoClass');
    this.ctx = this.canvas.getContext('2d');
    this.canvas.width = 400;
    this.canvas.height = 400;
    this.time = 0;

    // Bmo 上台
    this.bmo = new Bmo(this.ctx, this.time);
    this.update();
    this.render();
  };
  update(){
    this.time ++;
    // bmo 時間也同步更新
    this.bmo.time = this.time;
    this.bmo.update();
    setTimeout(()=>this.update());
  };
  render(){
    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    this.ctx.beginPath();
    this.ctx.fillStyle = "rgba(0,0,0,0.2)";
    this.ctx.strokeStyle = "rgba(0,0,0,0.2)";
    for(let i=1;i<9;i++){
        let pos = 50*i
        // 畫垂直線
        this.ctx.moveTo(pos,0);
        this.ctx.lineTo(pos,400);
        // 畫水平線
        this.ctx.moveTo(0,pos);
        this.ctx.lineTo(400,pos);
        // 寫軸 x 座標與 y 軸座標
        this.ctx.fillText(pos,pos,10);
        this.ctx.fillText(pos,0,pos);
    }
    this.ctx.stroke();
    this.bmo.render();
    requestAnimationFrame(()=>this.render());
  };
};

// 呼叫遊戲舞台出場~
var gameBoard = new GameBoard();

當滑鼠經過遊戲舞台時,紀錄滑鼠 offset 座標,取得滑鼠在遊戲舞台內移動的狀態

var mouse = {
    x: 0,
    y: 0
};
gameBoard.canvas.addEventListener('mousemove',function(evt){
    mouse.x = evt.offsetX;
    mouse.y = evt.offsetY;
})

祝大家開開心心河河笑,如果上述理解有誤希望能協助提點~感謝大家 ε= ᕕ( ᐛ )ᕗ


上一篇
Day10 - 今天只先鋪底座標軸,明天來畫 BMO
下一篇
Day12 - audio tag 幫我設定背景音樂
系列文
JavaScript 嗨起來用 JS 做動畫 ε= ᕕ( ᐛ )ᕗ17
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言