Od papíru ke kódu: Proč jsou Snap Pointy srdcem digitální deskovky
Když vyvíjíte deskovou hru, všechno se točí kolem interakce hráče s komponenty. Ve fyzickém světě je to jednoduché – vezmete figurku a položíte ji na políčko. Vaše oko a ruka přirozeně korigují polohu tak, aby figurka stála tam, kde má. V digitální verzi, ať už je to simulátor nebo plnohodnotná adaptace, ale tento “lidský cit” chybí. A právě tady nastupují Snap Pointy.
Co je to Snap Point?
Snap Point (v překladu něco jako “přichytávací bod”) je neviditelný (nebo i viditelný) magnet na herním plánu. Jakmile se s figurkou přiblížíte k tomuto bodu, hra ji automaticky “přicucne” přesně na střed daného místa.
Příklad z praxe: Doba kamenná (Stone Age) Koukněte se na herní plán populární hry Doba kamenná. Jsou tam jasně namalovaná místa:
- Kolečka v lese pro sběr dřeva.
- Místa v lomu na kámen.
- Políčka v chýši pro rozmnožování nebo na poli pro jídlo.
- Počítadlo bodů je celá soustava snappointů.
- Stupnice zásob úrody.
- Nabídka chýší nebo nabídka obchodu s kartami.
Ve fyzické hře jsou tyto body hezky graficky znázorněny, abyste věděli, kam položit dělníky, kam chýše, kam karty, kde počítat body… V digitální verzi jsou přesně v těchto místech definovány souřadnice Snap Pointů. Bez nich by herní plán vypadal po pár tazích jako chaos.

