کار با لیدربورد - Android

در این مستند ما نحوه ساخت رویداد (Event) و ارسال آن به سرور و دیدن نتیجه‌ی آن در لیدربوردهای اپلیکیشن را خواهیم دید.

پیش‌نیازها

  1. در صورتی که با سرویس مرکز بازی آشنایی ندارید، به معرفی سرویس مرکز بازی مراجعه کنید.
  2. در صورتی که هنوز در پنل توسعه‌دهنده خود تنظیمات لازم برای مرکز بازی را انجام نداده‌اید، به تنظیمات پنل مراجعه کنید.
  3. در صورتی که هنوز SDK اندروید را راه‌اندازی نکرده‌اید، به راه‌اندازی SDK بکتوری در اندروید مراجعه کنید.

راه‌اندازی سرویس مرکز بازی

پس از راه‌اندازی SDK بکتوری در اندروید، در شروع اپلیکیشن بایستی SDK بکتوری را initialize کنید. در عمل initialize، شما تمامی سرویس‌هایی که علاقمند به استفاده هستید را ذکر خواهید کرد. برای سرویس مرکز‌بازی کدی مشابه زیر بایستی داشته باشید:

// Extending android application to initialize backtory
public class MainApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        // Initializing backtory
        BacktoryClient.init(KeyConfiguration.newBuilder().
            setAuthKeys("<X-Backtory-Authentication-Id>",
                        "<X-Backtory-Authentication-Key (Client)>").
            // Enabling Game Center
            setGameKey("<X-Backtory-Game-Id>").
            // Finalizing sdk
            build(), this);
    }
}

ارسال یک رویداد (Event)

همان‌طور که در بالا گفتیم، با ارسال رویداد تغییرات لازم در لیدربورد اعمال می‌شوند و امتیاز بازیکن‌ها و رتبه‌ی آنها به‌روز می‌شود. برای ارسال یک رویداد می‌توانید از یکی از دو روش زیر استفاده کنید:

1. استفاده از لیست مقادیر

در این روش شما لیستی از key-valueها تولید کرده و به عنوان داده‌ی رویداد، به تابع ارسال یک رویداد، پاس می‌دهید. کد زیر نمونه‌ای از این روش می‌باشد:

// Step 1: Creating parameters for GameOver event
List<FieldValue> fieldValues = Arrays.asList(
    new FieldValue("gold", 100), 
    new FieldValue("time", 200));

// Step 2: Creating GameOver event and filling its data
BacktoryEvent event = new BacktoryEvent();
event.setName("GameOver");
event.setFieldsAndValues(fieldValues);

// Step 3: Sending event to server
event.sendInBackground(new BacktoryCallBack<Void>() {
    // Checking callback from server
    @Override
    public void onResponse(BacktoryResponse<Void> response) {
        if (response.isSuccessful()) { // = Event saved to server successfully
            Log.d("TAG", "saved event successfully");
        } else {
            // do something based on response.code()
        }
    }
});

همانطور که در درخواست بالا می‌بینید ما یک رخداد GameOver با زمان ۲۰۰ و طلای ۱۰۰ ارسال کردیم. در صورتی که تمایلی به انجام کاری در callback ندارید، کافیست آن را null پاس بدهید. یعنی:

event.sendInBackground(null);

2. استفاده از یک شیء جدید

در صورتی که مدل لیست مقادیر key-value را نمی‌پسندید و دوست دارید کمی شیء‌گراتر (Object-Oriented) باشید می‌توانید کلاس BacktoryEvent بکتوری را گسترش (Extend) دهید، منطق مورد نظر خود را به آن اضافه کنید و توابع سازنده (Constructor) دلخواه جهت سهولت استفاده به آن اضافه کنید.

برای مثال رخداد GameOver در مثال قبل به شکل زیر خواهد بود:

public class GameOverEvent extends BacktoryEvent {
    @EventName
    public static final String eventName = "GameOver";

    @FieldName("gold")
    int goldValue;

    @FieldName("time")
    int timeValue;

    public GameOverEvent(int goldValue, int timeValue) {
        this.goldValue = goldValue;
        this.timeValue = timeValue;
    }
}

همانطور که می‌بینید چند annotation بر روی خصوصیات کلاس، یک کد زیباتر و شکیل‌تر معادل با کد روش اول، تولید می‌کند. این annotationها عبارتند از:

ارسال این رخداد مانند روش اول خواهد بود، زیرا رخداد GameOverEvent فرزند BacktoryEvent است و توابع آن را به ارث می‌برد. پس کد زیر کار ارسال را انجام خواهد داد:

// Step 1 & 2: Create event and fill it
GameOverEvent event = new GameOverEvent(100, 200);

