Internetové počítače nabízejí oproti tradičním platformám cloud computingu několik výhod, které poskytují efektivnější vývoj aplikací.

Jsem inženýr ve společnosti DFINITY, ale jsem také vývojář softwaru, takže jsem chtěl otestovat tento předpoklad a zhodnotit zkušenosti se stavbou na internetovém počítači z pohledu webového vývojáře.

Rozhodl jsem se postavit reverzibilní verzi, strategickou deskovou hru pro dva hráče, ne jako ukázkovou aplikaci, ale jako skutečnou aplikaci se všemi možnostmi a detaily, které jsem si představoval, že má mít oboustranná hra pro více hráčů.

Než se ponořím do zákulisí technických detailů, chci se zaměřit na koncept na vysoké úrovni: virtuální prostředí, kde se internetové aplikace mohou vzájemně hladce propojit.

Osobně věřím, že s růstem cloud computingu se infrastruktura stane komoditou. Jinými slovy, už nezáleží na tom, kdo poskytuje infrastrukturu.

Důležité je: napsali jste aplikaci a ta běží na internetu.

Programovací model

Zkušenosti s vývojem webových aplikací na internetovém počítači byly blízké zkušenostem (dnes již zaniklých) novějších platforem, jako je Parse nebo podobné.

Základním předpokladem takových platforem je skrýt složitost budování a údržby backendových služeb (např. HTTP servery, databáze, přihlašování uživatelů atd.).

Místo toho poskytují abstraktní virtuální prostředí, které jednoduše spouští uživatelské aplikace, aniž by uživatel věděl nebo musel věnovat pozornost tomu, kde a jak jejich aplikace běží.

V tomto světle je internetový počítač známý i odlišný.

Základním stavebním kamenem internetových počítačových aplikací je kontejner, což je koncepčně běžící proces v reálném čase, který:

  • Je 100% deterministický (pokud jsou všechny vstupy a stavy stejné, výstup musí být stejný)

  • Transparentní persistence (také nazývaná ortogonální persistence)

  • Komunikujte s uživateli nebo jinými kontejnery prostřednictvím asynchronního zasílání zpráv (vzdálená volání funkcí)

  • Zpracujte jednu zprávu po druhé (podle modelu herce)

Pokud uvažujeme o kontejnerech Docker jako o virtualizaci celého operačního systému (OS), pak kontejnery virtualizují jeden program a skrývají téměř všechny detaily OS.

Vzhledem k tomu, že nemůže spustit váš oblíbený operační systém nebo databázi, zdá se být příliš omezující. K čemu se používá?

Osobně upřednostňuji uvažování z hlediska disciplín spíše než omezení, s výjimkou zdůraznění dvou vlastností (mezi mnoha), které odlišují model kontejneru od běžných webových služeb:

  • Atomicita: Aktualizace stavu každé nádoby zpráv je atomická (vzdálené volání funkce), volání je úspěšné a stav je aktualizován, nebo je vyvolána chyba a stav se nedotkne (jako by volání nikdy neproběhlo).

  • Obousměrné zasílání zpráv: Zprávy jsou doručeny maximálně jednou a volajícímu je vždy zaručena odpověď, ať už úspěch nebo neúspěch.

Takové záruky je obtížné získat bez omezení funkčnosti uživatelských programů.

Doufejme, že na konci tohoto článku budete souhlasit s tím, že model s omezeným kontejnerem může skutečně dosáhnout hodně tím, že najde nejlepší kombinaci účinnosti, robustnosti a jednoduchosti.

Klient: Serverová architektura

Hry pro více hráčů vyžadují výměnu dat mezi hráči a jejich implementace se obvykle řídí architekturou klient-server:

  • Server hostí aktuální hru a spravuje komunikaci s herními klienty

  • Dva nebo více klientů (každý představuje hráče) získávají stav ze serveru, vykreslují herní uživatelské rozhraní a také přijímají vstup hráče pro předání serveru

Vytváření hry pro více hráčů jako webové aplikace znamená, že klient musí běžet v prohlížeči s využitím protokolu HTTP pro datovou komunikaci a pomocí Javascriptu (JS) k vykreslení uživatelského rozhraní hry jako webové stránky.

