最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Lerp:理解線性插值

2023-07-05 01:03 作者:翻滾的肉喵  | 我要投稿

翻譯自:Derek Stobbe?Lerp: Understanding Linear Interpolation? ?Oct 7, 2016

blog.problematic.io?

如果你曾經(jīng)想要在玩家受到傷害時(shí)將他們的生命值條從綠色變?yōu)榧t色,根據(jù)能量水平計(jì)算攻擊的傷害,或者在關(guān)卡設(shè)計(jì)中從黑暗平滑地過(guò)渡到光明,那么你很可能使用了線性插值或“l(fā)erp”操作。在游戲編程中,掌握線性插值并對(duì)其應(yīng)用充滿(mǎn)信心是非常寶貴的,但我注意到也存在一些需要當(dāng)心的陷阱,所以我們來(lái)討論一下“l(fā)erp”的確切含義,以及我們?nèi)绾卧诖a中應(yīng)用它。

線性插值背后的思想相當(dāng)簡(jiǎn)單:尋找位于兩個(gè)已知值之間距離的某個(gè)百分比的未知值(從技術(shù)上講,它可以是一組任意大的已知值,但在游戲開(kāi)發(fā)中,我發(fā)現(xiàn)它通常是兩個(gè)值),為了清晰性和一致性,我們稱(chēng)第一個(gè)已知值為“a”,第二個(gè)已知值為“b”,距離百分比為“t”。以函數(shù)的形式,我們可以這樣寫(xiě): lerp(a, b, t).

這是我構(gòu)建的一個(gè)可視化工具。你可以拖動(dòng)點(diǎn)來(lái)實(shí)驗(yàn)兩點(diǎn)之間的線性插值(綠色的點(diǎn)表示插值的值);懸?;蛴|及方程頂部的某個(gè)點(diǎn)或有顏色的部分,將使所有匹配的值加粗:


https://codepen.io/Problematic/pen/qapXJa

有幾點(diǎn)需要注意。首先,參數(shù)要么是數(shù)字,要么是由數(shù)字組成的東西。這自然意味著,你可以在浮點(diǎn)數(shù)和整數(shù)之間做插值,而你也可以通過(guò)分別lerping每個(gè)組件的值,在顏色、數(shù)值向量(就像Unity中的Vector2和Vector3類(lèi)型),和由數(shù)字組成的自定義數(shù)據(jù)類(lèi)型之間進(jìn)行插值(Unity通過(guò)靜態(tài)方法為前兩項(xiàng)提供了包裝器 Vector3.Lerp和Color.Lerp)

其次,請(qǐng)注意插值的一個(gè)有趣屬性:

當(dāng)(藍(lán)色)t值為0時(shí),綠色的插值點(diǎn)等于第一個(gè)(紅色)點(diǎn)。當(dāng)t = 1時(shí),插值點(diǎn)等于第二個(gè)(紫色)點(diǎn)?;诖?,你可以推測(cè)當(dāng)t = 0.5時(shí),插值點(diǎn)位于兩者之間,t = 0.75是a到b距離的四分之三,以此類(lèi)推。

請(qǐng)注意,可視化工具允許你探索小于0或大于1的t值,但此時(shí),你不再是插值一個(gè)值,而是外推一個(gè)值。lerp函數(shù)的許多實(shí)現(xiàn)(包括Unity的Mathf.Lerp)將t值夾在0和1之間,這意味著你將無(wú)法重現(xiàn)超出0 > t > 1的結(jié)果:

當(dāng)夾緊輸入時(shí),例如lerp(a, b, 1.12358),給出與lerp(a, b, 1.0)相同的結(jié)果。

考慮到這一點(diǎn),讓我們談?wù)勎医?jīng)常看到開(kāi)發(fā)人員犯的一個(gè)錯(cuò)誤:使用lerp在值之間進(jìn)行插值,其中t值是由時(shí)間驅(qū)動(dòng)的。請(qǐng)看下面的偽代碼:

function charge_attack (target_value) {

? player.attack_power = lerp(0, target_value, elapsed_game_time);

}

function update_game () {

? if (button_held) {

? ? charge_attack(target_value);

? }

}

在這個(gè)例子中,當(dāng)玩家按住按鈕時(shí),我們希望代表玩家攻擊力的某些值在一段時(shí)間內(nèi)(比如一秒鐘)

從初始值0變?yōu)槟繕?biāo)值。

然而,這個(gè)實(shí)現(xiàn)中有一個(gè)bug

還記得lerp函數(shù)的t值是如何被限制在[0,1]范圍內(nèi)的嗎?

假設(shè)我們的elapsed_game_time值(由Time表示,例如Unity里的時(shí)間)

