天天看點

回合制MMORPG戰鬥系統程式設計

雖然許多人覺得即時制MMOPRG玩起來更加流暢爽快刺激,但回合制MMORPG在

國内的網遊市場上仍然擁有不少忠實玩家。個人覺得抛開某幾款大紅大紫的回合

制MMORPG帶來的跟風效應來說,回合制的戰鬥系統有其本身的優點,低操作門檻

且較休閑的戰鬥模式下提供了可以很深層挖掘的配合政策。

  好的回合制戰鬥系統需要:

  * 平衡的數值配置設定

  * 可控的屬性增長

  * 合理的技能設計

  * 與技能互補的BUFF設計

  * 有驚有喜的怪物AI

  * 可控的裝備系統設計

  * 低門檻的基本操作

  * 可深層挖掘的戰術搭配

  * 引導玩家溝通的戰場内容設計

  * ...

  要全部做到位真不容易。

  或許說遠了,本文要說的是回合制MMOPRG的戰鬥系統程式設計。

  而且,是非常傳統的那種。

  是以,下文會假設我心中的"非常傳統的那種回合制戰鬥系統"是衆所周知的*_#

---------------------------------------------------------------------

  回合制戰鬥特殊性是:它将參戰雙方陣營都納入一個看似副本的"戰場"中進行

