第三部開始,AI Adventure Island 要從「場景裡有互動元件」進入「互動背後有遊戲邏輯」。
第 8 章你已經建立了第一批互動入口:
ProximityPrompt。ProximityPrompt。Touched 做最小回饋。但你還沒有真正理解 Assistant 產生的 Script。
這一章要做的事很單純:讓 Crystal_01 到 Crystal_03 成為第一批由 Script 控制的可收集物。
玩家碰到水晶時:
本章不做完整分數。
本章不做背包。
本章不做任務進度。
這些都會在後面章節逐步加入。
本章的重點是讀懂第一個 Script:
物件在哪裡
Script 放在哪裡
事件何時觸發
function 做了什麼
Output 如何驗證
錯誤如何回到 Assistant 修正

圖 9-1 Assistant 可把 Script 插入 DataModel;執行前應先確認程式內容、父層位置與 server/client 執行環境。
本章依據以下 Roblox 官方文件撰寫:
官方 scripting 文件把 Script 定義得很直接:Script 是純文字檔,用 Luau 替遊戲加入自訂、動態行為。
官方 script locations 文件則提醒:在 Roblox 裡,Script 的位置很重要。因為 Roblox 遊戲預設是 multiplayer,程式可能跑在 server,也可能跑在 client。
本章只使用 server-side Script,並放在:
ServerScriptService
原因是:
ServerScriptService 的內容不會複製到 client。Output 是本章另一個重點。
在你還不熟 Luau 時,print() 和 Output 是最直接的觀察工具。
本章會把 Output 當成 AI 生成後的第一個驗證點。
目前你的 Explorer 大致有:
Workspace
AdventureIsland
Collectibles
Crystal_01
Crystal_02
Crystal_03
Interactables
Chest_Starter
NPCs
NPC_QuestGiver_Placeholder
World
Blockout_Parts
Visuals
ProceduralModels
ServerScriptService
InteractionPrototype
第 8 章的 InteractionPrototype 可能已經有水晶碰撞 prototype。
這章會把水晶收集行為整理成更清楚的 Script。
建議命名為:
CrystalCollectionService
雖然現在它還不是完整 service 架構,但這個名稱比 Script、CrystalScript、TouchScript 更清楚。
本章要保留一個界線:
現在只處理水晶收集行為。
NPC、寶箱、任務、分數、UI 都先不混進來。
這是學習 Script 時最重要的控制。
如果第一個 Script 同時做太多事,讀者會不知道自己是在學事件、資料、UI、任務,還是在修 AI 亂生成的架構。
請在 Assistant 輸入:
【Ch09 主任務|建立第一支 Script】
我正在製作 Roblox Studio 專案 AI Adventure Island。
目前 Workspace.AdventureIsland.Collectibles 裡有:
- Crystal_01
- Crystal_02
- Crystal_03
請幫我建立第一個正式可讀的 server Script,用來處理水晶收集 prototype。
要求:
1. 在 ServerScriptService 建立 Script,名稱為 CrystalCollectionService。
2. Script 只處理 Crystal_01 到 Crystal_03 的 Touched 行為。
3. 玩家碰到水晶時:
- 確認觸碰的是玩家角色。
- 在 Output 印出玩家名稱與水晶名稱,例如 "Wolke collected Crystal_01"。
- 將該水晶 Transparency 設為 1。
- 將該水晶 CanTouch 設為 false,避免短時間重複觸發。
- 等待 5 秒。
- 將 Transparency 設回 0。
- 將 CanTouch 設回 true。
4. 使用 Players:GetPlayerFromCharacter() 判斷玩家。
5. 使用 WaitForChild() 取得 AdventureIsland 和 Collectibles。
6. 不要建立 leaderstats、背包、任務、UI、RemoteEvent 或 DataStore。
7. 請在程式中加入少量清楚註解,讓初學者能看懂。
完成後請:
- 貼出完整 Script。
- 解釋 Script 應該放在哪裡。
- 逐段解釋 local 變數、function、Touched:Connect、print、task.wait。
- 告訴我 Playtest 時 Output 應該看到什麼。
這個 prompt 的目標不是讓 Assistant 寫最多功能。
它的目標是讓 Assistant 寫一段可教學、可讀、可測的 Script。
注意幾個限制:
這些限制是本書的核心方法。
AI 可以一次生成很多功能,但你要把學習順序切小。
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 function onCrystalTouched(crystal, otherPart)
local character = otherPart.Parent
local player = Players:GetPlayerFromCharacter(character)
if not player then
return
end
if not crystal.CanTouch then
return
end
print(player.Name .. " collected " .. crystal.Name)
crystal.Transparency = 1
crystal.CanTouch = false
task.wait(RESPAWN_SECONDS)
crystal.Transparency = 0
crystal.CanTouch = true
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
你的結果不一定完全相同。
但它應該具備這些元素:
Players service
Workspace service
WaitForChild()
RESPAWN_SECONDS
onCrystalTouched()
Players:GetPlayerFromCharacter()
print()
Transparency
CanTouch
task.wait()
Touched:Connect()
如果 Assistant 直接建立 leaderstats、RemoteEvent、ScreenGui 或 DataStoreService,先不要接受。
你可以要求它縮小範圍:
請把 Script 縮回水晶收集 prototype。不要做分數、UI、RemoteEvent 或 DataStore。
本章的好 Script 應該短到你可以逐行讀完。
本章的 Script 應該放在:
ServerScriptService
CrystalCollectionService
官方文件說明,ServerScriptService 是 server-only Script container,內容不會複製到玩家 client。這讓它適合放重要遊戲邏輯。

