摘要:所建議的刷新率是秒幀,大部分瀏覽器是遵循這一標(biāo)準(zhǔn)的?;跁r(shí)間的動(dòng)畫其實(shí)無論是還是定時(shí)器,都不能保證以特定速率播放。將物體每幀移動(dòng)距離,轉(zhuǎn)變?yōu)槲矬w每秒移動(dòng)距離。
前言
本文雖說是基礎(chǔ)教程,但這是相對(duì)動(dòng)畫/游戲領(lǐng)域來說,在前端領(lǐng)域算是中級(jí)教程了,不適合前端小白或萌新。閱讀前請(qǐng)確保自己對(duì)前端三大件(JavaScript+CSS+HTML)的基礎(chǔ)已經(jīng)十分熟悉,而且有高中水平的數(shù)學(xué)和物理知識(shí)。demo采用ES6編寫,遵循Airbnb規(guī)范,不依賴第三方框架或庫,請(qǐng)?jiān)诂F(xiàn)代瀏覽器里運(yùn)行。
大部分例子來自《Foundation HTML5 Animation with JavaScript》,感謝這本書作者的辛勞和啟發(fā)。本教程也可以算是該書的精(tian)簡(you)優(yōu)(jia)化(cu)版,既是我的個(gè)人讀書筆記,也是經(jīng)驗(yàn)總結(jié),方便沒空看書的忙人閱讀。
本人能力有限,歡迎牛人共同討論,批評(píng)指正。
【科普】動(dòng)畫是指由許多幀靜止的畫面,以一定的速度(如每秒16張)連續(xù)播放時(shí),肉眼因視覺殘象產(chǎn)生錯(cuò)覺,而誤以為畫面活動(dòng)的作品。為了得到活動(dòng)的畫面,每個(gè)畫面之間都會(huì)有細(xì)微的改變。而畫面的制作方式,最常見的是手繪在紙張或賽璐珞片上,其它的方式還包含了運(yùn)用黏土、模型、紙偶、沙畫等。
使用H5技術(shù)實(shí)現(xiàn)動(dòng)畫原理跟傳統(tǒng)動(dòng)畫是一樣的,都是利用“視覺暫留”現(xiàn)象,計(jì)算機(jī)通過一定的規(guī)則運(yùn)算得到一個(gè)畫面(像素?cái)?shù)據(jù)),然后以一定速度連續(xù)播放就形成動(dòng)畫。但也有些許不同,傳統(tǒng)動(dòng)畫的重點(diǎn)是繪畫技法的表現(xiàn),也就是每張圖畫得漂亮,而計(jì)算機(jī)動(dòng)畫更關(guān)心的是如何確立運(yùn)算規(guī)則,這也是數(shù)學(xué)和物理知識(shí)的運(yùn)用。
在計(jì)算機(jī)領(lǐng)域,動(dòng)畫和游戲界限并不明顯,他們的差別就是是否有交互性,如果玩家有一定的改變動(dòng)畫的操作,再加上一些游戲規(guī)則,那就可以稱得上是游戲了。
【PS】順便一提,常有疑問為什么電腦玩游戲卡,看電影不卡呢?H5相關(guān)技術(shù)概述 canvas
因?yàn)樗^的數(shù)字版電影,不論是三維動(dòng)畫還是二維動(dòng)畫,都是已渲染好的畫面,也就是數(shù)據(jù)是一幀幀的圖片,而計(jì)算機(jī)只需要按順序換圖片就能播放。但游戲的畫面是實(shí)時(shí)計(jì)算出來的,如果計(jì)算機(jī)性能不行,也就是無法在下一幀完成渲染,畫面自然就會(huì)卡頓。在PC和主機(jī)性能低下的年代,將部分游戲畫面預(yù)渲染后放入游戲也是常見的提高性能的做法。
【科普】 是 HTML5 新增的元素,可用于通過使用JavaScript中的腳本來繪制圖形。例如,它可以用于繪制圖形,制作照片,創(chuàng)建動(dòng)畫,甚至可以進(jìn)行實(shí)時(shí)視頻處理或渲染。
作為上世代flash的升級(jí)替代品,簡單來說就是瀏覽器提供一個(gè)畫布,你的工作就是用js操作畫筆在上面畫畫,不斷重復(fù)畫畫和擦除的工作,就可以實(shí)現(xiàn)動(dòng)畫。
canvas相關(guān)文檔
交互是游戲的根本,H5上的交互不外乎鼠標(biāo)、觸摸和鍵盤這幾種,其實(shí)就是DOM標(biāo)準(zhǔn)的事件流。我們?cè)谑录心玫狡聊簧系淖鴺?biāo)或鍵盤的鍵位代號(hào),執(zhí)行相應(yīng)的操作。這不是本教程重點(diǎn),不懂的右轉(zhuǎn)HTML相關(guān)基礎(chǔ),這里就不細(xì)說了。
這里有些簡單例子,可以在控制臺(tái)看到效果:
演示所有鼠標(biāo)事件
演示鼠標(biāo)按下坐標(biāo)獲取
演示觸摸事件
演示鍵盤事件
演示鍵盤上、下、左、右
demo中為了方便使用封裝了這些交互方法,放在工具庫utils.js里,這里以獲取鼠標(biāo)事件,觸摸事件同理為例。
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; };動(dòng)畫循環(huán)
這是計(jì)算機(jī)動(dòng)畫在代碼層面的核心,簡單來說就是一個(gè)循環(huán)調(diào)用(不斷遞歸)的過程,每次循環(huán)都是一幀畫面的產(chǎn)生,實(shí)現(xiàn)方式大體可以歸納為三類。
基于幀的動(dòng)畫(requestAnimationFrame)【科普】在視頻領(lǐng)域,電影、電視、數(shù)字視頻等可視為隨時(shí)間連續(xù)變換的許多張畫面,而幀是指每一張畫面。
一般來說1秒15幀就可讓人眼不發(fā)覺黑暗的間隔,25幀就可感覺流暢,每秒鐘幀數(shù) (fps) 愈多,所顯示的動(dòng)作就會(huì)愈流暢。W3C所建議的刷新率是1秒60幀,大部分瀏覽器是遵循這一標(biāo)準(zhǔn)的。
requestAnimationFrame是H5加入的函數(shù),用法類似于setTimeout,用于告訴瀏覽器下一幀的時(shí)候該干什么,比如一個(gè)物體每1幀要移動(dòng)多少距離。它提供基于瀏覽器的優(yōu)化實(shí)現(xiàn),是實(shí)現(xiàn)H5動(dòng)畫的首選,所有demo都有使用。至于它優(yōu)化了什么,下面會(huì)提到。
requestAnimationFrame文檔鏈接
在requestAnimationFrame還未出現(xiàn)的時(shí)代,一般是用setTimeout和setInterval實(shí)現(xiàn)動(dòng)畫,也可以使用他們模擬requestAnimationFrame,只需把時(shí)間間隔設(shè)為1000/60毫秒,也就是大約16.7毫秒執(zhí)行下一個(gè)循環(huán),當(dāng)然你也可以定義自己需要的幀率,達(dá)到游戲中常見的鎖幀效果。
所謂模擬,另一層意思就是不可能相同,我們的程序在瀏覽器沙盒中運(yùn)行是不知道顯卡和顯示器硬件實(shí)際是否在刷新的,但瀏覽器是可以知道的,所以瀏覽器才可以真正的知道什么時(shí)候屏幕會(huì)刷新,更好的配合硬件工作,這也是requestAnimationFrame優(yōu)于定時(shí)器的原因。
基于此我們可以創(chuàng)造一個(gè)polyfill放到工具庫utils.js里。
if (!window.requestAnimationFrame) { window.requestAnimationFrame = (window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function timeout(callback) { return window.setTimeout(callback, 1000 / 60); }); }
特別注意:js中給定時(shí)器規(guī)定的時(shí)間間隔僅僅表示最少的時(shí)間,而非確切的時(shí)間,對(duì)于過復(fù)雜需要超過時(shí)間間隔才執(zhí)行完的程序,執(zhí)行時(shí)間就會(huì)被延后。
基于時(shí)間的動(dòng)畫其實(shí)無論是requestAnimationFrame還是定時(shí)器,都不能保證以特定速率播放。也就是說復(fù)雜的動(dòng)畫在性能較差的計(jì)算機(jī)上播放,會(huì)比它設(shè)計(jì)速度慢。這個(gè)在游戲的體驗(yàn)上是十分不友好的,所以就有了游戲里常見的跳幀做法。
其實(shí)就是使用真實(shí)的時(shí)間來度量每個(gè)物體的運(yùn)動(dòng)變化,而不是依靠每幀的變化。將物體每幀移動(dòng)距離,轉(zhuǎn)變?yōu)槲矬w每秒移動(dòng)距離。
由于demo都是簡單動(dòng)畫,所以暫時(shí)不會(huì)使用這個(gè)操作。
日常我們使用角度會(huì)比較多,應(yīng)該沒有人不知道一個(gè)圓是360度吧(笑)。但計(jì)算機(jī)中不使用角度概念而是使用弧度。學(xué)校也有說過,這里就不講解他們的關(guān)系了,只要明確一圓周是2π弧度,兩者的轉(zhuǎn)換用代碼表示就是:
let radians = degrees * Math.PI / 180; let degrees = radians * 180 / Math.PI;坐標(biāo)系
計(jì)算機(jī)里的坐標(biāo)系也不是日常使用的標(biāo)準(zhǔn)坐標(biāo)系,可以說是標(biāo)準(zhǔn)坐標(biāo)系的顛倒版本,如下圖,越往右x軸值越大,越往下y軸值越大,反之亦然。
【科普】這個(gè)坐標(biāo)系有一定的歷史背景,因?yàn)椤按笃ü伞憋@示器里的電子槍是從左往右,從上往下掃描屏幕的。
這個(gè)坐標(biāo)系還導(dǎo)致了另一個(gè)問題,就是角度的正負(fù)值是與標(biāo)準(zhǔn)坐標(biāo)系相反的,如下圖,順時(shí)針角度才是正值,逆時(shí)針為負(fù)值。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/93660.html
摘要:所建議的刷新率是秒幀,大部分瀏覽器是遵循這一標(biāo)準(zhǔn)的?;跁r(shí)間的動(dòng)畫其實(shí)無論是還是定時(shí)器,都不能保證以特定速率播放。將物體每幀移動(dòng)距離,轉(zhuǎn)變?yōu)槲矬w每秒移動(dòng)距離。 前言 本文雖說是基礎(chǔ)教程,但這是相對(duì)動(dòng)畫/游戲領(lǐng)域來說,在前端領(lǐng)域算是中級(jí)教程了,不適合前端小白或萌新。閱讀前請(qǐng)確保自己對(duì)前端三大件(JavaScript+CSS+HTML)的基礎(chǔ)已經(jīng)十分熟悉,而且有高中水平的數(shù)學(xué)和物理知識(shí)。d...
摘要:十六進(jìn)制格式,紅綠藍(lán)分別用兩位十六進(jìn)制數(shù)表示。函數(shù)表達(dá)式,三原色分別由的整數(shù)值表示。開頭表示十六進(jìn)制數(shù),中不區(qū)分大小寫,至于不知道什么是十六進(jìn)制的,請(qǐng)自行百度紅色是,綠色是,藍(lán)色。 前言 本篇主要講解關(guān)于計(jì)算機(jī)顏色系統(tǒng)的概念,后續(xù)結(jié)合一些canvas的應(yīng)用。因?yàn)槭悄悴恢酪矝]關(guān)系的邊緣知識(shí),所以作為本系列教程的擴(kuò)展,沒有興趣的同學(xué)可以跳過。 開始我們?nèi)f紫千紅的故事吧! 本人能力有限...
摘要:十六進(jìn)制格式,紅綠藍(lán)分別用兩位十六進(jìn)制數(shù)表示。函數(shù)表達(dá)式,三原色分別由的整數(shù)值表示。開頭表示十六進(jìn)制數(shù),中不區(qū)分大小寫,至于不知道什么是十六進(jìn)制的,請(qǐng)自行百度紅色是,綠色是,藍(lán)色。 前言 本篇主要講解關(guān)于計(jì)算機(jī)顏色系統(tǒng)的概念,后續(xù)結(jié)合一些canvas的應(yīng)用。因?yàn)槭悄悴恢酪矝]關(guān)系的邊緣知識(shí),所以作為本系列教程的擴(kuò)展,沒有興趣的同學(xué)可以跳過。 開始我們?nèi)f紫千紅的故事吧! 本人能力有限...
閱讀 811·2023-04-25 22:57
閱讀 3061·2021-11-23 10:03
閱讀 623·2021-11-22 15:24
閱讀 3166·2021-11-02 14:47
閱讀 2910·2021-09-10 11:23
閱讀 3128·2021-09-06 15:00
閱讀 3950·2019-08-30 15:56
閱讀 3336·2019-08-30 15:52