Pro tuto reverzní hru pro více hráčů bych chtěl implementovat následující funkce:

  • Kterýkoli dva hráči se mohou rozhodnout hrát proti sobě

  • Hráči získávají body vítězstvím ve hrách, které se také započítávají do jejich kumulativního skóre

  • Skóre ukazuje nejlepší hráče

  • Samozřejmostí je obvyklý herní postup: přebírání vstupů od každého hráče v pořadí, vynucování pouze zákonných tahů a detekce konce hry pro výpočet bodů.

Velká část této herní logiky je o manipulaci se stavy a implementace na straně serveru pomáhá zajistit hráčům konzistentní zorné pole.

Backend Server

V tradičním backendovém nastavení bych si musel vybrat sadu softwaru na straně serveru, včetně databáze pro uchovávání hráčských a herních dat, webového serveru pro zpracování požadavků HTTP a pak napsat vlastní aplikační software, který tyto dva spojí a implementuje úplnou sadu logiky na straně serveru.

V „bezserverovém“ nastavení již platforma obvykle poskytuje webové serverové a databázové služby a já jen potřebuji napsat aplikační software, který volá platformu, aby tyto služby používal.

Navzdory zavádějícímu termínu „bez serveru“ budou aplikace stále hrát roli „serveru“, jak je diktováno architekturou klient-server.

Bez ohledu na nastavení backendu je ústředním bodem mého návrhu aplikace sada rozhraní API, která řídí komunikaci mezi herním serverem a jeho klienty.

Vývoj této aplikace na internetovém počítači se nijak nelišil, takže jsem začal s následujícím návrhem toku hry na vysoké úrovni:

Poté, co se hráči zaregistrují, pokud libovolní dva z nich vyjádří touhu hrát spolu, prostřednictvím volání start(jméno protivníka), začne nová hra.

Hráči se pak střídají v umístění svého dalšího tahu a druhý hráč bude muset pravidelně volat view(), aby si obnovil pohled na nejnovější stav hry, pak provést další tah a tak dále, dokud hra neskončí.

Jednoduchým pravidlem je, že hráči mohou hrát vždy pouze jednu hru.

Server musí udržovat následující datové sady:

  • Seznam registrovaných hráčů, jejich jména a skóre atd.

  • Seznam probíhajících her, každá hra obsahuje nejnovější herní plán, kdo hraje černou a bílou hru, kdo smí provést další tah a konečný výsledek po dokončení hry atd.

Rozhodl jsem se implementovat server v Motoko, ale teoreticky by jakýkoli jazyk, který lze zkompilovat do Web Assembly (Wasm), měl fungovat dobře, pokud používá stejná systémová API pro komunikaci s internetovou komponentou. (V době psaní tohoto článku, Rust SDK skutečně vyjde brzy.)

Jako nový jazyk má Motoko určité hrubky (např. jeho základní knihovny jsou trochu nevyvinuté a ještě nejsou stabilní), ale již má ve VSCode podporu pro správce balíčků a protokol LSP (Language Server Protocol), díky čemuž je proces vývoje docela příjemný (jsem uživatel Vim).

V tomto článku nebudu rozebírat samotný jazyk Motoko.

Místo toho budu diskutovat o některých pozoruhodných funkcích Motoko a Internet Computer, díky kterým je vývoj kontejnerů vzrušující.

Stabilní proměnné

Ortogonální persistence (OP) není nová myšlenka.

Nové generace počítačového hardwaru, jako je NVRam, do značné míry odstranily překážky trvalého ukládání veškeré programové paměti a přístup k externímu úložišti, jako jsou systémy souborů, se pro programy stává volitelným.

Jedna výzva, která je často zmiňována v literatuře OP, se však týká upgradů, konkrétně co se stane, když aktualizace musí změnit datové struktury nebo rozložení paměti programu?

Motoko odpověděl na tuto otázku pomocí stabilních proměnných. Mohou přežít upgrady, což je podle mého názoru ideální pro zachování hráčských dat, protože nechci, aby hráči přišli o své účty, když aktualizuji software kontejneru.

