【30分鐘學完】canvas動畫|遊戲基礎(1):理論先行

前言

本文雖然說是基礎教程,但這是相對動畫/遊戲領域來講,在前端領域算是中級教程了,不適合前端小白或萌新。閱讀前請確保本身對前端三大件(JavaScript+CSS+HTML)的基礎已經十分熟悉,並且有高中水平的數學和物理知識。demo採用ES6編寫,遵循Airbnb規範,不依賴第三方框架或庫,請在現代瀏覽器裏運行。
大部分例子來自《Foundation HTML5 Animation with JavaScript》,感謝這本書做者的辛勞和啓發。本教程也能夠算是該書的精(tian)簡(you)優(jia)化(cu)版,既是個人我的讀書筆記,也是經驗總結,方便沒空看書的忙人閱讀。
本人能力有限,歡迎牛人共同討論,批評指正。javascript

何爲動畫/遊戲

【科普】動畫是指由許多幀靜止的畫面,以必定的速度(如每秒16張)連續播放時,肉眼因視覺殘象產生錯覺,而誤覺得畫面活動的做品。爲了獲得活動的畫面,每一個畫面之間都會有細微的改變。而畫面的製做方式,最多見的是手繪在紙張或賽璐珞片上,其它的方式還包含了運用黏土、模型、紙偶、沙畫等。

使用H5技術實現動畫原理跟傳統動畫是同樣的,都是利用「視覺暫留」現象,計算機經過必定的規則運算獲得一個畫面(像素數據),而後以必定速度連續播放就造成動畫。但也有些許不一樣,傳統動畫的重點是繪畫技法的表現,也就是每張圖畫得漂亮,而計算機動畫更關心的是如何確立運算規則,這也是數學和物理知識的運用。
在計算機領域,動畫和遊戲界限並不明顯,他們的差異就是是否有交互性,若是玩家有必定的改變更畫的操做,再加上一些遊戲規則,那就能夠稱得上是遊戲了。html

【PS】順便一提,常有疑問爲何電腦玩遊戲卡,看電影不卡呢?
由於所謂的數字版電影,不管是三維動畫仍是二維動畫,都是已渲染好的畫面,也就是數據是一幀幀的圖片,而計算機只須要按順序換圖片就能播放。但遊戲的畫面是實時計算出來的,若是計算機性能不行,也就是沒法在下一幀完成渲染,畫面天然就會卡頓。在PC和主機性能低下的年代,將部分遊戲畫面預渲染後放入遊戲也是常見的提升性能的作法。

H5相關技術概述

canvas

【科普】 <canvas> 是 HTML5 新增的元素,可用於經過使用JavaScript中的腳原本繪製圖形。例如,它能夠用於繪製圖形,製做照片,建立動畫,甚至能夠進行實時視頻處理或渲染。

做爲上世代flash的升級替代品,簡單來講就是瀏覽器提供一個畫布,你的工做就是用js操做畫筆在上面畫畫,不斷重複畫畫和擦除的工做,就能夠實現動畫。
canvas相關文檔前端

用戶交互

交互是遊戲的根本,H5上的交互不外乎鼠標、觸摸和鍵盤這幾種,其實就是DOM標準的事件流。咱們在事件中拿到屏幕上的座標或鍵盤的鍵位代號,執行相應的操做。這不是本教程重點,不懂的右轉HTML相關基礎,這裏就不細說了。
這裏有些簡單例子,能夠在控制檯看到效果:java

demo中爲了方便使用封裝了這些交互方法,放在工具庫utils.js裏,這裏以獲取鼠標事件,觸摸事件同理爲例。git

utils.captureMouse = function captureMouse(element) {
  const mouse = {
    x: 0,
    y: 0,
  };
  element.addEventListener('mousemove', (event) => {
    let x;
    let y;
    if (event.pageX || event.pageY) {
      x = event.pageX;
      y = event.pageY;
    } else {
      x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
      y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
    }
    x -= element.offsetLeft;
    y -= element.offsetTop;

    mouse.x = x;
    mouse.y = y;
  }, false);

  return mouse;
};

