久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Cocos2dx中的加減速效果

 清輝花園 2017-12-15

原文地址:http://blog.csdn.net/yanghuiliu/article/details/7261808


在實現(xiàn)運動中,,我們常常需要實現(xiàn)一些加速度或者減速度的效果,,cocos2d-x引擎為我們提供了相應(yīng)的實現(xiàn)接口,這樣我們就不用再用原來的公式計算方法來實現(xiàn)加減速度的效果

Ease系列的方法改變了運動的速度,,但是并沒有改變總體時間,如果整個的action持續(xù)5秒鐘,那么整個的時間仍然會持續(xù)5秒鐘,。

這些action可以被分成3類:

In actions: action開始的時候加速

Out actions: action結(jié)束的時候加速

InOut actions: action開始,,結(jié)束的時候加速

第一個參數(shù)為要加減速度的動作,第二個為加減的速率

還有一些特殊的緩沖公式繼承了進來

1.指數(shù)緩沖


 

EaseExponentialIn

EaseExponentialOut

EaseExponentialInOut

2.賽因緩沖


 

EaseSineIn

EaseSineOut

EaseSineInOut

 

3.彈性緩沖



 

EaseElasticIn

EaseElasticOut

EaseElasticInOut

4.跳躍緩沖


 

EaseBounceIn

EaseBounceOut

EaseBounceInOut

5.回震緩沖


 

EaseBackIn

EaseBackOut

EaseBackInOut

另外還可以設(shè)置速度的倍數(shù)

通過把動作定義為CCSpeed并改變速度,,使用setSpeed將速度按參數(shù)的倍數(shù)變大或者縮小,這樣可以手動實現(xiàn)加減速度




尊重作者勞動,,轉(zhuǎn)載時請標明文章出處。
作者:Bugs Bunny
地址:http://www.cnblogs.com/cocos2d-x/archive/2012/03/13/2393898.html

本文函數(shù)圖像使用GeoGebra繪制,,感謝它才華橫溢的作者,。

為了方便用戶靈活地控制精靈運動,cocos2d-x提供了CCActionEase類系的動作,。它們擁有相似的名字——CCEaseXxxxIn,、CCEaseXxxxOut、CCEaseXxxxInOut,,同時也擁有相似的行為——速度由慢至快,、速度由快至慢、速度先由慢至快再由快至慢,。但是除了這些,,我們對CCActionEase一無所知。就算查閱參考手冊,,我們能得到的信息也不過是類似Ease Sine In的簡短說明,。它們究竟是什么模樣,我們該如何選擇,?

今天我們就來解決這個問題,。鑒于CCActionEase類系的龐大,文章可能會分成兩到三篇,。

1)CCEaseSineIn

在《cocos2d-x動作系統(tǒng)淺析》一文中提到:
update函數(shù)接受一個百分比參數(shù),,它表示動作的完成進度。update根據(jù)這個百分比將目標對象做出相應(yīng)的調(diào)整,。
可以說這個update函數(shù)就是CCActionEase的靈魂,。

1 void CCEaseSineIn::update(ccTime time)
2 {
3 m_pOther->update(-1 * cosf(time * (float)M_PI_2) + 1);
4 }

之前我們已經(jīng)知道CCActionEase類系的動作就是調(diào)整其他動作的速度,變換出新的效果,。這里的m_pOther就是那個被影響的動作,,而一切魔力的源頭就在它接受的參數(shù)上。CCEaseSineIn將傳入的百分比參數(shù)進行了一系列變換,,然后傳給了m_pOther,。

我們將這個變換公式提取出來,記作:
f(x)=1-cos(π/2*x) x∈[0,1]
這個就是已用時間百分比與實際完成進度的關(guān)系,。在勻速運動中,,它們應(yīng)該是相等的,但是在變速運動中,,它們的關(guān)系就會變幻莫測,。

上圖中的黑色曲線就是f(x)的函數(shù)圖像,。它的定義域從0開始,到1結(jié)束,,值域也是這樣,。根據(jù)這條線的走勢,可以粗略看出速度是越變越快的,,但還是不夠形象,。
在運動學(xué)中,物體的位移對于時間的導(dǎo)數(shù)就是物體的瞬時速度,。如果我們能得到這條瞬時速度的曲線,,那就直觀多了。上面的函數(shù)f(x)是已用時間百分比與實際完成進度的關(guān)系,,這里可以近似地理解為時間與路程的關(guān)系,。
所以我們對f(x)求導(dǎo),得出:
f'(x)=π/2*sin(π/2*x) x∈[0,1]
它對應(yīng)圖中那條紅色曲線,??梢院苊黠@地看出,速度越變越快,,在C點達到了最高,。
正如它名字說的那樣,它的速度由慢至快,,呈正弦變化,。

2)CCEaseSineOut

