CryptoBotWars أو كيفية بناء عروض غزر ولماذا

لماذا غزر؟ لأنني أحب إهمال الذات واللعبة ليست مكان قريب من الإنتاج.

الرموز والروبوتات وقنوات الدفع والبث المباشر

لذلك قمت ببناء CryptoBotWars ، لعبة على شبكة Raiden.

تريد أن تلعبه؟ واصل القراءة…

ألق نظرة خاطفة على اللعبة ، خلف الكواليس أو نموذج البث المباشر. وانضم إلى دردشة الشغب لدينا!

لماذا ا؟ ... لدي بعض الأسئلة:

  1. هل من السهل بناء شيء ما على رايدن الآن؟ هل نفتقر إلى أي شيء سهل التغيير إلى حد ما؟
  2. كيف ستعمل Raiden في الوقت الحالي على دفعات رأس بأكثر من شخص لآخر والعديد من الحالات ، وغالبًا ما ترتبط الحالات بالأعمال التجارية
  3. هل سيجد الناس أخطاء في ريدن؟ أفضل اختبار هي اختبار جاهل على متن الطائرة.
  4. هل يتصرف ريدن بشكل جيد مع إنتاجية عالية؟
  5. هل تتم الوساطة بنجاح (مواقع مختلفة وإعدادات النظام)

هناك لعبة ، مقترنة بشكل خاص مع قدر من الترفيه ، لديها القدرة على تحفيز أشخاص جدد لتجربة Raiden. حتى أكثر من ذلك ، إذا قمت بإضافة بعض المكافآت على القمة.

لعبة ... أو خدمة جادة للغاية تقبل الدفعات خارج السلسلة but ، لكن لم يكن لدي الوقت الكافي لهذا الأخير ، لذلك تذهب:

الظلام فيدر والأزرق يودا. صحن الشوربة وكرة الطاولة سانتا هات! تبدو رائعة! ... من 4 أمتار

هذه المدونة مكرسة جزئيًا للمطعم التايلاندي حيث أحصل على حساء جوز الهند-التوفو-الخضروات المفضل لدي في برلين. لهذا السبب لدينا دائمًا مجموعة من الأوعية الجاهزة لصنع Vader Helmets & Santa Hats .

كيف خطرت لك الفكرة؟

في يوم من الأيام ، بعد الغداء ، كنا نناقش أفكارًا حول ورشة Devcon4 Raiden Network ، في محاولة للتفكير في تطبيق ممتع وبسيط يمكن بناؤه فوق Raiden. بطريقة ما ، توصلنا إلى استنتاج مفاده أن اللعبة قد تحفز المزيد من الناس على تجربتها.

فكرت في الأمر أكثر قليلاً بعد ذلك وقررت أن لعبة بها عدد غير محدود من المستخدمين قد تعرض Raiden بشكل أفضل ، حيث ستختبر الإنتاجية.

ولكن ما هي الألعاب التي يمكنك لعبها بين عدد لا حصر له من اللاعبين؟ ربما شيء يتطلب التصويت للحصول على نتيجة.

لقد تذكرت نمط معضلة Prisoner ، حيث يحاول لاعبان تقليل خسائرهما إلى الحد الأدنى دون أن يكونا قادرين على التواصل مع بعضهما البعض ، لكنهما لم يعثرا على شكل لعبة مناسب لغرضي.

بعد ذلك عدت إلى لوحة الرسم: التصويت للحصول على نتيجة.

ثم أدركت أن أبسط شيء يمكنك القيام به هو مقص الصخور الورقية. لاعبان ، ثلاث حركات ، يختار كل مستخدم لاعب وحركة والأغلبية لكل لاعب يقرر الخطوة الأخيرة. ثم يمكن لعب اللعبة الفعلية بين الحركات المختارة بالأغلبية.

في النهاية ، أظهر الفريق سباقًا ممتعًا بين Deva وبعض الأشخاص المعروفين في الفضاء ، حيث تم دمج ورشة العمل التمهيدية مع الميمات المناسبة لـ Devcon some وبعض الإثارة .

