Data stores เป็นบริการที่คุณสามารถใช้เพื่อบันทึกและโหลด ข้อมูลของผู้เล่นที่คงอยู่ ระหว่างเซสชันของผู้เล่นต่าง ๆ พวกมันเก็บข้อมูลที่สำคัญ เช่น ความก้าวหน้าของผู้เล่นหรือสิ่งของในคลังและอนุญาตให้คุณดึงข้อมูลนี้มาเพื่อผู้เล่นในครั้งถัดไปที่พวกเขาเข้าร่วมเกมส์ของคุณ หากไม่มี Data Store ผู้เล่นจะสูญเสียความก้าวหน้าทั้งหมดทุกครั้งเมื่อพวกเขาออกจากเกม
มี Data Store สองประเภท: มาตรฐานและเรียงลำดับ. บทช่วยสอนนี้ใช้ Data Store ที่เรียงลำดับ ซึ่งจะเก็บข้อมูลที่คุณสามารถจัดอันดับและเรียงลำดับแบบตัวเลขและดึงข้อมูลตามลำดับที่เก็บอย่างเพิ่มขึ้นหรือลดลงตามค่าตัวเลขที่เก็บไว้
ใช้ไฟล์ Gold Rush create leaderboard tutorial - Start .rbxl เป็นจุดเริ่มต้นและไฟล์ Gold Rush create leaderboard tutorial - Complete .rbxl เป็นข้อมูลอ้างอิง บทช่วยสอนนี้จะให้พื้นฐานที่คุณต้องการในการสร้างกระดานผู้นำของผู้เล่นแบบกำหนดเอง รวมถึงคำแนะนำใน:
- การจัดเก็บคะแนนทองใน Data Store ที่เป็นระเบียบเรียบร้อย
- การดึงและจัดเรียงคะแนนสูงสุดในระดับโลกจากเซิร์ฟเวอร์ต่าง ๆ
- การแสดงคะแนนสูงสุดในกระดานผู้นำแบบกำหนดเองใน UI
- การรีเฟรชกระดานผู้นำแบบกำหนดเองโดยอัตโนมัติทุก ๆ ไม่กี่วินาที
เมื่อสิ้นสุดบทช่วยสอนนี้ คุณควรมีดังนี้:
- ภายใต้ ServerScriptService:
- สคริปต์ GoldManager ที่อัปเดตซึ่งบันทึกคะแนนของผู้เล่นไปยัง Data Store ที่เรียงลำดับสำหรับกระดานผู้นำ
- โมดูลสคริปต์ใหม่ LeaderboardRemoteHandler ที่ดึงและส่งกลับรายการคะแนนสูงสุดที่เรียงลำดับจากกระดานผู้นำ
- สคริปต์ใหม่ LeaderboardManager ที่ตอบสนองต่อตำแหน่งข้อมูลกระดานผู้นำจากไคลเอนต์ ทำหน้าที่เป็นสะพานเชื่อมร่วมกับไคลเอนต์ใน LeaderboardGuiScript และเซิร์ฟเวอร์ใน LeaderboardManager
- ภายใต้ StarterGui เป็นสคริปต์ท้องถิ่นใหม่ LeaderboardGuiScript ที่แสดงผล UI กระดานผู้นำสำหรับผู้เล่น

