CryptoBotWars sau Cum se construiește Demoți Shitty și de ce

De ce căcat? Pentru că îmi place auto deprecarea, iar jocul nu este aproape de producție.

Jetoane, roboți, canale de plată și fluxuri live

Așa că am construit CryptoBotWars, un joc în Rețeaua Raiden.

Vrei să-l joci? Citiți mai departe…

Aruncați o privire la joc, în spatele scenei sau proba live stream. Și alăturați-vă chatului nostru antidisturbiu!

De ce? ... Am avut câteva întrebări:

  1. Este ușor să construiești ceva pe vârful Raiden chiar acum? Ne lipsește ceva destul de ușor de schimbat?
  2. Cum ar funcționa Raiden chiar acum pentru plăți unu-la-multe și multe-la-unu, cazuri frecvent legate de companii
  3. Oare oamenii ar găsi bug-uri în Raiden? Cei mai buni testeri sunt testerii neîncărcați și noi.
  4. Raiden s-ar comporta frumos cu un randament ridicat?
  5. Plățile vor fi mediate cu succes (diverse locații și setări de sistem)

Un joc, în special combinat cu un anumit grad de divertisment, are potențialul de a stimula oamenii noi să încerce Raiden. Cu atât mai mult, dacă adăugați câteva recompense.

Un joc… sau un serviciu foarte serios, care ar accepta plățile în afara lanțului , dar nu am avut suficient timp pentru acesta din urmă, așa că acolo mergi:

Dark Vader și Blue Yoda. Supa bol și pălărie de ping-pong Santa Hat! Arata bine! ... de la 4 m distanță

Acest blogpost este dedicat parțial restaurantului thailandez, unde obțin supa mea preferată de nucă de cocos-tofu-veggie din Berlin . Acesta este motivul pentru care avem întotdeauna o grămadă de castroane pentru a face cască Vader și pălării Mos Craciun .

Cum a apărut ideea?

Într-o zi, în timpul prânzului, discutam idei pentru atelierul Devcon4 Raiden Network, încercând să ne gândim la o aplicație distractivă și simplă care poate fi construită în partea de sus a Raiden. Cumva, am ajuns la concluzia că un joc poate încuraja mai mulți oameni să îl încerce.

M-am gândit la un pic mai mult după aceea și am decis că un joc cu un număr nelimitat de utilizatori ar putea să-i prezinte mai bine lui Raiden, deoarece va testa randamentul.

Dar ce jocuri poți juca între un număr infinit de jucători? Poate ceva care a necesitat votarea pentru un rezultat.

Mi-am amintit de modelul Dilemmei prizonierului, în care doi jucători încearcă să-și reducă la minimum pierderea fără să poată comunica între ei, dar nu au putut găsi o variantă de joc adecvată scopului meu.

Am revenit apoi la tabloul de desene: votând pentru un rezultat.

Apoi mi-am dat seama că cel mai simplu lucru pe care îl puteți face este foarfeca de hârtie rock. Doi jucători, trei mișcări, fiecare utilizator alege un jucător și o mișcare, iar majoritatea pe jucător decide mutarea finală. Apoi, jocul propriu-zis poate fi jucat între cele două mișcări alese cu majoritate.

În cele din urmă, echipa a prezentat o cursă distractivă între Deva și unii oameni cunoscuți din spațiu, combinând atelierul introductiv cu memorii adecvate Devcon și o anumită emoție .

Dar, tot îmi doream să-mi construiesc demo-ul cu foarfece rock-paper și ETHSingapore mi s-a părut un moment bun pentru a face asta! (Dark Vader și Blue Yoda au vizitat Singapore, dar nu au fost incluși în demo, din cauza altor probleme tehnice diferite pe care a trebuit să le rezolv )

Roboții vor Crypto

Ai un joc, îl ai pe Raiden, de ce să adaugi o altă variabilă la ecuație?