我們再來看下CCEaseSineOut類。

1 void CCEaseSineOut::update(ccTime time)
2 {
3 m_pOther->update(sinf(time * (float)M_PI_2));
4 }

同理得出:
f(x)=sin(π/2*x) x∈[0,1]
f'(x)=π/2*cos(π/2*x)

同樣我們更關(guān)注那條紅色曲線,,它從最高點C出發(fā),,一路下降到達A點。這表明在CCEaseSineOut動作中,,速度是越來越慢的,,它的圖像也呈正弦變化,。

3)CCEaseSineInOut

我們知道CCEaseXxxxInOut的速度變化是先由慢至快,,再由快至慢。如果我們將上面兩個圖像拼在一起,,然后在將橫軸比例縮小一倍,,那結(jié)果就是這條曲線的模樣了。
一般情況下,,我們需要將函數(shù)分成兩段,,第一段在0到0.5之間,第二段在0.5到1之間,。我們來看看CCEaseSineInOut是如何實現(xiàn)的,。

1 void CCEaseSineInOut::update(ccTime time)
2 {
3 m_pOther->update(-0.5f * (cosf((float)M_PI * time) - 1));
4 }

f(x)=-0.5*(cos(π*x)-1) x∈[0,1]
f'(x)=π/2*sin(π*x)

在CCEaseSineInOut中,,這兩段曲線正好是同一個函數(shù)(非分段函數(shù))的圖像。很巧妙是不是,?
圖中紅色曲線從原點O出發(fā),,一路上升到達最高點C,然后又一路下滑降至D點,。它同樣也是一條正弦變化的曲線,。動作的速度看起來就是由慢至快,再由快至慢的,。

小結(jié)

CCEaseSineIn,、CCEaseSineOut、CCEaseSineInOut這三個動作同屬速度正弦變化,,變化的范圍是[0,π/2],。

4)CCEaseExponentialIn

有了前面的經(jīng)驗,后面就容易多了,,先來看一下CCEaseExponentialIn的update函數(shù),。

1 void CCEaseExponentialIn::update(ccTime time)
2 {
3 m_pOther->update(time == 0 ? 0 : powf(2, 10 * (time/1 - 1)) - 1 * 0.001f);
4 }

大家可能已經(jīng)注意到,這里使用了一個條件運算符,,于是表達式變作了分段函數(shù),。
當x=0時,f(x)=0
當x∈(0,1]時,,f(x)=2^(10*(x-1))-0.001

注意這條不是速度的曲線,。
上面副繪圖區(qū)中的圖像就是這個函數(shù)的整體走勢,我們在主繪圖區(qū)給原點附近的曲線一個特寫,??梢钥吹剑藊=0的情況,,曲線與x軸還有一個交點,。
對2^(10*(x-1))-0.001=0求解,得出:
x=1-ln(1000)/(10*ln(2))=0.00342

現(xiàn)在我們開始在腦中想象一下精靈按照CCEaseExponentialIn動作移動的詳細步驟,。
首先,,時間從零開始,精靈被設(shè)置到起始位置,。這一步是正常的沒有問題,。
接下來,精靈猛地朝著反方向跳動了很小的一段距離,。這個距離是非常非常小的,,也就是圖上的B點附近,大約只占整個移動距離的0.00234%
然后,精靈開始以變化的速度朝著目標點移動,。經(jīng)過點A時精靈回到初始位置,。這時,我們設(shè)計的運動才剛剛開始,。
如果我們將x=1代入公式,,可以推算出:
f(x)=1-0.001=0.999
也就是說,圖像最終沒有到達終點,,而是差了一小段距離,。

簡單來說,總時間的前0.342%部分以及最終的那一瞬間的運動是不太正常的,。
如果你設(shè)計了一個超過1000秒的運動,,那么前3秒內(nèi),精靈的準確位置不會在你設(shè)計的軌跡上,。
當然如果想觀察到這個問題,,運動的距離也是一個關(guān)鍵。
假設(shè)你瘋狂地設(shè)計了一個運動10萬像素的精靈,,并且運動時間超過1000秒,,那你就能觀察到這一現(xiàn)象了。3秒鐘,,反向2個像素,。

但是為什么會這樣呢?是引擎的bug嗎,?
確切來說,,這應(yīng)該算不上是bug,這只是精度引起的問題,。

下面這段都是我自己的推測,,也就是猜到,大家看看就好了,。
我猜測這個公式的最初原型應(yīng)該是:
f(x)=2^(10*(x-1)) x∈[0,1]
但是它有一個問題,,那就是當x=0的時候,f(0)=1/1024
時間為零的時候,,精靈大約就已經(jīng)有了千分之一的位移,,而且是在一個物體運動剛開始的時候,猛然地跳動是非常明顯的,。所以設(shè)計者將千分之一的誤差移動到了末尾,,也就是運動要結(jié)束的時候,。
那公式現(xiàn)在的樣子就是:
f(x)=2^(10*(x-1))-1/1024 x∈[0,1]

