最近每天猛猛搓遊戲demo,剛好碰到遊戲任務系統這個問題,花了三天時間終於折騰明白了這個任務系統是怎麼個事遂寫個devlog記錄一下思路歷程。
這個devlog會分成幾個部分,這部分(Part1)我們就來設計一下這個任務系統的結構。
疊甲:非專業人士,內容僅供參考
![]()
一張UI設計
在開始之前,讓我們思考這樣一個問題:如果現在要讓你爲某個遊戲設計一個任務系統,你會怎麼做?
這個問題從表面上看可能非常簡單。那無非就是加載任務、看玩家做了什麼然後更新這些任務,再做點什麼花裏胡哨的UI特效,對吧?對...對嗎?
那麼,先讓我們來想一想一個任務系統都有哪些職責吧
1.1 任務的儲存和讀取
首先肯定是儲存和讀取任務嘛。我們的任務系統總得先把任務讀取進來才能管理它們。
那麼問題來了:具體的任務數據應該怎麼存儲呢?一個任務裏面有那麼多描述、數據、關係、要求,怎麼才能讓它們以一種結構化的方式存在我們的遊戲裏呢?
這個時候就要請出這方面的專家了:JSON格式。
JSON是個什麼東西呢?讓我們看看大D老師怎麼說
![]()
只需要知道它對於人和機器來說,讀寫都很簡單就好了
JSON剛好能夠滿足我們的要求:既能被程序結構化解析,人也能輕鬆的看懂。那麼我們就用JSON來存儲任務吧
1.2 任務的結構
現在我們解決了怎麼存的問題,那自然下一個問題就是“存什麼”了。一個任務裏面有什麼呢?讓我們看看其他遊戲是怎麼做的。
![]()
超級柱頭2,有需要優先完成的子任務和最後完成的主任務
![]()
2077,一個任務的某個階段可以包含多個子目標
我們可以大致總結一下任務在這些遊戲裏的表現:
一個任務由多個任務階段組成。
以上面HD2爲例,“建立通信上行鏈路”可以分爲 和終端互動-擰信號塔-再次和終端互動 這三個階段。
每個任務階段中都存在一系列需要玩家完成的目標。
比如,和終端互動這個階段就可以包含輸入啓動指令和升起信號塔這兩個目標。
每個目標都有目標描述和完成條件。
當完成一定的目標以後,任務從一個階段進入下一個階段。
當完成了任務的所有階段以後,這個任務就算完成了。
一個任務可以擁有一定的前提條件。只有當前提條件滿足一定的規則時,這個任務才能被玩家接受(處於“解鎖狀態”)。
一個任務還可以擁有一個接取條件,只有當滿足這個接取條件時,任務纔算真正的被玩家“接受”了。
上述兩種條件的區別可能會有點讓人困惑。舉一個例子:
一個“清剿某地區怪物”的任務可能需要玩家滿足 “到達等級10”和 “探索過XX地區”這兩個條件,纔會在當地的冒險家協會NPC頭頂上 顯示有可以接取的任務。
當玩家和這個NPC 對話結束,這個任務才能正式被玩家所接受,進入到玩家的人物列表裏。
在這個例子裏,“到達等級10”和“探索過XX地區”就是這個任務的前提條件 ,“和冒險家協會NPC完成關於城郊怪物的對話”就是這個任務的接取條件。
到這裏,任務內容我們已經總結的差不多了。但是爲了讓我們的任務系統能夠正確的讀入、分類和管理這些任務,我們還需要回答幾個問題:
對於任務系統來說,沒有什麼簡單可靠的方法來區分和辨別不同的任務呢?
遊戲裏會不會有主線任務、支線任務、委託任務等任務種類的區別呢?
爲了回答上面這兩個問題,我們可以再爲任務添加兩個屬性:
每個任務都有自己唯一的任務ID。這樣,只要通過判斷ID,我們就能辨別不同的任務了。
每個任務都有一個任務類型。
現在,我們的任務結構大概看起來會像這樣:
任務ID(必需)
任務類型(必需)
前置條件(多個,可選)
接取條件(一個,可選)
任務階段(一個或多個,必需)
這個階段的任務目標(一個或多個,必需)
目標描述
完成條件
本階段的完成條件
現在,讓我們來試着定義一下一個任務的JSON應該是什麼樣的吧
![]()
大概長這樣...?
現在我們又遇到問題了
我們怎麼知道一個前置條件(或者一個任務目標)完成了呢?完成標準千變萬化,怎麼把它們統統寫成一個統一的結構呢?
現在我們只能支持通過“完成所有前置條件”(或者“完成所有目標”)來判定任務可用或者一個任務階段完成。如果需要更復雜的邏輯呢?
舉個例子:
假設進入最終決戰任務需要:
1. 完成“打敗不死人將軍”或者“召喚惡靈”兩個任務其一;
2. 角色等級達到100級;
3. 角色身上不能有“不潔”這個屬性。
這種“前置條件之間的關係”就是 “任務前置條件的滿足規則”;“任務階段的滿足規則”也是同理。
1.3 拆解“條件”
其實,不管是目標也好,還是前置條件也好,它們都可以被統一抽象爲“條件”,也就是“需要某個特定的條件被滿足”。
上面提到的第一個問題,就可以簡化成一個根本問題:如何把一個“條件”拆解成一個可序列化的結構
遊戲裏有些什麼條件呢?我們可以列舉一下:
對於玩家角色自身屬性的要求(如,等級)
需要玩家持有某個物品(如,“祕密房間的鑰匙” / “逝去英雄的佩劍” / ...)
需要玩家完成某個前置任務
需要玩家進行某個互動(如“打開牆上的電閘”)
需要玩家完成某個對話 / 劇情過場(如“和老鐵匠交談”)
需要玩家擊殺指定的NPC (如“殺死3個史萊姆”)
可以發現,這些條件都可以被抽象成一種 “做什麼”+ 參數的形式。以上面列舉的爲例:
要求玩家等級 >= 5(等級, 5)
要求玩家持有3個“失落的殘片”(擁有物品, 失落的殘片, 5)
需要玩家完成某個前置任務(完成任務, <任務ID>)
需要玩家打開牆上的電閘(場景互動, 電閘)
需要玩家和老鐵匠交談(完成對話, 老鐵匠, <對話ID>)
需要玩家殺死3個史萊姆(殺死敵人, 史萊姆, 3)
那麼,我們就可以把“條件”抽象成一個這樣的結構:
![]()
使用插件:CodeSnap
1.4 拆解“完成邏輯”
現在,我們解決了條件怎麼存的問題,那麼條件之間邏輯的問題又該怎麼解決呢
讓我們再回到上面提到的例子:
進入最終決戰需要:
1. 完成“打敗不死人將軍”或者“召喚惡靈”兩個任務其一;
2. 角色等級達到100級;
3. 角色身上不能有“不潔”這個屬性。
按照上一節的內容,這個要求可以拆分成四個條件:
A: 完成任務, 打敗不死人將軍
B:完成任務, 召喚惡靈
C: 等級, 100
D: 屬性, 不潔
那麼最終的條件就可以抽象成“A或者B選一個,並且需要C,並且不能有D”。
前有數學,接下來布爾邏輯很有用。讓我們來問問大D老師
想象一下一個電燈開關,它只有兩種狀態:
開 - 燈亮着
關 - 燈熄滅了
布爾邏輯就是一套專門處理這種“非黑即白”、“是或否”情況的規則。
在計算機世界裏,我們用: True (真) 代表“是”、“開”、“成立” False (假) 代表“否”、“關”、“不成立”
什麼是布爾表達式?
布爾表達式就是一個最終會得出 True 或 False 的提問或式子。你可以把它想象成一個只能回答“是”或“否”的問題。
一些簡單的例子:
今天下雨了嗎? → 答案只能是 是 或 否。
我的銀行餘額大於100元嗎? → 答案只能是 是 或 否。
這個蘋果是紅色的嗎? → 答案只能是 是 或 否。
在編程中,這些表達式看起來像這樣:
10 > 5 (10大於5嗎?)→ 結果是 True
age >= 18 (年齡大於或等於18歲嗎?)→ 根據變量 age 的值,可能是 True 或 False
name == "張三" (名字是“張三”嗎?)→ 根據變量 name 的值,可能是 True 或 False
布爾邏輯的三大基本操作
爲了組合這些“是/否”問題,我們使用三個最基本的邏輯運算符:AND, OR, NOT。
1. AND (邏輯與,符號通常是 && 或 and)
含義: 所有條件 都必須 爲真,結果才爲真。
口語化: “並且”
例子: 我想找一個“高” **並且** “富有” **並且** “帥”的人。
在這裏,三個條件(高、富有、帥)必須全部滿足,結果纔是 True。
只要有一個不滿足(比如不高),結果就是 False。
2. OR (邏輯或,符號通常是 || 或 or)
含義: 至少有一個條件爲真,結果就爲真。
口語化: “或者”
例子: 進入酒吧需要出示“身份證” **或者** “護照”。
在這裏,你只要有身份證 或者 有護照 或者 兩者都有,結果就是 True。
只有當你兩樣都沒有時,結果纔是 False。
3. NOT (邏輯非,符號通常是 ! 或 not)
含義: 取反。把真的變成假的,假的變成真的。
口語化: “不/不是”
例子: `NOT` 下雨 (即“不下雨”)
如果 下雨 是 True,那麼 不下雨 就是 False。
如果 下雨 是 False,那麼 不下雨 就是 True。
一個綜合的生活實例
想象一個自動門開啓的條件: 如果 (有人靠近 **並且**NOT是寵物) **或者** 有人按了開門按鈕,那麼門就打開。
我們用布爾邏輯來分解一下:
有人靠近 是一個布爾表達式(True/False)
是寵物 是一個布爾表達式(True/False)
NOT 是寵物 就是“不是寵物”
有人靠近 AND (NOT 是寵物) 就是“有人靠近並且不是寵物”
有人按了開門按鈕 是另一個布爾表達式
最終,如果第4步的結果 或者 第5步的結果爲真,門就會打開。
有了這個,我們就可以把上面那個條件表達成這樣一個簡單的式子:(A || B) && C && !D
把ABCD字母替換成對應的條件ID,我們現在就可以明確的定義任意複雜的完成邏輯了。
讓我們完善一下之前的JSON:
![]()
策劃看完頭都大了(不是
看起來沒什麼問題
下一篇就寫怎麼在UE5裏面實現這個任務系統吧。
感謝看到這裏,喜歡的可不可以點點關注喵
更多遊戲資訊請關註:電玩幫遊戲資訊專區
電玩幫圖文攻略 www.vgover.com
