關(guān)于定幀游戲的平滑記錄

定幀帶來的問題

游戲的心跳,往往因當(dāng)前一幀運算量的不同擎淤,而有不同的delta時間奢啥。但是定幀則要求每間隔固定時間執(zhí)行一次運算。

我們對于定幀的常規(guī)實現(xiàn)之一如下:

// 邏輯定幀的時長
float logicFrameStep;
float timeCount;

// 顯示幀的心跳函數(shù)
void Update(float deltaTime)
{
    timeCount += deltaTime;
    while (timeCount >= logicFrameStep)
    {
        // 邏輯心跳
        LogicTick();
        timeCount -= logicFrameStep;
    }
}

通過此種方式嘴拢,可以實現(xiàn)邏輯定幀的實現(xiàn)桩盲。

但是,當(dāng)游戲需要平滑顯示而邏輯卻需要定幀運算時席吴,矛盾便產(chǎn)生了赌结。由于邏輯幀定時長執(zhí)行,而現(xiàn)實幀不定時長孝冒,所以在同一顯示幀中可能會運行n個邏輯幀柬姚,且n個邏輯幀的總時長不一定等于該顯示幀的時長。

邏輯定幀與顯示幀的錯位關(guān)系

雖然定幀的方式可以確保每一邏輯幀運算后庄涡,所有數(shù)據(jù)都是正確的(起碼站在邏輯的角度是這樣)量承,但是根據(jù)上圖可以發(fā)現(xiàn),顯示幀是會存在時間富余的(邏輯幀3在顯示幀1內(nèi)是沒有執(zhí)行完的)穴店。

因此從顯示的角度看撕捍,顯示幀1只進行了2幀邏輯,而顯示幀2則進行了4幀邏輯迹鹅,雖然顯示幀1與2之間的時間比為5:7卦洽。正是因為顯示幀內(nèi) 邏輯定幀的比值時間的比值 不同贞言,從而導(dǎo)致了顯示層的一個大問題 —— 抖動斜棚。

顯示平滑的處理

針對抖動,筆者曾嘗試用數(shù)學(xué)的方式進行矯正,但是結(jié)果證明效果并不理想弟蚀,運算量提升不說蚤霞,效率也不太高(使用的是最小二乘法义钉,但是它顯然不太可以勝任我們的需求)昧绣。

筆者也曾使用變速的方法讓移動平滑,即當(dāng)前數(shù)據(jù)離目標(biāo)數(shù)據(jù)越遠(yuǎn)捶闸,則以更高速度接近夜畴,否則接近速度降低税灌。但是這樣一來會產(chǎn)生與邏輯相比失真的問題洛勉,且速度的變動公式會很大程度影響體驗粘秆,因而該方案也被我們的項目拋棄了(這種方案是我從《夢幻西游》的攝像機移動上學(xué)來的)翻擒。

后來筆者意識到自己把簡單問題復(fù)雜化了巩趁。其實問題的核心就是數(shù)值要在指定事件內(nèi)變化指定大小炉菲。既然抖動是當(dāng)前幀的顯示與邏輯不匹配造成的拍霜,那么讓顯示延遲個1-2幀嘱丢,不就有可以修復(fù)這種抖動了嗎,畢竟延遲顯示1-2幀還不太會影響用戶體驗(我不信《守望先鋒》里早這么1幀你就會變成神槍手)祠饺。

核心代碼如下:

// 經(jīng)過平滑后的結(jié)果值
public double Value;

// 插入新值
// duration代表邏輯幀時長
// target代表這一邏輯幀的目標(biāo)值
public void Insert(float duration, double target)
{
    __waitSeconds += duration;
    __targetValue = target;
}

// 核心心跳
// 利用__waitSeconds計算當(dāng)前顯示幀對應(yīng)的值Value
public void Tick(float delta)
{
    if (__waitSeconds <= delta)
    {
        Value = __targetValue;
        return;
    }

    double p = delta / __waitSeconds;
    Value = Value * (1 - p) + __targetValue * p;

    __waitSeconds -= delta;
}

每個顯示幀調(diào)用Insert方法收集數(shù)據(jù)越驻。而每個顯示幀則調(diào)用Tick方法計算平滑后的結(jié)果值Value

結(jié)尾

最終經(jīng)過測試道偷,這種方法實現(xiàn)簡單缀旁,利用1顯示幀的緩沖達到了符合項目的平滑需求。所以記錄下來勺鸦,為自己曾經(jīng)走過的彎路默哀诵棵。

希望下次碰到問題的時候,不會把自己帶入太深的彎路 :P祝旷。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末履澳,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子怀跛,更是在濱河造成了極大的恐慌距贷,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吻谋,死亡現(xiàn)場離奇詭異忠蝗,居然都是意外死亡,警方通過查閱死者的電腦和手機漓拾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門阁最,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人骇两,你說我怎么就攤上這事速种。” “怎么了低千?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵配阵,是天一觀的道長。 經(jīng)常有香客問我示血,道長棋傍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上癞志,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好么库,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布脚祟。 她就那樣靜靜地躺著绍在,像睡著了一般感帅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上地淀,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天失球,我揣著相機與錄音,去河邊找鬼帮毁。 笑死实苞,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的烈疚。 我是一名探鬼主播黔牵,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼爷肝!你這毒婦竟也來了猾浦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤灯抛,失蹤者是張志新(化名)和其女友劉穎金赦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體对嚼,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡夹抗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了纵竖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漠烧。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖靡砌,靈堂內(nèi)的尸體忽然破棺而出已脓,到底是詐尸還是另有隱情,我是刑警寧澤通殃,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布摆舟,位于F島的核電站,受9級特大地震影響邓了,放射性物質(zhì)發(fā)生泄漏恨诱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一骗炉、第九天 我趴在偏房一處隱蔽的房頂上張望照宝。 院中可真熱鬧,春花似錦句葵、人聲如沸厕鹃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽剂碴。三九已至把将,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間忆矛,已是汗流浹背察蹲。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留催训,地道東北人洽议。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像漫拭,于是被迫代替她去往敵國和親亚兄。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容