圖 9-2 除了 Script 放置位置,也要檢查 RunContext;執行環境錯誤時,程式可能完全不跑,或只在錯誤的一側執行。
水晶收集是 server-side 行為。
原因是:
如果 Script 放在錯誤地方,可能發生:
初學者常以為「有寫 Script 就會跑」。
Roblox 不是這樣。
Script 的位置是行為的一部分。
程式一開始通常會取得需要的 services:
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
game:GetService() 會取得 Roblox 內建 service。
本章用到兩個:
Players:用來判斷觸碰水晶的是不是玩家角色。Workspace:用來找到場景中的 AdventureIsland。接著取得本章需要的資料夾:
local adventureIsland = Workspace:WaitForChild("AdventureIsland")
local collectibles = adventureIsland:WaitForChild("Collectibles")
WaitForChild() 的意思是等待指定 child 出現,再繼續執行。
這比直接寫:
local collectibles = Workspace.AdventureIsland.Collectibles
更穩。
在 Roblox 中,物件載入和複製有時機問題。即使本章跑在 server,用 WaitForChild() 也能讓第一個 Script 更不容易因為找不到物件而出錯。
本章你不需要理解所有 replication 細節。
先記住:
Script 要操作某個物件,先清楚取得它。
這行:
local RESPAWN_SECONDS = 5
是本章第一個簡單常數。
local 表示這個變數只在目前 Script 範圍內使用。
RESPAWN_SECONDS 用大寫,是一種常見寫法,用來表示這個值像設定值,不應該在流程中隨意改來改去。
如果之後想把水晶恢復時間從 5 秒改成 10 秒,只要改這裡:
local RESPAWN_SECONDS = 10
不要把 5 散落在整段程式裡。
這是第一次接觸「可維護」的寫法。
AI 生成的程式能跑,不代表好維護。
你要開始學會要求 Assistant 把重要數值拉成清楚名稱。
這段是事件發生後要執行的邏輯:
local function onCrystalTouched(crystal, otherPart)
local character = otherPart.Parent
local player = Players:GetPlayerFromCharacter(character)
if not player then
return
end
if not crystal.CanTouch then
return
end
print(player.Name .. " collected " .. crystal.Name)
crystal.Transparency = 1
crystal.CanTouch = false
task.wait(RESPAWN_SECONDS)
crystal.Transparency = 0
crystal.CanTouch = true
end
function 是一段可以被呼叫的程式。
這裡命名為:
onCrystalTouched
這個名稱很好,因為它說明了觸發情境:水晶被碰到時。
參數有兩個:
crystal
otherPart
crystal 是哪一顆水晶。
otherPart 是碰到水晶的 Part。這個 Part 可能是玩家角色的一部分,也可能不是玩家。
所以程式先做判斷:
local character = otherPart.Parent
local player = Players:GetPlayerFromCharacter(character)
if not player then
return
end
GetPlayerFromCharacter() 用來從角色 Model 找到對應的 Player。
如果找不到 player,就代表這次碰撞不是玩家造成的,function 直接 return。
這是第一個安全觀念:
不要假設每次 Touched 都是玩家。
最後這段會替每顆水晶接上事件:
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
collectibles:GetChildren() 取得 Collectibles 裡的所有 child。
for _, crystal in ... do 代表逐一處理每個 child。
crystal:IsA("BasePart") 是檢查它是不是可以被觸碰的 3D part 類型。
然後這一行最重要:
crystal.Touched:Connect(function(otherPart)
onCrystalTouched(crystal, otherPart)
end)
可以讀成:
當 crystal 的 Touched event 發生時,
呼叫這個 function,
並把碰到它的 otherPart 傳進來。
這就是事件驅動。
不是程式一直問「玩家有沒有碰到水晶」。
而是 Roblox 偵測到碰撞後,觸發 Touched,再執行你連接的 function。
這行是本章的第一個驗證點:
print(player.Name .. " collected " .. crystal.Name)
當玩家碰到水晶時,Output 應該出現類似:
Wolke collected Crystal_01
官方 Output 文件說明,Output 會顯示 errors、engine messages、print() 與 warn()。
本章請打開 Output,並建議啟用:
Show Context
Show Source
這樣你會更容易知道訊息來自 server 還是 client,以及哪個 Script 行號。
對 AI 生成工作流來說,Output 是你和 Assistant 溝通的證據。
不要只說:
水晶壞了。
要說:
Playtest 時碰到 Crystal_01,Output 沒有印出訊息。
或 Output 顯示 ServerScriptService.CrystalCollectionService 第 12 行錯誤。
這會讓 Assistant 修正得更準。
現在進入 Play mode。
測試步驟:
1. 打開 Output。
2. 確認 Output 已清空。
3. 玩家走向 Crystal_01。
4. 讓角色碰到 Crystal_01。
5. 觀察 Output。
6. 等待 5 秒。
7. 確認 Crystal_01 是否恢復。
8. 重複測 Crystal_02 和 Crystal_03。
預期結果:
PlayerName collected Crystal_01
PlayerName collected Crystal_02
PlayerName collected Crystal_03
視覺上:
如果水晶沒有消失,但 Output 有訊息,代表事件成功,視覺狀態可能沒改對。
如果水晶消失,但 Output 沒有訊息,代表可能沒有執行到 print(),或 Output filter 隱藏了訊息。
如果完全沒有反應,先檢查:
ServerScriptService。Enabled=true。AdventureIsland 名稱是否正確。Collectibles 名稱是否正確。BasePart。CanTouch 是否為 true。不要一開始就重寫整段 Script。
先確認哪個假設錯了。
如果 Script 沒有執行,用:
【Ch09 修正 1|診斷水晶沒有輸出】
我 Playtest 後碰到 Crystal_01,Output 完全沒有訊息。
目前 Script 名稱是 CrystalCollectionService,位置在 ServerScriptService。
請幫我檢查可能原因:
1. Script 是否應該放在 ServerScriptService。
2. Script 是否 Enabled。
3. 是否有正確使用 Workspace:WaitForChild("AdventureIsland")。
4. 是否有正確取得 Collectibles。
5. 是否有替 Crystal_01 到 Crystal_03 連接 Touched event。
請不要新增 leaderstats、UI、RemoteEvent 或 DataStore。
請只修正這個水晶收集 prototype。
如果 Output 有錯誤,用:
【Ch09 修正 2|分析水晶 Script 錯誤】
Playtest 時 Output 顯示這個錯誤:
###
貼上完整錯誤訊息,包含 Script 名稱與行號
###
這是目前 CrystalCollectionService 的程式:
###
貼上目前 Script
###
請:
1. 解釋錯誤原因。
2. 指出是哪一行造成。
3. 修正 Script。
4. 保持功能範圍不變:只處理 Crystal_01 到 Crystal_03 的 Touched prototype。
5. 不要新增其他系統。
如果水晶重複觸發,用:
【Ch09 修正 3|限制水晶重複觸發】
玩家碰到 Crystal_01 時,Output 連續印出很多次。
請在 CrystalCollectionService 裡加入最小 debounce。
要求:
1. 每顆水晶被收集後,立刻 CanTouch=false。
2. 5 秒後才恢復 CanTouch=true。
3. 不要使用全域單一 debounce,避免 Crystal_01 影響 Crystal_02。
4. 請解釋每顆水晶如何各自管理狀態。
如果 Assistant 生成太複雜,用:
【Ch09 修正 4|簡化水晶 Script】
請把這段 Script 簡化成第 9 章教學用版本。
保留:
- Players:GetPlayerFromCharacter()
- Touched:Connect()
- print()
- Transparency
- CanTouch
- task.wait(5)
移除或不要使用:
- leaderstats
- DataStore
- RemoteEvent
- UI
- 任務系統
- 背包系統
請貼出簡化後完整 Script,並逐段解釋。
修 bug 時,把 Output 當作證據。
AI 不在你的 Studio 裡看 Playtest 結果。你要把錯誤訊息、目前 Script、預期行為一起提供。
完成本章後,建議 Explorer 結構如下:
Workspace
AdventureIsland
Collectibles
Crystal_01
Crystal_02
Crystal_03
ServerScriptService
CrystalCollectionService
如果第 8 章留下 InteractionPrototype,現在有兩種做法:
做法 A:把水晶相關程式搬到 CrystalCollectionService,InteractionPrototype 只保留 NPC/Chest prototype。
做法 B:如果 InteractionPrototype 只剩水晶程式,改名為 CrystalCollectionService。
不要同時留下兩段水晶 Touched 程式。
否則你可能會看到:
本章整理清單:
Script name: CrystalCollectionService
Location: ServerScriptService
Scope: Crystal_01 到 Crystal_03
Behavior: touch -> print -> hide -> wait -> restore
Not included: score, backpack, quest, UI, save
Verified by: Output message and visual disappear/restore
這份整理會成為第 10 章的起點。
第 10 章會開始處理玩家資料與狀態。到時候你會把「玩家碰到水晶」從 Output 訊息推進到真正的數值變化。
這一章,你第一次讓 Assistant 寫出正式可讀的 Script-driven 行為。
你學到:
ServerScriptService 適合放 server-side 遊戲邏輯。game:GetService() 用來取得 Roblox services。WaitForChild() 用來穩定取得場景物件。Touched:Connect() 把事件和 function 接起來。Players:GetPlayerFromCharacter() 可以判斷碰撞是否來自玩家。print() 和 Output 是第一個驗證工具。到這裡,AI Adventure Island 已經有第一個真正由 Script 驅動的遊戲行為。
下一章,我們會在這個基礎上建立玩家資料與狀態:讓收集水晶不只是印出訊息,而是能累積成玩家可見、可管理的數值。
嗨!我是 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 體驗,我每個月會開放:
參加方式:
確認完成後,我會邀請你加入並設定 50 點額度。名額有限,歡迎把握機會!