大家都知道cocos2d-x多使用單精度浮點型數(shù)字,,以及寫0.0009765625f比較麻煩等諸多因素,最后這個公式就簡化成了現(xiàn)在的模樣。

我的猜想說完了,,我們接著來求導(dǎo):
f'(x)=10*2^(10*(x-1))*ln(2) x∈[0,1]

按照最理想的那個公式繪制出圖像,,這里我們只看那條紅色的曲線。這條曲線從D點開始一路上升,,迅速到達C點,。如果你對它再次求導(dǎo),就能得出其加速度的變化規(guī)律,。從DC曲線上應(yīng)該可以看出其加速度也是越來越大的,。
額,說得有點兒遠了,。我們把注意力先集中起來,,計算出速度的最小值和最大值。
f'(0)=10*2^(-10)*ln(2)=0.006769
f'(1)=10*2^0*ln(2)=6.931472

CCEaseExponentialIn的速度由慢至快,,從0.006769上升至6.931472,,呈指數(shù)級變化。

5)CCEaseExponentialOut

1 void CCEaseExponentialOut::update(ccTime time)
2 {
3 m_pOther->update(time == 1 ? 1 : (-powf(2, -10 * time / 1) + 1));
4 }

CCEaseExponentialOut與CCEaseExponentialIn的實現(xiàn)是相似的,,唯一的不同是CCEaseExponentialOut在最后一瞬間會有短距離的跳躍(千分之一的誤差),,而CCEaseExponentialIn是舍棄部分。個人認為CCEaseExponentialOut的處理方式更合理些,。
好了直接上圖

這里沒有難點,,我直接讓工具生成的導(dǎo)函數(shù)圖像。
我們關(guān)心的是A點(0,6.93147)和D點(1,0.00677),,與CCEaseExponentialIn的速度范圍是一樣的,。從6.93147下降至0.00677,速度為由快至慢的指數(shù)變化,。

6)CCEaseExponentialInOut

在《知易游戲開發(fā)教程cocos2d-x移植版003》中有一段CCEaseExponentialInOut的演示代碼,,測試運行時會發(fā)現(xiàn)精靈最后以極快的速度飛出了屏幕,是筆者使用不當,,還是別的什么原因,?當時由于時間、精力的問題沒有深入研究,,今天借此機會將問題分析一下,。

復(fù)制代碼
 1 void CCEaseExponentialInOut::update(ccTime time)
2 {
3 time /= 0.5f;
4 if (time < 1)
5 {
6 time = 0.5f * powf(2, 10 * (time - 1));
7 }
8 else
9 {
10 time = 0.5f * (-powf(2, 10 * (time - 1)) + 2);
11 }
12
13 m_pOther->update(time);
14 }
復(fù)制代碼

呵呵,典型的分段函數(shù),。繪制函數(shù)圖像如下:

圖中這條藍色的曲線就是CCEaseExponentialInOut使用的分段函數(shù),。很明顯可以看到在A點處,曲線走向發(fā)生了90°的變化,,向著點(1,-511)延伸,。它沒有像前面說過的函數(shù)那樣逼近點C(1,1),,這就解釋了為什么精靈莫名其妙地飛出了屏幕。

這是一個bug,,我們希望曲線的后半段能像那條綠色的曲線AC那樣,。(我只在Win32平臺上測試的,不知其他平臺上是否也存在這個問題,,有興趣的朋友可以測試下,。)

我的修改如下:

復(fù)制代碼
 1 void CCEaseExponentialInOut::update(ccTime time)
2 {
3 time /= 0.5f;
4 if (time < 1)
5 {
6 time = 0.5f * powf(2, 10 * (time - 1));
7 }
8 else
9 {
10 // 將(time - 1)變作(1 - time)
11 time = 0.5f * (-powf(2, 10 * (1 - time)) + 2);
12 }
13
14 m_pOther->update(time);
15 }
復(fù)制代碼

修正后,,動作的行為正常了,。
對新的函數(shù)求導(dǎo),得出圖中的紅色曲線,。其中點D,、點E,、點F的坐標分別為(0.5,6.93147)、(0,0.00677),、(1,0.00677),。
細心的朋友可能已經(jīng)發(fā)現(xiàn)了點C沒有到達(1,1)。是的,,這里存在0.000488的誤差,,曲線的起始點也一樣。即原來1/1024的誤差被平分到了開頭和末尾,。

CCEaseExponentialIn,、CCEaseExponentialOut、CCEaseExponentialInOut這三個動作同屬速度指數(shù)級變化,,變化的范圍是[0.00677,6.93147],。


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約