Při běžném vývoji na straně serveru musím ukládat hráčské účty do souborů nebo databází, což je základní systémová služba „bezserverové“ platformy.

Stabilní mohou být pouze určité typy proměnných, ale jinak jsou stejné jako jakékoli jiné proměnné, které ukládají data na hromadu a lze je jako takové používat.

To znamená, že v současné době existuje omezení, které brání použití HashMaps jako stabilních proměnných, takže se musím uchýlit k polím. Zde je příklad:

Doufám, že budoucí verze DFINITY SDK toto omezení odstraní, takže budu moci jednoduše používat stabilní var player bez jakýchkoli konverzí.

Ověření uživatele

Každý kontejner, stejně jako každý klient (např. příkazový řádek dfx nebo prohlížeč) získá hlavní ID, které je jednoznačně identifikuje (u klientů je takové ID automaticky generováno z páru veřejného/soukromého klíče a spravuje ho knihovna DFINITY JS, která se aktuálně nachází v místním úložišti prohlížeče).

Motoko umožňuje kontejneru identifikovat volajícího „sdílené“ funkce, kterou můžeme použít pro účely autentizace.

Například definuji funkce registrace a prohlížení takto:

Výraz msg.caller udává hlavní ID volajícího zprávy. Všimněte si, že se liší od volajícího funkce.

V Motoko musí být zprávy odeslané hercům odeslány veřejně přístupné funkci, která musí mít asynchronní návratový typ.

Výše uvedený kód ukazuje dvě veřejné funkce: register a view, přičemž druhá je voláním dotazu, označeným klíčovým slovem query.

Jak vidíme, přístup k polím volajícího musí používat speciální syntaxi: shared(msg) nebo shared query(msg), kde msg je formální parametr, který odkazuje na předávanou zprávu jako celek.

V současné době má jedinou vlastnost, kterou má, je volající.

Možnost přístupu k jedinečnému ID volajícího (odesílatele zprávy) je povědomá, jako HTTP cookie.

Na rozdíl od HTTP však internetový počítačový protokol ve skutečnosti zajišťuje, že hlavní ID je kryptograficky bezpečné a že uživatelské programy běžící na internetovém počítači mohou plně důvěřovat jeho pravosti.

Osobně si myslím, že informování programu o svém volajícím je pravděpodobně příliš silné a příliš rigidní (např. co se stane, když je třeba takové ID změnit?).

Ale prozatím to vede k velmi jednoduchému schématu ověřování, které mohou vývojáři aplikací využít, a doufám, že v této oblasti uvidím další vývoj.

Souběžnost a atomicita

Herní klienti mohou posílat zprávy na herní server kdykoli, takže je odpovědností serveru správně zpracovat souběžné požadavky.

V konvenční architektuře bych musel vybudovat nějakou logiku, abych určil pořadí, ve kterém se hráči pohybují, obvykle prostřednictvím fronty zpráv nebo mutexu.

S modelem programování herců, který kontejner používá, se o to automaticky postará, aniž bych musel psát jakýkoli kód.

Zprávy jsou pouze vzdálená volání funkcí a kontejner je zaručeno, že zpracuje pouze jednu zprávu najednou. To vede ke zjednodušené programovací logice a vůbec se nemusím bát, že by se funkce volaly souběžně.

Protože stav kontejneru přetrvává až po úplném zpracování zprávy (tj. návrat běžného volání funkce), nemusím se starat o vyprázdnění paměti na disk, zda by výjimka nezpůsobila poškozený stav disku nebo cokoli jiného souvisejícího se spolehlivostí.

Všimněte si také, že atomicita trvalých změn stavu je na každou zprávu.

Veřejná funkce může volně volat jakoukoli jinou neasynchronní funkci, a pokud se celé provádění dokončí bez chyb, je změněný stav zachován (pro volání aktualizace jsou uvedeny další podrobnosti níže).

Jemnější granularity lze dosáhnout vydáváním asynchronních volání namísto synchronních volání, která se stávají novými zprávami do systému, které mají být naplánovány, nikoli okamžitě provedeny.

