熵與負熵
熵遵循熵增原理,即無序非熱能與熱能之間的轉換具有方向性。薛定諤說過:生命本質在於負熵。熵代表的是無序,負熵就是熵的對立,而負熵表示的則是有序。汲取負熵(米飯、麵包、牛奶、雞蛋),可以簡單的理解為從外界吸收了物質或者能量之後,轉化成負熵流,使系統的熵降低,人體變得更加有序。
那麼一直吃飯為何還衰老?一日吃6餐行不行?答案是肯定不行。
負熵流和熵增伴從出生到死亡一直在對抗,隨著時間流逝,負熵流慢慢對抗不過熵增,人體組織體系結構越來越無序。越無序就越難以抵抗疾病,所以通常死亡不是熵增到無序而老死,而是熵值較大時,難以抵抗其他疾病而死亡。最終歸於塵土、灑向大海(更加無序了)。
所以:熵增加的方向就是時間的方向,時間不可逆,回到過去是不可能的,才有了AlloyTicker-讓時光倒流成為可能….
Github: https://github.com/AlloyTeam/AlloyTicker
Demo: http://alloyteam.github.io/AlloyTicker/
傳統的動畫和運動
涉及到動畫和運動才能和時間關聯起來。這裡做下分類:
1.精靈圖動畫:如利用精靈圖實現人物跑、走等
2.積分運動:如粒子系統、子彈飛行等
3.緩動:如骨骼動畫、彈出層特效、金幣拾取等其他擁有起點、終點、時間和緩動函式的運動
精靈圖動畫
如上面的精靈圖動畫,當需要求出當前播放哪一幀的時候,通常按照下面這種方式計算:
1 |
var index = Math.floor(dt / interval) % length; |
其中index為當前求出的結果。
dt為過去了多長時間
interval每一幀的間隔時間
length為總共的幀數
精靈圖動畫可逆設計
要實現精靈圖動畫可逆,必須對dt進行動態計算。dt怎麼計算?
dt = 當前時間 – 開始時間
即:
1 2 |
var dt = currentTime - startTime; var index = Math.floor(dt / interval) % length; |
只需要把currentTime和startTime儲存好方便sprite物件使用即可實現可逆。
當然這裡要做邊界處理,即dt小於0,代表播放時間還未開始,index是沒有對應的值。
積分運動
1 2 3 4 |
this.vx += this.ax * dt; this.vy += this.ay * dt; this.x += this.vx* dt; this.y += this.vy * dt; |
即:
速度是加速度在時間上的累加
位移是速度在時間上的累加
積分運動可逆設計
問題建模:根據起點位置(startX startY)、起始速度(vx vy)、加速度(ax ay)、開始時間(startTime)、當前時間(currentTime)求當前位置(x y)。
1 2 3 4 |
var dt = this.currentTime - this.startTime; var h_sqDt = dt * dt/2; this.x = this.startX + this.vx * dt + this.ax * h_sqDt; this.y = this.startY + this.vy * dt + this.ay * h_sqDt; |
緩動
1 2 |
this.dv = this.endValue - this.startVaule ; var result = this.startVaule + this.dv * this.ease(dt / this.time); |
其中result為當前求出的結果。
endValue為最終要運動到的結果
startVaule為開始運動的狀態
ease為緩動函式
time為總時間
緩動可逆設計
緩動天生就是支援可逆設計。只需計算好dt便可。
1 |
var dt = currentTime - startTime; |
當然還要處理一下邊界情況,因為時間的流動性,dt是可能大於0或者dt大於傳入的總時間this.time。
當dt小於0,即result等於this.startVaule
當dt大於總時間,即result等於this.endVaule
精靈圖動畫+積分運動
如上面的超級瑪麗,不僅需要播放精靈圖動畫,還需要向右的積分運動。所以需要同時顧及兩種狀態:
1 2 3 4 5 6 7 8 9 10 |
var dt = this.currentTime - this.startTime; //計算關鍵幀索引的結果 if (dt < 0) { this.index = -1; } else { this.index = Math.floor(dt / this.interval) % this.length; } //計算積分運動的結果 this.x = this.startX + this.vx * dt; this.y = this.startY + this.vy * dt; |
AlloyTicker
是時候抽象出一個時間機器的-AlloyTicker。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
var AlloyTicker = function(){ this.interval= null; this.intervalTime= 16; this.tickIntervalTime = 16; this.currentTime = 0; this.clockwise = true; this.ticks=[]; this.isPause = false; this.isStop = false; } AlloyTicker.prototype = { //時間開始 start: function () { this.interval = setInterval(function () { if(!this.isPause){ this.currentTime += (this.clockwise ? this.intervalTime : -1 * this.intervalTime); if(this.currentTime<0)this.currentTime=0; this.tick(); } }.bind(this), this.tickIntervalTime); }, tick: function () {}, //時光倒流 back: function () { this.clockwise = false; }, forward: function () {}, goto: function(time){}, pause:function(){}, play :function(){}, stop:function() {}, scale:function(value){} } |
因為:
1.從邏輯層面上currentTime不屬於動畫或運動物件的屬性,都屬於AlloyTicker時間機器的屬性。
2.統一時間管理(倒流(back)、暫停(pause)、加速減速(scale)、時間跳轉(goto)…)
3.所有物件的動畫和運動都跟AlloyTicker掛鉤,AlloyTicker時間狀態的變更會影響到所有掛鉤的物件
Github: https://github.com/AlloyTeam/AlloyTicker
Demo: http://alloyteam.github.io/AlloyTicker/