ولكن ، ما زلت أرغب في إنشاء عرض مقص مقصور على ورق الصخور ، وبدا ETHSingapore وكأنه وقت مناسب للقيام بذلك! (زار Dark Vader و Blue Yoda سنغافورة ، لكن لم يتم تضمينهما في العرض التوضيحي ، نظرًا لوجود العديد من المشكلات الفنية الأخرى التي كان علي حلها )

الروبوتات تريد تشفير

لديك لعبة ، لديك Raiden ، لماذا تضيف متغيرًا آخر إلى المعادلة؟

والروبوتات تسبب الكثير من الألم وأنا لا أتحدث عن روبوت نهاية العالم. على الرغم من أنك ترى ، إلا أنني كنت أستعد الآن لفترة من الوقت لأصبح واحدًا من البشر المتسامحين: uRaiden Devcon3 Robo ، تريد طائرات بدون تشفير تشفيرًا أيضًا

  1. أنا وشريكي ، الذين بنوا بالفعل سيارة Devcon3 RC Car ، أحبوا الروبوتات حقًا. وقد أحضر بالفعل جيشًا منهم في المنزل ... إنه الأسرع في الحياة بالنسبة للأشخاص الذين لا يريدون أن يكبروا.
  2. الروبوتات ممتعة ولطيفة ( vs. meme duel الآن!)
  3. أنا وضعت صوتي يودا للعمل! (بداية مهنة أخرى ..)
  4. ولكن في الواقع ، تعطينا الروبوتات إحساسًا بما يمكن أن يكون عليه المستقبل.

كيف بدأت البناء؟

~ كان 5.5 يومًا كافيًا للقيام باتصالات الإعداد الأولي والنموذج الأولي لـ ETHSingapore.

ثم ، خلال عطلة الشتاء ، قمت ببناء اللعبة الحالية على رأس النموذج الأول.

أول الأشياء أولاً: اختبار SDK Robot

عرف شريكي بالفعل أن Wonder Robots كان لديه Python SDK واختبر بعض الأوامر. كان هذا هو الوقت المناسب لتقديم كلوديو ، صديق لنا للبرمجة - ماذا يمكن أن يكون أكثر متعة من برمجة الروبوتات؟ هكذا فعل! وأضاف أوامر لسلوك الفوز / الخسارة ، جنبا إلى جنب مع الموسيقى التصويرية المخصصة.

تدفق اللعبة