Pokud bych měl tuto hru postavit pomocí konvenční architektury, pravděpodobně bych také zvolil herní framework jako Akka pro Javu, Actix pro Rust atd.

Motoko poskytuje podporu nativním hercům a připojuje se k rodině programovacích jazyků založených na hercích, jako jsou Erlang a Pony.

Volání aktualizace vs. volání dotazu

Myslím, že tato funkce by mohla skutečně zlepšit uživatelskou zkušenost s internetovými počítačovými aplikacemi tím, že by je postavila na roveň tomu, co je hostováno na tradičních cloudových platformách (a řádově rychlejší ve srovnání s jinými blockchainy).

Je to také jednoduchý koncept: jakákoli veřejná funkce, která nevyžaduje změnu stavu programu, může být označena jako volání „dotazu“, jinak je ve výchozím nastavení považována za volání „aktualizace“.

Rozdíl mezi dotazy a aktualizacemi je latence a souběžnost:

  • Dokončení volání dotazu může trvat jen několik milisekund, zatímco volání aktualizace může trvat přibližně dvě sekundy.

  • Dotazová volání lze provádět souběžně s dobrou škálovatelností, aktualizační volání se provádějí sekvenčně (na základě modelu aktéra) a poskytují záruky atomicity.

Stejně jako ve výše uvedeném příkladu kódu jsem byl schopen označit funkci zobrazení jako volání dotazu, protože jednoduše vyhledá a vrátí stav hry, kterou hráč hraje.

Ve skutečnosti většinu času při procházení webu provádíme dotazovací volání: data se načítají ze serveru, ale neupravují se.

Na druhou stranu je výše uvedená funkce registrace zachována jako aktualizační volání, protože musí po úspěšné registraci přidat nového hráče do seznamu hráčů.

Volání aktualizace bude trvat déle z mnoha důvodů, včetně konzistence dat, atomicity a spolehlivosti.

Ale to není přirozený problém počítačů na internetu.

Dnes mnoho akcí na webu trvá doslova déle než dvě sekundy, jako je platba kreditní kartou, zadání objednávky nebo přihlášení k bankovnímu účtu, abychom jmenovali alespoň některé.

Myslím, že dvě sekundy jsou kritickým bodem pro dobrou uživatelskou zkušenost.

Vrátíme-li se zpět k reverzní hře, když hráč provede další tah, musí to být také výzva k aktualizaci:

Pokud hra obnoví obrazovku pouze dvě sekundy poté, co hráč klikne myší (nebo se dotkne obrazovky), nebude reagovat a nikdo nebude chtít hrát hru s tak špatným načasováním.

Proto jsem musel tuto část optimalizovat tak, že jsem reagoval na vstup uživatele přímo na klientovi, aniž bych musel čekat na odpověď serveru.

To znamená, že front-end UI bude muset ověřit hráčovy tahy, vypočítat, které figurky budou převráceny, a okamžitě je zobrazit na obrazovce.

To také znamená, že cokoli, co frontend zobrazí hráči, když se to vrátí, musí odpovídat odpovědi serveru na stejnou akci, jinak riskujeme nekonzistenci.

Ale znovu se domnívám, že jakákoli rozumná implementace obousměrné hry pro více hráčů nebo šachové hry by to dokázala bez ohledu na to, zda její backendu trvá odpověď 200 ms nebo 2 sekundy.

Přední zákazníci

Sada DFINITY SDK poskytuje rozhraní, které načítá aplikace přímo do prohlížeče.

Liší se však od běžných HTML stránek obsluhovaných webovým serverem.

Komunikace s backendovým kontejnerem probíhá prostřednictvím vzdálených volání funkcí, které jsou v případě prohlížeče překryty nad HTTP.

To transparentně zpracovává uživatelská knihovna JS, takže program JS může pouze importovat kontejner jako objekt JS a může volat své veřejné funkce stejně jako běžné asynchronní funkce JS objektu.

Sada DFINITY SDK obsahuje sadu návodů, jak nastavit frontend JS, takže zde nebudu zacházet do podrobností.

