成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【30分鐘學完】canvas動畫|游戲基礎(chǔ)(2):從零開始畫畫

Baoyuan / 1780人閱讀

摘要:前言上篇主要是理論的概述,本篇會多些實踐,來講講的基礎(chǔ)用法,并包含一些基礎(chǔ)三角函數(shù)的應用,推薦沒有基礎(chǔ)的朋友閱讀,熟悉的朋友可以跳過。完整實例一個會跟蹤鼠標位置的箭頭三角函數(shù)上下運動終于順利過渡到三角函數(shù)的話題笑。

前言

上篇主要是理論的概述,本篇會多些實踐,來講講canvas的基礎(chǔ)用法,并包含一些基礎(chǔ)三角函數(shù)的應用,推薦沒有canvas基礎(chǔ)的朋友閱讀,熟悉的朋友可以跳過。
本人能力有限,歡迎牛人共同討論,批評指正。

一起來畫畫吧

canvas的API有很多,如果一一列舉30分鐘你是絕對看不完的,而且怎么流水賬還不如自己去看文檔呢(笑),本教程的思路是用實例一步一步從無到有講解基礎(chǔ)用法。
canvas相關(guān)文檔

準備工作

布置畫布:通過添加標簽,添加canvas元素;

獲取畫布:通過標簽的id,獲得canvas對象;

獲得畫筆:通過canvas對象的getContext("2d")方法,獲得2D環(huán)境。

const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
畫個箭頭

首先我們來畫個紅邊黃底的箭頭,使用面向?qū)ο蟮拇a組織方式,全部代碼如下。
類名為Arrow。它擁有x軸坐標、y軸坐標、底的顏色color、旋轉(zhuǎn)弧度rotation四個屬性。
實例方法是draw(),它需要一個context對象作為參數(shù),就是準備工作里的context,它就相當于是畫筆,這里其實是類似依賴注入的過程,將canvas的畫筆交給實例的draw()方法,實例用這個畫筆去畫出箭頭,繪畫過程見代碼注釋。特別注意以下幾點:

beginPath()方法調(diào)用后moveTo()和lineTo移動坐標是相對與beginPath()時畫筆的坐標的,可以理解成畫筆自帶一個坐標系,它可以旋轉(zhuǎn)和在畫布上移動,繪制工作的坐標都是屬于這個坐標系的;

beginPath()是繪制設(shè)置狀態(tài)的起始點,它之后代碼設(shè)置的繪制狀態(tài)的作用域結(jié)束于繪制方法stroke()、fill()或者closePath();

save()的作用是保存筆的狀態(tài),因為一個畫布的筆只有一支,會在不同對象中傳遞,為了不污染后續(xù)的畫就應該先保存,畫完再restore()還原;

本身是透明的,可以使用CSS給它個背景,例子中普遍使用白色背景。

/**
 * 箭頭類
 * @class Representing a arrow.
 */
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "Arrow" }] */
class Arrow {
  /**
    * Create a arrow.
    */
  constructor() {
    this.x = 0;
    this.y = 0;
    this.color = "#ffff00";
    this.rotation = 0;
  }
  /**
   * Draw the arrow.
   * @param {Object} _context - The canvas context.
   */
  draw(_context) {
    const context = _context;
    // 會先保存畫筆狀態(tài)
    context.save();
    // 移動畫筆
    context.translate(this.x, this.y);
    // 旋轉(zhuǎn)畫筆
    context.rotate(this.rotation);
    // 設(shè)置線條寬度
    context.lineWidth = 2;
    // 設(shè)置線條顏色
    context.strokeStyle = "#ff0000";
    // 設(shè)置填充顏色
    context.fillStyle = this.color;
    // 開始路徑
    context.beginPath();
    // 將筆移動到相對位置
    context.moveTo(-50, -25);
    // 畫線到相對位置
    context.lineTo(0, -25);
    context.lineTo(0, -50);
    context.lineTo(50, 0);
    context.lineTo(0, 50);
    context.lineTo(0, 25);
    context.lineTo(-50, 25);
    context.lineTo(-50, -25);
    // 閉合路徑
    context.closePath();
    // 填充路徑包圍區(qū)
    context.fill();
    // 繪制路徑
    context.stroke();
    // 載入保存的筆信息
    context.restore();
  }
}

