[游戲開發(fā)筆記]buff與屬性計(jì)算邏輯重構(gòu)

最近項(xiàng)目針對buff系統(tǒng)做了一些重構(gòu)糠雨,主要針對屬性修改的邏輯辣恋,這里做一些總結(jié)潘酗。

之前的設(shè)計(jì)

目前屬性是有依賴關(guān)系的,程序這邊提供了公式的配置方式揪阿,比如當(dāng)屬性A是需要用其他屬性來計(jì)算時疗我,可以配置B + C * 0.1表示A 和 B,C的公式關(guān)系南捂,然后通過導(dǎo)表可以得出所有屬性的依賴關(guān)系吴裤,順便檢測下死循環(huán)等。

在制作Buff時的效果時黑毅,有時會需要修改屬性的值嚼摩,修改方式有按固定值的,也有按百分比的。最開始設(shè)計(jì)的時候枕面,給策劃提供了set_attr和get_attr兩個函數(shù)愿卒,策劃可以寫出很多種邏輯:

  • 增加10:set_attr(A, get_attr(擁有者, A) + 10)
  • 變?yōu)?0%:set_attr(A, get_attr(擁有者, A) * 0.8)
  • 關(guān)聯(lián)另一個屬性:set_attr(A, get_attr(擁有者, A) - get_attr(擁有者, A) * 0.2)
  • 關(guān)聯(lián)另一個角色的屬性:set_attr(生命, get_attr(擁有者, 生命) - get_attr(攻擊者, 力量) * 0.2)

我們把配置轉(zhuǎn)換成了可執(zhí)行的代碼,每個影響屬性的效果潮秘,會到目標(biāo)屬性下注冊一個函數(shù)琼开,buff消失后,就會注銷相關(guān)的函數(shù)枕荞,然后按需重算屬性柜候,大概過程如下:

按公式計(jì)算屬性的基礎(chǔ)值

遍歷buff的相關(guān)修改函數(shù)

return 結(jié)果

這種設(shè)計(jì)起初也挺好用,策劃寫起來比較自由躏精,但隨著復(fù)雜度的增加渣刷,開始發(fā)現(xiàn)一些問題。

修改函數(shù)執(zhí)行順序?qū)Y(jié)果的影響比較大

當(dāng)存在多個效果作用于同一個屬性時矗烛,計(jì)算的順序會導(dǎo)致計(jì)算結(jié)果不一致辅柴。比如先加再乘先乘再加會有明顯的不同。關(guān)于還存一個set的功能瞭吃,策劃希望的是直接修改為指定的值碌嘀,比如攻擊變?yōu)?點(diǎn)之類的,這種優(yōu)先級會超過公式計(jì)算歪架,和buff的加成股冗,雖然目前也可以用set_attr函數(shù)達(dá)到相同的效果,但必須放最后一個后才行和蚪。

對于這個問題止状,我們把屬性計(jì)算的過程重新梳理了一下。buff不再按順序執(zhí)行惠呼,而是y = a * x + b的方式导俘,buff改變只是這個公式中的乘法因子a和加法因子b峦耘,而x繼續(xù)套用原本的公式邏輯剔蹋,過程大概如下:

if buff 中存在set操作 then
    return set操作的值
end

按公式計(jì)算屬性的基礎(chǔ)值x

遍歷buff計(jì)算出a和b的值

return a * x + b

對于set,用流程保證優(yōu)先級辅髓,然后再增加了兩個函數(shù)用于修改a和b值泣崩。為了防止利用set函數(shù)填寫出加法或者乘法的邏輯,或者用加法函數(shù)寫出乘法的邏輯洛口,則直接利用語法解析器矫付,在導(dǎo)表檢查時禁止掉了這種寫法。

屬性關(guān)聯(lián)