Jak to dělá Tabletop Simulator (a proč je to chytré)
V komunitě vývojářů prototypů je zlatým standardem Tabletop Simulator (TTS). Ten posunul Snap Pointy o úroveň výš. Nejsou to jen “souřadnice X a Y”, ale inteligentní objekty.
V TTS se tato funkce jmenuje Snap Points a má několik zásadních vlastností, které dělají hru plynulou:
- Rotation Snap (Orientace): V TTS můžete nastavit, aby se objekt po přichycení automaticky otočil konkrétním směrem. To je klíčové u karet – nechcete je jen položit na hromádku, chcete, aby se srovnaly podle orientace balíčku.
- Snap Point Tags (Omezení): Tohle je ta pravá magie. Snap Pointu můžete přiřadit tag (štítek). Pokud má Snap Point tag “Dělník” a vy tam zkusíte položit “Kartu civilizace”, Snap Point ji prostě nepřitáhne.
Tím v digitální verzi definujete pravidla hry přímo skrze fyziku herních komponent. Můžete tak omezit, že na políčko pro těžbu surovin smí jen figurky dělníků, nikoliv žetony jídla, nebo kostky osudu.
Proč jít v prototypování dál než za hranice Tabletop Simulatoru?
Možná se ptáte, proč při tvorbě digitálního prototypu vaší deskové stolní hry nezůstat u osvědčeného Tabletop Simulatoru (TTS). TTS je naprosto geniální jako fyzikální pískoviště – skvěle se tam tahají komponenty a vysvětlují pravidla „naživo“. Jenže jakmile chcete do hry dostat skutečné vynucování pravidel (rule enforcement), narazíte. Skriptování v LUA není pro každého a jeho naroubování na fyzikální engine TTS je občas dost krkolomné. Hráči tam mají absolutní volnost, což je sice fajn pro volnou zábavu, ale u komplexnějších her to může být na škodu. Moje hra Olgoj Chorchoj (stejně jako další moje projekty Gangzzz, Piknik u cesty, RunArch, Biatlon atd.) obsahuje spoustu počítání a nuancí, kterých chci hráče v digitální verzi zbavit. Nechci ale, aby výsledkem byla „excelová tabulka v grafice“. Proto volím Babylon.js. Umožňuje mi vytvořit vizuálně stejně působivou 3D scénu jako v TTS, ale s tím rozdílem, že díky TypeScriptu mám pod kontrolou vynucování pravidel, fázování hry a střídání tahů. Hráč se tak může soustředit na strategii, zatímco engine na pozadí hlídá, aby nikdo nepohnul figurkou, když nemá, nebo jí dal někam, kam nepatří a podobně a navíc počítá všechnu tu matematiku na pozadí za hráče.
Moje cesta: Z Illustratoru do Babylon.js přes Python
Rozhodl jsem se, že podobnou logiku se Snap Pointy, jakou používá TTS, přenesu i do svých vlastních digitálních prototypů, které teď nově začínám dělat v Babylon.js. Protože jsem v programování spíše začátečník, hledal jsem cestu, jak si práci usnadnit a nemuset souřadnice každého snappointu v kódu “střílet od boku” nebo číst očima v nějakém grafickém programu.
Můj aktuální workflow vypadá takto:
Adobe Illustrator:
Herní plán mám nakreslený ve vektorech. Každé jednotlivé místo, na které se ve hře pokládá figurka nebo karta, má většinou stejně nějakou grafickou podobu. Takže to řeším nakreslením koleček nebo čtverečků přímo do vizuálu té herní komponenty. Pokud nechci, aby tyhle “ošklivé geometrické obrazce byly vidět”, prostě je překryju nakonec nějakým plátnem s grafikou hry. Podobně, jako to vidíte na tom plánu té Doby kamenné. Důležité je, že mimo TTS, který má vlastní správu Snap Pointů, existuje tedy způsob, jak si do vlastních herních komponent pomocí nějakého vizuálního nástroje mohu umístit ty moje “snappointy”. A jednoduše je přesouvat a umisťovat na správná místa.
Pokud budou snappointy nakonec překryté nějakým plátnem, tak vlastně vůbec nezáleží na tom, jestli použijete kolečka nebo čtverečky a ani jak velké je uděláte, hlavně to musí být nějaký tvar, u kterého je možné snadno zjistit souřadnice jeho geometrického středu. Já to většinou řeším tak, že snappoint, ať už vidět bude nebo bude překrytý, má stejný půdorysný tvar jako žeton, figurka nebo karta, které se na něj ve fyzické hře budou pokládat. To mi dává hned i vizuální kontrolu nad tím, jestli se třeba někde nepřekrývají komponenty, které do hry přijdou. Ale v zásadě to klidně mohou být opravdu jen ta kolečka či malé čtverečky.
A teď přijde to důležité! Všechny snappointy, které spolu nějak souvisí, například jsou to snappointy v počítadle surovin nebo ta místa v lese v Době kamenné, dám do jedné vrstvy. Tu nějak popisně pojmenuji a přidám postfix “_snappoints”, takže mám například v Illustratoru vrstvu “Landing_track_snappoints”, pod kterou mám všechna políčka té stupnice, po které se bude ve hře Olgoj Chorchoj pohybovat počítadlo přesnosti přistání Výsadkářů na planetě Zerta.
Další důležitou věcí je, že každá jedna vrstva se snappointem, která je vnořenou vrstvou pod tou řídící vrstvou, má jedinečný název té vrstvy. A zase nejlépe nějaký popisný, nebo s nějakým interním významem. Třeba políčka pro bodování se mohou jmenovat právě tou bodovou hodnotou. Sám jsem si vytvořil poměrně komplexní systém pro pojmenovávání vrstev s objekty snappointů, aby se mi snadno s tím bodem jako s entitou pracovalo.
Dám opět příklad z Olgoje Chorchoje. Tam je na hráčské desce několik samostatných bodových stupnic. Jedna pro získávání vítězných bodů, jiná třeba výše uvedený “Landing track” a podobně. Tenhle “Landing track” je dvourozměrná matice, protože potřebuju nejenom evidovat, kolik bodů hráč za přesná přistání získal, ale protože sbírá body za přesnost Výsadkářů různých profesí, je třeba, aby označovače na té stupnici pro stejnou bodovou hodnotu bylo možné dát vedle sebe, nikoli na sebe, jak mnohdy v hrách stačí. Každý snappoint si tedy sám pamatuje, ke které skupině snappointů patří – to řeším prefixem v jeho názvu, tady například písmenkem “L”, dále jestli je v té matici snapointů v první nebo druhé nebo třetí nebo dokonce až ve čtvrté řadě – to řeším číslem řady, například 1 až 4, a konečně jaké bodové hodnoty se týká – to značím také číslem shodným s bodovým stavem, jen s tím rozdílem, že čísla menší než 10 doplním zleva uvozující nulou. Takže na první pohled vidím, že snappoint “L212” patří do “Landing track”, že se nachází ve druhé řadě snappointů a ve 12tém sloupci, který je vyhrazen pro evidenci zisku 12ti bodů. Co je nepříjemné na celé záležitosti, je přejmenovávání tolika vrstev (v tomhle případě 4×12=48) v Illustratoru z generických názvů “Vrstva 1”, “Vrstva 2” a tak dále, nebo třeba ze stejného “L101”, pokud jsem těch 48 koleček snappointů udělal pomocí kopírování a vkládání vrstev z té první základní. To je opruz, ale i na to už mám řešení. Zůstaňte naladěni, na konci článku prozradím.
Python Script:
Napsal jsem si skript, který vezme ten obrázek z Illustratoru a vyexportuje souřadnice těchto značek, těchto snappointů přímo z dat Illustratoru do souboru s daty. Jaký soubor nebo typ souboru je vhodný jako datová struktura prakticky na všechna data, která chcete o hře udržovat? Dozvíte se níže. Pokud nic jiného, tak si z tohoto odstavce pro stejně postižené lidi vymýšlením deskových her pamatujte, že Python je kamarád. A je třeba se ho nebát, protože za vás odvede spoustu černé práce na pozadí.
JSON jako “Jediná pravda”:
Výstupem skriptu v Pythonu je JSON soubor. Jasně, mohla by to být excelovská tabulka nebo jen csv soubor, ale pro ty, kteří JSON neznají, tak silně doporučuju, abyste se s jejím veličenstvem JSONem seznámili! Jeho obrovskou výhodou je jeho popisnost, protože si sebou nese jak názvy položek / klíčů, tak jejich hodnoty v rámci každého jednoho záznamu, takže je velmi dobře čitelný pro stroje i pro lidi. Tahle jeho obrovská výhoda je i jeho obrovskou nevýhodou – prostě je hrozně “ukecaný” a tak většinou vychází soubory mnohem větší, než v nějakém jiném formátu. Ta ukecanost s sebou totiž nese jistou režii, která může být klidně 50% a více, zejména, pokud máte hodně popisné názvy klíčů a poměrně atomické hodnoty v těch klíčích. Ale v tom množství dat, které s sebou nese projekt deskových her tohle jeho nabobtnání jistě unesete jak na disku, tak v textovém editoru a jeho scrollbaru, zejména tom vertikálním, protože jeden záznam o něčem se klidně může rozlést na několik jednotek až desítek řádků! Ale Python je s JSONem kamarád a i další technologie jsou s JSONem minimálně nakročeny k velmi prospěšnému sňatku, tak nevymýšlejte kolo a držte se JSON souborů pro uchovávání dat o hře. A ano, i framework a engine Babylon.js, který začínám používat jako náhradu za TTS při prototypování deskových her snadno JSON soubory načte a s minimem úsilí z nich automaticky vytvoří aktivní snappointy na herním plánu.