同理我們還可以畫點其他的,比如一個圓ball.js,稍微多些參數(shù),慢慢理解。
成品的效果可以先看這個(稍微劇透):一個會跟蹤鼠標位置的箭頭

加入循環(huán)動起來

現(xiàn)在我們已經(jīng)掌握了畫畫的基本功,并且可以畫箭頭arrow.js和圓ball.js,然而這樣只是靜止畫,接下來我們需要一個循環(huán),不斷的執(zhí)行擦除和重畫的工作才能實現(xiàn)幀動畫。
下面這段代碼的中繪圖函數(shù)drawFrame被立即執(zhí)行,并遞歸調(diào)用自身,你將會在大部分例子中看到。
循環(huán)原理上一篇已經(jīng)說明,不再重復。這里要說明的是clearRect(),這個函數(shù)接受一個矩形坐標,也就是(x軸坐標,y軸坐標,矩形寬度,矩形高度),用于清除矩形區(qū)域內(nèi)的畫。
例子里直接是清除了整個畫布,但這不是絕對的,刷不刷新,是局部刷新還是全部刷新,都需要靈活處理。
這里有個不刷新的例子:鼠標畫圖工具

(function drawFrame() {
  // 類似setTimeout的操作
  window.requestAnimationFrame(drawFrame, canvas);
  // 將畫布擦干凈
  context.clearRect(0, 0, canvas.width, canvas.height);
  // ...繼續(xù)你的作畫
}());
給它點動力

現(xiàn)在畫面已經(jīng)是在不斷的重繪,但為什么還是靜止的呢?因為每一次刷新都沒有改變要畫的內(nèi)容。
那我們就給它一個目標吧,這樣它才能動起來,比如就讓箭頭始終指向鼠標。
下面是核心代碼,主要目的就是求出每幀arrow的旋轉(zhuǎn)角度,這里使用的工具類mouse會實時返回鼠標的x,y軸坐標,封裝原理上一篇已經(jīng)講過,根據(jù)這鼠標的坐標和arrow的坐標,即可得到鼠標的相對于arrow的距離dx和dy,如下圖:

而arrow的旋轉(zhuǎn)角度即可以通過dx和dy使用反正切函數(shù)得到,這里需要注意幾點:

仔細看上面代碼中arrow的繪制過程,可知其原點是在中心位置的,所以剛好旋轉(zhuǎn)角度就是畫筆的旋轉(zhuǎn)角度;

dx和dy是鼠標相對與arrow的坐標,所以圖中把坐標系挪動箭頭中心是沒毛病的;

用atan2,而不是atan,是因為tan值本來就可能是重復的,比如-1/2和1/(-2)兩個都是-0.5,無法區(qū)分象限,而atan2就可以區(qū)分開。

完整實例:一個會跟蹤鼠標位置的箭頭

window.onload = function () {
  const canvas = document.getElementById("canvas");
  const context = canvas.getContext("2d");
  const mouse = utils.captureMouse(canvas);
  const arrow = new Arrow();

  arrow.x = canvas.width / 2;
  arrow.y = canvas.height / 2;

  (function drawFrame() {
    window.requestAnimationFrame(drawFrame, canvas);
    context.clearRect(0, 0, canvas.width, canvas.height);
    const dx = mouse.x - arrow.x;
    const dy = mouse.y - arrow.y;

    arrow.rotation = Math.atan2(dy, dx);
    arrow.draw(context);
  }());
};
三角函數(shù) 上下運動

終于順利過渡到三角函數(shù)的話題(笑)。三角函數(shù)不止有反正切一個應用,下面再看一個例子。
下面是一個ball在上下運動的核心代碼,重點就是ball的y軸坐標改變,就是這句:

ball.y = clientY + Math.sin(angle) * range;

利用Math.sin(angle)的取值范圍是-1到1,并且會隨著angle增大而反復,使ball在一定范圍上下運動。
完整例子:一個上下運動的球(可調(diào)參數(shù)版)