Příkaz dfx v sadě SDK používá Webpack ke sdružování vašich aktiv, včetně JS, CSS, obrázků a dalších souborů, které můžete mít.

Můžete také zkombinovat svůj oblíbený rámec JS (jako je React, AngularJS, Vue.js atd.) s uživatelskou knihovnou DFINITY a vyvinout front-end JS pro použití v prohlížeči nebo mobilní aplikaci.

Hlavní komponenty uživatelského rozhraní

Jsem relativně nový ve vývoji front-endu a s Reactem mám jen krátké zkušenosti.

Tentokrát jsem si dovolil naučit se Mithril, protože jsem o Mithrilu slyšel mnoho dobrých věcí, zejména jeho jednoduchost.

Pro jednoduchost jsem také navrhl design pouze se dvěma obrazovkami:

  • Obrazovka „Hrát“, která umožňuje hráčům zadat své vlastní jméno a jméno soupeře před vstupem na obrazovku „Hra“. Zobrazí také některé tipy a pokyny, žebříček nejlepších hráčů, nedávných hráčů a další.

  • „Herní“ obrazovka, která přijímá vstup hráče a komunikuje s backendovým kontejnerem, aby vykreslila obrácenou šachovnici. Na konci hry se také zobrazí skóre hráče a poté se hráč vrátí na obrazovku hry.

Následující fragment kódu ukazuje kostru frontendu hry JS:

Je třeba poznamenat několik věcí:

  • Stejně jako každá jiná knihovna JS se importuje reversi hlavního backendového kontejneru. Představte si to jako proxy, která předává volání funkcí na vzdálené servery, přijímá odpovědi a transparentně zpracovává nezbytnou autentizaci, podepisování zpráv, serializaci/deserializaci dat, šíření chyb atd.

  • Bude také importován další kontejner reversi_assets. Toto je způsob, jak získat potřebná aktiva v balíčku Webpack při montáži backendového kontejneru. V tomto případě mám zvukový soubor, který se přehraje, když přehrávač umístí nový kus.

  • Obrázek loga, který jde přímo do akce. To je třeba nakonfigurovat ve Webpacku pomocí url-loaderu, což je nástroj, který ve skutečnosti vloží obsah obrázku jako řetězec Base64, který se má použít pro prvek obrázku. Funguje pro malé obrázky, ale ne pro velké obrázky.

  • Konečná aplikace je nastavena pomocí Mithril se dvěma cestami: /play a /game. Ten bere jméno hráče a soupeře jako dva parametry, což umožňuje znovu načíst herní obrazovku do prohlížeče bez přerušení hry.

Načítání zdrojů z kontejneru aktiv

Protože jsem v asynchronním načítání prvků DOM v JS nový, trochu s tím bojuji.

Když dfx sestaví jar, vytvoří také jar reversi_assets, který v podstatě pouze zabalí vše v src/reversi_assets/assets/.

Používám to k načtení zvukového souboru, ale jeho správné načtení není tak přímočaré, jako pouhé umístění adresy URL souboru mp3 do pole src prvku HTML.

Takto to načtu (pokud jste front-end vývojář, pravděpodobně to už víte):

Když je zavolána funkce start (z asynchronního kontextu), pokusí se načíst soubor "put.mp3" ze vzdáleného kontejneru.

Po úspěšném načtení použije JS nástroj AudioContext k dekódování zvukových dat a inicializaci globální proměnné putsound.

Pokud je putsound správně inicializován, volání playAudio (putsound) přehraje skutečný zvuk:

Ostatní zdroje lze načíst podobným způsobem. Nepoužívám žádné obrázky kromě loga, logo je poměrně malé a jeho zdrojový kód lze vložit do Webpack přidáním následující konfigurace do webpack.config.js:

Formát výměny dat

Koncept Motoko je „sdílitelná“ data, tedy data, která lze posílat přes hranice kontejneru nebo jazyka.

Samozřejmě bych si nepředstavoval ukazatel haldy v C jako „sdílitelný“, ale podle mě může být „sdíleno“ vše, co lze namapovat na JSON.

