電子遊戲中的 NPC · 四個可玩世界

電子遊戲中的 NPC:非玩家角色如何運作(附可玩 Demo)

做一個自己的 npc 電子遊戲

什麼是電子遊戲裡的 NPC?看 NPC 怎麼被建出來、怎麼行動,並實際玩四個在瀏覽器裡跑的 3D 遊戲,裡面的非玩家角色會移動、會說話、會反應。

✦遊戲
做一個npc 電子遊戲

電子遊戲裡的 NPC 就是非玩家角色:一個不直接由玩家操控、但佔據空間、持有狀態、並會對世界中的條件做出反應的實體。這個詞刻意定得很寬,而正是這個寬度造成了大部分的混淆。一個有作息的老闆、一個跟著你走過走廊的隊友、一個只重複一句話的流浪商人,全都是 NPC,但它們的建法不一樣,跑起來的成本也不一樣。

本頁談的是 NPC 到底是什麼、一個 NPC 怎麼被建出來,以及怎麼把它和一個只是看起來像活的腳本觸發器區分開。本站有四個可玩世界當作實例——Agent Sprite Forge、The Cyclops' Island、Mini World,以及 3D 遊戲建構器本身——讓你可以直接走到 NPC 旁邊看它的行為,而不是只用讀的。

快速解答:電子遊戲裡什麼算 NPC

NPC 就是遊戲世界中任何不直接受玩家操控的角色。它有位置、有狀態,而且至少有一個行為會在玩家沒按任何按鍵的情況下觸發。如果你把玩家從場景裡拿掉,這個角色還是會做事——走一段路線、開一扇門、對附近的事件做出反應——那它就是 NPC。

角色和機制之間的界線在於狀態的歸屬。角色擁有跨幀存續的變數:當前血量、當前目標、當前巡邏索引、當前對話節點。機制在實務上是無狀態的——條件滿足時觸發一次,然後就結束了。一塊打開閘門的壓力板是機制。一個對閘門開啟做出反應、記得你剛才站在那裡、並且改變自己路線的守衛是 NPC。差別不在視覺精緻度,而在事件發生的那一幀之後,有沒有任何東西留下來。

電子遊戲 NPC 簡史

1970 年代末到 1980 年代的文字冒險把 NPC 當成剖析器的目標。一個角色只以剖析器認得的名詞形式存在,外加一小塊旗標。早期文字冒險裡的小偷,只要你和他同房、而且他還沒偷過,就會偷走一件物品——那就是一個只有兩個變數的 NPC:在場與否,以及一個 has-stolen 旗標。沒有尋路、沒有動畫、沒有排程。行為在旗標裡,不在角色裡。

精靈時期的 NPC 加上了動畫和碰撞,但行為依舊很薄。一個村民走固定的兩點循環,玩家進入半徑內就播 idle 動畫,接觸時開一個對話框。關鍵的技術變化是 NPC 現在在物理世界裡有位置,所以它必須便宜。在 8 位元與 16 位元硬體上一次要放幾十個在畫面上,每個 NPC 只分到幾個位元組的狀態,每幀跑一個不會比距離比較更複雜的檢查。

排程驅動的 NPC 出現在記憶體和 CPU 預算足以讓一個角色獨立於玩家所在位置而存在之後。一個有營業時間值、有住家路徑點、有行走路線的老闆,在你到達時可能人在別的地方,而這個「不在」對玩家是可讀的。實作上就是一個時鐘加一張查找表:遊戲時間 21 點,目標指向住家路徑點;8 點,目標指向店鋪。玩家永遠看不到那張表,只看得到結果。

生成式 NPC 是當前的階段。與其為每個狀態手寫一句台詞,你寫一段角色描述,讓模型在執行時產出對話、短喊或行為。取捨不再是儲存空間,而是決定性:生成的一句話沒辦法完全預覽,所以你需要對語氣、長度、以及 NPC 被允許引用什麼設下護欄。在 3D 遊戲建構器裡,NPC 的提示詞被限制成一段描述加一組很小的行為,正是這個原因。

現代 NPC 怎麼被建出來

每個 NPC 都是五個互相配合的部分疊起來的:狀態、導航、動畫、對話、感知。狀態是 NPC 擁有的資料——血量、目標、巡邏索引、對話節點、警戒等級。導航是它在點與點之間怎麼移動。動畫是移動和待機時刻怎麼被呈現。對話是對條件做出反應而產生的文字與語音。感知是告訴 NPC「有東西變了」的輸入,通常是距離檢查、視線 raycast,或觸發體積重疊。