window.onload = function () {
  const canvas = document.getElementById("canvas");
  const context = canvas.getContext("2d");
  const ball = new Ball();
  let angle = 0;
  // 運動中心
  const clientY = 200;
  // 范圍
  const range = 50;
  // 速度
  const speed = 0.05;

  ball.x = canvas.width / 2;
  ball.y = canvas.height / 2;

  (function drawFrame() {
    window.requestAnimationFrame(drawFrame, canvas);
    context.clearRect(0, 0, canvas.width, canvas.height);

    ball.y = clientY + Math.sin(angle) * range;
    angle += speed;
    ball.draw(context);
  }());
};
向前運動

只是上下運動不過癮,那就讓圓前進吧,其實就是每幀改變x軸的位置。
核心代碼如下,相比前面的上下運動,多了x軸的速度,每幀移動一點就形成了波浪前進的效果。
完整實例:一個波浪運動的球

window.onload = function () {
  const canvas = document.getElementById("canvas");
  const context = canvas.getContext("2d");
  const ball = new Ball();
  let angle = 0;
  const centerY = 200;
  const range = 50;
  const xspeed = 1;
  const yspeed = 0.05;

  ball.x = 0;
  (function drawFrame() {
    window.requestAnimationFrame(drawFrame, canvas);
    context.clearRect(0, 0, canvas.width, canvas.height);
    ball.x += xspeed;
    ball.y = centerY + Math.sin(angle) * range;
    angle += yspeed;
    ball.draw(context);
  }());
};
其他示例

其他的應用就不一一講解,羅列出來一些:

不斷縮放的球

兩軸同時改變的圓

繪制波

一個做圓周運動的圓

一個做橢圓形運動的圓

計算兩個隨機塊的距離

中心點到鼠標的距離

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/93682.html

相關(guān)文章

  • 30分鐘學完canvas動畫|游戲基礎(chǔ)(2):從零開始畫畫

    摘要:前言上篇主要是理論的概述,本篇會多些實踐,來講講的基礎(chǔ)用法,并包含一些基礎(chǔ)三角函數(shù)的應用,推薦沒有基礎(chǔ)的朋友閱讀,熟悉的朋友可以跳過。完整實例一個會跟蹤鼠標位置的箭頭三角函數(shù)上下運動終于順利過渡到三角函數(shù)的話題笑。 前言 上篇主要是理論的概述,本篇會多些實踐,來講講canvas的基礎(chǔ)用法,并包含一些基礎(chǔ)三角函數(shù)的應用,推薦沒有canvas基礎(chǔ)的朋友閱讀,熟悉的朋友可以跳過。 本人能力...

    anyway 評論0 收藏0
  • 30分鐘學完canvas動畫|游戲基礎(chǔ)(1):理論先行

    摘要:所建議的刷新率是秒幀,大部分瀏覽器是遵循這一標準的?;跁r間的動畫其實無論是還是定時器,都不能保證以特定速率播放。將物體每幀移動距離,轉(zhuǎn)變?yōu)槲矬w每秒移動距離。 前言 本文雖說是基礎(chǔ)教程,但這是相對動畫/游戲領(lǐng)域來說,在前端領(lǐng)域算是中級教程了,不適合前端小白或萌新。閱讀前請確保自己對前端三大件(JavaScript+CSS+HTML)的基礎(chǔ)已經(jīng)十分熟悉,而且有高中水平的數(shù)學和物理知識。d...

    wind5o 評論0 收藏0
  • 30分鐘學完canvas動畫|游戲基礎(chǔ)(1):理論先行

    摘要:所建議的刷新率是秒幀,大部分瀏覽器是遵循這一標準的?;跁r間的動畫其實無論是還是定時器,都不能保證以特定速率播放。將物體每幀移動距離,轉(zhuǎn)變?yōu)槲矬w每秒移動距離。 前言 本文雖說是基礎(chǔ)教程,但這是相對動畫/游戲領(lǐng)域來說,在前端領(lǐng)域算是中級教程了,不適合前端小白或萌新。閱讀前請確保自己對前端三大件(JavaScript+CSS+HTML)的基礎(chǔ)已經(jīng)十分熟悉,而且有高中水平的數(shù)學和物理知識。d...

    wemall 評論0 收藏0

發(fā)表評論

0條評論

Baoyuan

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<