iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
Software Development

Roblox Studio AI 協作開發大全系列 第 10

第 10 章:玩家資料與狀態

  • 分享至 

  • xImage
  •  

本章目標

第 9 章完成了第一個 Script-driven 行為。

玩家碰到水晶時,水晶會暫時消失,Output 會印出:

PlayerName collected Crystal_01

這代表事件成立、Script 執行、server 能判斷碰到水晶的是玩家。

但 Output 不是遊戲狀態。

Output 是開發者看的。

玩家需要的是可累積、可顯示、可被後續系統使用的狀態。

這一章要把「碰到水晶」推進成「玩家的水晶數增加」。

本章成果:

  • 玩家加入遊戲時,server 建立 leaderstats
  • leaderstats 裡有一個 IntValue,名稱為 Crystals
  • 玩家碰到水晶時,Crystals.Value 增加 1。
  • Roblox 內建 leaderboard 會顯示這個數值。

本章仍然不做永久保存。

玩家離開遊戲後,數值不會保存。DataStore 會在第 18 章處理。

本章也不做自訂 HUD。UI 會在第 11 章處理。

現在只要讓 server 管理最基本的玩家狀態。

玩家資料系統的 DataModel 階層範例。

圖 10-1 玩家狀態會跨越多個服務與模組;清楚的階層能避免資料邏輯散落在 Workspace 物件中。

Context Pack

本章依據以下 Roblox 官方文件撰寫:

Roblox DataModel 中可在 client 執行 LocalScript 的常見容器位置。

圖 10-2 圖中是常見 client Script 容器;本章建立 leaderstats 與權威玩家狀態時,邏輯應放在 server,而不是只存在玩家端的 LocalScript。

官方 record-and-display player data 教學從 coin collection 延伸到玩家資料與 leaderboard。它介紹了更完整的 ModuleScript 做法。

本書這一章先採用較輕的版本:

leaderstats + IntValue

原因是本章讀者剛開始讀 Script。如果立刻加入 ModuleScriptrequire()、資料存取函式、Leaderboard module,會一次跨太多概念。

先把玩家狀態看見。

再談架構。

官方教學也說明,Roblox 會識別名為 leaderstats 的 Folder,並將裡面的 value objects 顯示在內建 leaderboard 上。

這讓我們不用先建立自訂 UI,就能看到數值變化。

開場情境

第 9 章完成後,你應該有:

Workspace
  AdventureIsland
    Collectibles
      Crystal_01
      Crystal_02
      Crystal_03

ServerScriptService
  CrystalCollectionService

目前 CrystalCollectionService 只做:

touch -> print -> hide -> wait -> restore

這一章要改成:

player joins -> create leaderstats.Crystals
touch crystal -> Crystals.Value += 1
print debug message -> hide -> wait -> restore

你會第一次看到 Player 物件底下長出狀態:

Players
  Wolke
    leaderstats
      Crystals

這不是自訂 GUI。

這是 Roblox 內建 leaderboard 機制。

它適合初學時確認 server 真的在替玩家維護數值。

第一個 Prompt

請在 Assistant 輸入:

【Ch10 主任務|建立玩家狀態】
我正在製作 Roblox Studio 專案 AI Adventure Island。

目前 ServerScriptService 裡有 CrystalCollectionService。
它會處理 Workspace.AdventureIsland.Collectibles 裡 Crystal_01 到 Crystal_03 的 Touched 行為。

請幫我把第 9 章的水晶收集 prototype 升級成玩家狀態:

要求:
1. 仍然只使用 server Script,放在 ServerScriptService。
2. 玩家加入時,建立 player.leaderstats Folder。
3. 在 leaderstats 裡建立 IntValue,名稱為 Crystals,初始值為 0。
4. 玩家碰到水晶時,除了原本 Output print、透明、CanTouch=false、5 秒後恢復之外,也要讓該玩家的 Crystals.Value 增加 1。
5. 如果玩家已經有 leaderstats 或 Crystals,請不要重複建立。
6. 保留 Players:GetPlayerFromCharacter()。
7. 保留每顆水晶自己的 debounce,不要讓一顆水晶影響其他水晶。
8. 不要建立 DataStore、RemoteEvent、自訂 HUD、背包、任務系統或 ModuleScript。

完成後請:
- 貼出完整 CrystalCollectionService。
- 逐段解釋 PlayerAdded、leaderstats、IntValue、Crystals.Value。
- 說明 Playtest 時我要如何確認 leaderboard 顯示與數值增加。