Takhle vypadá ukázka dat, se kterými pracuji:
{
"metadata": {
"source_file": "player_board_2026_v01.svg",
"base_width_px": 841,
"base_height_px": 492
},
"layers": {
"Hospital_snappoints": [
{
"id": "pit",
"x_px": 146,
"x_pct": 0.1746,
"z_px": 333,
"z_pct": 0.6774
},
{
"id": "far",
"x_px": 146,
"x_pct": 0.1746,
"z_px": 251,
"z_pct": 0.5103
},
{
"id": "wat",
"x_px": 146,
"x_pct": 0.1746,
"z_px": 168,
"z_pct": 0.3432
},
======spousta dalších snappointů pro nemocnici========
],
"Landing_track_snappoints": [
{
"id": "C5401",
"x_px": 242,
"x_pct": 0.2882,
"z_px": 113,
"z_pct": 0.2298
},
{
"id": "C5301",
"x_px": 242,
"x_pct": 0.2882,
"z_px": 215,
"z_pct": 0.4373
},
{
"id": "C5201",
"x_px": 242,
"x_pct": 0.2882,
"z_px": 181,
"z_pct": 0.3681
},
{
"id": "C5101",
"x_px": 242,
"x_pct": 0.2882,
"z_px": 147,
"z_pct": 0.299
},
{
"id": "C5402",
"x_px": 282,
"x_pct": 0.3354,
"z_px": 113,
"z_pct": 0.2298
},
======spousta dalších snappointů pro počítadlo přistávání========
]
}
}
V ukázce vidíte mnoho předností JSON souborů, třeba to, že v rámci jednoho souboru můžete uchovávat informace o více různých datových entitách – něco jako více databázových tabulek v jednom souboru společně, aniž by se ovlivňovaly a aniž by musely mít stejnou strukturu (i když to zrovna v ukázce mají, inu, jsou to všechno stejná entita – snappointy). Dokonce i dva snappointy moou mít, pokud vám to dává smysl, jiné informace, které o sobě drží. To mi připomíná trochu vzdáleně záznamy v Pascalu, kde také záznam nemusel mít vždy stejné informace, ale například jiné informace o ženách a jiné o mužích, ačkoli valná většina byla společných pro obě pohlaví.
Ukládám si jak jejich identifikátor, tak souřadnice snappointu, a to jak ve fyzických bodech, tak v procentních hodnotách, aby byla možná případná škálovatelnost velikosti této herní komponenty, což je herní deska hráče ve hře Olgoj Chorchoj.
Co mě čeká dál?
A to je zatím pro dnešek všechno. Další informace přidám v dalších článcích, protože tenhle už je dlouhý až až. I když základní systém funguje, stále je co zlepšovat. Aktuálně pracuji na dvou vylepšeních, která posunou zážitek blíž k profesionálním simulátorům:
- Automatická rotace: Chci, aby skript z Illustratoru poznal i natočení / orientaci snappointu a předal ho dál.
- Inteligentní filtry: Implementace systému tagů přímo do mého Babylon.js frameworku, aby Snap Pointy “věděly”, co na ně hráč pokládá, respektive co na ně položit může a co ne.
- Manažer snappointů: Bude samostatná aplikace, která mi pomůže tam, kde Illustrator už jako grafický program svou práci odvedl.
- Přejmenovávač vrstev: To je jednoduchý skript, respektive celá kaskáda malých skriptů a pomocných JSON souborů, které umožní jednoduché přejmenovávání vrstev se snappointy, což v Illustratoru je pruda, ale pro Python a JavaScript v Illustratoru je to chroupání písmenek, co ušetří spoustu času a nervů.
Digitální adaptace deskovky není jen o grafice, ale hlavně o tom, jak se ovládá. Dobře nastavené Snap Pointy jsou ten největší rozdíl mezi frustrací a plynulým herním zážitkem. Pokud vás zajímá game design nebo programování v Babylon.js, určitě doporučuji se touto cestou vydat! Případně sledujte, jestli zde něco dalšího přidám a podělím se tak s vámi o další postupy ze zákulisí tvůrce deskových her.