เปิดใช้งานการเข้าถึง Studio ไปยังบริการ API
Data stores ไม่ได้ถูกเก็บไว้ในอุปกรณ์ของคุณ ดังนั้นเกมของคุณจึงขึ้นอยู่กับการสื่อสารจากเซิร์ฟเวอร์ไปยังเซิร์ฟเวอร์กับแบ็คเอนด์ของ Roblox เพื่อที่จะใช้มัน โดยค่าเริ่มต้น Studio จะจำกัดการสื่อสารนี้เพื่อป้องกันการละเมิดหรือการใช้งานโดยไม่ได้ตั้งใจ การเข้าถึงบริการ API ใน Studio ถูกปิดใช้งานจนกว่าคุณจะเปิดใช้งานอย่างชัดเจนเพื่อให้แน่ใจว่าเกมที่เชื่อถือได้เท่านั้นที่สามารถอ่านและเขียนจากเซิร์ฟเวอร์แบ็คเอนด์ของ Roblox ได้
เพื่อเปิดใช้งานการเข้าถึง Studio ไปยังบริการ API เพื่อให้คุณสามารถใช้ Data Store ได้:
- เปิดไฟล์ Gold Rush create leaderboard tutorial - Start ใน Studio ไฟล์จุดเริ่มต้นนี้มีโค้ดจากบทช่วยสอน บันทึกข้อมูลผู้เล่น และโครง UI สำหรับกระดานผู้นำของผู้เล่นแล้ว
- กลับไปที่ Studio ไปที่ File ⟩ Experience Settings ⟩ Security.
- เปิด Enable Studio Access to API Services.
- บันทึกการเปลี่ยนแปลงของคุณ.
สร้าง Data Store ที่เรียงลำดับ
เมื่อคุณสร้าง Data Store คุณควรเรียกใช้ DataStoreService จาก Script ด้านเซิร์ฟเวอร์เสมอ การทำเช่นนี้สำคัญเพราะ:
- Roblox จะบล็อกการเข้าถึง Data Store จากไคลเอนต์เพื่อให้เฉพาะเซิร์ฟเวอร์เท่านั้นที่มีสิทธิ์เข้าถึงและแก้ไขข้อมูลผู้เล่นที่คงอยู่
- สคริปต์ด้านเซิร์ฟเวอร์ทำงานในสภาพแวดล้อมที่รวมศูนย์ เพื่อให้มั่นใจว่าข้อมูลที่อ่านและเขียนลงใน Data Store ของคุณแม่นยำและถูกต้อง
- เนื่องจากสคริปต์ด้านไคลเอนต์ทำงานบนอุปกรณ์ของผู้เล่น ผู้เล่นใดสามารถหาประโยชน์จากเกมและขโมยหรือเขียนข้อมูลของผู้เล่นอื่นได้หากไคลเอนต์มีการเข้าถึง Data Store ของคุณ
คุณยังควรตั้งชื่อ Data Store ให้เป็นเอกลักษณ์เพื่อทำให้ข้อมูลของคุณจัดระเบียบและเพื่อป้องกันไม่ให้ข้อมูลซ้อนทับหรือขัดแย้งใน Data Store ต่าง ๆ ในบทช่วยสอนนี้ Data Store สำหรับกระดานผู้นำเรียกว่า GlobalLeaderboard.
ในการสร้าง Data Store ที่เรียงลำดับ GlobalLeaderboard:
เปิดสคริปต์ GoldManager ที่มีอยู่ภายใต้ ServerScriptService.

