برگزاری رقابت آنلاین

دقت کنید که این مستند مخصوص رقابت آنلاین است و برای نیازمندی‌های چت هیچ کاربردی ندارد.

در این مستند، قصد داریم نحوه انجام یک رقابت آنلاین را از طریق SDK بلادرنگ بکتوری به شما نشان دهیم. شما خواهید دید که چگونه پس از آنکه چند بازیکن با هم انطباق داده شدند و یا با چالش کاربران دیگر، در نهایت یک رقابت آنلاین (Realtime Game) را ایجاد کردند، می‌تواند رقابت را آغاز کنند، به یکدیگر پیام ارسال کنند و در نهایت رقابت را به پایان ببرند.

مهم: با توجه به قدیمی‌بودن SDK اندروید، در این مستند match به دو معنا به کار رفته است: هم به معنی انطباق در Match-Making و هم به معنی Realtime Game. با توجه به زمینه، باید خودتان به معنی درست match پی ببرید. :) این مشکل در SDK یونیتی برطرف شده و به زودی در SDK اندروید نیز برطرف خواهد شد.

پیش‌نیاز

  1. در صورتی که با سرویس بلادرنگ آشنایی ندارید، به معرفی سرویس بلادرنگ مراجعه کنید.
  2. در صورتی که هنوز با تنظیمات پنل سرویس بلادرنگ آشنا نشده اید، به تنظیمات پنل سرویس بلادرنگ مراجعه کنید.
  3. اگر با سرویس Match-Making آشنایی ندارید، به آشنایی با سرویس Match-Making مراجعه کنید.
  4. اگر هنوز SDK اندروید را راه‌اندازی نکرده‌اید، به راه‌اندازی SDK اندروید مراجعه کنید.
  5. در صورتی که با نحوه‌ی اتصال به سرویس بلادرنگ و ایجاد یک چت ساده به کمک آن آشنایی ندارید، مستند اتصال ساده و ارسال پیام را حتما مطالعه کنید.
  6. دو روش درخواست Match-Making و چالش کاربران دیگر را بسته به نیاز اپلیکیشن خود مطالعه کنید.

روش‌های ساخت یک Match

برای ساختن یک رقابت آنلاین (Realtime Game) در بکتوری، شما باید یکی از دو روش زیر را پیاده‌سازی کرده و در نهایت یک شناسه‌ی MatchId معتبر به دست آورید.

  1. از بکتوری درخواست Match-Making کنید، بکتوری درخواست‌های Match-Making کاربران مختلف را دریافت کرده و سعی می‌کند کاربرانی که سطح بازی نزدیک به هم دارند را با هم انطباق دهد و در تابع onMatchFound، در صورتی که به تعداد کافی کاربر هم‌سطح درخواست دهند، یک رقابت آنلاین ایجاد کرده و به شما شناسه‌ی MatchId را می‌دهد.
  2. از مفهوم چالش کاربران دیگر استفاده کنید؛ یعنی، کاربر موبایل شما تعدادی کاربر دیگر را مشخص کند و درخواست یک رقابت آنلاین (در اینجا چالش نامیده می‌شود) برای آنها رفته و اگر تعداد کافی از آنها درخواست را بپذیرند، در تابع onChallengeReady شناسه‌ی MatchId در اختیار آنها قرار خواهد گرفت.

در هر یک از دو روش بالا در نهایت یک شناسه‌ی MatchId دارید که پیش‌نیاز شروع یک رقابت آنلاین است. در ادامه این مستند تمامی اعمالی که لازم به دانستن است، تا بتوانید یک رقابت آنلاین کامل را پیاده‌سازی کنید، خواهیم گفت.

تنظیمات آغازین Realtime Game

قدم اول در بلادرنگ قبل از شروع بازی، انجام تنظیمات رقابت آنلاین است. شما باید برای SDK بکتوری تعیین کنید که به ازای هر اتفاق در بازی چه کاری انجام دهد. برای این کار کدی مانند زیر لازم است. (فرض بر این است که شناسه‌ی MatchId در اختیار ماست.)

public class MainClass implements MatchListener, RealtimeSdkListener {