Și roboții provoacă multă durere și nu vorbesc despre Apocalipsa robotului. Deși vezi, mă pregătesc de ceva vreme pentru a fi unul dintre oamenii tolerați: uRaiden Devcon3 Robo, Drones își doresc și cripto

  1. Eu și partenerul meu, care am construit de fapt mașina Devcon3 RC, ne plac foarte mult roboții. Și a adus deja o armată din ei în casă ... este cea mai sălbatică pentru oamenii care nu vor să crească.
  2. Roboții sunt amuzanți și drăguți ( vs. meme duel acum!)
  3. Mi-am pus vocea Yoda la treabă! (începutul încă o carieră ..)
  4. Însă, de fapt, roboții ne dau o idee despre viitorul care poate fi .

Cum am început să construiesc?

~ 5,5 zile au fost suficiente pentru a realiza configurațiile inițiale și conexiunile prototipului robotului pentru ETHSingapore.

Apoi, în timpul vacanței de iarnă am construit jocul actual pe partea de sus a primului prototip.

Primele lucruri în primul rând: Testarea robotului SDK

Partenerul meu știa deja că Robotii Wonder au un SDK Python și au testat unele dintre comenzi. Acesta a fost un moment bun pentru a-l prezenta pe Claudiu, un prieten al nostru în programare - ce poate fi mai distractiv decât roboții de programare ?? Așa a făcut! El a adăugat comenzi pentru comportamentul câștig / pierdere, împreună cu coloana sonoră personalizată.

Fluxul jocului