是一個(gè)表示游戲已經(jīng)運(yùn)行的秒數(shù)的浮點(diǎn)數(shù)

并且在游戲開(kāi)始時(shí)從0開(kāi)始遞增,這段代碼只會(huì)在游戲的第一秒按預(yù)期工作

在這之后,“消耗時(shí)間”將是一個(gè)大于1的數(shù)字,并且調(diào)用charge_attack會(huì)

立即將attack_power設(shè)置為目標(biāo)值,而不是隨著時(shí)間的推移不斷增加,讓玩家進(jìn)行完全充滿(mǎn)能量的攻擊而不受懲罰,

從而破壞我們完美調(diào)整的游戲平衡。

我們?nèi)绾谓鉀Q這個(gè)問(wèn)題?

我們需要將t的值重新映射到0到1(包括0和1)之間,最簡(jiǎn)單的方法是緩存用戶(hù)開(kāi)始按下按鈕的時(shí)間。

在我們的示例實(shí)現(xiàn)中,它可能看起來(lái)像這樣:

function charge_attack (target_value) {

? progress = elapsed_game_time - button_pressed_at;

? player.attack_power = lerp(0, target_value, progress);

}

function update_game () {

? if (button_pressed) {

? ? button_pressed_at = elapsed_game_time;

? }

if (button_held) {

? ? charge_attack(target_value);

? }

}

唯一不同的是緩存了按下按鈕的時(shí)間,并從游戲循環(huán)中調(diào)用charge_attack更新attack_power時(shí),當(dāng)前消耗的游戲時(shí)間中減去這個(gè)時(shí)間。

我們可以看到,這適用于我們所期望的1秒的持續(xù)時(shí)間,例如,假設(shè)玩家在3.1秒時(shí)按下按鈕。

在半秒之后,這樣在游戲時(shí)間為3.6秒時(shí),我們計(jì)算的t值是3.6 - 3.1,也就是0.5…正是我們想要的值。


如果我們不想在一秒內(nèi)將attack_power改變?yōu)槟繕?biāo)值,而是想在更長(zhǎng)的一段時(shí)間內(nèi)改變它,比如2.5秒呢?

我們的實(shí)現(xiàn)再次失敗了,因?yàn)樵诎聪掳粹o一秒后,elapsed_game_time - button_pressed_at超過(guò)1.0,并且被夾住了。我們?nèi)绾谓鉀Q這個(gè)問(wèn)題?

好吧,如果我們看看我們當(dāng)前的解決方案,我們可以看到elapsed_game_time - button_pressed_at給了我們一個(gè)小數(shù),

表示我們當(dāng)前在“填充”attack_power的進(jìn)展,使其等于target_value。

我們知道任何數(shù)字除以1等于這個(gè)數(shù)本身,

所以我們可以用公式(elapsed_game_time - button_pressed_at) / 1.0表示我們的進(jìn)度。

巧合的是(或者不是),1.0恰好代表了充能效果持續(xù)時(shí)間的舊需求,所以如果我們把這個(gè)常量換成一個(gè)表示充能時(shí)間的變量,就又回到了正軌:

function charge_attack (target_value) {

? progress = (elapsed_game_time - button_pressed_at) / charge_duration;

? player.attack_power = lerp(0, target_value, progress);

}

function update_game () {

? if (button_pressed) {

? ? button_pressed_at = elapsed_game_time;

? }

if (button_held) {

? ? charge_attack(target_value);

? }

}

一切都按照預(yù)期運(yùn)行,我們還得到一個(gè)額外的好處,就是可以輕松地調(diào)整充能持續(xù)時(shí)間來(lái)控制玩家的攻擊需要多長(zhǎng)時(shí)間才能達(dá)到最大威力。

游戲平衡完好無(wú)損!

正如我希望展示的那樣,在游戲中成功使用線性插值的問(wèn)題域主要涉及到如何將 t 進(jìn)度變量映射到0到1之間的浮點(diǎn)數(shù)。


Lerp:理解線性插值的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
晋宁县| 岳池县| 周宁县| 泾阳县| 公安县| 类乌齐县| 阿克陶县| 长兴县| 郑州市| 图片| 平湖市| 富平县| 马关县| 同江市| 团风县| 彭阳县| 舞钢市| 喜德县| 鞍山市| 大厂| 珲春市| 米脂县| 泰州市| 禹城市| 铜川市| 石楼县| 永嘉县| 社旗县| 尉氏县| 大安市| 江都市| 新河县| 北票市| 永胜县| 夏邑县| 伊川县| 米脂县| 厦门市| 濉溪县| 广南县| 阿合奇县|