    public void init() {
        BacktoryRealtimeMatchAndroidApi matchApi =
                BacktoryRealtimeAndroidApi.getMatchApi("<MATCH-ID-HERE>");

        // 2. Set required listener
        matchApi.setRealtimeSdkListener(this);

        // 3. Set MATCH listener
        matchApi.setMatchListener(this);
    }

    /*********** Start Match Listener *************/
    @Override
    public void onMatchJoinedMessage(MatchJoinedMessage matchJoinedMessage) {}
    @Override
    public void onMatchStartedMessage(MatchStartedMessage matchStartedMessage) {}
    @Override
    public void onStartedWebhookMessage(StartedWebhookMessage startedWebhookMessage) {}
    @Override
    public void onDirectChatMessage(DirectChatMessage directChatMessage) {}
    @Override
    public void onMatchEvent(MatchEvent matchEvent) {}
    @Override
    public void onMatchChatMessage(MatchChatMessage matchChatMessage) {}
    @Override
    public void onMasterMessage(MasterMessage masterMessage) {}
    @Override
    public void onWebhookErrorMessage(WebhookErrorMessage webhookErrorMessage) {}
    @Override
    public void onJoinedWebhookMessage(JoinedWebhookMessage joinedWebhookMessage) {}
    @Override
    public void onMatchEndedMessage(MatchEndedMessage matchEndedMessage) {}
    @Override
    public void onMatchDisconnectMessage(MatchDisconnectMessage matchDisconnectMessage) {}
    /*********** End Match Listener *************/

    /*********** Start Realtime Sdk Listener *************/
    @Override
    public void onDisconnect() {}
    @Override
    public void onException(ExceptionMessage exceptionMessage) {}
    /*********** End Realtime Sdk Listener *************/
}

توضیح:

  1. در قدم اول به کمک ()BacktoryRealtimeUnityApi.getMatchApi ما دسترسی به امکانات یک Match پیدا می‌کنیم.
  2. با پیاده‌سازی MatchListener و با صدا زدن تابع setMatchListener، تعداد زیادی تابع در اختیار ما قرار می‌گیرد که می‌توانیم آن‌ها را پیاده‌سازی کنیم.

در ادامه، به توضیح مبسوط هریک از لیسنرهای فوق می‌پردازیم.

پذیرفتن یک Match

قدم اول در یک رقابت آنلاین بعد از آنکه تنظیمات گفته شده در قسمت قبل را انجام دادید، این است که به آن Match وصل شوید. برای وصل شدن به یک Match کافیست کدی مانند زیر را، در جایی از برنامه که قصد وصل شدن دارید، اجرا کنید:

// Get match api
BacktoryRealtimeMatchAndroidApi matchApi =
        BacktoryRealtimeAndroidApi.getMatchApi("<MATCH-ID-HERE>");

// Connect to match
matchApi.connectAndJoinAsync(new BacktoryCallBack<ConnectResponse>() {
    @Override
    public void onResponse(BacktoryResponse<ConnectResponse> response) {
        // Check result of connection
        if (response.isSuccessful()) {
            Log.d("TAG", "Connected to match now.");
        } else {
            Log.d("TAG", "Failed to connect, code: "
                    + response.code()
                    + " and message: "
                    + response.message());
        }
    }
});

به سادگی با استفاده از ()connectAndJoin می‌توانید وارد رقابت آنلاین شوید.

دریافت اتصال کاربران دیگر

از لحظه‌ای که شما به رقابت آنلاین وصل شوید، از کاربرانی که پس از شما متصل می‌شوند، مطلع خواهید شد. برای این کار کافیست تابع onMatchJoinedMessage در تنظیمات رقابت را به شکل زیر پیاده‌سازی کنید:

@Override
public void onMatchJoinedMessage(MatchJoinedMessage joinedMessage) {
    Log.d("TAG", "User with id: " + joinedMessage.getUserId()
            + " and username: " + joinedMessage.getUsername() + " joined the match.");
    Log.d("TAG", joinedMessage.getConnectedUserIds().size() + " users have already joined the match.");
}

همچنین اگر وب‌هوک Join تنظیم کرده باشید و از سمت سرور در این وب‌هوک پیامی ارسال کنید، این پیام توسط تابع زیر به دست اپلیکیشن شما خواهد رسید:

@Override
public void onJoinedWebhookMessage(JoinedWebhookMessage joinedWebhookMessage) {
    Log.d("TAG", "Your join webhook sent this message to you: "
            + joinedWebhookMessage.getMessage());
}

دریافت شروع بازی (اتصال همه)

پس از آنکه همه بازیکنان به بازی Join شوند، پیام MatchStarted به آنها ارسال خواهد شد، دریافت این پیام بدین معنی است که از این لحظه همه در جریان رقابت هستند و می‌توان رقابت آنلاین را آغاز کرد. در صورتی که می‌خواهید اپلیکیشن شما از این اتفاق باخبر شود، تابع onMatchStartedMessage در تنظیمات رقابت را پیاده‌سازی کنید:

@Override
public void onMatchStartedMessage(MatchStartedMessage matchStartedMessage) {
    Log.d("TAG", "Match finally started, let's do our best.");
}

دریافت پیام وب‌هوک شروع بازی

اگر وب‌هوک شروع بازی را فعال‌سازی کرده باشید، جواب وب‌هوک مورد نظر در سرور از طریق تابع OnStartedWebhookMessage در تنظیمات رقابت به دست اپلیکیشن شما خواهد رسید. برای چاپ پیام آغاز بازی کدی مانند زیر لازم است:

@Override
public void onStartedWebhookMessage(StartedWebhookMessage startedWebhookMessage) {
    Log.d("TAG", "Your start webhook returned this message: "
            + startedWebhookMessage.getMessage());
}

ارسال و دریافت Event در بازی

مهم‌ترین و پرکاربردترین عمل در یک رقابت آنلاین، ارسال پیام Event است. پیام Event به هر اتفاقی که در بازی بیافتد و مربوط به منطق بازی باشد گفته می‌شود، مانند حرکت دادن یک مهره، زدن یک کارت، پاسخ به یک سوال، شلیک یک گلوله و یا هر چیز دیگر…

ارسال: جهت ارسال یک پیام Event باید کدی مانند زیر را در هر جایی از رقابت که آن Event اتفاق می‌افتد، فراخوانی کرد:

// Get match api
BacktoryRealtimeMatchAndroidApi matchApi = BacktoryRealtimeAndroidApi.getMatchApi("<MATCH-ID-HERE>");

// Send event
Map<String, String> data = new HashMap<String, String>();
data.put("Name", "Freeze Card");
data.put("Power", "2");

matchApi.sendEvent("Special Card Used", data);

همانطور که در بالا می‌بینید، شما به همراه هر Event می‌توانید یک دیکشنری data نیز بفرستید. در صورتی که وب‌هوک Event را تنظیم کرده باشید، این data به دست وب‌هوک می‌رسد و می‌توانید از اطلاعات آن استفاده کنید.

هم‌چنین، می‌توانید تابع sendEvent را با یک آرگومان اضافه‌تر نیز مشابه کد زیر فراخوانی کنید. این آرگومان اختیاری ignoreWebhook نام دارد و در صورتی که مقدار آن برابر true باشد، وب‌هوک اصلا در نظر گرفته نمی‌شود؛ انگار که اصلا شما وب‌هوکی ست نکرده باشید. در صورتی که مقدار آن برابر false باشد، مشابه حالتی عمل می‌کند که اصلا این آرگومان را پاس نداده اید. فایده‌ی چنین آرگومانی این است که ممکن است در شرایطی شما بخواهید رویدادهایی بفرستید که نیازی به وب‌هوک ندارند.

boolean ignoreWebhook = true;
matchApi.sendEvent("Special Card Used", data, ignoreWebhook);

دریافت: جهت دریافت Eventهایی که توسط بازیکنان در یک رقابت آنلاین جابه‌جا می‌شود، باید از onMatchEvent در تنظیمات رقابت استفاده کرد:

@Override
public void onMatchEvent(MatchEvent matchEvent) {
    Log.d("TAG", "Event sent from: " + matchEvent.getUserId());
    Log.d("TAG", "Message is: " + matchEvent.getRawMessage());
    Log.d("TAG", "Extra data of event: " + matchEvent.getData());
}