Za tímto účelem vyvinula společnost DFINITY jazyk IDL (Interface Description Language) nazvaný Candid for Internet Computer applications.

Candid výrazně zjednodušuje způsob, jakým frontendy komunikují s backendy nebo mezi kontejnery.

Zde je například (neúplný) fragment backendového reverzibilního kontejneru popsaného Candidem:

Vezměte si jako příklad metodu přesunu:

  • Toto je jedna z metod exportovaných v rozhraní služby kontejneru.

  • Jako vstup bere dvě celá čísla (představující souřadnici) a vrací výsledek typu MoveResult.

  • MoveResult je varianta (aka výčet), která představuje možné výsledky a chyby, které mohou nastat, když se hráč pohybuje.

  • V každé větvi MoveResult GameOver označuje, že hra je dokončena, a bere parametr ColorCount, který představuje počet černých a bílých figurek na herním plánu.

Zdrojový kód Motoko automaticky generuje soubor Candid pro každý kontejner a je automaticky používán uživatelskou knihovnou JS bez účasti vývojáře:

  • Na straně Motoko každý typ Candid odpovídá typu Motoko a každá metoda odpovídá veřejné funkci.

  • Na straně JS každý typ Candid odpovídá objektu JSON a každá metoda odpovídá členské funkci importovaného objektu kontejneru.

Většina typů Candid má přímou reprezentaci JS, některé vyžadují určitou konverzi.

Například nat má libovolnou přesnost v Motoko i Candid a v JS je mapován na celé číslo bignumber.js, takže musí být převeden na typ nativního čísla JS pomocí n.toNumber().

