순위표는 모든 게임에 소셜 및 경쟁 요소를 추가할 수 있는 좋은 방법입니다. 이는 플레이어 간의 경쟁을 유도하는 재미있는 방법입니다. 서버는 각각 별도의 레코드를 추적하는 순위표로 각 순위표를 무제한으로 지원합니다.
서버에는 점수 값이 게임에서 무엇을 나타내야 하는지에 대한 특별한 요구 사항이 없습니다. 순위표는 값으로 정렬된 순서로 생성됩니다. 레코드에 랩 타임이나 통화를 사용하는 경우 원하는 대로 ASC 또는 DESC 모드에서 결과를 정렬할 수 있습니다. 생성 시 점수가 순위표에 제출되는 방식을 제어하는 연산자(“best”, “set”, “incr” 또는 “decr”)도 지정해야 합니다.
순위표를 사용하여 원하는 점수를 추적할 수 있습니다. 몇 가지 좋은 예로 가장 높은 점수, 가장 긴 생존 시간, 가장 빠른 랩 타임, 가장 빠른 레벨 완료 및 경쟁할 수 있는 모든 것을 들 수 있습니다!
순위표는 과거에 Google Play 게임 또는 Apple Game Center를 사용한 적이 있는 경우와 같이 미리 구성할 필요가 없기 때문에 서버에서 동적입니다. 순위표는 서버 측 코드를 통해 생성할 수 있습니다.
각 순위표에 선택적 재설정 일정을 할당할 수 있습니다. 순위표에 포함된 레코드는 이 일정에 따라 만료되며 사용자는 각 재설정 주기에 대해 새 점수를 제출할 수 있습니다. 각 재설정 기간이 만료되면 서버는 현재 순위표 상태로 콜백을 트리거합니다. 순위표 모범 사례를 읽고 용례는 티어 리그 가이드를 참조하세요.
재설정 일정은 순위표 생성 시 CRON 형식으로 정의됩니다. 순위표에 재설정 일정이 설정되지 않은 경우 해당 레코드는 만료되지 않습니다.
모든 레코드는 소유자에게 속합니다. 소유자는 일반적으로 사용자지만 그룹 ID 또는 일부 다른 사용자 지정 ID와 같은 다른 개체를 사용할 수 있습니다. 각 소유자는 순위표 당 하나의 레코드만 갖습니다. 순위표 만료 시 각 소유자는 이월되는 새 점수를 제출할 수 있습니다.
각 레코드의 점수는 소유자가 진행함에 따라 업데이트될 수 있습니다. 점수는 원하는 만큼 자주 업데이트할 수 있으며 순위표 정렬 순서와 연산자의 조합에 따라 증가 또는 감소할 수 있습니다.
varleaderboardId="level1";varsubmission={score:100};varrecord=awaitclient.writeLeaderboardRecord(session,leaderboardId,submission);console.log("New record username %o and score %o",record.username,record.score);
Client
1
2
3
4
conststringleaderboardId="level1";constlongscore=100L;varr=awaitclient.WriteLeaderboardRecordAsync(session,leaderboardId,score);System.Console.WriteLine("New record for '{0}' score '{1}'",r.Username,r.Score);
Client
1
2
3
4
5
6
7
8
9
autosuccessCallback=[](constNLeaderboardRecord&record){std::cout<<"New record with score "<<record.score<<std::endl;};stringleaderboardId="level1";int64_tscore=100;client->writeLeaderboardRecord(session,leaderboardId,score,opt::nullopt,opt::nullopt,successCallback);
Client
1
2
3
4
finalStringleaderboard="level1";longscore=100L;LeaderboardRecordr=client.writeLeaderboardRecord(session,leaderboard,score);System.out.format("New record for %s score %s",r.getUsername(),r.getScore());
Client
1
2
3
4
5
6
7
varleaderboard_id="level1"varscore=100varrecord:NakamaAPI.ApiLeaderboardRecord=yield(client.write_leaderboard_record_async(session,leaderboard_id,score),"completed")ifrecord.is_exception():print("An error occurred: %s"%record)returnprint("New record username %s and score %s"%[record.username,record.score])
사용자는 점수를 순위표에 제출하고 언제든지 업데이트할 수 있습니다. 점수가 제출되면 순위표의 사전 구성된 정렬 순서 및 연산자에 의해 작업에 대한 영향이 결정됩니다.
“set” 연산자를 사용하면 값이 이전 값보다 나빠도 순위표 레코드에서 항상 최신 값이 유지됩니다.
“best” 연산자를 사용하여 순위표를 제출하면 레코드가 해당 레코드에 대해 확인된 최고 값을 추적합니다. 내림차순 순위표의 경우 이는 가장 높은 값을 의미하고 오름차순 순위표의 경우 가장 낮은 값을 의미합니다. 레코드에 대한 이전 값이 없으면 “set"와 동일하게 작동합니다.
“incr” 연산자를 사용하면 해당 레코드에 대한 기존 점수에 새 값이 추가됩니다. 레코드에 대한 이전 값이 없으면 “set"와 동일하게 작동합니다.
varleaderboardId="level1";varsubmission={score:100};varrecord=awaitclient.writeLeaderboardRecord(session,leaderboardId,submission);console.log("New record username %o and score %o",record.username,record.score);
Client
1
2
3
4
conststringleaderboard="level1";constlongscore=100L;varr=awaitclient.WriteLeaderboardRecordAsync(session,leaderboard,score);System.Console.WriteLine("New record for '{0}' score '{1}'",r.Username,r.Score);
Client
1
2
3
4
5
6
7
8
9
autosuccessCallback=[](constNLeaderboardRecord&record){std::cout<<"New record with score "<<record.score<<std::endl;};stringleaderboardId="level1";int64_tscore=100;client->writeLeaderboardRecord(session,leaderboardId,score,opt::nullopt,opt::nullopt,successCallback);
Client
1
2
3
4
finalStringleaderboard="level1";longscore=100L;LeaderboardRecordr=client.writeLeaderboardRecord(session,leaderboard,score);System.out.format("New record for %s score %d",r.getUsername(),r.getScore());
Client
1
2
3
4
5
6
7
varleaderboard_id="level1"varscore=100varrecord:NakamaAPI.ApiLeaderboardRecord=yield(client.write_leaderboard_record_async(session,leaderboard_id,score),"completed")ifrecord.is_exception():print("An error occurred: %s"%record)returnprint("New record username %s and score %s"%[record.username,record.score])
curl -X GET "http://127.0.0.1:7350/v2/leaderboard/<leaderboardId>"\
-H 'Authorization: Bearer <session token>'
Client
1
2
3
4
5
varleaderboardId="level1";varresult=awaitclient.listLeaderboardRecords(session,leaderboardId);result.records.forEach(function(record){console.log("Record username %o and score %o",record.username,record.score);});
Client
1
2
3
4
5
6
conststringleaderboardId="level1";varresult=awaitclient.ListLeaderboardRecordsAsync(session,leaderboardId);foreach(varrinresult.Records){System.Console.WriteLine("Record for '{0}' score '{1}'",r.Username,r.Score);}
Client
1
2
3
4
5
6
7
8
9
10
11
autosuccessCallback=[](NLeaderboardRecordListPtrrecordsList){for(auto&record:recordsList->records){std::cout<<"Record username "<<record.username<<" and score "<<record.score<<std::endl;}};stringleaderboardId="level1";client->listLeaderboardRecords(session,leaderboardId,{},opt::nullopt,opt::nullopt,successCallback);
Client
1
2
3
4
5
finalStringleaderboard="level1";LeaderboardRecordListrecords=client.listLeaderboardRecords(session,leaderboard);for(LeaderboardRecordrecord:records.getRecordsList()){System.out.format("Record for %s score %d",record.getUsername(),record.getScore());}
Client
1
2
3
4
5
6
7
8
varleaderboard_id="level1"varresult:NakamaAPI.ApiLeaderboardRecordList=yield(client.list_leaderboard_records_async(session,leaderboard_id),"completed")ifresult.is_exception():print("An error occurred: %s"%result)returnforrinresult.records:varrecord:NakamaAPI.ApiLeaderboardRecord=rprint("Record username %s and score %s"%[record.username,record.score])
curl -X GET "http://127.0.0.1:7350/v2/leaderboard/<leaderboardId>?cursor=<next_cursor>"\
-H 'Authorization: Bearer <session token>'
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
varleaderboardId="level1";varresult=awaitclient.listLeaderboardRecords(session,leaderboardId);result.records.forEach(function(record){console.log("Record username %o and score %o",record.username,record.score);});// If there are more results get next page.
if(result.next_cursor){result=awaitclient.listLeaderboardRecords(session,leaderboardId,null,null,result.next_cursor);result.records.forEach(function(record){console.log("Record username %o and score %o",record.username,record.score);});}
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
conststringleaderboardId="level1";varresult=awaitclient.ListLeaderboardRecordsAsync(session,leaderboardId);foreach(varrinresult.Records){System.Console.WriteLine("Record for '{0}' score '{1}'",r.Username,r.Score);}// If there are more results get next page.if(result.NextCursor!=null){varc=result.NextCursor;result=awaitclient.ListLeaderboardRecordsAsync(session,leaderboardId,null,100,c);foreach(varrinresult.Records){System.Console.WriteLine("Record for '{0}' score '{1}'",r.Username,r.Score);}}
autosuccessCallback=[this](NLeaderboardRecordListPtrrecordsList){for(auto&record:recordsList->records){std::cout<<"Record username "<<record.username<<" and score "<<record.score<<std::endl;}if(!recordsList->nextCursor.empty()){autosuccessCallback=[this](NLeaderboardRecordListPtrrecordsList){for(auto&record:recordsList->records){std::cout<<"Record username "<<record.username<<" and score "<<record.score<<std::endl;}};stringleaderboardId="level1";client->listLeaderboardRecords(session,leaderboardId,{},opt::nullopt,recordsList->nextCursor,successCallback);}};stringleaderboardId="level1";client->listLeaderboardRecords(session,leaderboardId,{},opt::nullopt,opt::nullopt,successCallback);
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
finalStringleaderboard="level1";LeaderboardRecordListrecords=client.listLeaderboardRecords(session,leaderboard);for(LeaderboardRecordrecord:records.getRecordsList()){System.out.format("Record for %s score %d",record.getUsername(),record.getScore());}// If there are more results get next page.if(records.getCursor()!=null){varc=result.NextCursor;records=client.listLeaderboardRecords(session,leaderboard,null,100,records.getNextCursor());for(LeaderboardRecordrecord:records.getRecordsList()){System.out.format("Record for %s score %d",record.getUsername(),record.getScore());}}
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
varleaderboard_id="level1"varresult:NakamaAPI.ApiLeaderboardRecordList=yield(client.list_leaderboard_records_async(session,leaderboard_id,null,null,100),"completed")ifresult.is_exception():print("An error occurred: %s"%result)returnforrinresult.records:varrecord:NakamaAPI.ApiLeaderboardRecord=rprint("Record username %s and score %s"%[record.username,record.score])ifresult.next_cursor:result=yield(client.list_leaderboard_records_async(session,leaderboard_id,null,null,100,result.next_cursor),"completed")ifresult.is_exception():print("An error occurred: %s"%result)returnforrinresult.records:varrecord:NakamaAPI.ApiLeaderboardRecord=rprint("Record username %s and score %s"%[record.username,record.score])
각 순위표 재설정 후 만료된 레코드는 순위표 순위에서 제거되지만 삭제되지는 않습니다. 사용자는 기간을 정해 만료된 레코드를 나열할 수 있습니다.
예를 들어 지난 주에 만료된 레코드를 나열하려면 다음을 수행합니다.
Client
1
2
curl -X GET "http://127.0.0.1:7350/v2/leaderboard/<leaderboardId>?overrideExpiry=604800"\
-H 'Authorization: Bearer <session token>'
Client
1
2
3
4
5
6
varleaderboardId="<leaderboardId>";varoverrideExpiry=604800;varresult=awaitclient.listLeaderboardRecords(session,leaderboardId,overrideExpiry);result.records.forEach(function(record){console.log("Record username %o and score %o expired on %o",record.username,record.score,record.expiryTime);});
Client
1
2
3
4
5
6
7
conststringleaderboardId="<leaderboardId>";constint64overrideExpiry=604800;varresult=awaitclient.ListLeaderboardRecordsAsync(session,leaderboardId,overrideExpiry);foreach(varrinresult.Records){System.Console.WriteLine("Record for '{0}' and score '{1}' expired on '{2}'",r.Username,r.Score,r.ExpiryTime);}
Client
1
2
3
4
5
6
7
8
9
10
11
12
autosuccessCallback=[](NLeaderboardRecordListPtrrecordsList){for(auto&record:recordsList->records){std::cout<<"Record username "<<record.username<<" and score "<<record.score<<" expired on "<<record.expiryTime<<std::endl;}};stringleaderboardId="<leaderboardId>";intoverrideExpiry=604800;client->listLeaderboardRecords(session,leaderboardId,overrideExpiry,{},opt::nullopt,opt::nullopt,successCallback);
Client
1
2
3
4
5
6
finalStringleaderboard="<leaderboardId>";finalLongoverrideExpiry=604800;LeaderboardRecordListrecords=client.listLeaderboardRecords(session,leaderboard,overrideExpiry).get();for(LeaderboardRecordrecord:records.getRecordsList()){System.out.format("Record for %s score %d",record.getUsername(),record.getScore());}
Client
1
2
3
4
5
6
7
8
9
varleaderboard_id="<leaderboardId>"varoverride_expiry=604800varresult:NakamaAPI.ApiLeaderboardRecordList=yield(client.list_leaderboard_records_async(session,leaderboard_id,override_expiry),"completed")ifresult.is_exception():print("An error occurred: %s"%result)returnforrinresult.records:varrecord:NakamaAPI.ApiLeaderboardRecord=rprint("Record username %s and score %s expired on %s"%[record.username,record.score,record.expiry_time])
stringleaderboardId="level1";stringownerId="some user ID";int32_tlimit=100;client->listLeaderboardRecordsAroundOwner(session,leaderboardId,ownerId,limit,successCallback);