在一個典型的專案裡,這五個部分住在不同的地方。狀態是 NPC 實體上的一個腳本或元件——以 Unity 來說是 MonoBehaviour,以 Godot 來說是一個 Node 腳本,以瀏覽器 Three.js 的組建來說是掛在網格上的一個普通物件。導航要嘛是路徑點資料,要嘛是導航網格。動畫是一個狀態機,帶著像 idle、walk、attack 這種具名片段。對話是一個資料檔,通常是小小的節點圖,或是一張以狀態為鍵的表。感知通常是一個碰撞形狀加一個每幀檢查。

最常見的失敗模式是狀態和動畫走偏。NPC 處於追逐狀態,卻還在播 idle 片段,於是你看到它朝你滑過來,腿卻沒動。解法不是加更多動畫;而是程式碼裡只能有一個地方寫入當前狀態,一個地方讀取它來挑片段。當這兩件事住在不同腳本裡,你就會看到滑行。當它們是同一個函式,就不會。

第二常見的失敗是導航和關卡對不上。一條對著舊佈局寫的巡邏路線,會在幾何改動之後把 NPC 送進牆裡或送下平台。在瀏覽器組建裡,最便宜又最穩的做法是把巡邏點留成具名的空物件,並在載入時重新解析,這樣移動一道牆就不會讓路線變成孤兒。

感知是 NPC 開始變貴的地方。每個 NPC 每幀一根 raycast 對少數幾個角色沒問題,對幾百個就是浪費。常見的優化是共用一個空間網格、拉長檢查間隔,以及在任何 raycast 執行之前先做一次距離剔除。如果一個 NPC 在 40 公尺外、感知半徑是 8,那根 raycast 根本不該發生。

每個部分在場景裡住在哪

狀態:就在 NPC 實體上。保持精簡——幾個數字,加上一個字串存當前對話節點。如果你需要更多,就把這個 NPC 拆成兩個角色。

導航:存成一串世界空間座標點,跟場景放在一起,不要烘進模型裡。動畫:當成骨架上的具名片段,由單一個狀態切換來挑選。對話:放在獨立的資料檔,讓寫手不用碰程式碼就能改。感知:用一個觸發體積加距離檢查,raycast 放最後一步,不是第一步。

1

01

把 NPC 模型丟進場景,掛上一個狀態元件,欄位包含當前狀態、目標、巡邏索引。

2

02

加三到四個路徑點物件,命名要好到能撐過關卡編輯。

3

03

接一個動畫狀態機,至少要有 idle 和 walk,而且只由當前狀態值來驅動。

4

04

加一個感知觸發體積,大小設成 NPC 的察覺半徑。

5

05

把對話寫成一張以狀態為鍵的小表,並為沒對到的狀態留一句預設台詞。

6

06

在載入時重新解析路徑點和對話鍵,然後測試:移一道牆,確認巡邏還是照跑。

四個可玩世界,四種 NPC

理解 NPC 行為最清楚的方式,就是站在一個 NPC 旁邊,改變它能看到的東西。Neta Studio 上這四個世界各示範了一種不同的行為模式。打開它們,走進 NPC 的感知範圍,再走出來,看什麼變了。

Agent Sprite Forge 跑的 NPC 是由一段簡短的角色描述加上一組很小的狀態定義出來的。走過去,它的回應就是從那段描述生成、並被限制在世界所暴露的狀態之內。有趣的測試是重複:接近同一個 NPC 兩次,比較第二次的回應變化多大。那個變化是模型的,不是世界的——狀態機是固定的。

The Cyclops' Island 用了一個大型 NPC,採追逐加搜索的模式。玩家在感知半徑內時獨眼巨人會追;玩家斷開視線時,它會搜索最後已知位置,然後回到巡邏路線。那個搜索步驟是它讀起來像角色、而不像一枚追熱飛彈的原因——它是對過期的資訊做出行動。

Mini World 把幾個小型 NPC 放在短循環上,附帶互動提示。它們的行為刻意很薄:走、停、玩家在一公尺內時回應。這裡的價值在於數量。你可以一次看五六個,看看一個有說服力的 NPC 循環實際上有多便宜。

3D 遊戲建構器則是你直接放置與設定 NPC 的地方。每個 NPC 拿到一段描述、一條巡邏路線、一組狀態。做個小東西——一個房間、一個 NPC、一條路線——然後測邊界:把感知半徑縮到 NPC 永遠不會注意到你,再放大到它永遠停不下來注意你。這兩個極端之間那條可用區帶的寬度,就是調校問題,而它在每個引擎裡都存在。

