# ลีดเดอร์บอร์ดสำหรับเกม PlayDrop

ประกาศลีดเดอร์บอร์ดใน catalogue.json ส่งคะแนนด้วย sdk.leaderboards และแสดงอันดับสูงสุดกับผู้เล่นรอบข้าง พร้อมชนิดคะแนน ขีดจำกัด และกฎการอัปเดต

Source: https://www.playdrop.ai/th/create/learn/leaderboards

ลีดเดอร์บอร์ดให้ผู้เล่นมีเหตุผลที่จะเล่นซ้ำและมีอันดับไว้แชร์ PlayDrop เก็บคะแนนที่ดีที่สุดของผู้เล่นแต่ละคนในแต่ละลีดเดอร์บอร์ดและแสดงไว้ในเกม

## ประกาศลีดเดอร์บอร์ด

เพิ่มลงในแอปใน [catalogue.json](https://www.playdrop.ai/th/create/learn/catalogue-json):

```json
{
  "leaderboards": [
    { "key": "high-score", "displayName": "High score", "description": "Most points in one run",
      "scoreType": "INTEGER", "sort": "DESC", "unitLabel": "pts" },
    { "key": "best-time", "displayName": "Fastest run", "description": "Time to reach the flag",
      "scoreType": "TIME_MS", "sort": "ASC" }
  ]
}
```

- `key`: ยาว 3 ถึง 64 ตัวอักษร ขึ้นต้นด้วยตัวอักษรพิมพ์เล็ก ตามด้วยตัวอักษรพิมพ์เล็ก ตัวเลข `_` `.` หรือ `-`
- `scoreType` และ `sort` มาเป็นคู่ได้สองแบบ: `INTEGER` คู่กับ `DESC` (ค่าสูงกว่าชนะ คะแนนตั้งแต่ 0 ขึ้นไป) หรือ `TIME_MS` คู่กับ `ASC` (ค่าต่ำกว่าชนะ เป็นมิลลิวินาทีที่เป็นบวก)
- `unitLabel` เป็นข้อความแสดงผลที่ไม่บังคับ

เมื่อเผยแพร่แล้ว คีย์จะลบไม่ได้ และเปลี่ยน `scoreType` กับ `sort` ไม่ได้ เลิกใช้ลีดเดอร์บอร์ดด้วย `"status": "RETIRED"` ลีดเดอร์บอร์ดต้องใช้[แพ็กเกจ](https://www.playdrop.ai/th/create/learn/packaging)

## ส่งและอ่านคะแนน

```js
const result = await sdk.leaderboards.submitScore("high-score", 1200);
// { accepted, improved, previousBestScore, bestScore, rank, previousRank, bestScoreAt, leaderboard }
if (result.improved) showNewBest(result.bestScore, result.rank);

const { leaderboard } = await sdk.leaderboards.get("high-score", { top: 10, aroundMe: 3 });
// leaderboard: { definition, top, player, playerEntry, aroundPlayer }

const { leaderboards } = await sdk.leaderboards.list();
```

- คะแนนเป็นจำนวนเต็มในช่วงที่ JavaScript แทนค่าได้แม่นยำ (safe integer) เฉพาะคะแนนที่ดีกว่าเท่านั้นที่จะแทนที่สถิติเดิม
- `top` รับ 1 ถึง 100 รายการ และ `aroundMe` รับ 1 ถึง 20 รายการในแต่ละฝั่งของผู้เล่น
- `list({ includeRetired: true })` ส่งคืนลีดเดอร์บอร์ดที่เลิกใช้แล้วด้วย

ส่งคะแนนตอนจบรอบ ไม่ใช่ทุกเฟรม และส่งเฉพาะในช่วง `play` จัดการการเรียกที่ถูกปฏิเสธเหมือนการเรียกผ่านเครือข่ายทั่วไป และให้เกมยังเล่นต่อได้

## ผู้เยี่ยมชมและออฟไลน์

ส่งคะแนนได้โดยไม่ต้องตรวจสอบการเข้าสู่ระบบ หากไม่มีเซสชันผู้เล่นเลย การส่งจะเสร็จสิ้นโดยไม่ได้บันทึกไว้ โฮสต์ที่ประกาศว่ารองรับข้อมูลบนอุปกรณ์ เช่น แอป PlayDrop ที่เล่นออฟไลน์ได้ จะเก็บคะแนนที่ทำขณะออฟไลน์ไว้และซิงค์ภายหลัง การอ่านแบบออฟไลน์ในแอปเหล่านี้จะแสดงเฉพาะสถิติที่ดีที่สุดของผู้เล่นเองโดยไม่มีอันดับ ในที่อื่น การส่งคะแนนต้องใช้การเชื่อมต่อ

## สิ่งที่ลีดเดอร์บอร์ดไม่ได้ทำ

SDK ไม่มีภูมิภาค การรีเซ็ตตามกำหนดเวลา ฤดูกาล หรือรางวัลรายสัปดาห์อัตโนมัติ หากต้องการลีดเดอร์บอร์ดรายสัปดาห์ ให้ออกแบบเรื่องสัปดาห์เอง เช่น ใช้คีย์ใหม่ต่อฤดูกาลที่ประกาศในเวอร์ชันใหม่

ที่เกี่ยวข้อง: [ความสำเร็จ](https://www.playdrop.ai/th/create/learn/achievements) [การบันทึกบนคลาวด์](https://www.playdrop.ai/th/create/learn/cloud-saves) [การแชร์คะแนน](https://www.playdrop.ai/th/create/learn/social)

## คู่มือที่เกี่ยวข้อง

- [ความสำเร็จ](https://www.playdrop.ai/th/create/learn/achievements): ประกาศความสำเร็จแบบมาตรฐานและแบบสะสมพร้อมไอคอนใน catalogue.json แล้วปลดล็อกและรายงานความคืบหน้าด้วย sdk.achievements
- [การบันทึกบนคลาวด์](https://www.playdrop.ai/th/create/learn/cloud-saves): บันทึกและโหลดความคืบหน้าของผู้เล่นด้วย sdk.me.appData และ updateAppData สำหรับผู้เยี่ยมชมและผู้เล่นที่เข้าสู่ระบบ พร้อมกฎการเขียน การแสดงตัวอย่าง และการเล่นออฟไลน์
- [catalogue.json](https://www.playdrop.ai/th/create/learn/catalogue-json): ฟิลด์ catalogue.json ที่เกม PlayDrop ใช้: ตัวตน หน้าเกม โหมดการเล่น หน้าจอ การเข้าสู่ระบบ Instant การโหลดล่วงหน้า สื่อ คำแปล คะแนน และเซิร์ฟเวอร์