這個 prompt 的重點是「升級既有 Script」。

不是重新生成所有東西。

如果 Assistant 想建立完整 PlayerData module,也先不要接受。那是正確方向,但不是這章的節奏。

本章只需要:

PlayerAdded
leaderstats
IntValue
Crystals.Value += 1

Assistant 可能產生的結果

Assistant 可能產生類似這段 Script:

local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")

local adventureIsland = Workspace:WaitForChild("AdventureIsland")
local collectibles = adventureIsland:WaitForChild("Collectibles")

local RESPAWN_SECONDS = 5
local CRYSTAL_STAT_NAME = "Crystals"

local function setupLeaderstats(player)
	local leaderstats = player:FindFirstChild("leaderstats")
	if not leaderstats then
		leaderstats = Instance.new("Folder")
		leaderstats.Name = "leaderstats"
		leaderstats.Parent = player
	end

	local crystals = leaderstats:FindFirstChild(CRYSTAL_STAT_NAME)
	if not crystals then
		crystals = Instance.new("IntValue")
		crystals.Name = CRYSTAL_STAT_NAME
		crystals.Value = 0
		crystals.Parent = leaderstats
	end

	return crystals
end

local function addCrystal(player, amount)
	local crystals = setupLeaderstats(player)
	crystals.Value += amount
	return crystals.Value
end

local function onCrystalTouched(crystal, otherPart)
	if not crystal.CanTouch then
		return
	end

	local character = otherPart.Parent
	local player = Players:GetPlayerFromCharacter(character)

	if not player then
		return
	end

	crystal.CanTouch = false
	crystal.Transparency = 1

	local newTotal = addCrystal(player, 1)
	print(player.Name .. " collected " .. crystal.Name .. ". Crystals: " .. newTotal)

	task.wait(RESPAWN_SECONDS)

	crystal.Transparency = 0
	crystal.CanTouch = true
end

Players.PlayerAdded:Connect(setupLeaderstats)

for _, player in Players:GetPlayers() do
	setupLeaderstats(player)
end

for _, crystal in collectibles:GetChildren() do
	if crystal:IsA("BasePart") then
		crystal.CanTouch = true
		crystal.Touched:Connect(function(otherPart)
			onCrystalTouched(crystal, otherPart)
		end)
	end
end

這段比第 9 章多了幾個新概念:

  • setupLeaderstats(player)
  • Instance.new("Folder")
  • Instance.new("IntValue")
  • Players.PlayerAdded:Connect(...)
  • Players:GetPlayers()
  • crystals.Value += amount

你不用一次背下所有 API。

先看懂資料流:

玩家加入 -> 建立 Crystals
玩家碰到水晶 -> 找到 Player
Player -> 找 leaderstats.Crystals
Crystals.Value + 1
leaderboard 顯示變化

元件拆解

Player 與 Players

Players 是一個 service,代表目前連到 server 的玩家集合。

每位玩家進入遊戲時,server 會有對應的 Player 物件。

在 Explorer 裡,Playtest 時可以看到:

Players
  PlayerName

第 9 章用過:

local Players = game:GetService("Players")
local player = Players:GetPlayerFromCharacter(character)

這行是從角色 Model 找回 Player。

第 10 章新增:

Players.PlayerAdded:Connect(setupLeaderstats)

這代表:

當玩家加入時,呼叫 setupLeaderstats(player)。

在單人 Playtest 裡你可能只看到自己一個 Player。

但你要從這章開始習慣:Roblox 遊戲預設是多人。

玩家狀態應該掛在各自的 Player 底下,而不是用一個全域數字代表所有人。

leaderstats

leaderstats 是 Roblox 內建 leaderboard 的約定名稱。

官方教學說明,當你在 Player 底下建立一個名為 leaderstats 的 Folder,Roblox 會把其中的 value objects 顯示在內建 leaderboard。

所以這段很重要:

local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player

注意大小寫。

它必須叫:

leaderstats

不是:

Leaderstats
LeaderStats
leaderStats
stats

如果名稱錯了,Folder 仍然會存在,但 leaderboard 不一定會用它顯示。

本章不需要自訂 UI,因為 Roblox 內建 leaderboard 已經足夠讓你確認數值變化。

第 11 章才會開始做 HUD。

IntValue

IntValue 是一種 value object。

它的用途是把一個整數存在 Instance 裡。