關於效能的一點說明。在瀏覽器組建裡,NPC 的成本主要由感知檢查和動畫決定,不是幾何。十個每幀做 raycast 的 NPC,會比十個用共用間隔檢查的 NPC 還貴,就算高細節模型是掛在間隔檢查的那一批身上也一樣。如果一個場景在 NPC 活躍時會卡頓,先看感知迴圈。

  • Agent Sprite Forge由描述驅動的 NPC,生成的回應受到約束。用它來看看一組很小的狀態加上一段角色提示,怎麼產出不會離題的對話。
  • The Cyclops' Island單一大型 NPC,有追擊、搜索、回到巡邏三種狀態。用它來研究對過期資訊做出行動為什麼讀起來像智慧。
  • Mini World幾個輕量 NPC 跑短循環,附帶接近提示。用它來看看在一個角色讀起來「在場」之前,需要多麼少的行為。
  • 3D 遊戲建構器放置 NPC、設定描述、畫巡邏路線、調整感知半徑。用它來找出「永遠不會注意到你」和「永遠停不下來」之間的那條可用區帶。
Little Ritual — 小行星上的任務 NPC。

為什麼賣 NPC 的是行為,不是畫面

一個低細節的角色,只要會走一條路線、在門口停一下、在你回來時人在別的地方,就會讀起來像活的。一個高細節的角色,站在一個點上重複一句台詞,就會讀起來像傢俱。玩家不是在評估多邊形。玩家在建一個關於這個角色想要什麼的模型,而那個模型來自時序和位置,不是來自網格。

機制是預期。如果一個角色早上在市集、晚上在家,玩家就會形成一個假設——這個角色有作息——而這個假設會在第二次造訪時被確認。那個確認就是整個效果。它花一個時鐘和一张查找表。它沒辦法靠在一尊雕像上加細節來取代,因為雕像從不否認、也從不確認任何事。

這就是為什麼老很多遊戲裡的排程驅動 NPC 至今還被討論,而視覺上更優的靜態 NPC 被遺忘。行為才是內容。模型是包裝。如果你在一個瀏覽器編輯器裡開發、時間有限,先把時間花在狀態轉換和巡邏路線上,再花在貼圖上。

怎麼分辨 NPC 和腳本觸發器

NPC 和觸發器都會對玩家做出反應,這就是它們在設計評審裡常被搞混的原因。區別在於事件之後有沒有東西留下來。當你在判斷眼前是哪一種時,把下面這些訊號當成檢查清單。

這張表不是純度測驗。很多遊戲用觸發器來啟動 NPC 的行為——一個觸發體積把守衛從巡邏翻成警戒。那是正常且正確的。問題出在一個觸發器被當成角色呈現給玩家:它觸發一次,這個角色此後再也不理會任何事,而這層假象在第二次遇到時就崩了。

訊號這是 NPC這是腳本觸發器
重複第二次遇到時同一個角色還是會回應觸發一次,之後再也不
狀態擁有跨幀存續的變數——警戒等級、巡邏索引除了已觸發/未觸發的旗標之外沒有狀態
位置在兩次遭遇之間會在世界裡移動停在被放下的地方
反應範圍依情境(時間、血量、距離)有不同反應不論情境都是同一個回應
失敗會卡住、會丟目標、尋路會走爛不會失敗——它要嘛觸發了,要嘛沒有
成本每幀的感知與動畫預算事件之後可忽略
對話從以狀態為鍵的集合裡挑一句播一句固定的台詞
The Cyclops' Island — 一個帶碰撞的敵人 NPC。
Ashenmere — 一個你在決鬥時能讀出意圖的對手 AI。
Mini World — 走進一個世界,遇見被放進去的角色。

走進它所屬的那個世界

精靈就是一個無處可站的角色。最後一步是別人沒給的:把你剛建好的精靈表放進一個有人能走進去的世界——一座小島、一顆行星、一個下雨的街角。本站的每一個世界都是由一段文字描述做出來,並發佈成一個可以玩的頁面。

回到 3D 遊戲建構器

全部 31 個完成的 3D 世界、遊戲與場景都在同一頁——每一個都能玩。

平台:Neta Studio頁面:電子遊戲中的 NPC:非玩家角色如何運作(附可玩 Demo)接著讀:/explore/guide/what-is-a-non-player-character · /explore/guide/what-are-npcs · /explore/guide/npc-behavior
×