2017-1-23 資深UI設(shè)計(jì)者
如果您想訂閱本博客內(nèi)容,每天自動發(fā)到您的郵箱中, 請點(diǎn)這里
Janilychen:以往做一些H5的運(yùn)營項(xiàng)目,都是動畫設(shè)計(jì)師使用Animate cc(原來的Flash)先設(shè)計(jì)好動畫原型,然后交給我們UI開發(fā)來實(shí)現(xiàn)。做過動畫開發(fā)的童鞋都知道動畫開發(fā)都是比較耗費(fèi)時間精力的,而且還要高質(zhì)量的還原動畫設(shè)計(jì)師設(shè)計(jì)好的動畫,來回溝通成本也非常高。
那有沒有一種的方法來改善這種流程,提高開發(fā)效率的同時還能完成高品質(zhì)的動畫呢?
經(jīng)過一段時間的摸索,發(fā)現(xiàn)AnimateCC(就是原來的Flash)可以導(dǎo)出canvas動畫,而且是基于createjs這個開發(fā)輕量級游戲的js庫的,非常適合用來做移動端的一些h5動畫。不僅縮短制作動畫所需要的時間。同時它也是一個可視化的IDE,不需要編寫代碼就可以完成高品質(zhì)的動畫效果;還可以通過Javascript,為動畫效果添加交互性。
比如下面這一頁動畫,如果使用傳統(tǒng)的html css3的動畫開發(fā)或者是canvas方式來硬寫代碼來實(shí)現(xiàn),切圖加上動畫開發(fā)沒有一天應(yīng)該是搞不定的;而使用AnimateCC導(dǎo)出配合自己寫一點(diǎn)點(diǎn)代碼,一兩個小時就可以搞定。
開始之前先來了解下Animate CC中做動畫的概念。
幀頻
是指每秒鐘放映或顯示的幀或圖像的數(shù)量,這個數(shù)值設(shè)置越大,動畫越快,但同時也是性能消耗大戶,一般設(shè)置24幀就可以了。
圖形與影片剪輯
我們可以將單獨(dú)的動畫,放到一個獨(dú)立的影片剪輯里,這樣可以更好的控制動畫。幾個獨(dú)立的剪片剪輯,可以組成一個完整的動畫。
當(dāng)我們把圖片從資源庫拖到舞臺時,它這個時候,只是普通的位圖,并不能做補(bǔ)幀動畫,所以我們必須把它轉(zhuǎn)換成元件。
圖形由矢量圖或者是位圖組成。
影片剪輯包含在動畫影片中的影片片段,有自己的時間軸和屬性。具有交互性,是用途最廣、功能最多的部分。
時間軸
時間軸是我們創(chuàng)作動畫時使用層和幀組織和控制動畫內(nèi)容的窗口,層和幀中的內(nèi)容隨時間的改變而發(fā)生變化,從而產(chǎn)生了動畫。時間軸主要由層、幀和播放頭組成。
Createjs
CreateJS為CreateJS庫,可以說是一款為HTML5游戲開發(fā)的引擎。目前被Adobe整合到Animate CC中,作為導(dǎo)出canvas動畫的基礎(chǔ)javascript庫。
它是一款為HTML5游戲開發(fā)的引擎,包含:
EaselJS:用于 Sprites、動畫、位圖的繪制,交互體驗(yàn)(包含多點(diǎn)觸控)功能。
TweenJS:補(bǔ)間動畫”引擎
SoundJS:音頻播放引擎
PrloadJS:資源預(yù)加載
具體的文檔和Demo介紹以及API的使用方法,可以通過官網(wǎng)來了解:http://createjs.com/docs
一般動畫設(shè)計(jì)給我們都是單個的使用Animate CC導(dǎo)出的fla源文件,就以我上面說的demo為例,長這樣:
拿到之后我們需要做一點(diǎn)點(diǎn)整理工作,先在Animate CC里面建立一個影片剪輯元件:
建好之后在Animate CC中的庫面板中就會生成剛剛建好的影片剪輯元件,點(diǎn)擊剛剛建好影片剪輯元件鏈接的欄目就會變成可編輯的狀態(tài),然后取個名字,比如我這里取名為view1:
然后雙擊這個元件,時間軸里面是空白的,這個時候需要做的事情就是打開動畫設(shè)計(jì)師給我們的fla源文件,復(fù)制時間軸上所有的圖層粘貼到剛剛新建的影片剪輯里時間軸里。
這樣我們這個叫page1的影片剪輯就包含了這一頁的所有動畫,想一想如果你是要做有5頁游動畫的h5項(xiàng)目,就單獨(dú)把每一頁的動畫放到對應(yīng)的影片剪輯里。這幾個單獨(dú)的影片剪輯就組成了一個完整的動畫。
做完這一步整理工作后,就可以點(diǎn)擊導(dǎo)出了。
它會直接把資源導(dǎo)出到你當(dāng)前fla文件所在的目錄:
images -> 動畫所用的圖片資源:
1. hmt -> html文件
1. js -> canvas所需要的圖形全部轉(zhuǎn)成canvas繪制的元件庫
打開導(dǎo)出的js文件,可以看到剛剛在影片剪輯里做的類鏈接已經(jīng)在js生成了一個view1的方法在里頭:
然后可以發(fā)現(xiàn)在導(dǎo)出來的html文件里中混合了js代碼,我們可以新建一個main.js文件把html文件中的js代碼放進(jìn)去,專門用來控制動畫的播放以及一些交互邏輯的編寫,整理代碼如下(詳細(xì)的說明有寫注釋):
html:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>1</title> <style type="text/css"> body { overflow:hidden; } </style> </head> <body onload="init();" style="margin:0px;"> <canvas id="canvas" width="750" height="1206"></canvas> <!--可以下載下來放在自己的服務(wù)器--> <script src="createjs-2015.11.26.min.js"></script> <script src="1.js"></script> <script src="main.js"></script> </body> </html>
接下來只要把js中對應(yīng)的兩行代碼修改為下面這兩句代碼就可以運(yùn)行我們的動畫:
var view1; view1= new lib.view();
stage.addChild(view);
瀏覽器上就可以顯示出剛才在animate cc里面經(jīng)過類鏈接的影片剪輯的動畫。
但是有時候有些額外的對象或者方法是需要放在view1里面的,那怎么辦呢? 我們新建一個View1的類把a(bǔ)nimate cc里的view1給復(fù)合進(jìn)去。
//view1 (function() { "use strict"; function View1(){ this.Container_constructor(); this.back = new lib.view1(); this.addChild(this.back); this.show = function (){ //這里可以寫額外的方法 } //this.con = new createjs.Container() 這里可以是額外處理的對象 } var p = createjs.extend(View1,createjs.Container); cls.View1 = createjs.promote(View1, "Container"); }());
然后創(chuàng)建這個類把它放到舞臺上就可以了:
js代碼:
view = new cls.View(); stage.addChild(view);
最后js代碼整理如下,相關(guān)代碼已經(jīng)有詳細(xì)的注釋:
// 定義一些需要用到的變量 var canvas, stage, exportRoot, cls={}; // model來專門處理接收事件,記得要是EventDispatcher類 model = new createjs.EventDispatcher(); stageWidth = document.documentElement.clientWidth; stageHeight = document.documentElement.clientHeight; stageScale = stageWidth/(750/2); canvas = document.getElementById("canvas"); if(stageWidth/stageHeight > 0.665) { stageScale = stageHeight/(1206/2); } else { stageScale = stageWidth/(750/2); } canvas.style.width = 750/2*stageScale + 'px'; canvas.style.height = 1206/2*stageScale + 'px'; function init() { canvas = document.getElementById("canvas"); images = images||{}; // LoadQueue是一個預(yù)加載類,可以把需要加載的資源提前加載,基本支持大多數(shù)的文件預(yù)加載。 //我這里主要處理了它的2個事件,fileload,complete。 var loader = new createjs.LoadQueue(false); //這里一共可以是3個參數(shù) 第一個是是否用XHR模式加載 第二個是基礎(chǔ)路徑 第三個是跨域 loader.addEventListener("fileload", handleFileLoad); loader.addEventListener("complete", handleComplete); loader.loadManifest(lib.properties.manifest); } function handleFileLoad(evt) { //這是單個文件加載完成的事件,把它保存到一個地方之后可以直接拿來創(chuàng)建對象 if (evt.item.type == "image") { images[evt.item.id] = evt.result; } } function handleComplete(evt) { var queue = evt.target; var ssMetadata = lib.ssMetadata; for(i=0; i<ssMetadata.length; i++) { ss[ssMetadata[i].name] = new createjs.SpriteSheet( {"images": [queue.getResult(ssMetadata[i].name)], "frames": ssMetadata[i].frames} ) } view1 = new cls.View1(); stage = new createjs.Stage(canvas); //獲取舞臺 Stage是我們的舞臺類,可以理解為所有canvas內(nèi)部對象的總?cè)萜骰蛘哒f是根顯示對象。 stage.addChild(view1); //將容器放在舞臺上 model.addEventListener("complete",function (){ alert("complete"); }) //Ticker是一個計(jì)時類,不過他是每過一幀觸發(fā)一次的,也就是說跟時間其實(shí)沒關(guān)系(因?yàn)閹l是會波動的)。 // createjs.Ticker.setFPS();和createjs.Ticker.addEventListener("tick", stageBreakHandler);是必須要加的,stageBreakHandler里面放的是刷新舞臺的方法,因?yàn)閏reatejs需要不停的刷新舞臺來刷新動畫,也就是一個重繪的過程。 平時也可以拿Ticker類做動畫。 fnStartAnimation = function() { createjs.Ticker.setFPS(lib.properties.fps); createjs.Ticker.addEventListener("tick", stageBreakHandler); } fnStartAnimation(); } function stageBreakHandler(event) { if(stageWidth!=document.documentElement.clientWidth||stageHeight!= document.documentElement.clientHeight) { stageWidth = document.documentElement.clientWidth; stageHeight = document.documentElement.clientHeight; if(stageWidth/stageHeight > 0.665) { stageScale = stageHeight/(1206/2); } else { stageScale = stageWidth/(750/2); } canvas.style.width = 750/2*stageScale + 'px'; canvas.style.height = 1206/2*stageScale + 'px'; } stage.update(); } //view1 (function() { "use strict"; function View1(){ this.Container_constructor(); this.back = new lib.view1(); this.addChild(this.back); } var p = createjs.extend(View1,createjs.Container); cls.View1 = createjs.promote(View1, "Container"); }());
一個動畫效果就完成,當(dāng)然剛開始的時候可能要花點(diǎn)時間來熟悉。一旦熟悉這個套路后,后面就會越發(fā)越熟練了。
像我們一般做這些運(yùn)營項(xiàng)目,都會和用戶發(fā)生些交互動作或者是監(jiān)聽頁面的動畫事件來做進(jìn)一步反饋,這個是還怎么辦呢?
這里有一個小訣竅,我們可以在幀上加上dispatchEvent,來告知程序動畫結(jié)束了,或者播放到哪個關(guān)鍵地方了。 比如這里我們在動畫的最后一幀上加上:
this.stop(); if(model) model.dispatchEvent("complete");
然后在js上新建一個model來專門處理接收事件,記得要是EventDispatcher類:
model = new createjs.EventDispatcher();
然后在代碼中監(jiān)聽就可以了:
model.addEventListener("complete",function (){ alert("complete"); })
在動畫結(jié)束的時候就會監(jiān)聽到complete事件了:
如果碰到圖片很多的項(xiàng)目怎么辦呢?Animate CC也支持導(dǎo)出雪碧圖的功能,在發(fā)布之前設(shè)置下就可以了:
這里要注意的是在選擇的時候選擇兩者兼有,這樣就會把jpg和png格式分別導(dǎo)出;png品質(zhì)選擇32位的就可以了。
左邊是沒有選擇雪碧圖的,右邊是選擇導(dǎo)出雪碧圖的,圖片數(shù)量瞬間少了很多。導(dǎo)出雪碧圖就是這么簡單。
說到做動畫性能是繞不開的話題,同樣在使用fla導(dǎo)出canvas動畫的時候也會碰到性能問題,這里總結(jié)下遇到的性能問題,一般都是在用Animate CC做動畫的時候可以規(guī)避掉,總結(jié)一句話就是:
減少矢量 減少影片剪輯(movie clip) 減少嵌套 減少濾鏡。
詳情如下:
1、嵌套規(guī)范
在使用CC設(shè)計(jì)動畫效果時,盡量不要太多的嵌套,比如:影片剪輯里面再嵌套影片剪輯或者是幀里面再嵌套其它幀。
2、濾鏡和動畫規(guī)范
不要使用濾鏡比如(陰影濾鏡和發(fā)光濾鏡)來做動畫,因?yàn)檫@樣會非常耗費(fèi)性能,在移動端上性能不可控。
可以使用逐幀圖片來代替相關(guān)濾鏡來實(shí)現(xiàn)動畫效果。比如下面效果里面的花瓣飄落和螢火蟲的效果可以使用逐幀圖片來做。
3、素材規(guī)范
少用矢量多用位圖,Text shape都算矢量(如果是用 flashCC或者animateCC做的,在里面就直接把字和矢量圖轉(zhuǎn)成位圖)。
使用Animate CC做動畫效果的基本知識就介紹到這了,有什么問題可以留言一起交流交流。
各位設(shè)計(jì)的小伙伴們,可以嘗試下使用Animate CC來做動畫效果,特別是H5類型的動效。不僅還可以高質(zhì)的還原出設(shè)計(jì)師的動畫效果。
使用Animate CC來設(shè)計(jì)動效,你好,我好,大家都好!
原文地址:騰訊ISUX
藍(lán)藍(lán)設(shè)計(jì)( www.teruid.com )是一家專注而深入的界面設(shè)計(jì)公司,為期望卓越的國內(nèi)外企業(yè)提供卓越的UI界面設(shè)計(jì)、BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 、平面設(shè)計(jì)服務(wù)
藍(lán)藍(lán)設(shè)計(jì)的小編 http://www.teruid.com