本章建立:

local crystals = Instance.new("IntValue")
crystals.Name = "Crystals"
crystals.Value = 0
crystals.Parent = leaderstats

這代表玩家有一個整數狀態:

Crystals = 0

當玩家收集水晶時:

crystals.Value += 1

就會變成:

Crystals = 1

再收集一次:

Crystals = 2

IntValue 適合這章,因為水晶數量是整數。

如果你之後要記錄小數,例如經驗倍率,可以用 NumberValue

如果要記錄文字,例如目前任務名稱,可以用 StringValue

但本章只用 IntValue

避免重複建立

這段程式看起來有點長:

local leaderstats = player:FindFirstChild("leaderstats")
if not leaderstats then
	leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
end

為什麼不直接每次都建立新的?

因為玩家只需要一個 leaderstats

如果每次碰到水晶都建立一次,Explorer 會變得混亂,leaderboard 也可能出錯。

所以先用:

FindFirstChild("leaderstats")

檢查它是否已存在。

不存在才建立。

Crystals 也一樣:

local crystals = leaderstats:FindFirstChild(CRYSTAL_STAT_NAME)
if not crystals then
	-- create IntValue
end

這是很常見的 AI 生成後整理重點。

你要要求 Assistant 不要盲目重複建立 Instance。

PlayerAdded 與既有玩家

這行處理新玩家:

Players.PlayerAdded:Connect(setupLeaderstats)

但 Script 啟動時,可能已經有玩家存在。

所以範例裡又加了:

for _, player in Players:GetPlayers() do
	setupLeaderstats(player)
end

這是一個穩健寫法。

在 Studio Playtest 裡通常影響不大,但它建立了好的習慣:

處理未來加入的玩家,也處理現在已存在的玩家。

當你之後寫更複雜的系統,例如任務、背包、UI 初始化,這個習慣很重要。

Playtest

看見玩家狀態

現在進入 Play mode。

測試步驟:

1. 打開 Explorer。
2. 展開 Players。
3. 展開你的 Player。
4. 確認有 leaderstats。
5. 展開 leaderstats。
6. 確認有 Crystals,Value = 0。
7. 打開 Output。
8. 走去碰 Crystal_01。
9. 確認 Crystals.Value 變成 1。
10. 確認 leaderboard 顯示 Crystals = 1。
11. 碰 Crystal_02,確認數值變成 2。

預期 Output:

PlayerName collected Crystal_01. Crystals: 1
PlayerName collected Crystal_02. Crystals: 2

如果 Output 有訊息,但 leaderboard 沒變,檢查:

  • leaderstats 名稱是否正確。
  • Crystals 是否是 IntValue
  • Crystals.Parent 是否是 leaderstats
  • leaderstats.Parent 是否是 player

如果 leaderboard 有 Crystals 但數值不增加,檢查:

  • addCrystal(player, 1) 是否被呼叫。
  • crystals.Value += amount 是否存在。
  • player 是否正確由 GetPlayerFromCharacter() 找到。

如果每次碰水晶都回到 1,檢查:

  • 是否每次都重新建立 IntValue
  • 是否沒有先 FindFirstChild("Crystals")

修正 Prompt

如果 leaderboard 沒出現:

【Ch10 修正 1|顯示 leaderboard 數值】
我 Playtest 後 Players.PlayerName 底下有資料,但 Roblox 內建 leaderboard 沒有顯示 Crystals。

請檢查 CrystalCollectionService:
1. Folder 名稱是否精確為 leaderstats。
2. leaderstats 是否 parent 到 player。
3. Crystals 是否是 IntValue。
4. Crystals 是否 parent 到 leaderstats。
5. 不要建立自訂 HUD。
6. 不要新增 DataStore、RemoteEvent 或 ModuleScript。

如果數值不增加:

【Ch10 修正 2|修復水晶計數增加】
我碰到水晶時 Output 有印出 collected,但 Crystals.Value 沒有增加。

請檢查:
1. onCrystalTouched 是否有取得 player。
2. 是否有呼叫 addCrystal(player, 1)。
3. addCrystal 是否會找到或建立 leaderstats.Crystals。
4. 是否有執行 crystals.Value += amount。
5. 請保持本章範圍,只修正 player state,不要做 DataStore。

如果 Assistant 加太多架構:

【Ch10 修正 3|簡化玩家狀態版本】
這章只需要 leaderstats + IntValue 入門版本。