كنت قد كتبت بالفعل بعض الأفكار حول شكل اللعبة. لذلك ، بدلاً من إنشاء المخططات المنطقية للعبة في الوقت الحالي ، قفزت إلى مرحلة التنفيذ. تبين أن هذا كان خطوة سيئة ، لأنه "ساعد" على اتخاذ بعض القرارات الخاطئة بسبب عدم رؤية الصورة كاملة (حالات اللعبة المعاد تشكيلها و UI ، منطق خادم الألعاب المعيب عند حساب النتيجة ، هذا الخطأ الذي استغل.

قمت في نهاية المطاف بإصلاح الأشياء لاحقًا وإنشاء تسلسل منطقي أفضل:

المكونات النهائية

  1. الظلام فيدر RobotServer والأزرق يودا RobotServer
  2. GameGuardianServer
  3. GameGuardianRaidenNode
  4. GameClient
  5. بث مباشر على نشل

2 ، 3 ، 4 مستضافة على Digital Ocean VPS.

يتم استضافة خوادم الروبوت على جهازي كمبيوتر منزلي.

يقوم أحد أجهزة الكمبيوتر هذه أيضًا بالتدفق المباشر عبر كاميرا الويب. لقد جربنا الكثير من خيارات البث المباشر - من الأكثر شعبية إلى الاستضافة الذاتية ، وحتى النظر في الحلول اللامركزية ، ولكن جميعها كانت بها عيوب (زمن الوصول ، الدقة ، معرف الدفق الديناميكي ، مضيعة للوقت في الإعداد إلخ)

GameClient UI

لقد بدأت بالفعل مع واجهة المستخدم الأولى.

اقترح شريكي استخدام شريط التمرير نفسه الذي كان لدي بالفعل في Pipeline وإظهار كل حالة لعبة على شريحة فردية. أعتقد أن هذا كان فكرة عظيمة. شعرت وكأنها كتاب قصة.

تصدير const GameState = {
    null: 0، // لا توجد لعبة حالية قيد التشغيل
    open: 1 ، // أثناء وقت اللعبة ، يمكن للمستخدمين اتخاذ خطوات
    مغلق: 2 ، // أثناء وقت دقة اللعبة ، ينتظر المستخدمون النتائج والمدفوعات
    حل: 3 ، // اللعبة والقرار قد انتهت.
}

يمكنك رؤية رمز مشاهدات حالة اللعبة هنا.

GameGuardianServer

بعد امتلاك فكرة عن حالات اللعبة ، شرعت في تحديد نماذج اللعبة ونقلها ، والتي تتوافق مع مجموعات MongoDB لقاعدة البيانات. انظر الإصدار الحالي هنا.

ثم أضفت واجهة برمجة تطبيقات GameGuardian Raiden ونفذت منطق نتائج اللعبة ، لحساب الفائزين ، وإرسال المدفوعات خارج السلسلة وإطلاق تحركات الروبوت. أثار من قبل رمز؟ جعل العلاقات العامة لتحسينه!

move = await moveController.find ({where: {gameId: id}، order: ["_id ASC"]})؛
raidenPayments = ننتظر this.getRaidenPayments (TOKEN)
move.forEach (sentMove => {
    إذا (
        sentMove.amount &&
        sentMove.move &&
        sentMove.amount> = game.move_amount
    ) {
        raidenPayment = raidenPayments [0] .find ((payment) => {
            return payment.identifier === sentMove.paymentIdentifier؛
        })؛
        if (raidenPayment) {
            total_amount + = sentMove.amount؛
            move_count [sentMove.playerId] [sentMove.move] + = 1 ؛
            validMoves.push (sentMove)؛
        }
    }
})؛

sorted_moves_1 = Object.entries (move_count ['1']). sort ((a: any، b: any) => {return a [1] - b [1]})؛
sorted_moves_2 = Object.entries (move_count ['2']). sort ((a: any، b: any) => {return a [1] - b [1]})؛
move1 = sorted_moves_1 [2] [1]> 0؟ sorted_moves_1 [2] [0]: null؛
move2 = sorted_moves_2 [2] [1]> 0؟ sorted_moves_2 [2] [0]: RockPaperScissorsGetLoser [move1]؛
/ / إذا كان لدينا لاعب واحد ، فتأكد من فوزه
إذا (! move1) {
    move1 = RockPaperScissorsGetLoser [move2] ؛
}
winMove = RockPaperScissorsGetLoser [move1] === move2؟ move1: move2 ؛
validMoves.forEach ((move) => {
    / / نحن نكافئ كلا اللاعبين إذا كانت تحركاتهم النهائية هي نفسها
    إذا (move.move === winMove) {
        winningMoves.push (الخطوة)؛
    }
})؛
guardian_amount = total_amount / 10 ؛
total_amount - = guardian_amount؛
winner_amount = total_amount / winMoves.length؛
gameUpdate = {
        winningMove،
        player1:  {
            عدد: sorted_moves_1 [0] [1] + sorted_moves_1 [1] [1] + sorted_moves_1 [2] [1] ،
            نقل: move1 ،
            move_count: move_count ['1'] ،
        }،
        player2:  {
            عدد: sorted_moves_2 [0] [1] + sorted_moves_2 [1] [1] + sorted_moves_2 [2] [1] ،
            نقل: move2 ،
            move_count: move_count ['2'] ،
        }،
        المبلغ: winner_amount ،
        كميةالجاردي: guardian_amount ،
        اللاعبين: التحركات.
}؛

this.updateById (id، gameUpdate)؛
// جعل المدفوعات رايدن للفائزين
winMoves.forEach ((move) => {
    this.sendRaidenPayment (
        TOKEN،
        move.userAddress،
        winner_amount،
        move.paymentIdentifier
    )؛
})؛
this.sendRobotCommands (move1، move2، winMove)؛

إدارة الوقت: مفتاح النجاح

أو ألم تنفيذ أجهزة ضبط الوقت في جانب العميل ، والتي يجب أن تطابق الخادم.

تم توقيت اللعبة وحالات اللعبة موقوتة أيضًا. لأنني اخترت أن يكون لدي عدد لا حصر له من المستخدمين المتزامنين ، فقد اضطررت إلى قصر الدعم على لعبة واحدة فقط في كل مرة ، من أجل الحفاظ على التطوير بسيطًا.

إذن من الذي يبدأ اللعبة؟

يبدو أن إنشاء وظيفة cron server أو ما شابهها لإنشاء ألعاب بشكل منتظم هو أسوأ طريقة ، حيث إنها تملأ قاعدة البيانات بطريقة غير مجدية.

اخترت عميل أثار بداية لعبة جديدة. باختصار ، إذا لم يكن هناك لعبة حالية قيد التشغيل ، فسيتم إنشاء واحدة من قبل العميل. إذا كان هناك ، يتم إرسال بيانات اللعبة إلى العميل.

تحتوي بيانات اللعبة أيضًا على startTime للعبة ، جنبًا إلى جنب مع gameTime (إلى متى ستستمر الحالة المفتوحة) و determTime (إلى متى ستستمر الدقة). يستخدم العميل هذه القيم لتعيين المؤقتات هنا وهنا.

يتم استخدام أجهزة ضبط الوقت لتشغيل بعض الطلبات إلى GameGuardianServer. على سبيل المثال ، عندما تنتهي حالة GameOpen ، يرسل GameClient بيانات النقل الخام. أو عند الوصول إلى حالة GameResolved ، يتم إرسال طلب إلى الخادم لحل حالة اللعبة أو إرجاع حالة العزم إذا تم حلها بالفعل ، مما يؤدي إلى تشغيل GameGuardianServer لحساب الفائزين وإرسال المدفوعات خارج السلسلة وتحريك تحركات الروبوت .

الروبوتات - اللمسات الأخيرة

يتم استضافة خوادم الروبوت على جهازي كمبيوتر منزلي. لماذا اثنين؟ لأن كلا الروبوتين Dash & Cue يستخدمان Bluetooth للاتصال بالكمبيوتر. يقوم SDK الحالي أولاً بفصل جميع الأجهزة المتصلة ثم يربط الروبوت المناسب.

لكل روبوت طرق متعددة: الاتصال بالروبوت ، ضبط المظهر ، نقل أوامر الكلام ، أوامر الفوز / الخسارة. لقد اخترت استخدام Gunicorn ، لأننا نحتاج إلى الحفاظ على عملية الاتصال حية في جميع الأوامر.

لاحظ أننا نعيش دفق الروبوتات من وقت لآخر ، وقد حول هذا منزلنا في استوديو mime غريب.

لم يجعل اتصال الإنترنت وجهاز التوجيه المنزلي المهمة أسهل.

الاستنتاجات

أثار اهتمامك؟ جرب اللعبة: https://cryptoplayer.one

قم بالدردشة معنا لتقديم ملاحظات أو طلب المساعدة في إعداد قنوات Raiden الخاصة بك أو اتصل بنا لإيقاظ الروبوتات! شغب الدردشة

الجزء 2 يأتي قريبًا مع المزيد من الاستنتاجات وحيل الروبوت ... لكنني بحاجة إلى رؤية بعض التصفيق هنا!

قراءة: CryptoBotWars - الجزء 2: الاستنتاجات