به این ترتیب، شما می‌توانید هر Eventای که بخواهید، ارسال و دریافت کنید.

پیام مستقیم به یک بازیکن

ارسال: اگر بازی‌های آنلاین را دیده باشید، در برخی از آنها شما می‌توانید پیام مستقیم به یکی دیگر از بازیکنان بدهید. این پیام‌ها کمک به بهبود بازی می‌کند و راه ارتباطی بین آنها برای چیدن استراتژی است. برای ارسال پیام مستقیم در رقابت آنلاین بکتوری، کدی مانند زیر را باید اجرا کنید:

// Get match api
BacktoryRealtimeMatchAndroidApi matchApi =
        BacktoryRealtimeAndroidApi.getMatchApi("<MATCH-ID-HERE>");

// Send direct message
matchApi.directToUserAsync("<USER-ID-HERE>", "Hello, what's up?",
        new BacktoryCallBack<Void>() {
    @Override
    public void onResponse(BacktoryResponse<Void> response) {
        // Check result of direct chat
        if (response.isSuccessful()) {
            Log.d("TAG", "Chat sent successfully.");
        } else {
            Log.d("TAG", "Failed to send, code: "
                    + response.code()
                    + " and message: "
                    + response.message());
        }
    }
});

دریافت: در طرف دیگر، یعنی اپلیکیشن مقصد، برای آنکه پیام را بتوان دریافت کرد و نمایش داد، باید تابع onDirectChatMessage در تنظیمات رقابت را مانند زیر پیاده‌سازی کنید:

@Override
public void onDirectChatMessage(DirectChatMessage directChatMessage) {
    Log.d("TAG", "A direct message from: " + directChatMessage.getUserId());
    Log.d("TAG", "Message is: " + directChatMessage.getMessage());
}

ارسال و دریافت پیام به همه بازیکنان

ارسال: معمولا در بازی‌های آنلاین لازم است که بازیکنان بتوانند به یکدیگر پیام ارسال کنند. مثلا برای یک نفر مشکلی پیش می‌آید و می‌خواهد بازی را Pause کرده و مشکل را از طریق چت با بقیه بازیکنان حل کند. برای این کار در رقابت آنلاین بکتوری باید کدی مانند زیر را اجرا کرد:

// Get match api
BacktoryRealtimeMatchAndroidApi matchApi =
        BacktoryRealtimeAndroidApi.getMatchApi("<MATCH-ID-HERE>");

// Send a message to all players in match
matchApi.sendChatToMatchAsync("Hey everyone, please pause :)",
        new BacktoryCallBack<Void>() {
    @Override
    public void onResponse(BacktoryResponse<Void> response) {
        // Check result of match chat
        if (response.isSuccessful()) {
            Log.d("TAG", "Chat sent successfully.");
        } else {
            Log.d("TAG", "Failed to send, code: "
                    + response.code()
                    + " and message: "
                    + response.message());
        }
    }
});

دریافت: جهت دریافت پیام‌های چتی که به همه بازیکنان ارسال می‌شود نیز، کافیست تابع OnMatchChatMessage در تنظیمات رقابت را مانند شکل زیر پیاده‌سازی کنید:

@Override
public void onMatchChatMessage(MatchChatMessage matchChatMessage) {
    Log.d("TAG", "A sent-to-all message in match from: "
            + matchChatMessage.getUserId());
    Log.d("TAG", "Message is: " + matchChatMessage.getMessage());
}

دریافت پیام‌های مدیر (Master)

با وجود پیام‌هایی که توسط بازیکنان به یکدیگر رد و بدل می‌شود و Eventهایی که هر بازیکن ممکن است ارسال کند، گاهی لازم است یک منطق در سرور اتفاقاتی در بازی ایجاد کند. برای مثال در یک بازی سبک دفاع مثل Tower Defence، در زمان‌های خاصی هیولاهایی در بازی ظاهر می‌شود. چنین اتفاقی توسط هیچ بازیکنی تعیین نمی‌شود، بلکه منطق بازی حکم می‌کند که چنین اتفاقی در زمان خاصی بیافتد. چنین کارهایی از طریق قابلیت‌های مدیر در بلادرنگ قابل انجام است.

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