請移除或不要使用:
- PlayerData ModuleScript
- Leaderboard ModuleScript
- DataStoreService
- RemoteEvent
- custom HUD
- inventory / quest system

請保留:
- Players.PlayerAdded
- setupLeaderstats(player)
- leaderstats Folder
- Crystals IntValue
- CrystalCollectionService 中收集水晶時 Crystals.Value += 1

如果多顆水晶互相干擾:

【Ch10 修正 4|分離每顆水晶狀態】
收集 Crystal_01 後,其他水晶也無法被收集。

請檢查 debounce 是否是每顆水晶各自管理。
要求:
1. 不要使用單一全域 debounce 阻擋所有水晶。
2. 每顆水晶收集後只停用自己的 CanTouch。
3. 其他水晶仍然可以被收集。
4. 保持 Crystals.Value 正確增加。

工程整理

完成本章後,整理目前狀態:

ServerScriptService
  CrystalCollectionService

Players
  PlayerName
    leaderstats
      Crystals

在你的筆記或章節紀錄中寫下:

State name: Crystals
Type: IntValue
Owner: Player
Created by: CrystalCollectionService
Updated by: onCrystalTouched
Visible through: Roblox built-in leaderboard
Persistence: none yet

特別標記:

Persistence: none yet

因為這章的玩家狀態只存在於當前 server session。

如果玩家離開、server 關閉、重新 Playtest,數值會歸零。

這不是 bug。

這是本章刻意邊界。

DataStore 會在後面處理。

現在先確定:

  • 玩家加入時狀態被建立。
  • 收集水晶時狀態增加。
  • 狀態能被看見。
  • 狀態由 server 管理。

本章總結

這一章,你把第 9 章的 Output prototype 變成玩家狀態。

你學到:

  • Players service 管理目前連線的玩家。
  • PlayerAdded 可用來初始化玩家狀態。
  • leaderstats 是 Roblox 內建 leaderboard 的約定 Folder 名稱。
  • IntValue 可以存放整數狀態。
  • Crystals.Value += 1 讓收集行為變成可累積數值。
  • 玩家狀態應該掛在各自的 Player 底下,而不是用一個全域數字代表所有玩家。
  • 本章的狀態不會永久保存,DataStore 會留到後面。

到這裡,AI Adventure Island 已經有第一個玩家可見的數值。

下一章,我們會處理 UI:不是只讓 Roblox 內建 leaderboard 顯示數字,而是讓遊戲畫面用 HUD、任務提示或回饋文字,把玩家狀態轉成更好的遊戲體驗。


關於 Wolke

嗨!我是 Wolke,曾任 Google Developer Expert(GDE,2019–2023)LINE API Expert

我熱衷於研究 AI Agent、n8n 自動化工作流與全端開發架構,致力於將 AI 技術轉化為真正能落地的生產力工具。

如果你喜歡這篇文章,歡迎透過以下方式與我交流:

📚 技術著作
《實用的 Gemini API 開發點子書》:帶你運用 Gemini App、Google AI Studio、Gemini CLI 與 Antigravity IDE,打造 AI Agent 與實用產品。

📝 技術部落格
歡迎追蹤我的 Medium,我會持續分享 Agentic Automation、架構設計與實際開發的踩坑心得。

🎤 技術講座與合作
我持續受邀至技術社群及研討會,分享 AI Agent、自動化工作流、DevOps 與全端開發實戰。

我曾於 DevOpsDays Taipei 2026 主講「不再只是寫腳本!讓 AI 代理人成為你的 SRE 最佳夥伴」工作坊。

如果你的企業、社群或學校正在尋找相關主題講者,歡迎私訊聯繫,洽談講座與工作坊合作!

🎮 我的 Roblox 遊戲

🎁 免費贈送 OpenAI 或 Claude AI 額度

為了鼓勵大家實際動手打造自己的 Roblox 體驗,我每個月會開放:

  • 10 個名額
  • 每人 50 點 AI 額度
  • 名額送完為止

參加方式:

  1. 訂閱本系列文章。
  2. 分享任一篇系列文章。
  3. 私訊分享截圖及你的 AI 帳號 Email。

確認完成後,我會邀請你加入並設定 50 點額度。名額有限,歡迎把握機會!


上一篇
第 9 章:第一次讓 Assistant 寫 Script
下一篇
第 11 章:UI 不是裝飾,是遊戲回饋
系列文
Roblox Studio AI 協作開發大全11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言