ใต้ Data Store PlayerGold ที่มีอยู่ เรียกใช้ GetOrderedDataStore โดยใช้สตริง "GlobalLeaderboard" นี่จะสร้าง Data Store ที่เรียงลำดับเพื่อบันทึกคะแนนของผู้เล่นเมื่อพวกเขาได้รับทองคำ
local leaderboardStore = DataStoreService:GetOrderedDataStore("GlobalLeaderboard")
หลังจากสร้าง Data Store แล้ว คุณสามารถอ้างอิง Data Store นี้ในสคริปต์ต่าง ๆ ได้ ตัวอย่างเช่น คุณสามารถเรียกใช้ GetOrderedDataStore ในทั้งสคริปต์ GoldManager และโมดูลสคริปต์ LeaderboardManager ที่คุณจะสร้างต่อไปในบทช่วยสอนนี้ การอ้างอิง Data Store เดียวกันในสองที่ไม่ได้หมายความว่าคุณกำลังทำให้ข้อมูลซ้ำซ้อน; แค่หมายความว่าสคริปต์สองตัวกำลังเข้าถึงการจัดเก็บข้อมูลที่รวมศูนย์เดียวกัน เหมือนกับเพื่อนร่วมทีมสองคนที่ใช้โฟลเดอร์เดียวกันเพื่อแชร์ข้อมูล
ส่งข้อมูลผู้เล่นไปยังกระดานผู้นำ
Data Store ประกอบด้วยคีย์ซึ่งใช้ระบุข้อมูล และค่าซึ่งใช้บันทึกข้อมูล ไม่เหมือนกับ Data Store มาตรฐาน Data Store ที่เรียงลำดับช่วยให้คุณจัดเรียงข้อมูลตาม ค่า ซึ่งทำให้เหมาะสมสำหรับการสร้างสิ่งของเช่นกระดานผู้นำ
แต่ละรายการใน Data Store ที่เรียงลำดับจะถูกเก็บไว้ภายใต้คีย์ที่ไม่ซ้ำกันซึ่งคุณสามารถจัดอันดับและเรียงลำดับแบบตัวเลขได้ จากนั้นดึงข้อมูลในลำดับเพิ่มหรือ ลดลงตามค่าตัวเลขที่เก็บไว้ นี่หมายความว่าคุณสามารถใช้ Data Store ที่เรียงลำดับเพื่อแสดงรายการ 3 อันดับที่อัปเดตแบบเรียลไทม์เมื่อผู้เล่นในเกมของคุณเก็บทองคำมากขึ้น
| คีย์ | ค่า | |
|---|---|---|
| คำอธิบาย | คีย์คือสตริงที่ไม่ซ้ำกันที่คุณสามารถใช้เพื่อเข้าถึงข้อมูลเฉพาะอย่างเช่น ID ผู้ใช้ของผู้เล่น คีย์ช่วยให้คุณจัดระเบียบข้อมูลเพื่อให้คุณจัดการและดีบักได้ง่าย | ค่าเป็นข้อมูลเชิงตัวเลขจริงที่คุณต้องการบันทึกหรือโหลด เช่น คะแนนของผู้เล่น ค่าช่วยให้คุณจัดเก็บความก้าวหน้าระหว่างเซสชัน รวมถึงดึงข้อมูลของผู้เล่นในการเข้าร่วมเกมในครั้งถัดไป |
| รูปแบบที่อนุญาต | เป็นสตริงเท่านั้น หากคุณใช้หมายเลข เช่น ID ผู้ใช้ ให้แปลงเป็นสตริงโดยใช้ tostring(). | เป็นตัวเลขเท่านั้น |
| ตัวอย่าง | "Player_A", "TopScore", "123456" (userID เป็นสตริง) | 100, 3.14, 0, -25 |
เมื่อคุณสร้าง Data Store GlobalLeaderboard แล้ว ให้ปรับปรุงฟังก์ชัน saveGold ที่มีอยู่ในสคริปต์ GoldManager เพื่อส่งคะแนนทองของผู้เล่นไปยังกระดานผู้นำที่กำหนดเองของคุณด้วย SetAsync:
local function saveGold(player, value)
local userId = player.UserId
local success, err = pcall(function()
goldStore:SetAsync(userId, value)
leaderboardStore:SetAsync(tostring(userId), value)
end)
if not success then
warn("ไม่สามารถบันทึกทองคำสำหรับ", player.Name, ":", err)
end
end
คุณสามารถคิดถึง Data Store ที่เรียงลำดับ GlobalLeaderboard เหมือนโฟลเดอร์ที่แชร์: SetAsync จะเพิ่มเนื้อหาในโฟลเดอร์ ในขณะที่ GetSortedAsync (ซึ่งคุณจะสร้างในโมดูลสคริปต์ LeaderboardManager ในภายหลัง) จะอ่านเนื้อหาในโฟลเดอร์และจัดเรียงตามคะแนน
ดึงคะแนนจากกระดานผู้นำ
ในการดึงคะแนนจากกระดานผู้นำ คุณควรใช้ ModuleScript. โมดูลสคริปต์ช่วยให้คุณจัดระเบียบและนำกลับมาใช้ใหม่โค้ดของคุณข้ามสคริปต์หลายตัว แทนที่จะคัดลอกตรรกะเดียวกันไปยังหลายที่ คุณสามารถเขียนโค้ดครั้งเดียวในโมดูลสคริปต์และเรียกใช้จากทุกที่ที่ต้องการ
เมื่อคุณจัดเก็บตรรกะกระดานผู้นำของคุณในโมดูล ไคลเอนต์แฮนด์เลอร์และสคริปต์เซิร์ฟเวอร์ต่าง ๆ สามารถใช้ฟังก์ชันเดียวกันเพื่อดึงคะแนนผู้เล่นสูงสุด หากคุณต้องการอัปเดตว่า ดึงชื่อผู้ใช้หรือจัดเรียงคะแนนอย่างไร คุณเพียงแค่ต้องเปลี่ยนโค้ดในที่เดียว หลังจากที่คุณปรับปรุงโมดูล สคริปต์อื่น ๆ ที่ใช้มันก็จะได้พฤติกรรมแบบอัปเดตโดยอัตโนมัติ
กระดานผู้นำที่กำหนดเองของคุณใช้วิธี Data Store ที่เรียงลำดับดังต่อไปนี้ในการแชร์ข้อมูลระหว่างเซิร์ฟเวอร์ต่าง ๆ:
- SetAsync (จากสคริปต์ GoldManager) เพื่อส่งคะแนนผู้เล่นไปยัง Data Store ที่เรียงลำดับ GlobalLeaderboard
- GetSortedAsync (ในโมดูลสคริปต์) เพื่อดึงคะแนนสูงสุดจากเซิร์ฟเวอร์ทั้งหมดจาก Data Store เดียวกัน วิธี GetSortedAsync เป็นเอกลักษณ์ของ Data Store ที่เรียงลำดับและสามารถดึงคีย์ที่เรียงลำดับหลายตัวตามลำดับการจัดเรียงเฉพาะ ขนาดหน้า และค่าต่ำสุดและสูงสุด
ในการดึงคะแนนจากกระดานผู้นำ:
ภายใต้ ServerScriptService ให้สร้าง ModuleScript ใหม่ชื่อ LeaderboardManager.
ที่ด้านบนของโมดูลสคริปต์ เรียกใช้ GetOrderedDataStore ด้วยสตริง "GlobalLeaderboard" การอ้างอิง Data Store ที่เรียงลำดับเดียวกันที่คุณสร้างในสคริปต์ GoldManager จะช่วยให้ UI ของกระดานผู้นำดึงและจัดเรียงคะแนนผู้เล่นสูงสุดได้ในภายหลัง
local DataStoreService = game:GetService("DataStoreService")local Players = game:GetService("Players")local leaderboardStore = DataStoreService:GetOrderedDataStore("GlobalLeaderboard")เตรียมตารางโมดูลเพื่อเก็บฟังก์ชันและข้อมูลทั้งหมดที่คุณต้องการเปิดเผยให้กับสคริปต์อื่น
local leaderboardManager = {}สร้างฟังก์ชันที่เรียกว่า GetTopScores เพื่อดึงคะแนนผู้เล่นสูงสุด ฟังก์ชันนี้จะ:
- เรียกใช้ GetSortedAsync เพื่อดึงคะแนนสูงสุดจำนวน limit ในลำดับลดลง หากการเรียกไม่สำเร็จ จะส่งกลับการแจ้งเตือนว่างเพื่อป้องกันไม่ให้โค้ดของคุณล้มเหลว
- วนรอบผ่านกระดานผู้นำเพื่อให้ได้ตารางของรายชื่อด้วย GetCurrentPage และชื่อผู้เล่นด้วย GetNameFromUserIdAsync
- เพิ่มผลลัพธ์แต่ละรายการลงในรายการสุดท้ายและสร้างตารางกระดานผู้นำที่มีชื่อผู้เล่นและคะแนนของพวกเขา
- ส่งกลับรายการสุดท้ายของผู้เล่นและส่งข้อมูลกระดานผู้นำกลับไปยังสคริปต์ใด ๆ ที่เรียกฟังก์ชัน leaderboardManager.GetTopScores
function leaderboardManager.GetTopScores(limit)local success, pages = pcall(function()return leaderboardStore:GetSortedAsync(false, limit)end)if not success or not pages thenreturn {}endlocal results = {}for _, entry in ipairs(pages:GetCurrentPage()) dolocal userId = tonumber(entry.key)local score = entry.valuelocal username = "Unknown"local ok, name = pcall(function()return Players:GetNameFromUserIdAsync(userId)end)if ok thenusername = nameendtable.insert(results, {Username = username,Score = score})endreturn resultsendทำให้โมดูลใช้งานได้โดยการส่งคืนตารางโมดูลที่คุณสร้างขึ้นก่อนหน้านี้ เมื่อตั้งค่าโมดูลสคริปต์ คุณต้องส่งคืนตารางโมดูลเพื่อให้สคริปต์อื่นสามารถเข้าถึงมันและเรียกฟังก์ชันภายใน
return leaderboardManager
ขอข้อมูลกระดานผู้นำจากเซิร์ฟเวอร์
เพื่อให้ UI ของไคลเอนต์แสดงคะแนนจากกระดานผู้นำ เซิร์ฟเวอร์ต้องตอบสนองเมื่อไคลเอนต์ขอข้อมูล RemoteFunction ช่วยให้ไคลเอนต์สามารถร้องขอข้อมูลจากเซิร์ฟเวอร์และรอคำตอบได้
ร้องขอข้อมูลจากกระดานผู้นำจากเซิร์ฟเวอร์:
- ภายใต้ ReplicatedStorage ใส่ RemoteFunction ที่เรียกว่า LeaderboardRemote ฟังก์ชันระยะไกลนี้ทำหน้าที่เป็นสะพานเชื่อมระหว่างสคริปต์ UI บนไคลเอนต์และตรรกะกระดานผู้นำบนเซิร์ฟเวอร์
- ภายใต้ ServerScriptService ให้สร้างสคริปต์ชื่อ LeaderboardRemoteHandler ในสคริปต์นี้:
เรียกใช้ ReplicatedStorage (พื้นที่แชร์ระหว่างไคลเอนต์และเซิร์ฟเวอร์), ServerScriptService (ซึ่งถือโมดูลกระดานผู้นำ), และ leaderboardRemote (ฟังก์ชันระยะไกลที่ไคลเอนต์จะเรียกเพื่อขอข้อมูลกระดานผู้นำ)
local ReplicatedStorage = game:GetService("ReplicatedStorage")local ServerScriptService = game:GetService("ServerScriptService")local leaderboardRemote = ReplicatedStorage:WaitForChild("LeaderboardRemote")โหลดโมดูล LeaderboardManager ที่คุณสร้างขึ้นก่อนหน้านี้ ซึ่งรวมถึงฟังก์ชันที่ดึงคะแนนสูงสุดจาก Data Store ที่เรียงลำดับ
local leaderboardManager = require(ServerScriptService:WaitForChild("LeaderboardManager"))ตั้งค่าพฤติกรรมสำหรับเมื่อไคลเอนต์เรียกใช้ InvokeServer. เซิร์ฟเวอร์ตอบสนองโดยการดึงคะแนนสูงสุด 3 คะแนนและส่งผลลัพธ์กลับไปยังไคลเอนต์
leaderboardRemote.OnServerInvoke = function(player)return leaderboardManager.GetTopScores(3)end
แสดงข้อมูลใน UI กระดานผู้นำแบบกำหนดเอง
หลังจากตั้งค่าสคริปต์ด้านเซิร์ฟเวอร์แล้ว ให้สร้างสคริปต์ท้องถิ่นเพื่อดึง 3 อันดับแรกทุก 3 วินาทีและแสดงผลลัพธ์ใน UI กระดานผู้นำทั่วโลกภายในเกม
ในการแสดงข้อมูลในกระดานผู้นำแบบกำหนดเองของคุณ:
ภายใต้ StarterGui ⟩ LeaderboardGui สร้างสคริปต์ท้องถิ่นชื่อ LeaderboardGuiScript.
ที่ด้านบนของสคริปต์ เชื่อมต่อกับฟังก์ชันระยะไกล เรียกใช้ ReplicatedStorage เพื่อเข้าถึงวัตถุที่แชร์ระหว่างเซิร์ฟเวอร์และไคลเอนต์ จากนั้นเรียกใช้ leaderboardRemote เพื่อให้ไคลเอนต์สามารถร้องขอข้อมูลกระดานผู้นำจากเซิร์ฟเวอร์ได้
local ReplicatedStorage = game:GetService("ReplicatedStorage")local leaderboardRemote = ReplicatedStorage:WaitForChild("LeaderboardRemote")อ้างอิง UI สิ่งของกระดานผู้นำที่มีอยู่ภายใต้ LeaderboardGui.
local gui = script.Parentlocal leaderboardFrame = gui:WaitForChild("LeaderboardFrame")local entriesFrame = leaderboardFrame:WaitForChild("EntriesFrame")local template = entriesFrame:WaitForChild("LeaderboardEntry")สร้างฟังก์ชันที่เรียกว่า clearEntries เพื่อล้างรายการกระดานผู้นำเก่า ฟังก์ชันนี้วนรอบผ่านเด็ก ๆ ทั้งหมดของ entriesFrame ซึ่งมีแถวกระดานผู้นำ และให้แน่ใจว่ากระดานผู้นำจะถูกอัปเดตเต็มที่ก่อนแสดงข้อมูลใหม่
local function clearEntries()for _, child in ipairs(entriesFrame:GetChildren()) doif child:IsA("TextLabel") and child.Name:match("^Row%d+$") thenchild:Destroy()endendendสร้างฟังก์ชันที่เรียกว่า renderLeaderboard เพื่อแทรกและแสดงข้อมูลผู้เล่นในแถวกระดานผู้นำ อ็อบเจกต์ data คือตารางที่ส่งคืนโดยเซิร์ฟเวอร์ซึ่งมีรายการที่มีชื่อผู้เล่นและคะแนน
local function renderLeaderboard(data)clearEntries()for i, entry in ipairs(data) dolocal row = template:Clone()row.Name = "Row" .. irow.Visible = truerow.LayoutOrder = irow.Text = string.format("%d%s place: %s - %d",i, i == 1 and "st" or i == 2 and "nd" or i == 3 and "rd" or "th",entry.Username, entry.Score)row.Parent = entriesFrameendendสร้างลูปเพื่อดึงข้อมูลของกระดานผู้นำเป็นระยะ ๆ ทุก 3 วินาที ลูปทำงานและเรียกเซิร์ฟเวอร์โดยใช้ฟังก์ชัน InvokeServer ที่คุณสร้างขึ้นก่อนหน้านี้ในสคริปต์ LeaderboardRemoteHandler หากการเรียกล้มเหลว UI จะถูกรีเฟรชด้วยคะแนนที่อัปเดต
while true dolocal success, data = pcall(function()return leaderboardRemote:InvokeServer()end)if success and data thenrenderLeaderboard(data)endtask.wait(3)end
โค้ดสุดท้าย
ดูส่วนโค้ดด้านล่างสำหรับ GoldManager, LeaderboardManager, LeaderboardRemoteHandler, และ LeaderboardGuiScript สคริปต์ทั้งหมด คุณสามารถวางและรันพวกมันในไฟล์ Gold Rush create leaderboard tutorial - Start .rbxl ใน Studio ได้อย่างตรงไปตรงมา
GoldManager
สคริปต์ GoldManager สร้าง Data Store ที่เรียงลำดับเพื่อจัดการการอัปเดตกระดานผู้นำ
-- ดึงบริการต่าง ๆ
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local DataStoreService = game:GetService("DataStoreService")
-- อีเวนต์ระยะไกลเพื่อติดตาม UI
local uiEvent = ReplicatedStorage:WaitForChild("UIEvent")
-- Data Store สำหรับบันทึกทองคำที่เป็นก้อนของผู้เล่น
local goldStore = DataStoreService:GetDataStore("PlayerGold")
-- Data Store ที่เรียงลำดับเพื่อบันทึกทองคำไปยังกระดานผู้นำ
local leaderboardStore = DataStoreService:GetOrderedDataStore("GlobalLeaderboard")
-- สร้างตัวสร้างหมายเลขสุ่มสำหรับการจัดตำแหน่งทองคำ
local random = Random.new()
-- ตารางเพื่อเก็บทองคำของผู้เล่นในเซสชันเดียว
local playerGold = {}
-- ค่าคงที่
local GOLD_VALUE = 10 -- จำนวนทองคำที่ก้อนทองคำแต่ละก้อนมีค่า
local GOLD_REGENERATION_BOUNDS = { -- ขอบเขตพื้นที่ที่ใช้ในการจัดตำแหน่งทองคำให้สุ่ม
minX = -72,
maxX = 72,
minZ = -72,
maxZ = 72
}
local GOLD_REGEN_DELAY = 2 -- ความล่าช้าก่อนที่จะแสดงทองคำใหม่ (ในวินาที)
local AUTOSAVE_INTERVAL = 30 -- ความถี่ที่ทองคำของผู้เล่นจะถูกบันทึก (ในวินาที)
-- ฟังก์ชันเพื่อจัดการการเก็บทองคำของผู้เล่น
local function processGoldTouch(chunk, player)
-- ซ่อนก้อนทองเมื่อผู้เล่นเก็บมันไป
chunk.Parent = nil
-- เพิ่มก้อนทองเข้ากับคะแนนทองคำของผู้เล่นในเซสชัน
local userId = player.UserId
playerGold[userId] = (playerGold[userId] or 0) + GOLD_VALUE
print(player.Name, "มีทองคำ", playerGold[userId], "ก้อนแล้ว")
-- อัปเดต UI แถบคะแนนเพื่อสะท้อนคะแนนทองคำใหม่ในเซสชันนี้
uiEvent:FireClient(player, {
gold = playerGold[userId],
doTween = true,
showAlert = false
})
-- รอสักครู่แล้วจึงแสดงก้อนทองที่ถูกเก็บในตำแหน่งสุ่มใหม่
task.delay(GOLD_REGEN_DELAY, function()
-- นำก้อนทองไปยังตำแหน่งสุ่มใหม่
local nextPositionX = random:NextInteger(GOLD_REGENERATION_BOUNDS.minX, GOLD_REGENERATION_BOUNDS.maxX)
local nextPositionZ = random:NextInteger(GOLD_REGENERATION_BOUNDS.minZ, GOLD_REGENERATION_BOUNDS.maxZ)
chunk.CFrame = CFrame.new(nextPositionX, 50, nextPositionZ) -- ย้ายก้อนทองไปยังตำแหน่งใหม่
chunk:SetAttribute("DropCollided", false) -- รีเซ็ตธงข้อขัดข้อง
chunk.Parent = workspace.GoldChunks
end)
end
-- วนรอบผ่านทุกส่วนที่ติดแท็กว่า "Gold" และเชื่อมต่อเข้ากับการตรวจจับการสัมผัส
for _, chunk in ipairs(CollectionService:GetTagged("Gold")) do
chunk.Touched:Connect(function(otherPart)
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
if player then
processGoldTouch(chunk, player)
end
end)
end
-- ฟังก์ชันเพื่อบันทึกทองคำของผู้เล่นลงใน Data Store ทั้งแบบมาตรฐานและแบบเรียงลำดับ
local function saveGold(player, value)
local userId = player.UserId
local success, err = pcall(function()
goldStore:SetAsync(userId, value)
leaderboardStore:SetAsync(tostring(userId), value)
end)
if not success then
warn("ไม่สามารถบันทึกทองคำสำหรับ", player.Name, ":", err)
end
end
-- ฟังก์ชันเพื่อจัดการผู้เล่นที่เข้าร่วมเกม
local function onPlayerAdded(player)
local userId = player.UserId
print(player.Name, "เข้าร่วมเกมแล้ว")
-- พยายามโหลดทองคำของผู้เล่นจาก Data Store
local success, storedGold = pcall(function()
return goldStore:GetAsync(userId)
end)
-- ตั้งค่าคะแนนทองคำในเซสชันปัจจุบันโดยใช้ค่าจาก Data Store สำหรับผู้เล่น
local currentGold = if success and storedGold then storedGold else 0
playerGold[userId] = currentGold
-- อัปเดต UI ด้วยค่าจาก Data Store สำหรับผู้เล่น
uiEvent:FireClient(player, {
gold = currentGold,
doTween = false,
showAlert = not success
})
if success then
print("โหลด", currentGold, "ทองคำ สำหรับ", player.Name)
else
-- แจ้งผู้เล่นว่าทองคำของพวกเขาไม่สามารถโหลดได้
uiEvent:FireClient(player, { showAlert = true })
warn("ไม่สามารถโหลดทองคำสำหรับ", player.Name)
end
-- เริ่มการอัปเดตอัตโนมัติเพื่อลงบันทึกทองคำของผู้เล่นทุก 30 วินาที
coroutine.wrap(function()
while player.Parent do
task.wait(AUTOSAVE_INTERVAL)
if playerGold[userId] then
saveGold(player, playerGold[userId])
print("บันทึกทองคำ", playerGold[userId], "สำหรับ", player.Name)
end
end
end)()
end
-- ฟังก์ชันเพื่อจัดการผู้เล่นที่ออกจากเกม
local function onPlayerRemoving(player)
local userId = player.UserId
print(player.Name, "ออกจากเกม")
-- ตรวจสอบว่าทองคำของผู้เล่นได้รับการติดตามไหม
if playerGold[userId] then
-- บันทึกทองคำของผู้เล่นลงใน Data Store ก่อนที่เขาจะออก
saveGold(player, playerGold[userId])
end
end
-- เชื่อมต่อเหตุการณ์ผู้เล่นที่เข้าร่วมและออกจากเกม
Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)
LeaderboardManager
โมดูลสคริปต์ LeaderboardManager:
- เรียก GetSortedAsync() บน Data Store ที่เรียงลำดับ GlobalLeaderboard
- แปลง userIds เป็นชื่อผู้ใช้โดยใช้ GetNameFromUserIdAsync.
- ส่งคืนรายการของ { Username, Score } ตารางสำหรับผู้เล่นที่ถูกจัดอันดับสูงสุด
- ถูกเรียกโดย LeaderboardRemoteHandler เมื่อใดก็ตามที่ไคลเอนต์ร้องขอข้อมูลกระดานผู้นำ
-- ดึงบริการต่าง ๆ
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
-- Data Store ที่เรียงลำดับสำหรับบันทึกคะแนนกระดานผู้นำ
local leaderboardStore = DataStoreService:GetOrderedDataStore("GlobalLeaderboard")
-- ตารางสำหรับจัดเก็บคะแนนกระดานผู้นำ
local leaderboardManager = {}
-- ฟังก์ชันเพื่อส่งคืนคะแนนสูงสุด
function leaderboardManager.GetTopScores(limit)
-- พยายามดึงรายการกระดานผู้นำที่เรียงลำดับจาก Data Store
local success, pages = pcall(function()
-- false = ลดลง (คะแนนสูงสุดมาก่อน)
return leaderboardStore:GetSortedAsync(false, limit)
end)
-- หากการเรียกล้มเหลวหรือไม่ส่งคืนอะไรเลย ให้บันทึกข้อควรระวังและส่งกลับตารางเปล่า
if not success or not pages then
warn("ไม่สามารถดึงข้อมูลกระดานผู้นำได้")
return {}
end
-- สร้างตารางสำหรับเก็บข้อมูลผู้เล่นระดับสูง
local topPlayers = {}
-- วนลูปผ่านแต่ละรายการในหน้าผลลัพธ์กระดานผู้นำ
for _, entry in ipairs(pages:GetCurrentPage()) do
local userId = tonumber(entry.key) -- แปลงกุญแจของรายการเป็นหมายเลข (userId ถูกจัดเก็บเป็นสตริง)
local score = entry.value -- ค่าเป็นคะแนนของผู้เล่น (จำนวนทองคำ)
local username = "Unknown" -- ชื่อเริ่มต้นในกรณีที่การค้นหาล้มเหลว
-- พยายามที่จะดึงชื่อผู้เล่นจาก userId ของพวกเขา
local ok, name = pcall(function()
return Players:GetNameFromUserIdAsync(userId)
end)
-- หากการค้นหาประสบความสำเร็จ ให้เก็บชื่อผู้ใช้จริง
if ok then
username = name
end
-- เพิ่มผู้เล่นนี้และคะแนนของเขาไปยังรายการ
table.insert(topPlayers, {
Username = username,
Score = score
})
end
-- ส่งคืนรายการผู้เล่นชั้นนำที่มีชื่อผู้ใช้และคะแนน
return topPlayers
end
-- ส่งคืนโมดูล LeaderboardManager เพื่อให้สคริปต์อื่นสามารถใช้งานได้
return leaderboardManager
LeaderboardRemoteHandler
สคริปต์ LeaderboardRemoteHandler ดึงและส่งคืนคะแนนสูงสุด 3 คะแนนไปยังไคลเอนต์ที่เรียก
-- ดึงบริการต่าง ๆ
local ServerScriptService = game:GetService("ServerScriptService") -- เข้าถึงโมดูลด้านเซิร์ฟเวอร์
local ReplicatedStorage = game:GetService("ReplicatedStorage") -- วัตถุที่ใช้ในการสื่อสารระหว่างไคลเอนต์กับเซิร์ฟเวอร์
-- รอให้ RemoteFunction ที่ไคลเอนต์ใช้ร้องขอข้อมูลกระดานผู้นำ
local leaderboardRemote = ReplicatedStorage:WaitForChild("LeaderboardRemote")
-- โหลดโมดูล LeaderboardManager ที่มีฟังก์ชัน GetTopScores
local leaderboardManager = require(ServerScriptService:WaitForChild("LeaderboardManager"))
-- ตั้งค่าการจัดการเมื่อไคลเอนต์เรียกใช้ฟังก์ชัน RemoteFunction ของกระดานผู้นำ
leaderboardRemote.OnServerInvoke = function(player)
-- เรียกใช้โมดูลกระดานผู้นำเพื่อดึงคะแนนสูงสุด 3 คะแนนและส่งกลับไปยังไคลเอนต์
return leaderboardManager.GetTopScores(3)
end
LeaderboardGuiScript
สคริปต์ท้องถิ่น LeaderboardGuiScript:
- ร้องขอข้อมูลกระดานผู้นำจากเซิร์ฟเวอร์ทุก 3 วินาทีโดยใช้ Class.RemoteHandler.InvokeServer|InvokeServer.
- ใช้เทมเพลต LeaderboardEntry ที่ซ่อนเพื่อแสดงแต่ละแถวของกระดานผู้นำ
- จัดรูปแถวแต่ละแถวในรูปแบบ "1st place: Username - Score".
- จัดการการสร้าง การแสดง และการจัดเลย์เอาต์ของแถวกระดานผู้นำโดยใช้ UIListLayout.
-- ดึงการจัดเก็บข้อมูลสำหรับการเข้าถึง RemoteFunction
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- ดึง RemoteFunction ที่ใช้ร้องขอข้อมูลกระดานผู้นำจากเซิร์ฟเวอร์
local leaderboardRemote = ReplicatedStorage:WaitForChild("LeaderboardRemote")
-- การอ้างอิง UI
local gui = script.Parent -- สคริปต์ท้องถิ่นภายใต้ ScreenGui
local leaderboardFrame = gui:WaitForChild("LeaderboardFrame") -- ตัวเก็บข้อมูลหลักสำหรับกระดานผู้นำ
local entriesFrame = leaderboardFrame:WaitForChild("EntriesFrame") -- เฟรมที่รายการคะแนนกระดานผู้นำปรากฏ
local template = entriesFrame:WaitForChild("LeaderboardEntry") -- TextLabel ที่เป็นเทมเพลตซ่อนที่ใช้สร้างแถว
-- ฟังก์ชันเพื่อลบแถวกระดานผู้นำเก่า (แต่ไม่ใช่เทมเพลต)
local function clearEntries()
for _, child in ipairs(entriesFrame:GetChildren()) do
-- ทำลายเฉพาะเลเบลที่ชื่อว่า "Row1", "Row2" เป็นต้น (เว้นแต่เทมเพลตเอาไว้)
if child:IsA("TextLabel") and child.Name:match("^Row%d+$") then
child:Destroy()
end
end
end
-- ฟังก์ชันเพื่อแสดงข้อมูลกระดานผู้นำบนจอ
local function renderLeaderboard(data)
-- ลบแถวเก่าก่อน
clearEntries()
for i, entry in ipairs(data) do
local row = template:Clone() -- โคลนเทมเพลตที่ซ่อนอยู่
row.Name = "Row" .. i -- ตั้งชื่อให้มีลักษณะเฉพาะ
row.Visible = true -- ทำให้มันแสดง
row.LayoutOrder = i -- ปล่อยให้ UIListLayout จัดลำดับมันได้อย่างถูกต้อง
-- รูปแบบกระดานผู้นำ: "1st place: Username - 123"
row.Text = string.format("%d%s place: %s - %d",
i,
i == 1 and "st" or i == 2 and "nd" or i == 3 and "rd" or "th",
entry.Username,
entry.Score
)
-- เพิ่มข้อมูลลงใน UI
row.Parent = entriesFrame
end
end
-- ลูปหลัก: อัปเดตกระดานผู้นำทุก 3 วินาที
while true do
-- ถามเซิร์ฟเวอร์เกี่ยวกับข้อมูลของกระดานผู้นำ
local success, data = pcall(function()
return leaderboardRemote:InvokeServer()
end)
if success and data then
-- แสดงผลลัพธ์บนกระดานผู้นำ
renderLeaderboard(data)
else
warn("ไม่สามารถดึงข้อมูลกระดานผู้นำได้")
end
-- รอ 3 วินาทีแล้วค่อยอัปเดตอีกครั้ง
task.wait(3)
end