對于一個屬性來說第焰,除了基礎(chǔ)的公式买优,buff的效果相當(dāng)會新增屬性之間的依賴關(guān)系,特別當(dāng)該效果是光環(huán)類型時(卸載時要還原效果)。除了對自身的屬性會有依賴杀赢,還可能對其他對象的屬性產(chǎn)生依賴烘跺,我們對此進(jìn)行了一些討論,做了下如下分類:

  • 依賴其他對象的屬性

為了降低復(fù)雜度脂崔,做成了執(zhí)行一次立即緩存滤淳,不再其他對象的屬性更新,而導(dǎo)致buff這邊連鎖更新

  • 依賴當(dāng)前對象的屬性本身

通過導(dǎo)表檢查和修改函數(shù)的改進(jìn)砌左,已經(jīng)填不出來脖咐,所以不再有這種情況

  • 依賴當(dāng)前對象的其他屬性,要繼續(xù)分兩種情況:
  1. 執(zhí)行結(jié)果是不需要還原的汇歹。比如每隔1s按自己生命上限的10%增加HP屁擅。這種是不會因?yàn)樾遁dbuff而需要扣血,所以不會有依賴
  2. 執(zhí)行結(jié)果是需要還原的产弹,比如按自己力量的10%增加攻擊力煤蹭。如果想做成力量變化了,對應(yīng)增加的攻擊力也變化取视,意味著增加一種攻擊力和力量的關(guān)系硝皂。這種關(guān)系和之前公式關(guān)系類似,只不過是動態(tài)增刪的作谭,并且會隨著buff動態(tài)增加和刪除的稽物,并且可能帶來循環(huán)依賴。我們認(rèn)真查了查目前項(xiàng)目的幾百種buff折欠,發(fā)現(xiàn)目前并沒有這種情況贝或。實(shí)在有需求,也存在還有個簡單的解法锐秦,就是新增一些屬性咪奖,作為要改變屬性公式的因子,然后buff去改變這個因子酱床,這樣就不會產(chǎn)生動態(tài)的依賴規(guī)則了羊赵,更新觸發(fā)的邏輯也會有。

DSL解析

這幾天除了討論改進(jìn)方案扇谣,最有意思還是DSL解析這塊昧捷。準(zhǔn)確來說,其實(shí)之前策劃填寫的是lua罐寨,只不過這次希望解析這些lua靡挥,方便做更加精準(zhǔn)的控制。比如只允許用指定的語法鸯绿,不允許填出一些依賴或者死循環(huán)等跋破,將填好的set_attr配置替換成其他的函數(shù)等簸淀。

主要元素是函數(shù),變量毒返,字符串啃擦,數(shù)字,和 加減乘除 操作之類的饿悬,最后選擇了lpeg庫令蛉,剛開始用的時候需要多想一想,熟悉后發(fā)現(xiàn)還是挺方便的狡恬,相對正則表達(dá)式好用太多珠叔。導(dǎo)出數(shù)據(jù)結(jié)果是類似lisp的方式,即[op, arg1, arg2, ...]的形式弟劲,這樣后期處理變得非常方便祷安。比如想禁止set_attr函數(shù)的第二個參數(shù)(可能是一個表達(dá)式)中包含第一個參數(shù),只要遍歷語法樹檢查就行了兔乞。再比如汇鞭,想把do_action(exp_a, exp_b, exp_c)中的3個表達(dá)式拆分出來,只要先轉(zhuǎn)成語法樹庸追,然后根據(jù)語法樹反轉(zhuǎn)為文本就好霍骄。具體的代碼可以看這里,PEG定義的規(guī)則大概如下:

