為什麼資料結構設計是遊戲策劃必備技能?
01、資料結構設計是遊戲設計的70%工作內容
這道理非常簡單,因為遊戲本身的執行原理,就是一系列邏輯系統在不斷地改變遊戲中執行的資料,最終當資料達到了一定情況的時候,一局遊戲就結束了,遊戲的結果(包括勝負、得分等等元素)也都在資料中了。這也正是Entity Component System(簡稱ECS)這個邏輯框架之所以能走紅的原因。ECS本身形式,就表現為System可以理解為遊戲系統的邏輯,Component可以理解為單純的資料結構,而Entity則是資料結構的集合,通過System對於帶有特定Component的Entity進行處理從而完成整個遊戲系的邏輯結構。
(2017GDC上暴雪大佬發表了守望先鋒的架構設計之後,ECS才進入了國人的視野,大多團隊才開始逐漸重視起資料設計這個工作)
為什麼說“資料結構設計好了,遊戲的設計就完成了70%了”?因為設計資料結構這件事情,不但是對於遊戲玩法的一次精確地抽象設計,還是遊戲所有擴充套件性創意靈感的根源。當然,我們並不是說所有資料結構的設計應該遵循ECS的思路,甚至絕大多數時候設計遊戲的資料結構都和ECS無關,遊戲的資料結構設計,本質上是對遊戲元素的邏輯化歸納。接下來我們就用一個實際的例子來看這件問題——中國象棋遊戲的資料結構:
(截圖來自《qq遊戲 中國象棋》)
在中國象棋的執行過程中,存在2個核心的資料結構,也就是遊戲的核心元素,他們分別是“棋子”和“棋局”:
首先是棋子(ChessObj),棋子的資料結構中包括的屬性有:
- 圖形(icon|string):這個棋子的貼圖是什麼,其實就是我們肉眼能看到的,比如“將”。
- 陣營(side|number/byte):是紅方還是黑方,這裡之所以不用boolean,是因為也許擴充套件為3方甚至4方可能更好玩,我們並不在這一層去“約束創意”,留多一些可能性,這也正是“創意發展點”的根本所在——當策劃去思考資料結構的時候,自然而然會多想一些玩法擴充套件,儘管這些擴充套件大多未必合適(玩法設計),但是他們一定是合理的(從邏輯上來說是對的,只是設計上是否pick這個idea的問題,至少絕不會是“天馬行空的創意”)。
- 行走規則(moveOffset|array<array<point>>):以自身position為中心,取所有偏移單元格,作為這個棋子允許移動的單元格,即offset[落點資訊][路徑]。當策劃設計到這裡的時候,應該思考一個問題——中國象棋裡的車,移動範圍是左右各8格、上下各9格(因為一些格子不在棋盤內,因此依然不能移動到,這就是規則,也就是系統的約束)?這個問題其實很有意思,因為我們作為玩家的時候,一直根深蒂固的理解就是“車可以橫豎走滿”,但是從沒有對這個定義進行過批判,而假如遊戲被擴充套件為棋盤是18x20的時候,車的移動範圍如何呢?還應該“走滿”嗎?這是一個非常有意思的思考,也是一個遊戲策劃設計遊戲時候必須要做出的思考,因為這是一個遊戲玩法平衡性的規則。而細心的朋友到這裡可能發現了一個問題,為什麼這採用的是二維陣列?可以移動的單元格不應該一維point就足夠了嗎?只要列出所有能走的offset就行了?這裡有一個細節,就是第一層array實際是指這個棋子有哪些可以走的路徑,而第二維則是這個路徑上的點,第二維最後一個元素,則有著這個棋子“落點”的性質,因為中國象棋裡面有個“卡腳”的設計,我們看下圖(圖解1):
(圖解1)
在“圖解1”中,紅色圈的象,原本的移動範圍應該是3個紅圈+1個紫色的圈,紫色的圈我們知道有了盟軍的象所以就不能走了,但是其實左上角那個紅色的圈依然無法走到,是因為象走路的規則中檢查青色和藍色的圈是否有子,有子(比如藍色圈中有個將,不論敵我)他都不能走到,因此我們在資料結構中應該定義一個“路徑”,路徑中的任何一格有其他棋子都不能移動。而從這裡,我們可以擴充套件出一個概念——如果我們把路徑做了修改,他就能成為另一個棋子,比如我把所有青色或者藍色的圈去掉,也就是最後結果是一個只有一單元(落點)的陣列,那麼象就變成了“飛象”。
- 特殊規則(special|enum):行動的特殊規則,用於炮吃子和飛將等“不符合邏輯”的規則。炮吃子,即炮的所有行動規則中,如果落點有非本陣營棋子,那麼路徑上必須有且只有一個任意棋子;而飛將則是根據執行時的地圖,動態判斷,如果雙方將之間沒有任何棋子,那麼行動方的將移動規則中將多出一條{對方將座標}的資料。
接下來就是棋局的設計,棋局肯定是一個存在的資料結構,因為一局遊戲玩的就是這個(即遊戲中核心的資料就是這個):
- 棋子(chess|array<array<ChessObj>>):實際上按照中國象棋標準棋盤來說,他是一個9x10的二維陣列,每一個單元可能是null(沒有棋子)或者1個棋子(ChessObj),和我們肉眼能看到的棋盤是對應的。但是我們在這裡其實偷了一個懶,事實上即使雙方對戰的中國象棋,他的棋盤也應該是三維陣列:Map[side][x][y],即各方陣內的5格高度才是真正的一個子棋盤,由規則(而非資料)建立起棋盤之間的“交通”,如“圖解2”:
(圖解2)
在圖解2中,我們可以看到,每一家陣營是一個“子棋盤”他是一個9x5的陣列,而對方陣營在雙人象棋中是一個180度旋轉後的“子棋盤”,這意味著規則上我們必須建立在2個子棋盤之間的交通,比如位於map[0][2][4]的棋子,前進一格達到的是map[1][6][4],即map[toSide][width - this.x][this.y]的單元格;除此之外,由於棋子移動有方向性,比如“兵”只能向前,因此在對方棋盤,即第一維下標不等於棋子的“陣營”時,他的“行走規則”中的y向是乘以-1的。
到這裡可能有人要問了,為什麼要自討麻煩?明明二維陣列就可以做好了的,其實這裡不光有一個非雙人象棋的問題:
(在我小時候,玩過這麼一個“三國象棋”)
其實“三國象棋”本身是好玩的,因為熱鬧,而玩遊戲,本質也並不是為了追求輸贏,畢竟不是體育比賽象棋,玩,最重要的是開心,輸贏,是帶來開心的“標尺”。當然也不光是因為多方陣營的可能性,還有比如我們為中國象棋增加一個“技能玩法”,某個技能可以在2輪內將敵人的小兵變為自己的,那麼這時候,這個小兵應該如何移動呢?因此真正的資料結構抽象,對於這種具有“雙反陣營”概念的棋類遊戲而言,他應該是3維陣列,而非2維陣列,同理《四國大戰》等也是如此。
- 行動方(side|number):現在是誰行動,正如我們說的,不光是三國象棋可能會有超過雙方行動的時刻,為了好玩,我們可以讓4個人走象棋,玩家1和3輪流控制一方,2和4輪流控制一方,行動順序1黑2紅3黑4紅,2人同時控制一局也可以帶出一些樂趣來,比如情侶象棋(當然現在的情侶多半不會土到去玩象棋就對了),這就是一個很好的擴充。而之所以沒有回合這個概念,也正是“回合”是一個虛的概念,他是f(總的行動次數)可以算出的東西,所以不需要儲存在資料結構裡。
到此,一箇中國象棋的核心資料結構被設計出來了,而基於這些資料結構,也可以輕易就實現出象棋的玩法。同時在這個設計過程中,我們看到了許多“存疑點”和“可擴充套件點”。比如“車的移動真的是全屏嗎?”,就像俄羅斯方塊“旋轉方塊,真的是旋轉90度,而不是切換成另一種組合了嗎?L旋轉一下一定不能變成正方形嗎?”,這些批判性的存疑點,並不是用來批判老的規則設計的,而是給我們一些啟迪,告訴我們還有什麼新的擴充套件契機,和“可擴充套件點”比如“能不能設計一個buff,讓我方2回合內所有的棋子都飛起來不受路徑上棋子影響?”一樣,任何擴充套件契機,都是一個邏輯十分完美的“創意”,但是這個“創意”本身是否是“好的創意”(合適現在的遊戲)就要回到設計層深入思考一下。
而看到這裡的小夥伴也許還會問“中國象棋哪兒有這麼麻煩的?我棋盤是一個array<array<int>>,負的代表紅方,正的代表黑方,1代表將,2代表士……這樣做不好嗎?為什麼要這麼麻煩呢?”,其實這個想法也是對的,只是這就是“需求實現者(coder)”和玩家的理解,不是一個“遊戲設計師(Game Designer)”應有的理解,Game Designer應該不放過遊戲可能出現的創意。
02、遊戲策劃如何去從做資料結構設計遊戲玩法
其實設計一個遊戲本身是設計多個玩法,每一個玩法的設計,都是30%的UI和系統規則+70%的資料結構(事實上在設計資料結構的時候,會對規則有一次鞏固和反思),所以一個玩法的設計過程,通常可以分為這樣幾個步驟,來做到用從資料結構出發設計玩法:
01、用一句簡練的話說清一個玩法
任何玩法,其實都是可以用一句、最多幾句話就能說清楚的。只要首先去掉那些感動自己,或者感動自己心中使用者的那些話術,比如“這樣設計玩家就能產生心流”,“這個設計的目的是為了讓玩家不會疲勞”,這些話正是因為聽起來非常有意義,所以會讓你陶醉其中,感覺這個設計完美無缺。但是這些話,在真正的遊戲設計這件“冰冷”的事情面前,就是純粹的浪費時間,毫無意義。你應該去掉一個“設計”中所有類似的語句,只留下清晰的邏輯性語句,比如:
我們要做的是一個小鎮經營的遊戲,小鎮上有幾個建築是玩家可以買下來的,買下後就會產錢給玩家。隨著小鎮等級的提高,每個建築物會產生的產品變多,每個產品都會帶來不同的產出。
(經營小鎮的遊戲產品其實挺多的,但是每個產品的細節設計都不一樣,因此這一句話要說清楚自身的特點,而不是簡單地“抄誰”)
這就是一句非常清晰的話,直觀的就表達出了一個玩法,但是他並不是完整的設計,因為缺乏資料結構的設計,因此會缺失很多細節設計,由此會帶來許多邏輯問題,因此我們接下來要:
02、分清每一件事情,找到玩法和資料結構
從語文上來說,這句話說的是一件事情,但是從邏輯設計上來說,這句話裡藏著幾件事情,我們需要進一步的分析一下,這些事情分別是:
- 我們經營的【小鎮】上有一些【建築物】。
- 【建築物】本來就在那裡,玩家要把它買下來變成自己的。
- 【建築物】本身不會產錢,產錢的是建築物中的【產品】。
- 【產品】的解鎖和【小鎮等級】掛鉤。
到此,我們從這4件事情裡面,就能分析出一個初步的資料結構:
接著,我們就要針對這個資料結構和對應的玩法,來進一步深入思考,因為很顯然這個結構反饋出的玩法裡還漏了不少細節:
先從產品出發:
- 產出是單位時間產出嗎?應該是的,那麼單位時間是多久?整個遊戲所有建築物的產出都是一樣的時間間隔嗎?
(在《芭芭農場》中,不同“建築物”中不同“產品”的產出速度是不同的)
如果是一個掛機遊戲,是不是應該鼓勵玩家經常上線,所以產出應該有一個時間上限的限制?
然後再看建築:
- 建築物的外觀總是一塵不變的嗎?
- 建築物的外觀應該如何變化?除了本身變化規則會不會還有節日等影響?
- 建築物的名稱會不會隨著外觀變化?
(建築外觀隨等級變化是經營類遊戲常有的)
- 如果產品有個產出上限,這個上限是否應該由建築物承擔?
- 這個產出上限和什麼屬性有關嗎?
- 這個產出屬性是否也可以升級?
最後我們來看小鎮:
- 等級是如何提升的?
當我們有了這些思考之後,會發現原來的一句話描述裡,有太多還沒說清楚的具體細節,然後這時候我們基於這些問題,又可以進一步修改資料結構,把它擴充套件為:
經過一輪對這些事情的思考和批判,我們得出了初步的資料結構,但這還遠遠不夠,接著我們要深入到做遊戲的細節和遊戲的一些可能會擴充套件的設計去進一步加工:
03、批判每一個細節找到“隱藏屬性”和解決“隱藏問題”
現在我們再來對於每一個元素的玩法進行一次更深入的思考和批判,這些思考與批判跟上一步的“補充”不太一樣,更多需要從玩法設計的角度去分析和判斷,而不再是從“常理”的角度看問題,我們依然針對每一個環節去分析:
產品:
產品是否存在季節性的產品?比如我們有個水果店,裡面的一些水果是季節性的,比如草莓只有春末夏初才有。如果需要,那麼產品屬性下就應該有一個live屬性,來表達當前產品是否啟用中,而對於“大樓產出”這件事的運算又會有不同的演算法,因為會關注這個live屬性,只有live==true的產品才會產錢。
產品是否存在限制性解鎖?比如有些產品必須在情人節活動的時候解鎖,然後就一直擁有了,否則就要等來年的情人節。如果是的,那麼至少在伺服器發來的資料中,需要有一個visible的資訊來表達產品是否需要顯示。
如果這個專案是一個和某資源合作的遊戲化專案,那麼這個產品是否會因為遊戲化內容而得到增幅的,比如我們做一個wegame小鎮,裡面有個拳頭大樓,當我們在wegame玩lol的時候,“英雄聯盟”這個產品產出的金幣會在這期間翻倍。或者在wegame平臺購買lol的某款英雄皮膚,可以讓“英雄聯盟”產出間隔縮短50%,持續2小時。如果是的話,那就會擴充套件出來一個增幅(boost)的資料,boost中有開始時間、結束時間、增幅內容。而boost本身並不是一件小事,我們可以展開看一下——問題的關鍵在於伺服器與客戶端的同步,尤其是不使用長連線的h5遊戲,客戶端在產出金幣的時候,每一次產出都是最小時間單位,因此產出的瞬間,根據所有的boost計算一下,就能得出一個精確地數字,但是伺服器不能這麼做,因為這樣客戶端伺服器互動頻次會非常多,只能採取客戶端每一定時間通告伺服器一次,伺服器根據時間戳算出2個時間點的產出,這時候問題就來了——2個時間點內的boost是會發生變化的,我們把2個時間點看成一個timeline:
我們從上圖不難看出,多個起始、結束時間不同的boost,把兩個產出時間中間的產出,按照產出量分出了5個區間,每個區間的產出量都不同。因此當我們設計這個boost的時候,就應該同時去設計一個伺服器產出金幣的演算法來支援同步。這也是在資料結構發生擴充套件時候需要考慮到的設計問題之一。
建築:
- 是否會有影響整個建築物產出收益的設計呢?比如玩家違規導致建築物停產?這些其實都是對於建築物下產品的boost,因此在建築層完全不需要這個屬性。
- 建築物是否允許增設?比如原來是賣手抓餅的店鋪,可以增設奶茶店,這樣產品列表裡就有了奶茶。而這個思考,就會帶來更深層次的思考:
- 增設的店鋪是否是隨著建築物就定下的,如果是那麼可以利用產品的visible和live屬性;如果不是,那本質上就是原本在地圖上的建築物,實際上是一個建築物array,而顯示依賴的是第一個建築物(預設必定有1個建築物)。
- 增設是否可以提供效果?比如增設了芝士加工間,會讓所有漢堡類產品產出提高?那這裡就有一個增設是否可以拆除的問題(可以替換=可以拆除),不能拆除的,只需要增設的時候直接改變產品列表裡對應的屬性就行;能拆除的,則得走boost(永久存在的,在拆除時移除)。
小鎮:
- 是否會有隨著時節換外觀的設定?如果有,則當前小鎮的外觀將會是一個屬性。比如聖誕節有一套特殊的小鎮美術等。
到此,我們做出了一些假設,這些假設本身都可能是合理的設計,並且除了這些情況,可能還會有很多擴充套件內容,因此在遊戲設計的過程中,基於資料結構,進一步思考設計細節,從而產生出新的idea;或者利用現有的資料結構略微改變一些規則產生出新的玩法,都是遊戲設計中的核心設計部分。當我們列好這些資料結構之後,工作還沒完,因為這些結構,只是執行時的,是在遊戲運作時候用到的,最終會交給程式設計師去實現,而這些資料中有一些資料是“非常主觀”的,他需要策劃填表來實現,我們稱之為“model”,也就是產生這個資料時用到的一些基礎資訊,也正是策劃填表的資料。
04、找到Model
Model一定被真包含於資料結構之中,也就是說Model擁有的屬性,在執行時的資料結構中也一定會有。從執行時的資料結構中找出Model,通常依賴於幾個“現象”:
這個屬性是主觀的——計算機程式算不出來,或者即使能算出來,也是策劃覺得是什麼就是什麼的,是model的屬性。比如名稱、圖示、外觀等,都必定是model的屬性。
(卡牌遊戲中角色造型、名稱、屬性等,都是主觀的,屬於Model的屬性)
- 這個屬性可以是靜態的——反例是比如清版射擊遊戲中的子彈座標,清版射擊遊戲的子彈座標每一幀都在變化,所以肯定不是model的屬性;而一些遊戲中建築物、技能等元素可以升級,如果升級只是某些屬性按規則變化了,那等級也不會是model的屬性。
(清版射擊遊戲中的子彈座標,一定不是Model的屬性)
當我們把每個資料結構裡的model都列出來的時候,那麼對應的資料表也就完成了。到此,遊戲設計基本也就落地了,剩下的就是一些UI和玩法設計。
03、設計遊戲資料結構的一些技巧
在設計遊戲資料結構的時候,其實還有一些非常重要的技巧,這些技巧其實和一個設計師玩遊戲有關,確切的說是一個遊戲設計師作為“遊戲批評師”的能力,這些技巧包括且不限於:
(寶可夢之父田尻智在製作寶可夢之前是一個“遊戲批評師”,“遊戲批評師”並不是無腦說遊戲怎麼不好,而是從專業的角度去分析遊戲設計中的一些缺陷和錯誤,作為遊戲分析師,首先得能精確地區分出遊戲的型別)
01、同類遊戲資料結構相似,不同型別則必然不同
精確地區分出遊戲的型別,不同的遊戲的資料結構必然不同,而類似的遊戲的資料結構則基本相似。所謂的相似,是指資料結構的類大同小異,區別僅僅是部分屬性。
舉個例子,動作遊戲和回合制遊戲(包含ARPG等)。動作遊戲和回合制遊戲的區分對於玩家來說是困難的,因為即使是realtime的遊戲,玩家都可能理解為是動作遊戲。但是從一個專業的遊戲設計師、遊戲批評師的角度,你應該非常輕易地可以看出兩者的差異,比如我們拿兩者的“技能”舉例。
在動作遊戲中,沒有技能這個概念,所有的都是“動作(action)”,而每一個動作由多個“幀(frame)”組成:
而回合制遊戲,比如diablo、lol等,其技能特點都是以一個技能為一個回合的,只是時間長短不同,我們可以把它看做一個Timeline的資料結構,在Timeline上有若干種點:
很顯然,從我們說的、寫的文件中的、交流中常用的“技能”這個詞出發,在不同的遊戲型別中,就有完全不同的資料結構。所以首先設計師必須能分清遊戲型別,如果對於遊戲型別都不夠清晰,那的確沒法建立好資料結構。而對於遊戲型別的掌握,只能說“多玩遊戲,多多感受”了。
02、一事一議,破除關聯
這不光是一個遊戲設計技術,也是一個人的理解能力。要求設計師能夠把一件事情分到最細,去除掉所有不存在的因果關係、去除掉話術、去除掉固有的預設前提,能把一個想法(一句話)還原出清楚成原原本本的事情陣列。這是需要抽象能力的,比如“麥當勞的安格斯牛排漢堡好吃,所以套餐賣50不貴”——在這句話裡有2件事情,並且沒有關聯,但是通常我們會錯誤的建立起因果關係,因為這句話裡有個“所以”,實際上這2件事情很顯然:
“我”覺得麥當勞的安格斯牛排漢堡好吃(前半句)
50塊錢的套餐“我”覺得不貴(後半句)
好不好吃和定價本身就是完全沒有任何邏輯關聯的事情,但是我們卻出於情感,會把他們關聯起來,認為“好吃所以值這個價”,這在做資料結構設計的時候是萬萬使不得的。過多的不必要關聯,會把邏輯帶向一個無法釐清的尷尬境界。
總結
只有在深入設計遊戲資料結構的時候,我們通常才能得出一些設計問題,以及發現許多設計的可擴充套件點、可維護點,通過利用這些點,我們可以進一步設計出更多合理的玩法。當我們完成設計資料結構之後,遊戲的核心邏輯基本也就清晰了。
來源:千猴馬的遊戲設計之道
原文:https://mp.weixin.qq.com/s/mdHzpkrHBS777g1wK0NU5w
相關文章
- 為什麼說程式碼註釋是程式設計師必備的技能?程式設計師
- Python為什麼成為了必備的技能?Python
- 策劃經驗談:遊戲策劃設計的是體驗遊戲
- 什麼是結構化資料?什麼是半結構化資料?
- 什麼是資料結構資料結構
- 遊戲文案策劃:什麼是通往高潮的過程?遊戲
- 資料是什麼——資料的結構
- 好程式設計師分享大資料三大必備技能程式設計師大資料
- 為什麼程式設計師應該儘早投資於決策技能 - Reforge程式設計師
- Mysql索引資料結構為什麼是B+樹?MySql索引資料結構
- Java程式設計師必備技能Java程式設計師
- Web前端職責是什麼?Web前端必備技能有哪些?Web前端
- 索然無味,遊戲策劃為什麼容易電子ED?遊戲
- 做UI設計需要具備什麼技能UI
- 為什麼我害怕資料結構學得好的程式設計師?資料結構程式設計師
- 為什麼要學資料結構?資料結構
- 阿里大資料架構師必備技能,你“佩奇”了嘛?阿里大資料架構
- python演算法與資料結構-什麼是資料結構Python演算法資料結構
- 什麼是技術策劃?應屆生能當技術策劃嗎?
- 大資料系統管理必備技能大資料
- 聊聊資料人的職場必備技能
- 軟體架構師必讀!什麼是設計?如何進行設計?架構
- 資料結構中抽象資料型別是什麼?資料結構抽象資料型別
- 程式設計師應該具備哪些必備技能程式設計師
- 電商遊戲設計與策劃大法——下遊戲設計
- 電商遊戲設計與策劃大法——上遊戲設計
- 遊戲策劃設計系統時,除了考慮設計目的,還需要考慮什麼?遊戲
- 資深程式設計師必備技能-如何對軟體系統做技術規劃程式設計師
- 新手程式設計師必備10大技能程式設計師
- 應聘遊戲策劃之前,應該做些什麼?遊戲
- 架構必備技能第一談架構
- 資料分析師必備技能都有哪些?
- 程式設計師必備技能-科學砍需求程式設計師
- Git算不算程式設計師的必備技能?Git程式設計師
- 程式設計師寫作的必備技能 Markdown程式設計師
- 傳說中的程式設計師必備技能程式設計師
- 成為一名大資料工程師,需要具備什麼技能?大資料工程師
- 遊戲AI之決策結構—行為樹遊戲AI