動畫循環

這是計算機動畫在代碼層面的核心,簡單來講就是一個循環調用(不斷遞歸)的過程,每次循環都是一幀畫面的產生,實現方式大致能夠概括爲三類。github

基於幀的動畫(requestAnimationFrame)

【科普】在視頻領域,電影、電視、數字視頻等可視爲隨時間連續變換的許多張畫面,而幀是指每一張畫面。

通常來講1秒15幀就可以讓人眼不發覺黑暗的間隔,25幀就可感受流暢,每秒鐘幀數 (fps) 愈多,所顯示的動做就會愈流暢。W3C所建議的刷新率是1秒60幀,大部分瀏覽器是遵循這一標準的。
requestAnimationFrame是H5加入的函數,用法相似於setTimeout,用於告訴瀏覽器下一幀的時候該幹什麼,好比一個物體每1幀要移動多少距離。它提供基於瀏覽器的優化實現,是實現H5動畫的首選,全部demo都有使用。至於它優化了什麼,下面會提到。
requestAnimationFrame文檔連接web

基於定時器的動畫

在requestAnimationFrame還未出現的時代,通常是用setTimeout和setInterval實現動畫,也可使用他們模擬requestAnimationFrame,只需把時間間隔設爲1000/60毫秒,也就是大約16.7毫秒執行下一個循環,固然你也能夠定義本身須要的幀率,達到遊戲中常見的鎖幀效果。
所謂模擬,另外一層意思就是不可能相同,咱們的程序在瀏覽器沙盒中運行是不知道顯卡和顯示器硬件實際是否在刷新的,但瀏覽器是能夠知道的,因此瀏覽器才能夠真正的知道何時屏幕會刷新,更好的配合硬件工做,這也是requestAnimationFrame優於定時器的緣由。
基於此咱們能夠創造一個polyfill放到工具庫utils.js裏。canvas

if (!window.requestAnimationFrame) {
  window.requestAnimationFrame = (window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function timeout(callback) {
      return window.setTimeout(callback, 1000 / 60);
    });
}

特別注意:js中給定時器規定的時間間隔僅僅表示最少的時間,而非確切的時間,對於過複雜須要超過期間間隔才執行完的程序,執行時間就會被延後。瀏覽器

基於時間的動畫

其實不管是requestAnimationFrame仍是定時器,都不能保證以特定速率播放。也就是說複雜的動畫在性能較差的計算機上播放,會比它設計速度慢。這個在遊戲的體驗上是十分不友好的,因此就有了遊戲裏常見的跳幀作法。
其實就是使用真實的時間來度量每一個物體的運動變化,而不是依靠每幀的變化。將物體每幀移動距離,轉變爲物體每秒移動距離。
因爲demo都是簡單動畫,因此暫時不會使用這個操做。框架

計算機中一些數學概念與標準的差別

弧度(radian)與角度(degree)

平常咱們使用角度會比較多,應該沒有人不知道一個圓是360度吧(笑)。但計算機中不使用角度概念而是使用弧度。學校也有說過,這裏就不講解他們的關係了,只要明確一圓周是2π弧度,二者的轉換用代碼表示就是:

let radians = degrees * Math.PI / 180;
let degrees = radians * 180 / Math.PI;

座標系

計算機裏的座標系也不是平常使用的標準座標系,能夠說是標準座標系的顛倒版本,以下圖,越往右x軸值越大,越往下y軸值越大,反之亦然。

【科普】這個座標系有必定的歷史背景,由於「大屁股」顯示器裏的電子槍是從左往右,從上往下掃描屏幕的。

座標系

這個座標系還致使了另外一個問題,就是角度的正負值是與標準座標系相反的,以下圖,順時針角度纔是正值,逆時針爲負值。

角度

相關文章
相關標籤/搜索