@Override
public void onMasterMessage(MasterMessage masterMessage) {
    Log.d("TAG", "A message from master of the game: " + masterMessage.getMessage());
}

ارسال و دریافت نتیجه بازی

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

// Get match api
BacktoryRealtimeMatchAndroidApi matchApi =
        BacktoryRealtimeAndroidApi.getMatchApi("<MATCH-ID-HERE>");

// Send winner list to server
List<String> winners = new ArrayList<String>();
winners.add("<WINNER-USER-ID-1>");
winners.add("<WINNER-USER-ID-2>");
winners.add("<WINNER-USER-ID-3>");

matchApi.sendMatchResultAsync(winners, new BacktoryCallBack<Void>() {
    @Override
    public void onResponse(BacktoryResponse<Void> response) {
        // Check result of send
        if (response.isSuccessful()) {
            Log.d("TAG", "Winners sent successfully.");
        } else {
            Log.d("TAG", "Failed to send, code: "
                    + response.code()
                    + " and message: "
                    + response.message());
        }
    }
});

در کد بالا کافیست یک لیست از شناسه UserId کاربرانی که از دید اپلیکیشن شما برنده هستند بدهید.

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

@Override
public void onMatchEndedMessage(MatchEndedMessage message) {
    Log.d("TAG", "Match ended now.");
    Log.d("TAG", "List of winners is: ");
    for (int i = 0; i < message.getWinners().size(); i++) {
        Log.d("TAG", i + ": " + message.getWinners().get(i));
    }
}

خروج از بازی

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

// Get match api
BacktoryRealtimeMatchAndroidApi matchApi =
        BacktoryRealtimeAndroidApi.getMatchApi("<MATCH-ID-HERE>");

matchApi.disconnectAsync(new BacktoryCallBack<Void>() {
    @Override
    public void onResponse(BacktoryResponse<Void> response) {
        // Check result of disconnect
        if (response.isSuccessful()) {
            Log.d("TAG", "Disconnected successfully.");
        } else {
            Log.d("TAG", "Failed to disconnect, code: "
                    + response.code()
                    + " and message: "
                    + response.message());
        }
    }
});

نکته‌ی مهم: به یاد داشته باشید که حتما با پایان بازی، تابع ()disconnectAsync را صدا بزنید؛ در غیر این‌صورت، اتصال شما باز مانده و علاوه بر مصرف منابع دستگاه، برای شما هزینه ایجاد می‌کند!

دریافت خروج یک بازیکن

در صورتی که یک بازیکن در میانه رقابت آنلاین از بازی خارج شود و یا عمدا شبکه خود را قطع کند، سرور از طریق onMatchDisconnectedMessage در تنظیمات رقابت به همه بازیکنان باقیمانده اطلاع‌رسانی خواهد کرد. برای مثال با دریافت این پیام می‌توانید، بر روی آیکون بازیکن حذف شده، یک علامت قطع شدن و یا ضربدر بزنید و از این طریق به بازیکن اطلاع‌رسانی کنید. نمونه کد برای دریافت این پیام به صورت زیر است:

@Override
public void onMatchDisconnectMessage(MatchDisconnectMessage dcMessage) {
    Log.d("TAG", "User with id: " + dcMessage.getUserId()
            + " is disconnected from the game.");
}

دریافت خطای وب‌هوک

اگر در تنظیمات وب‌هوک در پنل، تیک انتقال خطا را فعال کنید، خطاهایی که در وب‌هوک اتفاق می‌افتد، از طریق تابع OnWebhookErrorMessage در تنظیمات رقابت به دست اپلیکیشن شما خواهد رسید. کد زیر این خطا را دریافت و لاگ می‌زند:

@Override
public void onWebhookErrorMessage(WebhookErrorMessage webhookErrorMessage) {
    Log.d("TAG", "Error in server webhook.");
}

به این ترتیب، شما تمامی توانمندی‌هایی که در جریان یک رقابت آنلاین وجود دارد را دیدید و حال می‌توانید یک بازی با قابلیت رقابت آنلاین بسازید. در صورتی که بازخورد، پیشنهاد و یا انتقادی نسبت به مستندات دارید، از طریق ایمیل به پشتیبانی بکتوری ما را در جریان بگذارید.