Am scris deja câteva idei despre cum ar putea arăta jocul. Așa că, în loc să creez de fapt diagramele logice ale jocului în acest moment, am sărit la faza de implementare. Aceasta s-a dovedit a fi o mișcare proastă, pentru că m-a „ajutat” să iau niște decizii greșite, din cauza faptului că nu văd întreaga imagine (stări de joc refactorate și interfață de utilizator, logică a serverului de joc defectuos la calculul rezultatului, acest bug de exploatare.

În cele din urmă am rezolvat lucrurile mai târziu și am creat o secvență logică mai bună:

Componente finale

  1. Dark Vader RobotServer & Blue Yoda RobotServer
  2. GameGuardianServer
  3. GameGuardianRaidenNode
  4. GameClient
  5. Live Stream pe Twitch

2, 3, 4 sunt găzduite pe un VPS digital Ocean.

Serverele robot sunt găzduite pe două calculatoare de acasă.

Unul dintre aceste calculatoare face și streamingul în direct prin webcam. Am încercat o mulțime de opțiuni de transmisie live - de la cele mai populare la self-hosting-uri, chiar analizând soluții descentralizate, dar toate aveau dezavantaje (latență, rezoluție, id flux dinamic, consumatoare de timp pentru a configura etc.)

UI GameClient

De fapt, am început mai întâi cu UI.

Partenerul meu mi-a sugerat să folosesc același glisor pe care îl aveam deja în Pipeline și să arătăm fiecare stare de joc pe o diapozitivă individuală. Am crezut că aceasta este o idee grozavă. S-a simțit ca o carte de povești.

export const GameState = {
    null: 0, // Niciun joc curent nu rulează
    open: 1, // În timpul jocului, utilizatorii pot face mișcări
    închis: 2, // În timpul rezoluției jocului, utilizatorii așteaptă rezultate și plăți
    rezolvat: 3, // Jocul și rezoluția s-au încheiat.
}

Puteți vedea codul de vizualizări al stării jocului aici.

GameGuardianServer

După ce am avut o idee despre stările jocului, am procedat la definirea jocului și mișcarea modelelor, care corespund colecției de date MongoDB. Vezi aici versiunea curentă.

Am adăugat apoi API-ul GameGuardian Raiden și am implementat logica rezultatelor jocului, pentru a calcula câștigătorii, a trimite plățile off-chain și a declanșa mișcările robotului. Declanșat de cod? fă un PR pentru a-l îmbunătăți!

move = așteaptă moveController.find ({unde: {gameId: id}, comandă: ["_id ASC"]});
raidenPayments = așteptați acest lucru.getRaidenPayments (TOKEN)
moves.forEach (sentMove => {
    dacă (
        sendMove.amount &&
        sendMove.move &&
        sendMove.amount> = joc.move_amount
    ) {
        raidenPayment = raidenPayments [0] .find ((plată) => {
            return return.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];
// Dacă avem un singur jucător, asigurați-vă că câștigă
if (! move1) {
    move1 = RockPaperScissorsGetLoser [move2];
}
winMove = RockPaperScissorsGetLoser [move1] === move2? mutare1: mutare2;
validMoves.forEach ((mutare) => {
    // Recompensăm ambii jucători dacă mutările lor finale sunt la fel
    if (move.move === winMove) {
        winningMoves.push (mutare);
    }
});
tutore_amount = total_amount / 10;
total_amount - = tutore_amount;
win_amount = total_amount / winMoves.length;
gameUpdate = {
        winningMove,
        player1:  {
            numără: sorted_moves_1 [0] [1] + sortat_moves_1 [1] [1] + sortat_moves_1 [2] [1],
            muta: mută1,
            move_count: move_count ['1'],
        },
        player2:  {
            numără: sorted_moves_2 [0] [1] + sortat_moves_2 [1] [1] + sortat_moves_2 [2] [1],
            muta: muta2,
            move_count: move_count ['2'],
        },
        suma: câștigător_amount,
        sumaGuardian: tutore_amount,
        jucători: moves.length,
};

this.updateById (id, gameUpdate);
// Efectuați plăți Raiden către câștigători
winMoves.forEach ((mutare) => {
    this.sendRaidenPayment (
        JETON,
        move.userAddress,
        winner_amount,
        move.paymentIdentifier
    );
});
this.sendRobotCommands (move1, move2, irabaziMove);

Managementul timpului: cheia succesului

Sau durerea implementării cronometrelor în partea clientului, care trebuie să se potrivească cu serverul.

Jocul este cronometrat și stările jocului sunt, de asemenea, cronometrate. Deoarece am ales să am un număr infinit de utilizatori simultan, a trebuit să limitez suportul la un singur joc la un moment dat, pentru a menține dezvoltarea simplă.

Deci, cine începe jocul?

Configurarea unui job cron server sau similar pentru a crea jocuri în mod regulat părea a fi cea mai proastă abordare, deoarece ar completa complet baza de date într-un mod inutil.

Am optat pentru un început de joc nou declanșat de un client. Pe scurt, dacă nu există un joc curent, atunci unul este creat de client. Dacă există, datele jocului sunt trimise clientului.

Datele jocului conțin, de asemenea, startTime-ul jocului, împreună cu gameTime (cât va dura starea deschisă) și resolTime (cât va dura rezoluția). Clientul folosește aceste valori pentru a seta cronometrele aici și aici.

Cronometrele sunt utilizate pentru a declanșa unele dintre solicitările către GameGuardianServer. De exemplu, când starea GameOpen s-a încheiat, GameClient trimite datele de mutare brute. Sau atunci când se ajunge la starea GameResolved, o solicitare este trimisă serverului pentru a rezolva starea jocului sau a returna starea de rezolvare dacă a fost deja rezolvată, declanșând GameGuardianServer pentru a calcula câștigătorii, trimite plățile off-chain și declanșează mutarea robotului. .

Roboți - atingeri finale

Serverele robot sunt găzduite pe două calculatoare de acasă. De ce două? Deoarece ambii roboți Dash & Cue folosesc Bluetooth pentru a se conecta la computer. SDK-ul actual deconectează mai întâi toate dispozitivele conectate și apoi conectează robotul corespunzător.

Fiecare robot are mai multe rute pentru: conectarea la robot, setarea aspectului, mutarea comenzilor de vorbire, comenzile câștig / pierdere. Am optat pentru utilizarea Gunicorn, deoarece trebuie să menținem viu procesul de conectare pe parcursul tuturor comenzilor.

Rețineți că trăim roboți din când în când, iar acest lucru ne-a transformat casa într-un studio ciudat de mime.

Conexiunea la internet și routerul de acasă nu a ușurat treaba.

concluzii

V-a stârnit interesul? Încercați jocul: https://cryptoplayer.one

Discutați cu noi pentru a da feedback sau pentru a solicita ajutor pentru configurarea canalelor Raiden sau pentru a ne face să trezim roboții! Chat anti-revoltă

Partea a 2-a va veni în curând cu mai multe concluzii și trucuri de robot ... dar trebuie să văd câteva clapete aici!

Citește și: CryptoBotWars - Partea 2: Concluzii