// Step 3: send it
event.sendInBackground(new BacktoryCallBack<Void>() {
    @Override
    public void onResponse(BacktoryResponse<Void> response) {
        if (response.isSuccessful()) { // = Event saved to server successfully
            Log.d("TAG", "saved event successfully");
        } else {
            // do something based on response.code()
        }
    }
});

بروز خطا

در صورت بروز خطا در ارسال رخداد عبارت ()response.isSuccessful برابر false خواهد بود، و ()response.code نوع خطا را مشخص می‌کند که یکی از مقادیر زیر است:

Tables Description
417-Incorrect event data Event data is incorrect
400-Bad Request EventName or fieldName is null
500-Internal Server Error Data access was unsuccessful
503-Service Unavailable Backtory is unavailable right now

ساخت شیء لیدربورد در SDK

برای آنکه بتوانید به یک لیدربورد در بکتوری اتصال پیدا کنید و اطلاعات آن را از سرور دریافت کنید، باید از کلاس BacktoryLeaderBoard در SDK استفاده کنید.

برای ساخت لیدربورد دو روش دارید:

۱. یک شیء از کلاس BacktoryLeaderBoard ساخته و شناسه لیدربورد را به آن پاس دهید. به صورت زیر:

BacktoryLeaderBoard topPlayers = new BacktoryLeaderBoard("576d4a33e4b050913524162c");

۲. کلاس BacktoryLeaderBoard را گسترش دهید. مانند زیر:

public class TopPlayersLeaderBoard extends BacktoryLeaderBoard {
    @LeaderBoardId
    public static final String id = "576d4a33e4b050913524162c";
}

و هر جا که لازم بود از آن یک نمونه به صورت زیر بسازید:

TopPlayersLeaderBoard topPlayers = new TopPlayersLeaderBoard();

در هر یک از دو صورت بالا شما می‌توانید سه عمل مهم با لیدربورد انجام دهید:

رتبه یک بازیکن در لیدربورد

توجه: این سرویس تنها برای کاربر فعلی گوشی کاربرد دارد و امکان گرفته رتبه سایر بازیکنان در SDK، به خاطر مسئله امنیت، وجود ندارد. در صورتی که نیازمند به گرفتن رتبه دیگران هستید، باید از سرویس رایانش استفاده کنید.

برای آنکه بتوانید رتبه کاربری که از طریق سرویس کاربران در اپلیکیشن شما ورود انجام داده است، را دریافت کنید، کافیست لیدربورد مورد نظر خود را بسازید و تابع getPlayerRankInBackground را فراخوانی کنید:

// Create a leaderboard object
TopPlayersLeaderBoard topPlayers = new TopPlayersLeaderBoard();

// Get your loggedIn user's rank in topPlayers
topPlayers.getPlayerRankInBackground(new BacktoryCallBack<LeaderBoardRank>() {

    // Callback from server
    @Override
    public void onResponse(BacktoryResponse<LeaderBoardRank> response) {
        // Check if backtory returned result successfully
        if (response.isSuccessful()) {
            // Extract response info
            String leaderboardPosition = "my rank: " + response.body().getRank() 
                + "\n my scores: " + response.body().getScores();

            // Log it
            Log.d("TAG", leaderboardPosition);
        } else {
            // do something based on error code
        }
    }
});

در صورتی که عبارت ()response.isSuccessful برابر true باشد اطلاعات با موفقیت دریافت شده است و در غیر این صورت، عبارت ()response.code نوع خطا را به شما نشان خواهد داد که یکی از مقادیر زیر است:

Tables Description
200-OK Successful
417-Incorrect data Something is incorrect in leaderboard
400-Bad Request LeaderboardId is null or invalid
500-Internal Server Error Data access was unsuccessful
503-Service Unavailable Backtory is unavailable right now

نفرات برتر در لیدربورد

معمولا مهم‌ترین نیاز در لیدربورد این است که شما بتوانید آن را در اپلیکیشن خود نشان دهید. و معمولا منظور از نشان دادن لیدربورد نیز آن است که مثلا ۱۰۰ نفر برتر اپلیکیشن خود را در معرض دید قرار دهید، تا کاربران تشویق به بازی بیشتر و قرار گرفتن جز این نفرات شوند. برای آنکه بتوانید ۱۰۰ نفر بالای لیدربورد خود را از سرور دریافت کنید، باید کدی مانند زیر را اجرا کنید:

// Create a leaderboard object
TopPlayersLeaderBoard topPlayers = new TopPlayersLeaderBoard();