Jeden problém, který mám, je s nulovými hodnotami v Candid (a typu Motoko's Option).

V JSON je reprezentován jako prázdné pole [] namísto jeho nativního null. Toto slouží k rozlišení případu, kdy máme vnořené možnosti, jako je Option>:

Candid je velmi výkonný, i když na povrchu to zní hodně jako Protocolbuf nebo JSON.

Proč je to tedy nutné?

Kromě toho, co je zde uvedeno, existuje mnoho dobrých důvodů a doporučuji každému, kdo se o toto téma zajímá, aby si přečetl Candid Spec.

Synchronizace stavu hry s backendem

Jak již bylo zmíněno, používám trik, jak okamžitě reagovat na platný uživatelský vstup, aniž bych musel čekat na odpověď backendového herního serveru.

To znamená, že frontend potřebuje potvrzení od herního serveru pouze po pohybu hráče (nebo ošetření chyb, pokud existuje).

Kromě zasílání vlastních tahů si klient musí být vědom i tahů druhého hráče.

Toho je dosaženo pravidelným voláním funkce view() herního kontejneru hostovaného na straně serveru.

Důsledkem tohoto návrhu je, že musím duplikovat stejnou herní logiku jak v backendu (Motoko), tak ve frontendu (JS), což není ideální.

Protože Motoko může kompilovat do Wasm a Wasm může běžet v prohlížeči, nebylo by skvělé, kdyby frontend i backend mohly sdílet stejný modul Wasm, který implementuje základní logiku hry? Toto sdílení sdílí pouze kód, nikoli stát.

Může to vyžadovat nějaké nastavení, ale myslím, že je to zcela možné a mohl bych to zkusit v pozdější aktualizaci.

Zejména pro obrácenou hru existují situace, kdy jednomu hráči může být zabráněno v jakékoli akci, takže druhý hráč může provést dvě po sobě jdoucí akce nebo i více.

Abych ukázal každý pohyb hráče, rozhodl jsem se implementovat stav hry jako sled akcí, nikoli pouze poslední stav herního plánu.

To také znamená, že porovnáním seznamu akcí v místním stavu frontendu s tím, co bylo vráceno voláním funkce view(), můžeme snadno zjistit, co se změnilo od poslední akce hráče (když je na něm řada, aby provedl další tah) atd.

SVG animace

Téma animací pomocí Scalable Vector Graphics (SVG) do tohoto článku pravděpodobně nepatří, ale jednou jsem s tím opravdu bojoval.

Chci se tedy podělit o ponaučení, které jsem se naučil.

Problém, který mám, je, že když použiji nastavení repeatCount k zobrazení animace pouze jednou, animace se nespustí.

Většina online zdrojů na SVG poskytuje pouze příklady, které se nekonečně opakují nebo používají nastavení repeatCount.

Implicitně předpokládají, že pokud se má animace zobrazit pouze jednou, spusťte animaci po načtení stránky (nebo nastavte nějaké zpoždění).

U většiny jednostránkových aplikačních frameworků (jako React nebo Mithril) se však stránka obvykle znovu nenačte, ale pouze znovu vykreslí.

Takže když chci ukázat herní klip překlápějící se z bílé na černou nebo z černé na bílou, musí se to stát, když se stránka znovu vykreslí, ne když se stránka znovu načte.

Tento zásadní rozdíl mi unikal a objevil jsem ho až po mnoha pokusech.

Takže takto vykresluji animovaný prvek (jako dítě SVG) pomocí Mithril, kde se rx elipsy mění z počátečního poloměru na 0 a zpět.

Vysvětlení je následující:

  • begin je nastaveno na neurčité, takže animaci lze ovládat/spouštět ručně

  • Výplň je nastavena na zmrazené, což znamená, že po skončení animace zůstane její koncový stav nezměněn.

  • Hodnota je nastavena na 4 hodnoty, přičemž první dvě se opakují jako trik pro spuštění animace po prodlevě 0,1 s (1/4 doby trvání), protože začátek byl nastaven na neurčito

Hlavním bodem je, že animace by měla být spuštěna ručně. Používám setTimeout k jeho spuštění se zpožděním 0s, což je trik, jak počkat, až se nový prvek uživatelského rozhraní připravený Mithrilem vykreslí v prohlížeči DOM:

Jak bylo uvedeno výše, jakýkoli animovaný prvek, jehož ID nezačíná „tečkou“, se okamžitě spustí.

Vývojový proces

Hru jsem vyvíjel na Linuxu a počáteční nastavení spočívalo v instalaci sady DFINITY SDK a podle jejích pokynů k vytvoření projektu.

Je těžkopádné pamatovat si všechny příkazové řádky dfx, tak jsem vytvořil Makefile, který vám pomůže.

Ladění a testování se většinou provádí v prohlížeči, takže je potřeba hodně console.log().

V Motoko vlastně existuje způsob, jak psát testy jednotek, ale dozvěděl jsem se o tom až poté, co jsem napsal hru.

Zpočátku jsem také vyvinul terminálový frontend pomocí skriptů shellu a dfx.

Myslím, že by to pomohlo urychlit ladění, aniž byste museli procházet prohlížečem.

Testování jednotek je ale samozřejmě lepší způsob, jak zajistit správnost.

Hrajte hry!

Aby bylo možné tuto hru skutečně spustit na internetovém počítači, existuje nyní síť Tungsten Network, která je otevřena vývojářům třetích stran.

Doporučuji vám zaregistrovat se, naklonovat tento projekt a nasadit hru sami, abyste získali vývojářské zkušenosti z první ruky.

Aplikace na Tungstenu však nejsou přístupné nevývojářům, protože zatím nejsou veřejné.

Tak jsem to také hostoval sám pomocí dfx a nginx jako reverzní proxy, abych mohl pozvat přátele ke hře.

Nedoporučuji lidem, aby to dělali sami, protože software je stále ve verzi alfa.

Zde je odkaz na skutečnou hru, jen pro demonstrační účely. Můj plán je nasadit jej na veřejnou internetovou počítačovou síť po jejím spuštění koncem tohoto roku.

Pokud máte nějaké dotazy, neváhejte navštívit úložiště projektu a odeslat problémy, vítány jsou také žádosti o stažení!

Připojte se k naší komunitě vývojářů a začněte stavět na forum.dfinity.org.

Obsah IC, na kterém vám záleží

Technologický pokrok |. Globální aktivity |

Sbírejte a sledujte kanál IC Binance

Získejte nejnovější zprávy