一整場屬性互動;完畢後才可與真正的遊戲場景中的其他複雜系統互動。

  這個戰場上的互動對象通常包括以下幾類對象:

  * 玩家角色

  * 玩家寵物(召喚物)

  * 怪物

  * 戰場道具(通常隻指戰鬥背包中的藥,功能性物品等)

  而作為一個網絡遊戲,驅動這些對象進行互動的系統就隻有兩個:

  * 網絡協定系統(處理戰鬥協定的上/下行)

  * 定時器系統(觸發定時的時間片來驅動戰鬥狀态機) 

  據上所述,設計戰鬥系統的程式基礎架構時便可以有一定的原則:

  * 基礎子產品關系清晰

      似乎有點教條式了,但是,越複雜的系統越需要越清晰的子產品關系。

    自己造一座城,然後把自己困在裡面,那不就悲劇了嗎。

    戰鬥系統可能是一個回合制MMORPG中最複雜的系統之一,因為最長時間的

    玩家間連續有狀态互動就發生在這個系統中。什麼bug都可能出。

  * 基礎對象間複雜度差異盡量小

      其實基礎對象無非幾種:

      Fight(戰鬥對象)

      Camp(陣營對象)

      Host/Watcher(戰士對象/觀察者對象)

      Pet(寵物或怪物對象)

      AIChip(AI對象) 

      Buff(Buff對象)

      Skill(技能對象)

      Item(道具對象)

      ...

      雖然不可能每個子產品代碼行數量一緻。但是将複雜度差異控制到盡量小,

      能使你後續對功能點的定位速度提高一個數量級;你肯定不願意兩年

      内對為了對某個功能的修改而一次一次地對擁有10000行的fight.xx檔案

      vi + search上一萬次。

      一個有效的方法是引入更細粒度的新對象來分攤原有對象的功能點,

      比如Camp中可引入 Map(站位網格資訊對象) 來獨立處理陣法站位映射。

  * 絕大部分新需求隻需要簡單派生處理 

      基礎子產品中應該完成策劃案中對戰鬥系統的通用需求。

    而預留少量幾個接口:比如 (1)初始化配置接口 (2)獎勵接口 (2)懲罰接口

    供派生重寫。而預留之前應該與策劃人員商定絕大部分的新玩法需求可以用

    你預留的接口派生重寫的方式簡單滿足。隻有這樣戰鬥基礎子產品才有價值。

  * 對較特殊需求留有改動可能性的空間

      做遊戲不同于做一次性出最終版的傳統軟體。做遊戲,做的就是反複。

    所謂反複,可能是為了某個需求你得将整個構架反過來再複過去。

      有人很熱衷于重構麼?如果有,那也是出于不得已。

      将Fight包含的基礎對象鍊中的class作為可配置的,是相對靈活的方式。 

    在類似Python, Lua等将class作為first class value的語言中,很友善。

  * 将驅動方式抽離單獨子產品

      回合制戰鬥的主要的驅動方式是 網絡協定 的接收。

      隻是以要将驅動方式單獨抽離,可友善地提供不同形式的驅動源輸入。

      或許你隻希望一個單機版的錄像檔案驅動戰鬥?

      或許你希望一個文本行格式的測試用例驅動戰鬥?

      或許你徹底不需要任何形式的驅動?

  * 必須給策劃留下[極大的]配置空間

      如果有可能,最好編寫大量的代碼生成器,并提供一個策劃可接受的

    編輯方式(比如 xls / csv 等基于單元格的格式)。

      類似Skill,Buff,AI,Trigger,Equip等都交給策劃來100%控制吧。 

    想什麼時候改xls就什麼時候改,改完運作一下代碼生成器生成代碼檔案,

    立即可以看到改動效果,節省不少策劃<->程式的交流成本。

      當然,這樣做需要預先對Skill,Buff,AI,Trigger,Equip等的可配

    置内容有策劃<->程式間的讨論和約定;但很明顯這是一勞永逸的事情。

  * 可以線上熱更新絕大部分戰鬥配置

      配置,就難免出錯。特别是由策劃來配置。是以必須提供一個熱更新

    的機制使得伺服器不停機便可以令新配置生效。所幸的對是現在絕大部分

    腳本語言而言,做到這一點已經不是多難的問題。

  * 核心代碼不traceback

      是程式都會有錯誤,沒錯。但是經過嚴格的編寫和測試,我們應該保證 

    核心代碼極少出現緻命的錯誤。如果出現了,也别亂try/catch + log 讓

    它過去就算,讓戰鬥系統挂掉吧,早挂早好。

  * 配置代碼即使traceback,也使影響盡量小

      配置代碼是代碼生成器根據策劃填寫的xls生成的。可以列為"不受信任"

    的函數塊。戰鬥系統調用這些函數塊時,應該做好它們會traceback的

    準備。但是,即使它們出現traceback,也應該做一些事情使得對遊戲世界

    的影響盡量小,比如:(1)錯誤結束的戰鬥不給予獎勵 (2)錯誤結束的戰鬥

    至少能保證所有戰鬥中玩家能夠退出戰場傳回正常遊戲場景繼續遊戲。

    (3)認真記好錯誤現場的日志。

  * 嚴格時序的詳盡戰場日志記錄 

      在上下文戰場資訊缺失的戰鬥日志中追查錯誤,事倍功半。

      嚴格時序,所有戰場事件有效資訊的日志是必要的。至少前期是必要的。

    最好每場戰鬥有單獨不重複的戰鬥ID,每行日志有ID+回合數資訊再加事件

    資訊。為錯誤的追蹤查證提供有力的支援。

  * 可重入的戰鬥測試用例機制

      可重入是指同一份輸入資料驅動兩次獨立的戰鬥,戰鬥系統會得到兩次

    完全一緻的輸出結果。如果戰場日志足夠詳細,我們可以認為能得到兩份

    完全相同的戰場日志(包括所有的掉血,命中率,暴擊率計算結果值)。

      實作可重入的戰鬥測試用例機制在回合制戰鬥系統中是可以做到的, 

    使用自定制的随機數函數,并在輸入中将外部因素全部重置(其實外部因素

    不多),然後驅動(這裡就看出【将驅動方式抽離單獨子產品】的必要)直至

    完成一場戰鬥即可。

  * 可重入的性能分析用例

      引入合适的profiler機制來對可重入的測試用例進行性能分析。畢竟戰鬥

    在回合制MMORPG中是重頭戲。能看出瓶頸的點應該盡早優化,持續優化。

---------------------------------------------------------------------