// Request for top 100 to backtory
topPlayers.getTopPlayersInBackground(100, new BacktoryCallBack<LeaderBoardResponse>() {
    
    // Check server response
    @Override
    public void onResponse(BacktoryResponse<LeaderBoardResponse> response) {
        // Checking if response was fetched successfully
        if (response.isSuccessful()) {
            // Getting first person (Number 1) in leaderboard
            UserProfile topPlayer = response.body().getUsersProfile().get(0);
            String username = topPlayer.getUserBriefProfile().getUserName();
            List<Integer> scores = topPlayer.getScores(); 

            // Logging the best player
            Log.d(TAG, "best player is: " + username 
                + "\n scoring: " + scores);
        } else {
            // do something based on error code
        }
    }
});

توجه: محدودیت تعداد نفرات بالای لیدربورد ۱۰۰ است و اگر شما برای بیش از این تعداد درخواست دهید، با خطا مواجه خواهید شد.

در صورتی که عبارت ()response.isSuccessful برابر true باشد اطلاعات با موفقیت دریافت شده است و در غیر این صورت، عبارت ()response.code نوع خطا را به شما نشان خواهد داد که یکی از مقادیر زیر است:

Tables Description
200-OK Successful
417-Incorrect data Something is incorrect in leaderboard
400-Bad Request LeaderboardId is null or invalid
500-Internal Server Error Data access was unsuccessful
503-Service Unavailable Backtory is unavailable right now

اطرافیان من در لیدربورد

یکی از المان‌های اپلیکیشن که برای کاربران جذاب است این است که بدانند در لیدربورد بازی رتبه چندم را دارا هستند و اختلاف‌شان با اطرافیان چقدر است. به این ترتیب می‌توانند میزان زمانی که باید صرف بازی کنند و نتیجه‌ای که در لیدربورد آنها خواهد داشت را تخمین زده و به بازی بپردازند. به این عمل Around-me گفته می‌شود.

در صورتی که می‌خواهید ۵ نفر بالا و ۵ نفر پایین خود را دریافت کنید باید به تابع Around-me عدد ۱۰ را پاس بدهید. بکتوری در جواب یک آرایه حداکثر به طول ۱۱ برمی‌گرداند که شامل ۵ نفر بالا، کاربر شما و ۵ نفر پایین خواهد بود. دقت کنید که در صورتی که کاربر شما در شرایط مرزی باشد، برای مثال نفر اول لیدربورد باشد، ۵ نفر بالا برایش معنی ندارد و جواب یک آرایه به طول ۶ خواهد بود که شامل کاربر فعلی در صدر و ۵ کاربر پایین او خواهد شد.

کد زیر یک درخواست ساده برای دریافت اطلاعات ۱ نفر بالا و ۱ نفر پایین را به سرور بکتوری می‌دهد:

// Create a leaderboard object
TopPlayersLeaderBoard topPlayers = new TopPlayersLeaderBoard();

// Request for 2 players which are around me is TopPlayers leaderboard,
// Normally, index 0 is above me, index 1 is ME, and index 2 is below me
topPlayers.getPlayersAroundMeInBackground(2, 
    new BacktoryCallBack<LeaderBoardResponse>() {

    // Checking server response
    @Override
    public void onResponse(BacktoryResponse<LeaderBoardResponse> response) {
        if (response.isSuccessful()) { // = result is valid
            // Get above and below players
            UserProfile aboveMePlayer = response.body().getUsersProfile().get(0);
            UserProfile belowMePlayer = response.body().getUsersProfile().get(2);

            // Logging result
            Log.d(TAG, "you are behind " 
                + aboveMePlayer.getUserBriefProfile().getUserName() 
                + "\n but better than " 
                + belowMePlayer.getUserBriefProfile().getUserName());
        } else {
            // do something based on error code
        }
    }
});

در مثال بالا عدد ۲ بدین معنی است که می‌خواهید ۱ نفر بالا و ۱ نفر پایین کاربر فعلی را دریافت کنید. محدودیت تعداد اطرافیانی که بکتوری در اختیار شما می‌گذارید، عدد ۲۰ است (یعنی ۱۰ نفر بالا و ۱۰ نفر پایین) و اگر عدد بالاتری را درخواست کنید، با خطا مواجه خواهید شد.

در صورتی که عبارت ()response.isSuccessful برابر true باشد اطلاعات با موفقیت دریافت شده است و در غیر این صورت، عبارت ()response.code نوع خطا را به شما نشان خواهد داد که یکی از مقادیر زیر است:

Tables Description
200-OK Successful
417-Incorrect data Something is incorrect in leaderboard
400-Bad Request LeaderboardId is null or invalid
500-Internal Server Error Data access was unsuccessful
503-Service Unavailable Backtory is unavailable right now