local syntax = P {
    "Exp",
    Func = namedpat("func", name * Space * P"(" * Space * pat_list(V"Exp", P",") * P")" * Space),
    List = namedpat("list", P"{" * Space * pat_list(V"Exp", P",") * P"}" * Space),
    Exp = V"OrTerm",
    OrTerm = namedpat("or", lpeg.Ct(V"AndTerm" * (OrOp * V"AndTerm")^0)),
    AndTerm = namedpat("and", lpeg.Ct(V"CmpTerm" * (AndOp * V"CmpTerm")^0)),
    CmpTerm = namedpat("cmp", lpeg.Ct(V"AddSubTerm" * (CmpOp * V"AddSubTerm")^-1)),
    AddSubTerm = namedpat("addsub", lpeg.Ct(V"MulDivTerm" * (AddSubOp * V"MulDivTerm")^0)),
    MulDivTerm = namedpat("muldiv", lpeg.Ct(V"Factor" * (MulDivOp * V"Factor")^0)),
    Factor = V("Func") + V("List") + V"Str" + V("Bool") + V("Var") + V("Num") + Open * V"Exp" * Close,
    Var = namedpat("var", lpeg.Cmt((C((alpha+"."+alnum)^1)-(name+Number)), error_var) + name) * Space,
    Bool = namedpat("bool", Boolean) * Space,
    Str = namedpat("str", String) * Space,
    Num = namedpat("num", Number) * Space,
}

期間和公司的另一個項(xiàng)目的同事聊了聊淡溯,他們由于支持的語法規(guī)則比較復(fù)雜读整,出于不想維護(hù)過于復(fù)雜DSL解析器和提高解析效率,直接利用靜態(tài)檢查工具luacheck提取出的語法樹咱娶,然后就可以各種魔改了米间。感覺這個思路也不錯,唯一的問題就是需要熟悉下沒有官方說明的語法樹膘侮,以后有需求可以試試屈糊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市琼了,隨后出現(xiàn)的幾起案子逻锐,更是在濱河造成了極大的恐慌,老刑警劉巖表伦,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谦去,死亡現(xiàn)場離奇詭異慷丽,居然都是意外死亡蹦哼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門要糊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纲熏,“玉大人,你說我怎么就攤上這事【志ⅲ” “怎么了勺拣?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鱼填。 經(jīng)常有香客問我药有,道長,這世上最難降的妖魔是什么苹丸? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任愤惰,我火速辦了婚禮,結(jié)果婚禮上赘理,老公的妹妹穿的比我還像新娘宦言。我一直安慰自己,他們只是感情好商模,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布奠旺。 她就那樣靜靜地躺著,像睡著了一般施流。 火紅的嫁衣襯著肌膚如雪响疚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天瞪醋,我揣著相機(jī)與錄音稽寒,去河邊找鬼。 笑死趟章,一個胖子當(dāng)著我的面吹牛杏糙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蚓土,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼宏侍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蜀漆?” 一聲冷哼從身側(cè)響起谅河,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎确丢,沒想到半個月后绷耍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鲜侥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年褂始,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片描函。...
    茶點(diǎn)故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡崎苗,死狀恐怖狐粱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胆数,我是刑警寧澤肌蜻,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站必尼,受9級特大地震影響蒋搜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜判莉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一齿诞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧骂租,春花似錦祷杈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至互站,卻和暖如春私蕾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背胡桃。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工踩叭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人翠胰。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓容贝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親之景。 傳聞我的和親對象是個殘疾皇子斤富,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評論 2 355

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)锻狗,斷路器满力,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,144評論 25 707
  • 紅小青細(xì)嫩柳枝,寶鴨才試溪里群轻纪。 東風(fēng)料得三月意油额,拂丫驚醒睡梨魂。
    海棠1005閱讀 113評論 0 0
  • 昨天在《簡書》上咬著牙刻帚、捏著鼻子潦嘶、跺著腳,糾結(jié)無比的拋出了一篇其實(shí)自己也并不怎么滿意的文章我擂,完成了在《簡書》上發(fā)表...
    荷一合閱讀 583評論 4 4
  • 前言 開發(fā)中經(jīng)常會用到分享功能衬以,下面介紹下蘋果自帶的分享發(fā)方式缓艳,個人認(rèn)為還是比較好用的校摩。 開始 分享效果如下: 代...
    longjianjiang閱讀 1,004評論 0 0