{"id":12898,"date":"2026-04-12T22:30:08","date_gmt":"2026-04-12T22:30:08","guid":{"rendered":"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/"},"modified":"2026-04-12T22:30:12","modified_gmt":"2026-04-12T22:30:12","slug":"architektura-kodu-gry","status":"publish","type":"post","link":"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/","title":{"rendered":"Jak zaplanowa\u0107 architektur\u0119 kodu gry, by unikn\u0105\u0107 chaosu w p\u00f3\u017anym etapie produkcji"},"content":{"rendered":"\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-top\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;12898&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;top&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;0&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;0&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;0\\\/5 - (0 votes)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;title&quot;:&quot;Jak zaplanowa\u0107 architektur\u0119 kodu gry, by unikn\u0105\u0107 chaosu w p\u00f3\u017anym etapie produkcji&quot;,&quot;width&quot;:&quot;0&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 0px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 19.2px;\">\n            <span class=\"kksr-muted\">Rate this post<\/span>\n    <\/div>\n    <\/div>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_81 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Z tego wpisu dowiesz si\u0119\u2026<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Prze\u0142\u0105cznik Spisu Tre\u015bci\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #000000;color:#000000\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #000000;color:#000000\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Scenka_z_poznej_produkcji_kiedy_kod_zaczyna_sie_mscic\" >Scenka z p\u00f3\u017anej produkcji: kiedy kod zaczyna si\u0119 m\u015bci\u0107<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Czym_jest_dobra_architektura_w_grach_i_czym_rozni_sie_od_aplikacji_biznesowych\" >Czym jest dobra architektura w grach i czym r\u00f3\u017cni si\u0119 od aplikacji biznesowych<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Specyfika_gier_petla_glowna_i_morze_stanow\" >Specyfika gier: p\u0119tla g\u0142\u00f3wna i morze stan\u00f3w<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Balans_czystosc_wydajnosc_i_czas_produkcji\" >Balans: czysto\u015b\u0107, wydajno\u015b\u0107 i czas produkcji<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Dlaczego_dogmatyczny_OOP_i_DDD_czesto_zawodza_w_grach\" >Dlaczego dogmatyczny OOP i DDD cz\u0119sto zawodz\u0105 w grach<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Pragmatyczne_kryteria_oceny_architektury_gry\" >Pragmatyczne kryteria oceny architektury gry<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Fundamenty_rozbijanie_gry_na_warstwy_i_moduly\" >Fundamenty: rozbijanie gry na warstwy i modu\u0142y<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Logiczne_warstwy_oddzielenie_gry_od_silnika\" >Logiczne warstwy: oddzielenie gry od silnika<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Moduly_tematyczne_zamiast_jednego_wielkiego_projektu\" >Modu\u0142y tematyczne zamiast jednego wielkiego projektu<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Jak_zaczac_od_malego_rozwojowego_podzialu\" >Jak zacz\u0105\u0107 od ma\u0142ego, rozwojowego podzia\u0142u<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Konsekwencja_granic_co_jesli_system_%E2%80%9Emusi%E2%80%9D_siegnac_do_innego\" >Konsekwencja granic: co je\u015bli system \u201emusi\u201d si\u0119gn\u0105\u0107 do innego?<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Jak_planowac_architekture_juz_na_etapie_prototypu\" >Jak planowa\u0107 architektur\u0119 ju\u017c na etapie prototypu<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Brudny_prototyp_vs_prototyp_ktory_moze_isc_do_produkcji\" >Brudny prototyp vs prototyp, kt\u00f3ry mo\u017ce i\u015b\u0107 do produkcji<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Minimalne_zasady_prototypowania_ktore_ratuja_produkcje\" >Minimalne zasady prototypowania, kt\u00f3re ratuj\u0105 produkcj\u0119<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Decyzje_ktore_mozna_odlozyc_i_te_ktore_trzeba_podjac_od_razu\" >Decyzje, kt\u00f3re mo\u017cna od\u0142o\u017cy\u0107, i te, kt\u00f3re trzeba podj\u0105\u0107 od razu<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Style_architektury_w_grach_od_OOP_do_ECS_i_podejscia_mieszane\" >Style architektury w grach: od OOP do ECS i podej\u015bcia mieszane<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-17\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Kiedy_klasyczne_OOP_dziala_dobrze\" >Kiedy klasyczne OOP dzia\u0142a dobrze<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-18\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Gdzie_ECS_faktycznie_pomaga_a_gdzie_jest_przerostem_formy\" >Gdzie ECS faktycznie pomaga, a gdzie jest przerostem formy<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-19\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Hybrydy_%E2%80%93_pragmatyczny_srodek\" >Hybrydy \u2013 pragmatyczny \u015brodek<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-20\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Jak_nie_utknac_miedzy_paradygmatami\" >Jak nie utkn\u0105\u0107 mi\u0119dzy paradygmatami<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-21\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Projektowanie_systemow_gry_granice_odpowiedzialnosci_i_przeplyw_komunikatow\" >Projektowanie system\u00f3w gry: granice, odpowiedzialno\u015bci i przep\u0142yw komunikat\u00f3w<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-22\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#System_jako_%E2%80%9Eusluga%E2%80%9D_dla_reszty_gry\" >System jako \u201eus\u0142uga\u201d dla reszty gry<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-23\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Jak_wyznaczac_granice_systemow\" >Jak wyznacza\u0107 granice system\u00f3w<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-24\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Mechanizmy_komunikacji_bezposrednie_wywolania_eventy_message_bus\" >Mechanizmy komunikacji: bezpo\u015brednie wywo\u0142ania, eventy, message bus<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-25\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Bezposrednie_wywolania_serwisy_interfejsy\" >Bezpo\u015brednie wywo\u0142ania (serwisy, interfejsy)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-26\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Eventy_i_callbacki\" >Eventy i callbacki<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-27\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Message_bus_event_bus\" >Message bus \/ event bus<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-28\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Unikanie_%E2%80%9EBoga_systemu%E2%80%9D\" >Unikanie \u201eBoga systemu\u201d<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-29\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Dane_konfiguracja_i_balans_%E2%80%93_trzymanie_logiki_z_dala_od_contentu\" >Dane, konfiguracja i balans \u2013 trzymanie logiki z dala od contentu<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-30\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Single_source_of_truth_dla_danych_gameplayowych\" >Single source of truth dla danych gameplayowych<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-31\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Oddzielenie_danych_statycznych_od_stanu_gry\" >Oddzielenie danych statycznych od stanu gry<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-32\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Narzedzia_dla_designerow_zamiast_ifow_w_kodzie\" >Narz\u0119dzia dla designer\u00f3w zamiast if\u00f3w w kodzie<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-33\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Edytowalnosc_i_bezpieczenstwo\" >Edytowalno\u015b\u0107 i bezpiecze\u0144stwo<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-34\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Testowanie_architektury_jak_nie_oszukac_samego_siebie\" >Testowanie architektury: jak nie oszuka\u0107 samego siebie<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-35\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Systemy_gry_jako_testowalne_%E2%80%9Eczarne_skrzynki%E2%80%9D\" >Systemy gry jako testowalne \u201eczarne skrzynki\u201d<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-36\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Testy_regresji_dla_contentu_nie_tylko_dla_kodu\" >Testy regresji dla contentu, nie tylko dla kodu<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-37\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Symulacje_i_%E2%80%9Etime-lapse%E2%80%9D_na_silniku\" >Symulacje i \u201etime-lapse\u201d na silniku<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-38\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Architektura_pod_multiplayer_i_siec_minimalizowanie_bolu_synchronizacji\" >Architektura pod multiplayer i sie\u0107: minimalizowanie b\u00f3lu synchronizacji<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-39\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Input_jako_zdarzenia_nie_jako_bezposrednia_zmiana_stanu\" >Input jako zdarzenia, nie jako bezpo\u015brednia zmiana stanu<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-40\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Stan_gry_jako_cos_co_da_sie_replikowac\" >Stan gry jako co\u015b, co da si\u0119 replikowa\u0107<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-41\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Separacja_%E2%80%9Eautoritative_logic%E2%80%9D_od_reszty\" >Separacja \u201eautoritative logic\u201d od reszty<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-42\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Skalowanie_zespolu_a_architektura_jak_nie_zadeptac_sobie_nawzajem_kodu\" >Skalowanie zespo\u0142u a architektura: jak nie zadepta\u0107 sobie nawzajem kodu<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-43\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Wlasnosc_modulow_i_kontrakty_miedzy_zespolami\" >W\u0142asno\u015b\u0107 modu\u0142\u00f3w i kontrakty mi\u0119dzy zespo\u0142ami<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-44\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Granice_repozytoriow_i_feature_branchy\" >Granice repozytori\u00f3w i feature branchy<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-45\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Komunikacja_techniczna_jako_czesc_projektu\" >Komunikacja techniczna jako cz\u0119\u015b\u0107 projektu<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-46\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Najczesciej_zadawane_pytania_FAQ\" >Najcz\u0119\u015bciej zadawane pytania (FAQ)<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-47\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Jak_zaplanowac_architekture_gry_zeby_uniknac_chaosu_pod_koniec_produkcji\" >Jak zaplanowa\u0107 architektur\u0119 gry, \u017ceby unikn\u0105\u0107 chaosu pod koniec produkcji?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-48\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Jak_podzielic_kod_gry_na_warstwy_w_Unity_Unreal_lub_Godot\" >Jak podzieli\u0107 kod gry na warstwy w Unity, Unreal lub Godot?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-49\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Czym_rozni_sie_dobra_architektura_gry_od_architektury_aplikacji_biznesowych\" >Czym r\u00f3\u017cni si\u0119 dobra architektura gry od architektury aplikacji biznesowych?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-50\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Dlaczego_klasyczne_OOP_i_DDD_czesto_zle_sie_sprawdzaja_w_game_devie\" >Dlaczego klasyczne OOP i DDD cz\u0119sto \u017ale si\u0119 sprawdzaj\u0105 w game devie?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-51\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Jak_podzielic_gre_na_moduly_zeby_zespolowi_bylo_latwiej_pracowac\" >Jak podzieli\u0107 gr\u0119 na modu\u0142y, \u017ceby zespo\u0142owi by\u0142o \u0142atwiej pracowa\u0107?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-52\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Jakie_sa_praktyczne_kryteria_oceny_czy_architektura_gry_jest_dobra\" >Jakie s\u0105 praktyczne kryteria oceny, czy architektura gry jest dobra?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-53\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Czy_w_malej_grze_indie_naprawde_potrzebna_jest_przemyslana_architektura\" >Czy w ma\u0142ej grze indie naprawd\u0119 potrzebna jest przemy\u015blana architektura?<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-54\" href=\"https:\/\/excelraport.pl\/index.php\/2026\/04\/12\/architektura-kodu-gry\/#Zrodla\" >\u0179r\u00f3d\u0142a<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"Scenka_z_poznej_produkcji_kiedy_kod_zaczyna_sie_mscic\"><\/span>Scenka z p\u00f3\u017anej produkcji: kiedy kod zaczyna si\u0119 m\u015bci\u0107<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Deadline zbli\u017ca si\u0119 szybciej ni\u017c komukolwiek jest wygodnie, QA zg\u0142asza kilkana\u015bcie krytycznych bug\u00f3w dziennie, a ka\u017cda poprawka w systemie ekwipunku nagle psuje walk\u0119, zapis gry i UI. Zesp\u00f3\u0142 zamiast dodawa\u0107 ostatnie szlify, gasi po\u017cary, bo nikt ju\u017c nie rozumie, jak wszystko jest ze sob\u0105 po\u0142\u0105czone. I wtedy pada zdanie: \u201eGdyby\u015bmy tylko od pocz\u0105tku lepiej zaplanowali architektur\u0119 kodu gry\u201d.<\/p>\n<p>Do takiego chaosu zwykle nie dochodzi przez jeden wielki b\u0142\u0105d, ale przez setki ma\u0142ych decyzji z fazy prototypu i wczesnej produkcji. Ka\u017cde \u201ena szybko\u201d, ka\u017cdy \u201etylko tu podepn\u0119 si\u0119 do tego singletona\u201d, ka\u017cdy \u201ezrobimy porz\u0105dnie p\u00f3\u017aniej\u201d sk\u0142adaj\u0105 si\u0119 na architektur\u0119, kt\u00f3ra m\u015bci si\u0119 wtedy, gdy powinna by\u0107 najbardziej stabilna.<\/p>\n<p>Pierwsza kluczowa lekcja: <strong>architektura kodu gry nie jest luksusem zarezerwowanym dla AAA<\/strong>. Jest tarcz\u0105 przed parali\u017cem projektu, tak\u017ce (a cz\u0119sto przede wszystkim) w ma\u0142ym indie, gdzie nie ma dzia\u0142u narz\u0119dzi, armii tester\u00f3w i bud\u017cetu na kilkumiesi\u0119czne przepisywanie system\u00f3w.<\/p>\n<p>Niezale\u017cnie od tego, czy korzystasz z Unity, Unreala, Godota czy w\u0142asnego silnika, problemy s\u0105 w gruncie rzeczy podobne: zbyt silne powi\u0105zania mi\u0119dzy systemami, brak jasnych granic odpowiedzialno\u015bci, dane wymieszane z logik\u0105, zbyt p\u00f3\u017ane my\u015blenie o testowalno\u015bci. Silnik zmienia szczeg\u00f3\u0142y implementacyjne, ale rdze\u0144 problemu jest wsp\u00f3lny \u2013 <strong>brak \u015bwiadomego planu architektury<\/strong>.<\/p>\n<p>Kiedy architektura jest przemy\u015blana, ko\u0144c\u00f3wka produkcji wygl\u0105da inaczej. Nadal jest napi\u0119cie, ale zmiana balansu czy dodanie nowego typu przeciwnika nie powoduje efektu domina. Bugi s\u0105 lokalne, a nie globalne. To w\u0142a\u015bnie ten stan jest realnym celem planowania struktury kodu gry.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Czym_jest_dobra_architektura_w_grach_i_czym_rozni_sie_od_aplikacji_biznesowych\"><\/span>Czym jest dobra architektura w grach i czym r\u00f3\u017cni si\u0119 od aplikacji biznesowych<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3><span class=\"ez-toc-section\" id=\"Specyfika_gier_petla_glowna_i_morze_stanow\"><\/span>Specyfika gier: p\u0119tla g\u0142\u00f3wna i morze stan\u00f3w<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Gra to nie aplikacja, kt\u00f3ra reaguje tylko na klikni\u0119cia u\u017cytkownika i zapytania do bazy. Gra dzia\u0142a w trybie real-time, ma <strong>p\u0119tl\u0119 g\u0142\u00f3wn\u0105<\/strong>, kt\u00f3ra co klatk\u0119 musi:<\/p>\n<ul>\n<li>obs\u0142u\u017cy\u0107 wej\u015bcie gracza,<\/li>\n<li>zaktualizowa\u0107 logik\u0119 wielu system\u00f3w r\u00f3wnocze\u015bnie (AI, fizyka, animacje, questy, UI),<\/li>\n<li>narysowa\u0107 \u015bwiat i interfejs,<\/li>\n<li>utrzyma\u0107 to wszystko w docelowym FPS.<\/li>\n<\/ul>\n<p>Ka\u017cdy z tych element\u00f3w posiada w\u0142asny stan, a stany przeplataj\u0105 si\u0119: buff z systemu walki zmienia parametry w systemie ruchu, decyzja AI zale\u017cy od \u015bwiat\u0142a i d\u017awi\u0119ku, UI musi odzwierciedli\u0107 efekt skilli i statystyki z ekwipunku. <strong>Liczba potencjalnych interakcji ro\u015bnie wyk\u0142adniczo<\/strong>, je\u015bli architektura pozwala systemom odwo\u0142ywa\u0107 si\u0119 do siebie bez kontroli.<\/p>\n<p>Dobra architektura kodu gry musi wi\u0119c uwzgl\u0119dnia\u0107 dwie rzeczy jednocze\u015bnie: ci\u0105g\u0142y, cykliczny charakter wykonywania kodu oraz eksplozj\u0119 stan\u00f3w i zale\u017cno\u015bci. To w\u0142a\u015bnie tu zaczyna si\u0119 r\u00f3\u017cnica w stosunku do typowych aplikacji biznesowych.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Balans_czystosc_wydajnosc_i_czas_produkcji\"><\/span>Balans: czysto\u015b\u0107, wydajno\u015b\u0107 i czas produkcji<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>W \u015bwiecie biznesowym cz\u0119sto premiuje si\u0119 maksymaln\u0105 czytelno\u015b\u0107 i elastyczno\u015b\u0107, nawet je\u015bli kosztuje to nieco wydajno\u015bci. W grach <strong>wydajno\u015b\u0107 jest cech\u0105 funkcjonaln\u0105<\/strong> \u2013 gra poni\u017cej 30\/60 FPS jest po prostu \u201ezepsuta\u201d z perspektywy gracza. Dlatego planuj\u0105c architektur\u0119 kodu gry, trzeba ca\u0142y czas balansowa\u0107 mi\u0119dzy:<\/p>\n<ul>\n<li><strong>czytelno\u015bci\u0105 i prostot\u0105<\/strong> \u2013 \u017ceby da\u0142o si\u0119 kod rozwija\u0107,<\/li>\n<li><strong>wydajno\u015bci\u0105<\/strong> \u2013 szczeg\u00f3lnie w krytycznych \u015bcie\u017ckach (update, render, fizyka),<\/li>\n<li><strong>czasem produkcji<\/strong> \u2013 projekt ma deadline; architektura nie mo\u017ce zje\u015b\u0107 ca\u0142ego bud\u017cetu.<\/li>\n<\/ul>\n<p>Przelanie ka\u017cdego wzorca z ksi\u0105\u017cek o systemach biznesowych wprost do gry zwykle ko\u0144czy si\u0119 \u017ale. Z drugiej strony kod \u201cpisany na pa\u0142\u0119 pod performance\u201d bez zasad szybko robi si\u0119 nie do utrzymania. Dobra architektura gry <strong>\u015bwiadomie wybiera miejsca, gdzie jest bardzo czysto, oraz miejsca, gdzie jest \u015bwiadomy kompromis<\/strong>.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Dlaczego_dogmatyczny_OOP_i_DDD_czesto_zawodza_w_grach\"><\/span>Dlaczego dogmatyczny OOP i DDD cz\u0119sto zawodz\u0105 w grach<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Klasyczne podej\u015bcie obiektowe z g\u0142\u0119bokim dziedziczeniem prowadzi w grach do typowych potwork\u00f3w: <em>GodObject<\/em> (np. GameManager, kt\u00f3ry robi wszystko), gigantyczne hierarchie prefab\u00f3w, klasy Player dziedzicz\u0105ce po 5 r\u00f3\u017cnych abstrakcjach. Zmiana ma\u0142ej rzeczy wymaga przegl\u0105du ca\u0142ego drzewa dziedziczenia.<\/p>\n<p>Podobnie dogmatyczne DDD (Domain-Driven Design) w 100% przeniesione do gry cz\u0119sto generuje zbyt wiele warstw i abstrakcji wzgl\u0119dem realnych potrzeb. Gry s\u0105 niezwykle eksperymentalne \u2013 mechaniki zmieniaj\u0105 si\u0119 wielokrotnie, a ci\u0119\u017ckie modelowanie domeny na pocz\u0105tku bywa zwyczajnie strat\u0105 czasu.<\/p>\n<p>Sensowne podej\u015bcie do architektury kodu gry u\u017cywa OOP, ale <strong>preferuje kompozycj\u0119 nad dziedziczeniem<\/strong>, a elementy DDD stosuje tam, gdzie si\u0119 realnie op\u0142acaj\u0105 (np. model ekonomii gry, sieciowe kontrakty danych), zamiast rozci\u0105ga\u0107 je na ka\u017cdy timer i efekcik.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Pragmatyczne_kryteria_oceny_architektury_gry\"><\/span>Pragmatyczne kryteria oceny architektury gry<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Zamiast pyta\u0107, czy architektura jest \u201eczysta\u201d, lepiej u\u017cywa\u0107 pragmatycznych kryteri\u00f3w:<\/p>\n<ul>\n<li><strong>Szybko\u015b\u0107 wprowadzania zmian<\/strong> \u2013 ile miejsc trzeba zmodyfikowa\u0107, by doda\u0107 nowy typ przeciwnika lub now\u0105 mechanik\u0119?<\/li>\n<li><strong>Lokalno\u015b\u0107 skutk\u00f3w<\/strong> \u2013 czy b\u0142\u0105d w systemie ekwipunku mo\u017ce rozwali\u0107 dialogi i zapis gry? Je\u015bli tak, granice odpowiedzialno\u015bci s\u0105 rozmyte.<\/li>\n<li><strong>\u0141atwo\u015b\u0107 debugowania<\/strong> \u2013 czy z log\u00f3w i struktury kodu da si\u0119 zrozumie\u0107, sk\u0105d wzi\u0119\u0142a si\u0119 dana akcja i dlaczego?<\/li>\n<li><strong>Mo\u017cliwo\u015b\u0107 stopniowej refaktoryzacji<\/strong> \u2013 czy mo\u017cna poprawia\u0107 architektur\u0119 po kawa\u0142ku, czy konieczny jest \u201ewielki rewrite\u201d?<\/li>\n<\/ul>\n<p>Je\u017celi zesp\u00f3\u0142 jest w stanie prawie bezbole\u015bnie wprowadza\u0107 zmiany nawet pod koniec produkcji, a regresje s\u0105 stosunkowo lokalne, to znaczy, \u017ce architektura wspiera proces, a nie go blokuje.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Fundamenty_rozbijanie_gry_na_warstwy_i_moduly\"><\/span>Fundamenty: rozbijanie gry na warstwy i modu\u0142y<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3><span class=\"ez-toc-section\" id=\"Logiczne_warstwy_oddzielenie_gry_od_silnika\"><\/span>Logiczne warstwy: oddzielenie gry od silnika<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Podstaw\u0105 dobrej architektury kodu gry jest <strong>jasny podzia\u0142 na warstwy<\/strong>. Minimalny, ale praktyczny model, kt\u00f3ry sprawdza si\u0119 w wielu produkcjach, wygl\u0105da tak:<\/p>\n<ul>\n<li><strong>Warstwa silnika \/ adapter\u00f3w<\/strong> \u2013 to, co bezpo\u015brednio dotyka Unity\/Unreal\/SDL itp. Tu s\u0105 klasy MonoBehaviour\/Actor, komponenty renderuj\u0105ce, adaptery wej\u015bcia, integracje z systemem plik\u00f3w.<\/li>\n<li><strong>Warstwa domeny gry<\/strong> \u2013 \u201eczysta logika\u201d: zasady walki, ekonomii, questy, system do\u015bwiadczenia, kolejki zdarze\u0144. W idealnym \u015bwiecie ta warstwa nie wie, czy pracuje na Unity czy na customowym silniku.<\/li>\n<li><strong>Warstwa prezentacji<\/strong> \u2013 UI, efekty wizualne, audio. Odbiera dane ze \u015bwiata gry i prezentuje je graczowi.<\/li>\n<\/ul>\n<p>Taki podzia\u0142 nie musi by\u0107 formalnie wymuszony przez framework, ale <strong>powinien by\u0107 konsekwentnie stosowany w strukturze projektu<\/strong>. Na przyk\u0142ad: ka\u017cda klasa MonoBehaviour tylko \u201emostkuje\u201d dane mi\u0119dzy silnikiem a czyst\u0105 logik\u0105 (np. wywo\u0142uje metody domenowe w Update, przekazuje eventy wej\u015bcia, aktualizuje UI).<\/p>\n<p>Dzi\u0119ki temu zmiana silnika (lub spos\u00f3b \u0142adowania scen) nie wymusza przepisywania logiki gry, a z kolei zmiana zasad rozgrywki nie wymaga przerabiania setek komponent\u00f3w wizualnych.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Moduly_tematyczne_zamiast_jednego_wielkiego_projektu\"><\/span>Modu\u0142y tematyczne zamiast jednego wielkiego projektu<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Nast\u0119pny krok to poci\u0119cie gry na <strong>modu\u0142y logiczne<\/strong>. Typowy zestaw modu\u0142\u00f3w w \u015bredniej wielko\u015bci grze mo\u017ce wygl\u0105da\u0107 tak:<\/p>\n<ul>\n<li>Inventory (ekwipunek)<\/li>\n<li>Combat (walka, obra\u017cenia, statusy)<\/li>\n<li>Quests (zadania, cele, post\u0119p)<\/li>\n<li>Characters (statystyki, klasy postaci, levelowanie)<\/li>\n<li>World (spawning, interakcje ze \u015bwiatem)<\/li>\n<li>UI (ekrany, HUD, notyfikacje)<\/li>\n<li>Save\/Load (serializacja stanu gry)<\/li>\n<li>Meta-progression (odblokowania, achievementy, waluta meta)<\/li>\n<\/ul>\n<p>Warto, aby ka\u017cdy modu\u0142 mia\u0142:<\/p>\n<ul>\n<li>jasny punkt wej\u015bcia (np. mened\u017cer systemu lub \u201efasad\u0119\u201d API),<\/li>\n<li>zestaw modeli danych (np. struktury opisuj\u0105ce przedmioty, questy),<\/li>\n<li>zale\u017cno\u015bci tylko od tego, co jest naprawd\u0119 potrzebne (najlepiej \u201ew g\u00f3r\u0119\u201d \u2013 np. Combat mo\u017ce publikowa\u0107 eventy, kt\u00f3re odbiera UI, zamiast samemu zmienia\u0107 UI).<\/li>\n<\/ul>\n<p>Modu\u0142y nie musz\u0105 by\u0107 osobnymi assembly, ale dobrze, \u017ceby by\u0142y osobnymi folderami \/ przestrzeniami nazw, z ograniczon\u0105 liczb\u0105 publicznych klas. Dzi\u0119ki temu nawet po roku mo\u017cna si\u0119 w projekcie odnale\u017a\u0107.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Jak_zaczac_od_malego_rozwojowego_podzialu\"><\/span>Jak zacz\u0105\u0107 od ma\u0142ego, rozwojowego podzia\u0142u<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Przy ma\u0142ej grze kusi, \u017ceby \u201enie bawi\u0107 si\u0119\u201d w warstwy i modu\u0142y. Jednak nawet w 2\u20133 osobowym zespole prosty podzia\u0142 przynosi ogromn\u0105 korzy\u015b\u0107. Dobrym pocz\u0105tkiem jest:<\/p>\n<ul>\n<li>Wydzielenie <strong>osobnego folderu\/namespace\u2019u na logik\u0119 gry<\/strong>, gdzie nie umieszcza si\u0119 bezpo\u015brednio klas MonoBehaviour\/Actor.<\/li>\n<li>Stworzenie <strong>kilku podstawowych modu\u0142\u00f3w<\/strong> (np. Core, Player, Enemies, Items, UI), nawet je\u015bli na pocz\u0105tku s\u0105 ma\u0142e.<\/li>\n<li>Ustalenie zasady: \u201eKa\u017cdy nowy system ma <em>miejsce w strukturze<\/em>\u201d \u2013 nigdy nie wrzucamy klas luzem do \u201eScripts\u201d.<\/li>\n<\/ul>\n<p>Kluczowy jest tu kierunek my\u015blenia: architektura ma <strong>rosn\u0105\u0107 razem z projektem<\/strong>. Nie chodzi o to, \u017ceby od razu przewidzie\u0107 wszystko, ale by mie\u0107 szkic mapy, kt\u00f3ry da si\u0119 rozbudowywa\u0107 bez cofania si\u0119 na start.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Konsekwencja_granic_co_jesli_system_%E2%80%9Emusi%E2%80%9D_siegnac_do_innego\"><\/span>Konsekwencja granic: co je\u015bli system \u201emusi\u201d si\u0119gn\u0105\u0107 do innego?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>W praktyce szybko pojawiaj\u0105 si\u0119 pokusy: \u201esystem dialog\u00f3w musi tylko raz si\u0119gn\u0105\u0107 do systemu ekwipunku, to nie szkodzi\u201d. Jeden raz zamienia si\u0119 w pi\u0119\u0107, potem w dwadzie\u015bcia. Nagle questy sprawdzaj\u0105 sloty ekwipunku, a UI odpala cutscenki.<\/p>\n<p>Je\u017celi system musi skorzysta\u0107 z innego, postaw pytanie: czy zrobi to przez:<\/p>\n<ul>\n<li><strong>prost\u0105, jawnie wstrzykni\u0119t\u0105 zale\u017cno\u015b\u0107<\/strong> (np. interfejs IInventoryService przekazany w konstruktorze), czy<\/li>\n<li><strong>event lub komunikat<\/strong>, na kt\u00f3ry inny system si\u0119 zapisze?<\/li>\n<\/ul>\n<p>Pierwsza opcja jest dobra, gdy istnieje naturalna hierarchia (np. UI <em>czyta<\/em> dane z modelu gry). Druga \u2013 gdy systemy s\u0105 raczej r\u00f3wnorz\u0119dne, a zale\u017cno\u015b\u0107 jest opcjonalna lub wielokrotna. W obu przypadkach wygrywasz tym, \u017ce powi\u0105zanie jest <strong>\u015bwiadome i kontrolowane<\/strong>, a nie przypadkowe.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Jak_planowac_architekture_juz_na_etapie_prototypu\"><\/span>Jak planowa\u0107 architektur\u0119 ju\u017c na etapie prototypu<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3><span class=\"ez-toc-section\" id=\"Brudny_prototyp_vs_prototyp_ktory_moze_isc_do_produkcji\"><\/span>Brudny prototyp vs prototyp, kt\u00f3ry mo\u017ce i\u015b\u0107 do produkcji<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>W game devie potrzebne s\u0105 oba typy prototyp\u00f3w:<\/p>\n<ul>\n<li><strong>Prototyp jednorazowy<\/strong> \u2013 2\u20133 dni na sprawdzenie, czy dana mechanika \u201ema feeling\u201d. Tu mo\u017cna wrzuci\u0107 logik\u0119 do jednego pliku, byle by\u0142o szybko.<\/li>\n<li><strong>Prototyp produkcyjny<\/strong> \u2013 proof-of-concept, kt\u00f3ry prawdopodobnie stanie si\u0119 zal\u0105\u017ckiem finalnej gry.<\/li>\n<\/ul>\n<p>Najwi\u0119kszy problem pojawia si\u0119 wtedy, gdy <strong>prototyp jednorazowy \u201eprzypadkiem\u201d staje si\u0119 baz\u0105 produkcyjn\u0105<\/strong>. Nikt nie ma czasu na przepisanie kodu, wi\u0119c na istniej\u0105ce \u201espaghetti\u201d doklejane s\u0105 kolejne funkcje. Po paru miesi\u0105cach zespo\u0142owi trudno jest w og\u00f3le rozpozna\u0107, co jest prototypem, a co w\u0142a\u015bciw\u0105 gr\u0105.<\/p>\n<p>Dlatego ju\u017c na starcie op\u0142aca si\u0119 nazwa\u0107 rzeczy po imieniu: je\u017celi co\u015b ma szans\u0119 wej\u015b\u0107 do produkcji, trzeba mu nada\u0107 minimaln\u0105 struktur\u0119 architektoniczn\u0105. \u201eBrudne\u201d prototypy trzyma\u0107 osobno i traktowa\u0107 jako wyrzucalne.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Minimalne_zasady_prototypowania_ktore_ratuja_produkcje\"><\/span>Minimalne zasady prototypowania, kt\u00f3re ratuj\u0105 produkcj\u0119<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Nawet dla szybkiego, ale \u201epowa\u017cnego\u201d prototypu, kt\u00f3ry mo\u017ce i\u015b\u0107 dalej, przydaje si\u0119 kr\u00f3tka lista \u017celaznych zasad. Przyk\u0142adowa checklista:<\/p>\n<ul>\n<li>Nie mieszaj logiki z kodem UI \u2013 nawet je\u015bli UI to tylko kilka przycisk\u00f3w.<\/li>\n<li>Trzymaj dane gry (statystyki broni, HP, koszty) w jednym miejscu (np. ScriptableObjects \/ JSON), nie jako \u201emagiczne liczby\u201d w kodzie.<\/li>\n<li>Unikaj <strong>globalnych singleton\u00f3w<\/strong> do wszystkiego. Jeden globalny GameConfig \u2013 ok; globalny EverythingManager \u2013 nie.<\/li>\n<li>Wprowad\u017a chocia\u017c podstawowy <strong>podzia\u0142 na modu\u0142y<\/strong> (Player, Enemies, World, UI).<\/li>\n<li>Zadbaj, by kluczowe systemy by\u0142y <strong>aktualizowane w jednym, znanym miejscu<\/strong> (np. centralny GameLoop \/ SystemsRunner, zamiast setek Update w r\u00f3\u017cnych komponentach).<\/li>\n<\/ul>\n<p>Takie drobiazgi niemal nie spowalniaj\u0105 prototypu, a radykalnie u\u0142atwiaj\u0105 przej\u015bcie w faz\u0119 produkcyjn\u0105 bez przepisywania wszystkiego od zera.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Decyzje_ktore_mozna_odlozyc_i_te_ktore_trzeba_podjac_od_razu\"><\/span>Decyzje, kt\u00f3re mo\u017cna od\u0142o\u017cy\u0107, i te, kt\u00f3re trzeba podj\u0105\u0107 od razu<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Nie ka\u017cd\u0105 decyzj\u0119 architektoniczn\u0105 trzeba podejmowa\u0107 w dniu 1. Kilka rzeczy mo\u017cna spokojnie od\u0142o\u017cy\u0107:<\/p>\n<ul>\n<li>konkretny styl architektury (czyste OOP vs ECS vs hybryda),<\/li>\n<li>detaliczny podzia\u0142 modu\u0142\u00f3w (czy \u201eProgression\u201d ma by\u0107 osobno, czy w \u201ePlayer\u201d),<\/li>\n<li>szczeg\u00f3\u0142y implementacji systemu event\u00f3w lub messagingu,<\/li>\n<li>pe\u0142ny model balansu (jak dok\u0142adnie liczone s\u0105 obra\u017cenia, ile jest klas postaci).<\/li>\n<\/ul>\n<p>Te decyzje i tak trzeba b\u0119dzie zweryfikowa\u0107 na \u017cywym organizmie. Na pocz\u0105tku wa\u017cniejsze jest, \u017ceby istnia\u0142o miejsce, w kt\u00f3rym mo\u017cna je bezbole\u015bnie zmieni\u0107 \u2013 czysta logika oddzielona od silnika, sensownie rozdzielone modu\u0142y, przejrzyste granice odpowiedzialno\u015bci.<\/p>\n<p>S\u0105 jednak wybory, kt\u00f3re bardzo trudno odwr\u00f3ci\u0107 po kilku miesi\u0105cach, wi\u0119c lepiej zmierzy\u0107 si\u0119 z nimi od razu. Chodzi g\u0142\u00f3wnie o <strong>spos\u00f3b aktualizacji \u015bwiata gry<\/strong> (rozproszony po setkach Update vs centralny loop), <strong>model danych<\/strong> (czy wi\u0119kszo\u015b\u0107 jest w kodzie, czy w zewn\u0119trznej konfiguracji) oraz <strong>kontrakt mi\u0119dzy logik\u0105 a prezentacj\u0105<\/strong> (czy UI grzebie bezpo\u015brednio w stanie gry, czy tylko reaguje na zdarzenia).<\/p>\n<p>Kr\u00f3tki przyk\u0142ad z produkcji mobilnej: zesp\u00f3\u0142 zacz\u0105\u0142 od \u201ena szybko\u201d spi\u0119tego UI, kt\u00f3re bezpo\u015brednio modyfikowa\u0142o komponenty w scenie. Po p\u00f3\u0142 roku wej\u015bcie nowego designera UI sko\u0144czy\u0142o si\u0119 tygodniem refaktoru, bo ka\u017cda zmiana layoutu grozi\u0142a popsuciem ekonomii gry. Gdyby od pierwszego prototypu przyj\u0119to zasad\u0119, \u017ce UI tylko wysy\u0142a komendy i subskrybuje eventy, wymiana widok\u00f3w by\u0142aby kwesti\u0105 dni, a nie desperackiej akcji ratunkowej.<\/p>\n<p>Dobrym filtrem jest pytanie: \u201eCzy ta decyzja zamyka nam jakie\u015b drzwi za trzy miesi\u0105ce?\u201d. Je\u017celi odpowied\u017a brzmi \u201etak\u201d albo \u201enie wiemy\u201d, zatrzymaj si\u0119 na godzin\u0119, narysuj prosty diagram przep\u0142ywu danych i poszukaj wariantu, kt\u00f3ry zostawi wi\u0119cej elastyczno\u015bci, nawet kosztem kilku dodatkowych linii kodu dzi\u015b.<\/p>\n<p>Porz\u0105dna architektura gry rzadko powstaje z jednego genialnego diagramu. Przypomina raczej seri\u0119 \u015bwiadomych, ma\u0142ych wybor\u00f3w, kt\u00f3re razem sprawiaj\u0105, \u017ce kod nie walczy z zespo\u0142em, tylko go wspiera \u2013 zw\u0142aszcza wtedy, gdy projekt jest ju\u017c du\u017cy, a presja ro\u015bnie z ka\u017cdym sprintem.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Style_architektury_w_grach_od_OOP_do_ECS_i_podejscia_mieszane\"><\/span>Style architektury w grach: od OOP do ECS i podej\u015bcia mieszane<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Na milestone review designer m\u00f3wi: \u201ePotrzebujemy dwa razy wi\u0119cej przeciwnik\u00f3w na mapie, inaczej jest pusto\u201d. Programi\u015bci bledn\u0105, bo ka\u017cda dodatkowa jednostka dobija FPS-y. Kodowo wszystko \u201edzia\u0142a\u201d, ale architektura nie wytrzymuje skali \u2013 szczeg\u00f3lnie gdy ka\u017cda jednostka to ci\u0119\u017cki obiekt z w\u0142asn\u0105 logik\u0105, setkami p\u00f3l i referencji.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Kiedy_klasyczne_OOP_dziala_dobrze\"><\/span>Kiedy klasyczne OOP dzia\u0142a dobrze<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Przy ma\u0142ych i \u015brednich projektach klasyczne podej\u015bcie obiektowe jest cz\u0119sto najbardziej pragmatyczne. Czytelne klasy typu <code>Player<\/code>, <code>Enemy<\/code>, <code>Weapon<\/code>, pola opisuj\u0105ce stan, metody z zachowaniem \u2013 to da si\u0119 szanowa\u0107, je\u015bli nie przechodzi w dziedziczeniowe drzewo-bestiariusz.<\/p>\n<p>Najzdrowszy OOP w grach jest mocno \u201ep\u0142aski\u201d i kompozycyjny:<\/p>\n<ul>\n<li>preferuje <strong>kompozycj\u0119 nad dziedziczeniem<\/strong> (komponenty zachowa\u0144 zamiast klasy \u201eEnemyBossFlyingFireMage : EnemyBase\u201d),<\/li>\n<li>trzyma <strong>ma\u0142e klasy z jednym powodem do zmiany<\/strong> (AI ruchu oddzielnie od logiki zadawania obra\u017ce\u0144),<\/li>\n<li>opiera si\u0119 na <strong>czytelnych interfejsach<\/strong> pomi\u0119dzy systemami (np. <code>IDamageable<\/code>, <code>IMoveAgent<\/code>),<\/li>\n<li>nie pr\u00f3buje odwzorowa\u0107 ca\u0142ego design doca w hierarchii klas.<\/li>\n<\/ul>\n<p>Przy takiej dyscyplinie OOP jest \u015bwietny do system\u00f3w, gdzie jest sporo z\u0142o\u017conej logiki, ale umiarkowana liczba aktywnych obiekt\u00f3w: UI, ekonomia, questy, meta-progresja, system craftingu. Debugowanie te\u017c jest prostsze: stepping w debuggerze po metodach i polach klasy daje szybki obraz sytuacji.<\/p>\n<p>Wad\u0105 staje si\u0119 natomiast <strong>wydajno\u015b\u0107 i skalowanie<\/strong>, gdy pr\u00f3bujesz mie\u0107 tysi\u0105ce aktywnych twor\u00f3w z bogatym stanem. Cache CPU nie lubi rozrzuconych po pami\u0119ci obiekt\u00f3w, a ka\u017cdy dodatkowy <code>Update()<\/code> zaczyna kosztowa\u0107.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Gdzie_ECS_faktycznie_pomaga_a_gdzie_jest_przerostem_formy\"><\/span>Gdzie ECS faktycznie pomaga, a gdzie jest przerostem formy<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Entity Component System (ECS) rozbija byt na nagi identyfikator (entity) oraz zbiory danych (components), kt\u00f3rymi operuj\u0105 niezale\u017cne systemy. W dobrze wdro\u017conym ECS:<\/p>\n<ul>\n<li>dane tego samego typu le\u017c\u0105 obok siebie w pami\u0119ci (struktury tablicowe zamiast losowo porozrzucanych obiekt\u00f3w),<\/li>\n<li>logika jest skupiona w systemach, a nie w metodach obiekt\u00f3w,<\/li>\n<li>\u0142atwiej wykonywa\u0107 aktualizacje hurtowo, wektorowo, r\u00f3wnolegle.<\/li>\n<\/ul>\n<p>ECS b\u0142yszczy, gdy:<\/p>\n<ul>\n<li>masz <strong>du\u017co prostych byt\u00f3w<\/strong> (pociski, miniony, jednostki RTS, roje NPC),<\/li>\n<li>logika tych byt\u00f3w jest <strong>silnie zbli\u017cona<\/strong> (wszystkie poruszaj\u0105 si\u0119, maj\u0105 HP, AI w kilku wariantach),<\/li>\n<li>wydajno\u015b\u0107 jest realnym problemem, a nie tylko potencjaln\u0105 obaw\u0105.<\/li>\n<\/ul>\n<p>W takim \u015brodowisku ECS pozwala wycisn\u0105\u0107 z CPU znacznie wi\u0119cej i zachowa\u0107 przy tym spor\u0105 elastyczno\u015b\u0107 konfigurowania zachowa\u0144 (dodawanie\/usuwanie komponent\u00f3w zamiast przebudowy dziedziczenia).<\/p>\n<p>Natomiast full-ECS w ma\u0142ym, story-driven RPG z garstk\u0105 postaci mo\u017ce by\u0107 ci\u0119\u017carem: wi\u0119cej boilerplate\u2019u, narzuty narz\u0119dziowe, trudniejsza nauka dla nowych os\u00f3b, mniej intuicyjny debugging (\u201ekt\u00f3ry system w\u0142a\u015bnie zmieni\u0142 ten komponent?\u201d).<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Hybrydy_%E2%80%93_pragmatyczny_srodek\"><\/span>Hybrydy \u2013 pragmatyczny \u015brodek<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>W praktyce w wielu zespo\u0142ach wygrywa podej\u015bcie hybrydowe: <strong>systemy wysokiego poziomu w OOP<\/strong>, a <strong>ci\u0119\u017ckie p\u0119tle gameplayowe w ECS lub stylu \u201edata-oriented\u201d<\/strong>. Przyk\u0142adowy uk\u0142ad:<\/p>\n<ul>\n<li>Warstwa \u201emeta\u201d: kampania, ekrany, ekonomia, save\/load \u2013 klasyczne OOP, serwisy, kontrolery.<\/li>\n<li>Warstwa \u201eruntime\u201d: \u015bwiat, jednostki, pociski \u2013 ECS lub \u201elight ECS\u201d z tablicami struktur i systemami aktualizacji.<\/li>\n<li>Integracja: cienkie adaptery, kt\u00f3re translatuj\u0105 zdarzenia z logiki meta na operacje na \u015bwiecie ECS i odwrotnie.<\/li>\n<\/ul>\n<p>W jednym projekcie mobilnego RPG praktyczny kompromis wygl\u0105da\u0142 tak: ca\u0142a walka turowa (postaci, buffy, inicjatywa, liczenie obra\u017ce\u0144) by\u0142a zaimplementowana w czystym C# jako \u201eECS-like\u201d \u2013 tablice struktur + systemy \u2013 uruchamiana po stronie serwera i klienta. Otoczka w kliencie (UI, animacje, efekty) by\u0142a typowym OOP z MonoBehaviour, nas\u0142uchuj\u0105cym na zdarzenia z silnika walki. Logika by\u0142a przetestowana, szybka, a interfejs m\u00f3g\u0142 si\u0119 zmienia\u0107 praktycznie co sprint.<\/p>\n<p>Wniosek: wyb\u00f3r stylu architektury nie musi by\u0107 religi\u0105. Mo\u017cna \u015bwiadomie zdecydowa\u0107, \u017ce cz\u0119\u015b\u0107 gry idzie w kierunku data-oriented, a reszta zostaje w czytelnym OOP, o ile granice s\u0105 wyra\u017ane.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Jak_nie_utknac_miedzy_paradygmatami\"><\/span>Jak nie utkn\u0105\u0107 mi\u0119dzy paradygmatami<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Najgorsza sytuacja pojawia si\u0119 wtedy, gdy projekt \u201etroch\u0119 jest OOP, troch\u0119 ECS\u201d, ale bez jasnej zasady gdzie co \u017cyje. Jedne systemy modyfikuj\u0105 obiekty MonoBehaviour, inne te same informacje trzymaj\u0105 w komponentach ECS \u2013 desynchronizacja gwarantowana.<\/p>\n<p>\u017beby tego unikn\u0105\u0107, przyda si\u0119 kilka prostych regu\u0142:<\/p>\n<ul>\n<li>Zdefiniuj <strong>\u017ar\u00f3d\u0142o prawdy<\/strong> dla kluczowych danych. Je\u015bli HP jest w ECS \u2013 UI to tylko odczytuje, nie ma w\u0142asnego HP na obiekcie.<\/li>\n<li>Trzymaj si\u0119 <strong>jednego sposobu aktualizacji<\/strong> danego fragmentu \u015bwiata. Ten sam byt nie powinien by\u0107 modyfikowany jednocze\u015bnie przez metody klasy i system ECS.<\/li>\n<li>Ustal <strong>kontrakty komunikacji<\/strong>: np. ECS world publikuje eventy, reszta tylko reaguje. Brak bezpo\u015brednich referencji do wewn\u0119trznych struktur ECS poza jego modu\u0142em.<\/li>\n<\/ul>\n<p>Takie zasady na kartce A4, om\u00f3wione na pocz\u0105tku produkcji, zwykle ratuj\u0105 przed p\u00f3\u0142rocznym refaktorem \u201ena \u017cywym organizmie\u201d.<\/p>\n<figure class=\"oai-pexels-image\"><img decoding=\"async\" src=\"https:\/\/excelraport.pl\/wp-content\/uploads\/2026\/04\/zblizenie-szczegolowego-planu-architektonicznego-na-biurku-pexels-4458205.jpg\" alt=\"Zbli\u017cenie szczeg\u00f3\u0142owego planu architektonicznego na biurku\" loading=\"lazy\" class=\"oai-pexels-image__img\" \/><figcaption>\u0179r\u00f3d\u0142o: Pexels | Autor: Ivan S<\/figcaption><\/figure>\n<h2><span class=\"ez-toc-section\" id=\"Projektowanie_systemow_gry_granice_odpowiedzialnosci_i_przeplyw_komunikatow\"><\/span>Projektowanie system\u00f3w gry: granice, odpowiedzialno\u015bci i przep\u0142yw komunikat\u00f3w<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Na stand-upie pad\u0142o pytanie: \u201eDlaczego zniszczenie skrzynki wywo\u0142uje crash w oknie achievement\u00f3w?\u201d. Po godzinie debugowania okazuje si\u0119, \u017ce obiekt skrzynki modyfikuje UI, odpala zapis gry i jeszcze aktualizuje licznik quest\u00f3w. Wszystko w jednym handlerze OnDestroy.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"System_jako_%E2%80%9Eusluga%E2%80%9D_dla_reszty_gry\"><\/span>System jako \u201eus\u0142uga\u201d dla reszty gry<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Ka\u017cdy wi\u0119kszy obszar logiki \u2013 ekwipunek, walka, dialogi, progresja \u2013 warto my\u015ble\u0107 nie jako \u201ezlepek skrypt\u00f3w\u201d, ale jako <strong>system z jasno zdefiniowan\u0105 us\u0142ug\u0105<\/strong>. Co daje na zewn\u0105trz? Co potrzebuje, \u017ceby dzia\u0142a\u0107?<\/p>\n<p>Przyk\u0142adowo system quest\u00f3w mo\u017ce wystawia\u0107:<\/p>\n<ul>\n<li>operacje: <code>AcceptQuest(questId)<\/code>, <code>CompleteQuest(questId)<\/code>, <code>AbandonQuest(questId)<\/code>,<\/li>\n<li>zestaw prostych struktur do odczytu stanu (np. <code>QuestStatusDto<\/code>),<\/li>\n<li>eventy: <code>OnQuestAccepted<\/code>, <code>OnQuestUpdated<\/code>, <code>OnQuestCompleted<\/code>.<\/li>\n<\/ul>\n<p>W \u015brodku mo\u017ce panowa\u0107 z\u0142o\u017cona logika zale\u017cno\u015bci, warunk\u00f3w, skrypt\u00f3w \u2013 ale z zewn\u0105trz masz przejrzyste API. Dzi\u0119ki temu nowy system (np. achievements) korzysta z <strong>stabilnego kontraktu<\/strong>, zamiast grzeba\u0107 w szczeg\u00f3\u0142ach implementacji.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Jak_wyznaczac_granice_systemow\"><\/span>Jak wyznacza\u0107 granice system\u00f3w<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Granice nie musz\u0105 idealnie pokrywa\u0107 si\u0119 z dokumentem designu. Czasem lepiej rozci\u0105\u0107 system po linii technicznej ni\u017c czysto \u201efabularnej\u201d. Kilka praktycznych kryteri\u00f3w:<\/p>\n<ul>\n<li><strong>Wsp\u00f3lna odpowiedzialno\u015b\u0107<\/strong> \u2013 wszystko, co dotyczy jednego sp\u00f3jnego rodzaju decyzji (np. \u201ekto co posiada\u201d, \u201ekto komu zadaje obra\u017cenia\u201d), powinno by\u0107 w jednym miejscu.<\/li>\n<li><strong>Zmienia si\u0119 razem<\/strong> \u2013 je\u015bli grupa klas praktycznie zawsze jest modyfikowana w ramach jednej funkcjonalno\u015bci, to sygna\u0142, \u017ce tworzy system.<\/li>\n<li><strong>Inny cykl \u017cycia<\/strong> \u2013 rzeczy, kt\u00f3re \u017cyj\u0105 tylko w walce, mog\u0105 tworzy\u0107 system Combat odpalany i czyszczony w ramach scenariusza walki.<\/li>\n<\/ul>\n<p>Gdy granica jest niejasna (np. czy levelowanie postaci to \u201eCharacters\u201d czy \u201eMeta-progression\u201d), nie ma jednej s\u0142usznej odpowiedzi. Wa\u017cniejsze, by <strong>wybra\u0107 jedno miejsce na sta\u0142e<\/strong> i si\u0119 go trzyma\u0107, ni\u017c co sprint przesuwa\u0107 logik\u0119 mi\u0119dzy modu\u0142ami.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Mechanizmy_komunikacji_bezposrednie_wywolania_eventy_message_bus\"><\/span>Mechanizmy komunikacji: bezpo\u015brednie wywo\u0142ania, eventy, message bus<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Komunikacja mi\u0119dzy systemami to miejsce, gdzie chaos pojawia si\u0119 najszybciej. Do dyspozycji masz kilka typowych narz\u0119dzi \u2013 ka\u017cde dobre w innym kontek\u015bcie.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Bezposrednie_wywolania_serwisy_interfejsy\"><\/span>Bezpo\u015brednie wywo\u0142ania (serwisy, interfejsy)<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>Najprostsza opcja: system A ma referencj\u0119 do interfejsu systemu B i wywo\u0142uje jego metody. Dzia\u0142a dobrze, gdy:<\/p>\n<ul>\n<li>istnieje <strong>naturalna hierarchia<\/strong> (np. UI \u2192 GameState, AI \u2192 Navigation),<\/li>\n<li>zale\u017cno\u015b\u0107 jest <strong>jednokierunkowa i stabilna<\/strong>,<\/li>\n<li>nie spodziewasz si\u0119 tony \u201esubskrybent\u00f3w\u201d danego zdarzenia.<\/li>\n<\/ul>\n<p>Koszt: wi\u0119ksze sprz\u0119\u017cenie \u2013 trzeba uwa\u017ca\u0107, \u017ceby nie tworzy\u0107 p\u0119tli zale\u017cno\u015bci (\u201eCombat wo\u0142a Inventory, Inventory wo\u0142a Combat\u201d). Dlatego op\u0142aci si\u0119 wprowadzi\u0107 prost\u0105 zasad\u0119: modu\u0142y \u201eni\u017cszego poziomu\u201d (Core, World, Combat) <strong>nie wo\u0142aj\u0105 wprost<\/strong> modu\u0142\u00f3w \u201ewy\u017cszego poziomu\u201d (UI, Meta), tylko korzystaj\u0105 z event\u00f3w.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Eventy_i_callbacki\"><\/span>Eventy i callbacki<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>Eventy sprawdzaj\u0105 si\u0119 przy wzorcu \u201epublish\u2013subscribe\u201d: jeden system nadaje, wiele s\u0142ucha. Dobry przyk\u0142ad: system obra\u017ce\u0144 publikuje <code>OnDamageDealt<\/code>, kt\u00f3ry interesuje UI, system combo, system quest\u00f3w.<\/p>\n<p>Dobre praktyki przy eventach:<\/p>\n<ul>\n<li>Typuj eventy silnie (klasy\/struktury, nie stringi).<\/li>\n<li>Unikaj logiki biznesowej w handlerach UI (\u201eOnDamageDealt \u2192 je\u015bli HP &lt; 0 to respawn\u201d). To nale\u017cy do system\u00f3w core.<\/li>\n<li>Shutdown gry powinien czy\u015bci\u0107 subskrypcje albo korzysta\u0107 z mechanizmu lifetime (np. event bus powi\u0105zany z danym kontekstem sceny).<\/li>\n<\/ul>\n<p>Eventy zmniejszaj\u0105 sprz\u0119\u017cenie, ale utrudniaj\u0105 \u015bledzenie przep\u0142ywu, wi\u0119c pomocne s\u0105 narz\u0119dzia diagnostyczne: logowanie typ\u00f3w event\u00f3w, proste profile \u201ekto na co s\u0142ucha\u201d.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Message_bus_event_bus\"><\/span>Message bus \/ event bus<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>Centralny bus komunikat\u00f3w (czasem nazywany EventAggregator) jest u\u017cyteczny w wi\u0119kszych projektach, gdzie system\u00f3w i event\u00f3w jest du\u017co. Zamiast \u0142\u0105czy\u0107 ka\u017cdy z ka\u017cdym, ka\u017cdy system zna tylko bus, przez kt\u00f3ry nadaje i odbiera.<\/p>\n<p>Wad\u0105 jest ryzyko \u201emagicznej czarnej skrzynki\u201d: nie wida\u0107, kto na co reaguje, je\u015bli nie ma porz\u0105dnych narz\u0119dzi. Dlatego bus powinien mie\u0107 chocia\u017c:<\/p>\n<ul>\n<li>logowanie wa\u017cnych typ\u00f3w komunikat\u00f3w (debug mode),<\/li>\n<li>mo\u017cliwo\u015b\u0107 inspekcji subskrypcji w edytorze \/ debug overlayu,<\/li>\n<li>czytelne nazwy komunikat\u00f3w (np. <code>PlayerLevelGained<\/code>, a nie <code>Event42<\/code>).<\/li>\n<\/ul>\n<h3><span class=\"ez-toc-section\" id=\"Unikanie_%E2%80%9EBoga_systemu%E2%80%9D\"><\/span>Unikanie \u201eBoga systemu\u201d<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Je\u015bli wi\u0119kszo\u015b\u0107 strza\u0142ek w twoim diagramie klas prowadzi do jednej klasy typu <code>GameManager<\/code>, to znak, \u017ce granice s\u0105 iluzoryczne. Taki \u201eB\u00f3g systemu\u201d zaczyna od prostych zada\u0144 (\u201etylko startuje gr\u0119\u201d), a ko\u0144czy jako \u015bmietnik wszelkiej logiki, kt\u00f3rej nigdzie indziej nie uda\u0142o si\u0119 wcisn\u0105\u0107.<\/p>\n<p>Zamiast jednego mened\u017cera wszystkiego lepiej mie\u0107 <strong>zestaw mened\u017cer\u00f3w o w\u0105skim zakresie<\/strong> (GameFlowManager, MatchManager, SceneLoader, UIRouter) spi\u0119tych prostym kompozytorem startowym. Nawet je\u015bli pocz\u0105tkowo cz\u0119\u015b\u0107 z nich b\u0119dzie bardzo cienka, unikniesz sytuacji, w kt\u00f3rej jedna klasa ma trzy tysi\u0105ce linii i kilkadziesi\u0105t odpowiedzialno\u015bci.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Dane_konfiguracja_i_balans_%E2%80%93_trzymanie_logiki_z_dala_od_contentu\"><\/span>Dane, konfiguracja i balans \u2013 trzymanie logiki z dala od contentu<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Po kilku miesi\u0105cach developmentu balans zaczyna \u017cy\u0107 w\u0142asnym \u017cyciem. Projektanci prosz\u0105 o \u201eszybk\u0105\u201d zmian\u0119 obra\u017ce\u0144 jednej broni, a programista odpala wyszukiwark\u0119 w projekcie i znajduje pi\u0119\u0107 magicznych warto\u015bci \u201e25f\u201d w trzech systemach. Nikt nie wie, kt\u00f3ry numer jest \u201etym w\u0142a\u015bciwym\u201d.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Single_source_of_truth_dla_danych_gameplayowych\"><\/span>Single source of truth dla danych gameplayowych<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Podstawa higieny architektonicznej w grach to <strong>jedno \u017ar\u00f3d\u0142o prawdy<\/strong> dla danych gameplayowych. Niezale\u017cnie, czy u\u017cywasz ScriptableObjects, JSON, YAML czy bazy danych \u2013 wa\u017cne, \u017ceby:<\/p>\n<ul>\n<li>wszystkie statystyki, koszty, czasy, dropy by\u0142y w jednym, sp\u00f3jnym systemie danych,<\/li>\n<li>kod logiki <strong>nigdy nie zawiera\u0142 \u201emagicznych liczb\u201d<\/strong> opisuj\u0105cych balans,<\/li>\n<li>zmiana warto\u015bci w danych propagowa\u0142a si\u0119 automatycznie do ca\u0142ej gry.<\/li>\n<\/ul>\n<p>W praktyce oznacza to warstw\u0119 <strong>modeli danych<\/strong> (np. <code>WeaponConfig<\/code>, <code>EnemyConfig<\/code>, <code>LevelConfig<\/code>), kt\u00f3re:<\/p>\n<ul>\n<li>s\u0105 \u0142adowane przy starcie gry lub odpowiedniej sceny,<\/li>\n<li>s\u0105 odczytywane przez systemy logiki (Combat, Progression) wy\u0142\u0105cznie przez jawne API,<\/li>\n<li>nie s\u0105 dowolnie modyfikowane w runtime, chyba \u017ce design na to pozwala (np. rogalik z losowymi modyfikatorami).<\/li>\n<\/ul>\n<h3><span class=\"ez-toc-section\" id=\"Oddzielenie_danych_statycznych_od_stanu_gry\"><\/span>Oddzielenie danych statycznych od stanu gry<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Warto rozr\u00f3\u017cni\u0107 dwa typy danych:<\/p>\n<p>Jeden z designer\u00f3w ustawia w arkuszu Excela obra\u017cenia miecza, a tester zg\u0142asza, \u017ce w buildzie nadal bije jak plastikowa zabawka. Okazuje si\u0119, \u017ce zmiana trafi\u0142a do \u201ekonfiguracji\u201d, ale gra i tak u\u017cywa starej warto\u015bci z serializowanego save\u2019a. Klasyczny efekt pomieszania danych statycznych z bie\u017c\u0105cym stanem.<\/p>\n<p>Warto rozr\u00f3\u017cni\u0107 dwa typy danych:<\/p>\n<ul>\n<li><strong>dane statyczne (konfiguracyjne)<\/strong> \u2013 to, co opisuje typy obiekt\u00f3w i ich \u201efabryczne\u201d w\u0142a\u015bciwo\u015bci: bazowe obra\u017cenia broni, wzory skalowania poziomu, definicje przeciwnik\u00f3w,<\/li>\n<li><strong>stan gry<\/strong> \u2013 to, co opisuje <em>konkretny przebieg<\/em>: aktualne HP tej jednej jednostki, zmodyfikowane obra\u017cenia miecza po buffach, kt\u00f3re questy gracz ju\u017c zrobi\u0142.<\/li>\n<\/ul>\n<p>Dane statyczne powinny by\u0107 niemutowalne w runtime (z punktu widzenia zwyk\u0142ego kodu gameplayowego). Systemy tylko je <em>odczytuj\u0105<\/em> i u\u017cywaj\u0105 jako punktu wyj\u015bcia do liczenia stanu. Natomiast stan gry mo\u017ce si\u0119 zmienia\u0107 dowolnie, ale nigdy nie powinien \u201eprzepisywa\u0107\u201d konfiguracji \u2013 zamiast tego przechowuje referencje, identyfikatory i modyfikatory. Je\u015bli zapisujesz gr\u0119, do save\u2019a trafia wy\u0142\u0105cznie stan (ID broni + enchant + durability), a nie pe\u0142na kopia configu.<\/p>\n<p>Prosty test: je\u015bli designer zmienia warto\u015b\u0107 w pliku konfiguracyjnym, a na nowej kampanii od razu wida\u0107 efekt \u2013 znaczy, \u017ce separacja dzia\u0142a. Je\u015bli musisz czy\u015bci\u0107 save\u2019y albo r\u0119cznie \u201emigrowa\u0107\u201d dane gracza po ka\u017cdej zmianie balansu, to sygna\u0142, \u017ce gdzie\u015b stan zacz\u0105\u0142 si\u0119 miesza\u0107 z konfiguracj\u0105. Im wcze\u015bniej rozbijesz te dwa \u015bwiaty, tym mniej b\u00f3lu przy p\u00f3\u017anych poprawkach balansu i przy patchowaniu gry po premierze.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Narzedzia_dla_designerow_zamiast_ifow_w_kodzie\"><\/span>Narz\u0119dzia dla designer\u00f3w zamiast if\u00f3w w kodzie<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Gdy projektant wpada z pro\u015bb\u0105 \u201edodajmy +10% obra\u017ce\u0144, je\u015bli gracz ma mniej ni\u017c 20% HP\u201d, masz dwie drogi. Albo dopisujesz kolejnego ifa w CombatSystemie, albo dajesz mu mo\u017cliwo\u015b\u0107 wyklikania tego w danych. Pierwsze dzia\u0142a szybciej dzi\u015b, drugie skaluje si\u0119 przez kolejne miesi\u0105ce developmentu.<\/p>\n<p>Klucz to proste, ale ekspresywne formaty danych: tablice krzywych, listy warunk\u00f3w, drzewka efekt\u00f3w. System walki powinien rozumie\u0107 og\u00f3lne poj\u0119cia typu \u201ewarunek\u201d, \u201emodyfikator\u201d, \u201e\u017ar\u00f3d\u0142o warto\u015bci\u201d, a sam zestaw konkretnych buff\u00f3w, debuff\u00f3w i perk\u00f3w siedzi w konfiguracji. Dzi\u0119ki temu nowy efekt oznacza nowy wiersz w danych, a nie now\u0105 ga\u0142\u0105\u017a <code>switch<\/code> w kodzie.<\/p>\n<p>Takie podej\u015bcie wymusza te\u017c zdrowsz\u0105 dyskusj\u0119 w zespole. Zamiast \u201edopiszesz mi to na jutro?\u201d, pojawia si\u0119 pytanie \u201eczy ten typ efektu ju\u017c obs\u0142ugujemy w systemie?\u201d. Je\u015bli nie \u2013 trzeba poszerzy\u0107 <em>j\u0119zyk<\/em> systemu (nowy rodzaj warunku, nowe targetowanie), a dopiero potem produkowa\u0107 dziesi\u0105tki konkretnych konfiguracji. Raz dobrze przemy\u015blany j\u0119zyk danych potrafi zdj\u0105\u0107 z programist\u00f3w wi\u0119kszo\u015b\u0107 pracy przy tuningu gry.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Edytowalnosc_i_bezpieczenstwo\"><\/span>Edytowalno\u015b\u0107 i bezpiecze\u0144stwo<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Kiedy designerzy dostaj\u0105 w r\u0119ce edytor danych, pojawia si\u0119 inny problem: jak nie rozwali\u0107 gry jednym z\u0142ym wpisem. Jeden zesp\u00f3\u0142 dopuszcza edycj\u0119 JSON-\u00f3w w notatniku, inny inwestuje w customowe narz\u0119dzia z walidacj\u0105 i podpowiedziami. Im wi\u0119kszy projekt, tym bardziej op\u0142aca si\u0119 ta druga opcja.<\/p>\n<p>Dane gameplayowe powinny by\u0107 walidowane na kilku poziomach. Najpro\u015bciej: typy (brak string\u00f3w tam, gdzie powinny by\u0107 enumy), zakresy (np. mno\u017cnik obra\u017ce\u0144 mi\u0119dzy 0 a 10), sp\u00f3jno\u015b\u0107 referencji (czy wszystkie <code>itemId<\/code> istniej\u0105 w bazie przedmiot\u00f3w). Dobrze jest te\u017c mie\u0107 prosty tryb \u201econtent validation\u201d odpalany przy buildzie lub starcie gry w dev-buildzie, kt\u00f3ry przeleci wszystkie configi i wypluje list\u0119 ostrze\u017ce\u0144.<\/p>\n<p>Najgro\u017aniejsze s\u0105 b\u0142\u0119dy, kt\u00f3re \u201eprawie dzia\u0142aj\u0105\u201d: boss, kt\u00f3rego da si\u0119 zabi\u0107 tylko jednym konkretnym buildem, niesko\u0144czona ekonomia przez \u017ale wpisany mno\u017cnik, czy poziom, kt\u00f3rego nikt na QA nie przeszed\u0142, bo HP przeciwnik\u00f3w skoczy\u0142o dziesi\u0119ciokrotnie. Im bardziej elastyczny system danych, tym wi\u0119cej musisz mie\u0107 bezpiecznik\u00f3w. Samo ograniczenie typ\u00f3w czy zakres\u00f3w to za ma\u0142o \u2013 potrzebne s\u0105 jeszcze regu\u0142y biznesowe: minimalne i maksymalne sumy statystyk, zakazane kombinacje perk\u00f3w, ostrze\u017cenia przy podejrzanie skrajnych warto\u015bciach. Cz\u0119\u015b\u0107 takich regu\u0142 da si\u0119 zaszy\u0107 bezpo\u015brednio w edytorze, cz\u0119\u015b\u0107 w skryptach walidacyjnych, kt\u00f3re odpalaj\u0105 si\u0119 przy ka\u017cdym commicie do repozytorium danych.<\/p>\n<p>Dobr\u0105 praktyk\u0105 jest te\u017c separacja \u015brodowisk: osobne zestawy danych do prototypowania na boku, osobne do \u201eprawie gotowej\u201d kampanii i osobne do produkcyjnych build\u00f3w. Dzi\u0119ki temu eksperymenty jednego designera nie rozwal\u0105 pracy reszty zespo\u0142u, a przypadkowa zmiana w prototypowym drzewku talent\u00f3w nie trafi omy\u0142kowo do wersji na targi. Ten sam mechanizm mo\u017cna wykorzysta\u0107 do szybkiego przygotowywania wariant\u00f3w balansu pod playtesty \u2013 branch w danych, kilka zmian w konfiguracji, walidacja, build i gotowe.<\/p>\n<p>Ostatni element uk\u0142adanki to przejrzysty workflow zmian. Je\u015bli ka\u017cdy mo\u017ce nadpisa\u0107 dowolny plik konfiguracyjny w dowolnym momencie, konflikty i \u201eznikaj\u0105ce\u201d zmiany s\u0105 tylko kwesti\u0105 czasu. Du\u017co zdrowiej dzia\u0142a prosty proces: w\u0142a\u015bciciele obszar\u00f3w (combat, ekonomia, progresja) zatwierdzaj\u0105 pull requesty z danymi, a na poziomie narz\u0119dzi jest historia zmian z szybkim podgl\u0105dem diff\u00f3w. Gdy nagle po merge\u2019u co\u015b si\u0119 rozsypie, da si\u0119 w kilka minut sprawdzi\u0107, kt\u00f3ra konkretna liczba posz\u0142a nie tak, zamiast zgadywa\u0107, \u201eco wczoraj kto\u015b m\u00f3g\u0142 dotkn\u0105\u0107\u201d.<\/p>\n<p>Architektura gry nie polega tylko na \u0142adnych diagramach klas, ale przede wszystkim na decyzjach, gdzie p\u0142ynie logika, kt\u00f3r\u0119dy przep\u0142ywaj\u0105 dane i kto ma prawo je modyfikowa\u0107. Je\u015bli od pocz\u0105tku pilnujesz jasnych granic mi\u0119dzy systemami, rozs\u0105dnej komunikacji i jednego \u017ar\u00f3d\u0142a prawdy dla contentu, p\u00f3\u017any etap produkcji przestaje by\u0107 walk\u0105 z chaosem, a staje si\u0119 \u201etylko\u201d intensywnym dowo\u017ceniem \u2013 z kodem, kt\u00f3ry gra z zespo\u0142em do jednej bramki, zamiast strzela\u0107 samob\u00f3je w ostatniej minucie.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Testowanie_architektury_jak_nie_oszukac_samego_siebie\"><\/span>Testowanie architektury: jak nie oszuka\u0107 samego siebie<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Deadline za tydzie\u0144, build \u201eprawie stabilny\u201d, a tu nagle: gracz nie dostaje nagrody za misj\u0119, ekonomia wariuje, a czasami po wczytaniu save\u2019a przeciwnicy maj\u0105 dziwne statystyki. Zesp\u00f3\u0142 sp\u0119dza dwa dni na r\u0119cznym odtwarzaniu krok\u00f3w, bo ka\u017cde odpalenie gry to inny zestaw bug\u00f3w. Niby systemy s\u0105 \u201e\u0142adnie\u201d podzielone, ale nikt tak naprawd\u0119 nie testowa\u0142 ich w izolacji.<\/p>\n<p>Architektura, kt\u00f3rej nie da si\u0119 testowa\u0107 automatycznie, w praktyce przestaje by\u0107 architektur\u0105, a staje si\u0119 zbiorem optymistycznych za\u0142o\u017ce\u0144. Ju\u017c na poziomie projektowania warto zadba\u0107 o to, by najwa\u017cniejsze klocki da\u0142o si\u0119 odpi\u0105\u0107 od engine\u2019a, UI i contentu, a potem odpala\u0107 je w suchym, powtarzalnym \u015brodowisku. Chodzi o to, \u017ceby wiedzie\u0107, \u017ce <em>CombatSystem<\/em> dzia\u0142a poprawnie, zanim zacznie wsp\u00f3\u0142pracowa\u0107 z animacjami, efektami i sieci\u0105.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Systemy_gry_jako_testowalne_%E2%80%9Eczarne_skrzynki%E2%80%9D\"><\/span>Systemy gry jako testowalne \u201eczarne skrzynki\u201d<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Najzdrowszy wzorzec: traktujesz ka\u017cdy istotny system gry jak us\u0142ug\u0119 z wyra\u017anym API. Do \u015brodka wk\u0142adasz wej\u015bcia, z zewn\u0105trz obserwujesz wyj\u015bcia, a ca\u0142\u0105 reszt\u0119 ukrywasz. Je\u015bli system do policzenia obra\u017ce\u0144 wymaga bezpo\u015brednich odwo\u0142a\u0144 do komponent\u00f3w Unity, singleton\u00f3w i globalnych mened\u017cer\u00f3w, testy b\u0119d\u0105 bole\u0107 \u2013 a wi\u0119c nikt ich nie b\u0119dzie pisa\u0142.<\/p>\n<p>Zamiast tego projektuj systemy tak, by:<\/p>\n<ul>\n<li>przyjmowa\u0142y proste struktury danych (inputy), a nie referencje do GameObject\u00f3w,<\/li>\n<li>zwraca\u0142y wyniki w formie <em>komend<\/em> lub zmian stanu, kt\u00f3re mo\u017cna \u0142atwo zweryfikowa\u0107,<\/li>\n<li>nie polega\u0142y na czasie globalnym, tylko na parametrach typu <code>deltaTime<\/code> przekazywanych z zewn\u0105trz.<\/li>\n<\/ul>\n<p>Przyk\u0142ad z \u017cycia: zesp\u00f3\u0142 najpierw pisa\u0142 logik\u0119 ekonomii jako seri\u0119 skrypt\u00f3w MonoBehaviour, kt\u00f3re same si\u0119 rejestrowa\u0142y do event\u00f3w UI i save\u2019a. Po kilku sprintach przenie\u015bli regu\u0142y ekonomii do czystej klasy <code>EconomySimulation<\/code>, kt\u00f3ra przyjmowa\u0142a stan gracza i list\u0119 operacji (kupno, sprzeda\u017c, nagroda), a zwraca\u0142a zaktualizowany stan. Nagle da\u0142o si\u0119 w kilka minut przeklika\u0107 dziesi\u0105tki scenariuszy w testach jednostkowych, bez wstawania od konsoli.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Testy_regresji_dla_contentu_nie_tylko_dla_kodu\"><\/span>Testy regresji dla contentu, nie tylko dla kodu<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>W grach wi\u0119kszo\u015b\u0107 b\u0142\u0119d\u00f3w rodzi si\u0119 nie w samym kodzie, tylko na styku kod\u2013content. Nowy przeciwnik z niekompletn\u0105 konfiguracj\u0105, misja bez nagrody, skill bez opisu \u2013 wszystko formalnie \u201ekompiluje si\u0119\u201d, ale w runtime wybucha. Tu przydaje si\u0119 inny rodzaj test\u00f3w: automatyczne sprawdzanie <em>przep\u0142yw\u00f3w<\/em> gry z u\u017cyciem prawdziwych danych.<\/p>\n<p>Zamiast wymaga\u0107 od QA, by co build r\u0119cznie przechodzili ten sam samouczek, mo\u017cna:<\/p>\n<ul>\n<li>zbudowa\u0107 prostego \u201ebota\u201d, kt\u00f3ry klika podstawowe \u015bcie\u017cki (nowa kampania, pierwsza misja, podstawowy sklep),<\/li>\n<li>odpala\u0107 skrypty, kt\u00f3re przebiegaj\u0105 po wszystkich definicjach misji i sprawdzaj\u0105, czy ka\u017cda ma warunki startu, zako\u0144czenia i nagrody,<\/li>\n<li>przy ka\u017cdym merge\u2019u konfiguracji generowa\u0107 raport: czy kt\u00f3rakolwiek \u015bcie\u017cka progresji sta\u0142a si\u0119 nieosi\u0105galna lub nielogiczna.<\/li>\n<\/ul>\n<p>Takie testy dzia\u0142aj\u0105 tylko wtedy, gdy architektura gry prowadzi \u201enormalne\u201d akcje przez jeden, przewidywalny tor: np. <code>QuestSystem<\/code> zawsze emituje te same eventy przy starcie i zako\u0144czeniu questa, a <code>RewardSystem<\/code> zawsze u\u017cywa jednego API do przyznawania nagr\u00f3d. Je\u015bli cz\u0119\u015b\u0107 gry rozdaje z\u0142oto przez <code>GrantGold()<\/code>, a cz\u0119\u015b\u0107 przez bezpo\u015bredni\u0105 manipulacj\u0119 polem <code>player.Gold += x<\/code>, \u017caden automatyczny test nie z\u0142apie ca\u0142o\u015bci.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Symulacje_i_%E2%80%9Etime-lapse%E2%80%9D_na_silniku\"><\/span>Symulacje i \u201etime-lapse\u201d na silniku<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Ko\u0144c\u00f3wka produkcji to walka z b\u0142\u0119dami, kt\u00f3re wychodz\u0105 dopiero po d\u0142u\u017cszej rozgrywce: inflacja waluty po kilkunastu godzinach, akumuluj\u0105ce si\u0119 buffy, rzadkie kombinacje zdarze\u0144. R\u0119czne testowanie takich przypadk\u00f3w jest praktycznie nierealne w sensownym czasie, ale architektura mo\u017ce u\u0142atwi\u0107 wbudowanie \u201etrybu przyspieszonego \u017cycia gry\u201d.<\/p>\n<p>Je\u015bli kluczowe systemy s\u0105 odci\u0119te od realnego czasu i renderingu, mo\u017cesz zbudowa\u0107 specjalny modu\u0142 symulacji, kt\u00f3ry:<\/p>\n<ul>\n<li>odpala cykle gry z pomini\u0119ciem UI i grafiki,<\/li>\n<li>w jednym uruchomieniu symuluje dziesi\u0105tki lub setki \u201edni\u201d kampanii,<\/li>\n<li>loguje metryki: \u015brednie zarobki gracza, typowe poziomy trudno\u015bci, cz\u0119sto\u015b\u0107 \u015bmierci.<\/li>\n<\/ul>\n<p>W jednym projekcie mobilnym taki \u201etime-lapse\u201d uratowa\u0142 ekonomi\u0119 free-to-play. Dopiero po zasymulowaniu setek sesji wida\u0107 by\u0142o, \u017ce pewna promocja sklepu kumuluje si\u0119 z innymi bonusami i po kilku dniach gracze p\u0142ywaj\u0105 w walucie. Bez mo\u017cliwo\u015bci uruchomienia gry w trybie czystej symulacji problem wyszed\u0142by dopiero po soft-launchu.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Architektura_pod_multiplayer_i_siec_minimalizowanie_bolu_synchronizacji\"><\/span>Architektura pod multiplayer i sie\u0107: minimalizowanie b\u00f3lu synchronizacji<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Na pocz\u0105tku \u201eto ma by\u0107 single\u201d, a po p\u00f3\u0142 roku pojawia si\u0119 mail: \u201ePotrzebujemy co-opu, to zwi\u0119kszy retencj\u0119\u201d. Silnik niby ma wsparcie sieciowe, ale architektura gry zak\u0142ada, \u017ce wszystko dzieje si\u0119 lokalnie, po kolei, bez \u017cadnych op\u00f3\u017anie\u0144. Ka\u017cde wej\u015bcie gracza bezpo\u015brednio modyfikuje stan obiekt\u00f3w. W takiej sytuacji dorobienie multiplayera staje si\u0119 przepisywaniem fundament\u00f3w.<\/p>\n<p>O wiele bezpieczniej jest od pocz\u0105tku my\u015ble\u0107 o grze tak, jakby <em>mog\u0142a<\/em> kiedy\u015b trafi\u0107 na sie\u0107, nawet je\u015bli to tylko abstrakcja. Nie chodzi o pe\u0142ny netcode od dnia pierwszego, ale o dwie proste zasady: separacj\u0119 inputu od logiki oraz deterministyczny model stanu tam, gdzie to mo\u017cliwe.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Input_jako_zdarzenia_nie_jako_bezposrednia_zmiana_stanu\"><\/span>Input jako zdarzenia, nie jako bezpo\u015brednia zmiana stanu<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Je\u015bli klikni\u0119cie przycisku skoku od razu ustawia wektor pr\u0119dko\u015bci gracza na komponencie fizyki, synchronizacja przez sie\u0107 b\u0119dzie koszmarem. Zdecydowanie lepszy tor to: input generuje zdarzenie \u201egracz chce skoczy\u0107\u201d, system ruchu decyduje, czy mo\u017cna skoczy\u0107, a dopiero potem modyfikuje stan. Dla trybu solo to dodatkowa abstrakcja, ale dla sieci \u2013 konieczno\u015b\u0107.<\/p>\n<p>Podej\u015bcie zdarzeniowe daje kilka korzy\u015bci:<\/p>\n<ul>\n<li>te same zdarzenia mo\u017cna wys\u0142a\u0107 po sieci do innych klient\u00f3w lub na serwer,<\/li>\n<li>\u0142atwiej debugowa\u0107, co <em>naprawd\u0119<\/em> si\u0119 wydarzy\u0142o (\u201eplayerJumpRequested\u201d zamiast \u201egdzie\u015b kto\u015b zmieni\u0142 velocity\u201d),<\/li>\n<li>przechowywanie log\u00f3w wej\u015b\u0107 pozwala odtwarza\u0107 i reprodukowa\u0107 trudne bugi.<\/li>\n<\/ul>\n<p>W praktyce oznacza to wprowadzenie warstwy <code>InputCommands<\/code> lub <code>GameActions<\/code>, kt\u00f3re s\u0105 jedyn\u0105 walut\u0105 mi\u0119dzy graczem a \u015bwiatem. UI, kontrolery i sztuczna inteligencja produkuj\u0105 komendy, systemy gameplayowe je konsumuj\u0105. Zamiana local-play na online w najprostszym wariancie sprowadza si\u0119 do tego, kto jest \u017ar\u00f3d\u0142em komend: lokalny gracz czy zdalny peer\/serwer.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Stan_gry_jako_cos_co_da_sie_replikowac\"><\/span>Stan gry jako co\u015b, co da si\u0119 replikowa\u0107<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Kolejny k\u0142opot pojawia si\u0119 wtedy, gdy stan gry jest rozsiany po setkach obiekt\u00f3w, singletonach i polach statycznych. Sie\u0107 wymaga prostego pytania: \u201eco jest prawd\u0105 o \u015bwiecie w tym momencie?\u201d i \u201eco dok\u0142adnie trzeba przes\u0142a\u0107, by inna maszyna odwzorowa\u0142a ten stan?\u201d. Je\u015bli odpowied\u017a brzmi \u201eto zale\u017cy, gdzie akurat siedzi ten bool i ten licznik\u201d, jeste\u015b na straconej pozycji.<\/p>\n<p>Tu szczeg\u00f3lnie pomaga podej\u015bcie ECS-owe lub chocia\u017c silne rozdzielenie <code>GameState<\/code> od reszty. Nawet w klasycznym OOP mo\u017cesz zdefiniowa\u0107 zestaw <em>modeli stanu<\/em>, kt\u00f3re reprezentuj\u0105:<\/p>\n<ul>\n<li>list\u0119 byt\u00f3w w \u015bwiecie (ID, typ, kluczowe parametry),<\/li>\n<li>globalne parametry sesji (czas rundy, faza meczu, aktywne modyfikatory),<\/li>\n<li>stan graczy (pozycja, HP, zasoby, cooldowny).<\/li>\n<\/ul>\n<p>Silnik wizualny i audio tylko \u201erenderuj\u0105\u201d ten stan, ale nie s\u0105 jego w\u0142a\u015bcicielami. W takim uk\u0142adzie wys\u0142anie stanu przez sie\u0107 to serializacja jasno zdefiniowanych struktur, a nie b\u0142\u0105dzenie po drzewie sceny.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Separacja_%E2%80%9Eautoritative_logic%E2%80%9D_od_reszty\"><\/span>Separacja \u201eautoritative logic\u201d od reszty<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Je\u017celi w kt\u00f3rymkolwiek momencie zak\u0142adasz mo\u017cliwo\u015b\u0107 serwera autorytatywnego, rozdziel to, co <em>musi<\/em> by\u0107 egzekwowane po jednej stronie, od tego, co mo\u017ce by\u0107 tylko wizualizacj\u0105 lub predykcj\u0105. Inaczej b\u0119dziesz w panice wybiera\u0107, co przenie\u015b\u0107 na serwer, a co zostawi\u0107 na kliencie.<\/p>\n<p>Dobra praktyka to wydzielony modu\u0142 \u201ecore gameplay logic\u201d, kt\u00f3ry nie zale\u017cy od UI, kamery i lokalnych efekt\u00f3w. Zawiera przepisy na:<\/p>\n<ul>\n<li>regu\u0142y kolizji i obra\u017ce\u0144,<\/li>\n<li>warunki zako\u0144czenia meczu,<\/li>\n<li>sprawdzanie poprawno\u015bci akcji gracza (anti-cheat bazowy).<\/li>\n<\/ul>\n<p>Reszta \u2013 animacje, efekty cz\u0105steczkowe, drobne \u201epolishowe\u201d przesuni\u0119cia \u2013 jest dobudowana warstw\u0105 wy\u017cej. Dzi\u0119ki temu potencjalny serwer uruchamia w\u0142a\u015bnie ten \u201erdze\u0144\u201d, klienci za\u015b rekonstruuj\u0105 na jego podstawie atrakcyjny wizualnie obraz gry. Taki podzia\u0142 ratuje te\u017c projekty, w kt\u00f3rych multiplayer na koniec <em>nie<\/em> powstaje \u2013 rdze\u0144 nadal jest czytelniejszy i \u0142atwiejszy w utrzymaniu.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Skalowanie_zespolu_a_architektura_jak_nie_zadeptac_sobie_nawzajem_kodu\"><\/span>Skalowanie zespo\u0142u a architektura: jak nie zadepta\u0107 sobie nawzajem kodu<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Na pocz\u0105tku nad projektem siedzi jedna\u2013dwie osoby i wszystko \u201edogaduje si\u0119\u201d ustnie. Po roku w zespole jest dziesi\u0119ciu programist\u00f3w, kilku designer\u00f3w, osobne QA, a ka\u017cdy merge do g\u0142\u00f3wnej ga\u0142\u0119zi grozi kilkugodzinnym wstrzymaniem pracy. Kod niby \u201edzia\u0142a\u201d, ale ka\u017cdy boi si\u0119 go dotkn\u0105\u0107, bo nikt nie rozumie zale\u017cno\u015bci mi\u0119dzy modu\u0142ami.<\/p>\n<p>Architektura gry to te\u017c projekt komunikacji mi\u0119dzy lud\u017ami. Je\u017celi ka\u017cdy system ma mgliste granice, a odpowiedzialno\u015bci si\u0119 przenikaj\u0105, konflikty w repozytorium s\u0105 tylko objawem \u2013 przyczyn\u0105 jest brak podzia\u0142u w\u0142asno\u015bci i zaufanych interfejs\u00f3w.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Wlasnosc_modulow_i_kontrakty_miedzy_zespolami\"><\/span>W\u0142asno\u015b\u0107 modu\u0142\u00f3w i kontrakty mi\u0119dzy zespo\u0142ami<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Zdrowy projekt wyra\u017anie odpowiada na pytanie: kto jest w\u0142a\u015bcicielem kt\u00f3rego fragmentu \u015bwiata. Nie chodzi o formalne tytu\u0142y, tylko o jasno\u015b\u0107: \u201eza progresj\u0119 odpowiada ten podzesp\u00f3\u0142, za walk\u0119 ten, a za metagr\u0119 ten\u201d. Do ka\u017cdego z tych obszar\u00f3w przypisujesz modu\u0142y kodu i zestaw publicznych interfejs\u00f3w.<\/p>\n<p>W praktyce pomaga:<\/p>\n<ul>\n<li>mapa system\u00f3w (cho\u0107by w Notionie lub na \u015bcianie) z przypisanymi w\u0142a\u015bcicielami,<\/li>\n<li>prosty opis kontrakt\u00f3w: jakie eventy wystawia dany system, jakie dane przyjmuje i zwraca,<\/li>\n<li>zasada: zmiany wewn\u0105trz modu\u0142u mo\u017ce robi\u0107 ka\u017cdy z zespo\u0142u, ale zmiana publicznego API wymaga zgody w\u0142a\u015bciciela.<\/li>\n<\/ul>\n<p>To nie jest biurokracja dla samej biurokracji. Gdy pojawia si\u0119 nowy feature, od razu wiadomo, do kogo i z czym p\u00f3j\u015b\u0107. Zamiast \u201edopinam si\u0119 tu, bo jest najbli\u017cej\u201d, ludzie pytaj\u0105: \u201eczy progresja ma ju\u017c event na zdobycie poziomu?\u201d lub \u201eczy ekonomia wystawia interfejs na modyfikatory cen?\u201d. Kontrakty architektoniczne staj\u0105 si\u0119 tak samo wa\u017cne jak GDD.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Granice_repozytoriow_i_feature_branchy\"><\/span>Granice repozytori\u00f3w i feature branchy<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Przy wi\u0119kszych projektach dobrym krokiem jest rozdzielenie kodu na kilka logicznych pakiet\u00f3w lub nawet osobne repozytoria: core engine\/ramy gry, modu\u0142y gameplayowe, narz\u0119dzia edytorskie. Nie ka\u017cde studio musi od razu budowa\u0107 monorepo na wz\u00f3r du\u017cych firm, ale ju\u017c samo oddzielenie \u201etoolingu\u201d od kodu runtime bywa zbawienne.<\/p>\n<p>Dorzucaj\u0105c do tego rozs\u0105dne podej\u015bcie do ga\u0142\u0119zi w VCS, mo\u017cna znacz\u0105co ograniczy\u0107 chaos:<\/p>\n<ul>\n<li>du\u017ce featury powstaj\u0105 na osobnych branchach z cz\u0119st\u0105 synchronizacj\u0105 do g\u0142\u00f3wnej ga\u0142\u0119zi,<\/li>\n<li>ga\u0142\u0105\u017a \u201erelease\u201d jest zamro\u017cona na czas krytycznych build\u00f3w, a nowe ryzykowne zmiany l\u0105duj\u0105 gdzie indziej,<\/li>\n<li>dane gameplayowe maj\u0105 w\u0142asny cykl zatwierdzania, osobny od kodu.<\/li>\n<\/ul>\n<p>Taki porz\u0105dek tylko wtedy ma sens, je\u015bli architektura kodu u\u0142atwia rozdzielanie zmian. Je\u017celi pojedyncza zmiana w walce dotyka UI, ekonomii, progresji i trzech singleton\u00f3w globalnych, \u017caden workflow w Gitcie tego nie uratuje.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Komunikacja_techniczna_jako_czesc_projektu\"><\/span>Komunikacja techniczna jako cz\u0119\u015b\u0107 projektu<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Jeszcze jeden, niedoceniany w\u0105tek: dokumentowanie decyzji architektonicznych. Nie w formie stu stron diagram\u00f3w UML, tylko kr\u00f3tkich notatek: \u201edlaczego zrobili\u015bmy to tak, a nie inaczej\u201d. Gdy projekt \u017cyje dwa\u2013trzy lata, zesp\u00f3\u0142 si\u0119 zmienia, a nowi ludzie zaczynaj\u0105 grzeba\u0107 w kodzie, brak takiego dziennika decyzyjnego skutkuje \u201erefaktoryzacjami z niewiedzy\u201d.<\/p>\n<p>Sprawdza si\u0119 prosty rytua\u0142:<\/p>\n<ul>\n<li>przy wi\u0119kszej zmianie architektury powstaje kr\u00f3tki ADR (Architecture Decision Record) \u2013 plik z opisem problemu, rozwa\u017canych opcji i wybranej \u015bcie\u017cki,<\/li>\n<li>ADR-y livinguj\u0105 obok kodu, w repozytorium, a nie w zapomnianym folderze na dysku sieciowym,<\/li>\n<li>przegl\u0105d ADR-\u00f3w jest cz\u0119\u015bci\u0105 onboardingu nowych programist\u00f3w.<\/li>\n<\/ul>\n<p>Raz na kilkana\u015bcie sprint\u00f3w kto\u015b i tak zapyta: \u201eczemu ten system jest singletonem?\u201d albo \u201eczemu nie zrobili\u015bmy tego na eventach?\u201d. Zamiast po raz dziesi\u0105ty odgrywa\u0107 t\u0119 sam\u0105 dyskusj\u0119 na korytarzu, odsy\u0142asz do jednego pliku z kontekstem. Ludzie przestaj\u0105 naprawia\u0107 \u201eb\u0142\u0119dy architektoniczne\u201d, kt\u00f3re kiedy\u015b by\u0142y \u015bwiadomym kompromisem pod crunch lub ograniczenia silnika.<\/p>\n<p>Dobrze prowadzona komunikacja techniczna to te\u017c przegl\u0105dy kodu nastawione na architektur\u0119, a nie tylko na styl. Warto jasno powiedzie\u0107 w zespole, \u017ce code review to miejsce na pytania: \u201eczy ten modu\u0142 nie \u0142amie swojej odpowiedzialno\u015bci?\u201d, \u201eczy nie powinni\u015bmy rozbi\u0107 tego na dwa systemy?\u201d \u2013 nie tylko na poprawki nawias\u00f3w. Po kilku takich iteracjach granice system\u00f3w utrwalaj\u0105 si\u0119 nie tylko w diagramach, ale w nawykach ludzi.<\/p>\n<p>Przy rozproszonych zespo\u0142ach pomaga lekkie rytua\u0142y: raz na sprint kr\u00f3tkie \u201etech sync\u201d z jednym, dwoma diagramami, na kt\u00f3rych kto\u015b pokazuje nowy przep\u0142yw danych albo zmieniony kontrakt API. Bez slajd\u00f3w na godzin\u0119 \u2013 15 minut ekranu z edytorem lub tablic\u0105 online. Taki rytm pozwala szybko wychwyci\u0107, \u017ce dwa zespo\u0142y projektuj\u0105 r\u00f3wnolegle konkurencyjne systemy albo \u017ce kto\u015b w\u0142a\u015bnie zamierza wprowadzi\u0107 now\u0105 warstw\u0119 zale\u017cno\u015bci przecinaj\u0105c\u0105 p\u00f3\u0142 projektu.<\/p>\n<p>Im d\u0142u\u017cej gra \u017cyje, tym bardziej wida\u0107, \u017ce architektura nie jest tylko spraw\u0105 \u201e\u0142adnego kodu\u201d. To zestaw \u015bwiadomych ogranicze\u0144, kt\u00f3re chroni\u0105 projekt przed samym sob\u0105: przed feature creepem, przed przypadkowymi zale\u017cno\u015bciami, przed sytuacj\u0105, w kt\u00f3rej ka\u017cdy nowy system musi dotkn\u0105\u0107 wszystkich poprzednich. Dobrze zaprojektowany szkielet gry nie obiecuje, \u017ce unikniesz wszystkich po\u017car\u00f3w w ko\u0144c\u00f3wce produkcji, ale sprawia, \u017ce gasisz je szybko i bez wywracania ca\u0142ej konstrukcji.<\/p>\n<p>Gdy nadchodz\u0105 ostatnie miesi\u0105ce przed premier\u0105, r\u00f3\u017cnica mi\u0119dzy \u201ekodem, kt\u00f3ry jako\u015b dzia\u0142a\u201d a przemy\u015blan\u0105 architektur\u0105 jest brutalnie jasna. W jednym projekcie ka\u017cdy bug to ryzyko lawiny regresji, a ka\u017cdy nowy ekran czy przeciwnik wpycha si\u0119 \u0142okciem w obce modu\u0142y. W drugim \u2013 nawet je\u015bli tempo jest szalone \u2013 istniej\u0105 miejsca, gdzie nowe rzeczy naturalnie \u201esiadaj\u0105\u201d w istniej\u0105cych warstwach. Ten komfort nie bierze si\u0119 z magii ani genialnych pojedynczych programist\u00f3w, tylko z serii przyziemnych decyzji architektonicznych podj\u0119tych du\u017co wcze\u015bniej, kiedy jeszcze nikt nie krzycza\u0142, \u017ce \u201enie mamy czasu na my\u015blenie o strukturze\u201d.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Najczesciej_zadawane_pytania_FAQ\"><\/span>Najcz\u0119\u015bciej zadawane pytania (FAQ)<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3><span class=\"ez-toc-section\" id=\"Jak_zaplanowac_architekture_gry_zeby_uniknac_chaosu_pod_koniec_produkcji\"><\/span>Jak zaplanowa\u0107 architektur\u0119 gry, \u017ceby unikn\u0105\u0107 chaosu pod koniec produkcji?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Najcz\u0119\u015bciej zaczyna si\u0119 niewinnie: kilka \u201eszybkich hack\u00f3w\u201d w prototypie, jeden wszechmocny GameManager, troch\u0119 singleton\u00f3w \u201ena chwil\u0119\u201d i po kilku miesi\u0105cach ka\u017cda zmiana wywo\u0142uje efekt domina. Kluczem jest zaplanowanie podstawowych warstw i modu\u0142\u00f3w jeszcze na etapie prototypu, zanim kod uro\u015bnie i stanie si\u0119 trudny do ruszenia.<\/p>\n<p>Praktycznie oznacza to: wyra\u017any podzia\u0142 na logik\u0119 gry, warstw\u0119 silnika i prezentacj\u0119 (UI, efekty), a tak\u017ce osobne modu\u0142y tematyczne, jak Inventory, Combat, Quests. Ka\u017cdy modu\u0142 powinien mie\u0107 jasne API, minimalne zale\u017cno\u015bci i komunikowa\u0107 si\u0119 przez zdarzenia lub komunikaty, a nie bezpo\u015brednie \u201egrzebanie\u201d w stanie innych system\u00f3w.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Jak_podzielic_kod_gry_na_warstwy_w_Unity_Unreal_lub_Godot\"><\/span>Jak podzieli\u0107 kod gry na warstwy w Unity, Unreal lub Godot?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Typowy problem wygl\u0105da tak: logika walki, UI i operacje na scenie siedz\u0105 w jednym MonoBehaviour \/ Actorze, wi\u0119c ka\u017cda modyfikacja oznacza przebudow\u0119 ca\u0142ego potworka. Prostszym i bezpieczniejszym modelem jest rozdzielenie zale\u017cnych od silnika komponent\u00f3w od \u201eczystej\u201d logiki gry.<\/p>\n<p>W praktyce mo\u017cna to zrobi\u0107 tak: klasy MonoBehaviour\/Actor\/Godot Node pe\u0142ni\u0105 rol\u0119 adapter\u00f3w \u2013 odbieraj\u0105 wej\u015bcie, wo\u0142aj\u0105 metody z warstwy domeny (np. CombatService, InventoryService), a potem aktualizuj\u0105 animacje, UI i efekty. Logika zasad (obra\u017cenia, do\u015bwiadczenie, questy) nie powinna zna\u0107 szczeg\u00f3\u0142\u00f3w scen, prefab\u00f3w ani UI, dzi\u0119ki czemu da si\u0119 j\u0105 testowa\u0107 i przenosi\u0107 mi\u0119dzy projektami.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Czym_rozni_sie_dobra_architektura_gry_od_architektury_aplikacji_biznesowych\"><\/span>Czym r\u00f3\u017cni si\u0119 dobra architektura gry od architektury aplikacji biznesowych?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>W aplikacji biznesowej najgorsze, co si\u0119 zwykle stanie, to wolne zapytanie lub b\u0142\u0105d walidacji; w grze spadek poni\u017cej 30\/60 FPS jest od razu odczuwalny jako \u201egra jest zepsuta\u201d. Dlatego w grach trzeba ci\u0105gle balansowa\u0107 mi\u0119dzy czysto\u015bci\u0105 kodu a wydajno\u015bci\u0105 p\u0119tli g\u0142\u00f3wnej i krytycznych system\u00f3w, takich jak AI, fizyka czy renderowanie.<\/p>\n<p>Druga r\u00f3\u017cnica to skala zmienno\u015bci stanu. Gra co klatk\u0119 aktualizuje dziesi\u0105tki system\u00f3w, kt\u00f3re wp\u0142ywaj\u0105 na siebie nawzajem (buffy, \u015bwiat\u0142o, d\u017awi\u0119k, UI, questy). Architektura musi ogranicza\u0107 bezpo\u015brednie zale\u017cno\u015bci i zapewnia\u0107 lokalno\u015b\u0107 skutk\u00f3w b\u0142\u0119d\u00f3w; nadmiar warstw i \u201eenterprise\u2019owych\u201d wzorc\u00f3w z aplikacji biznesowych zwykle tylko spowalnia prac\u0119 i utrudnia eksperymentowanie z mechanikami.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Dlaczego_klasyczne_OOP_i_DDD_czesto_zle_sie_sprawdzaja_w_game_devie\"><\/span>Dlaczego klasyczne OOP i DDD cz\u0119sto \u017ale si\u0119 sprawdzaj\u0105 w game devie?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Wiele zespo\u0142\u00f3w przerabia ten scenariusz: na pocz\u0105tku powstaje eleganckie drzewo dziedziczenia postaci, broni i przeciwnik\u00f3w, a po kilku miesi\u0105cach drobna zmiana w logice gracza wymaga ruszenia po\u0142owy hierarchii. G\u0142\u0119bokie dziedziczenie i wszechmocne klasy bazowe prowadz\u0105 do kruchego kodu, kt\u00f3rego nikt nie chce rusza\u0107 pod koniec produkcji.<\/p>\n<p>DDD ma podobny problem, gdy stosuje si\u0119 je dogmatycznie: zbyt wiele warstw, zbyt ci\u0119\u017ckie modelowanie domeny i ma\u0142o przestrzeni na szybkie eksperymenty. W grach lepiej sprawdza si\u0119 kompozycja (sk\u0142adanie zachowa\u0144 z mniejszych komponent\u00f3w) oraz selektywne u\u017cycie DDD w miejscach o stabilnej domenie, np. ekonomii gry, systemie progresji czy kontraktach sieciowych.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Jak_podzielic_gre_na_moduly_zeby_zespolowi_bylo_latwiej_pracowac\"><\/span>Jak podzieli\u0107 gr\u0119 na modu\u0142y, \u017ceby zespo\u0142owi by\u0142o \u0142atwiej pracowa\u0107?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Chaotyczne repozytorium z folderem \u201eScripts\u201d pe\u0142nym losowych plik\u00f3w to prosta droga do sytuacji, w kt\u00f3rej nikt nie wie, gdzie co\u015b doda\u0107 ani co mo\u017cna bezpiecznie zmieni\u0107. Du\u017co lepiej dzia\u0142aj\u0105 modu\u0142y odzwierciedlaj\u0105ce g\u0142\u00f3wne obszary gry, z w\u0142asnymi modelami danych i punktami wej\u015bcia.<\/p>\n<p>Przyk\u0142adowy podzia\u0142 to: Inventory, Combat, Quests, Characters, World, UI, Save\/Load, Meta-progression. Ka\u017cdy modu\u0142 ma \u201efasad\u0119\u201d (np. InventorySystem), przez kt\u00f3r\u0105 reszta gry si\u0119 z nim komunikuje, oraz jasno okre\u015blone zale\u017cno\u015bci. Dzi\u0119ki temu \u0142atwiej delegowa\u0107 prac\u0119, szybciej debugowa\u0107 problemy i ogranicza\u0107 sytuacje, w kt\u00f3rych bug w ekwipunku psuje zapis gry i interfejs.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Jakie_sa_praktyczne_kryteria_oceny_czy_architektura_gry_jest_dobra\"><\/span>Jakie s\u0105 praktyczne kryteria oceny, czy architektura gry jest dobra?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Najbardziej obrazowy test to koniec produkcji: je\u015bli dodanie nowego typu przeciwnika albo zmiana balansu broni wymaga tkwienia tydzie\u0144 w refaktorach, co\u015b jest nie tak. Je\u015bli natomiast zmiany robi\u0105 si\u0119 szybko, a regresje s\u0105 lokalne (bug w combacie nie rozwala dialog\u00f3w), architektura spe\u0142nia swoje zadanie.<\/p>\n<p>Przydatne kryteria to: liczba miejsc, kt\u00f3re trzeba zmodyfikowa\u0107 przy typowej zmianie, lokalno\u015b\u0107 skutk\u00f3w b\u0142\u0119d\u00f3w, \u0142atwo\u015b\u0107 \u015bledzenia przep\u0142ywu zdarze\u0144 podczas debugowania oraz mo\u017cliwo\u015b\u0107 stopniowej refaktoryzacji modu\u0142 po module, bez \u201ewielkiego przepisywania\u201d wszystkiego naraz.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Czy_w_malej_grze_indie_naprawde_potrzebna_jest_przemyslana_architektura\"><\/span>Czy w ma\u0142ej grze indie naprawd\u0119 potrzebna jest przemy\u015blana architektura?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>W ma\u0142ych zespo\u0142ach presja \u201erobimy szybko, bo i tak wszystko si\u0119 zmieni\u201d jest ogromna, wi\u0119c prototypy cz\u0119sto wchodz\u0105 do produkcji prawie bez zmian. Skutek bywa taki, \u017ce przy pierwszym wi\u0119kszym scope creep\u2019ie projekt grz\u0119\u017anie, bo ka\u017cda nowa mechanika wymaga ruszenia starego, kruchego kodu, kt\u00f3rego nikt ju\u017c dobrze nie pami\u0119ta.<\/p>\n<p>Prosty, ale \u015bwiadomy szkielet architektoniczny \u2013 warstwy (silnik\/domena\/prezentacja) i kilka dobrze odseparowanych modu\u0142\u00f3w \u2013 to rodzaj ubezpieczenia. Koszt wdro\u017cenia jest niewielki, a zysk pojawia si\u0119 wtedy, gdy trzeba utrzyma\u0107 projekt przez wiele miesi\u0119cy, wprowadza\u0107 zmiany na finiszu i unika\u0107 parali\u017cu spowodowanego jednym, wszechw\u0142adnym GameManagerem.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Zrodla\"><\/span>\u0179r\u00f3d\u0142a<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<ul>\n<li><strong>Game Programming Patterns<\/strong>. Genever Benning (2014) \u2013 Wzorce architektury i organizacji kodu w grach, kompozycja vs dziedziczenie<\/li>\n<li><strong>Game Engine Architecture<\/strong>. A K Peters \/ CRC Press (2018) \u2013 Struktura silnik\u00f3w, p\u0119tla g\u0142\u00f3wna, warstwy system\u00f3w i zale\u017cno\u015bci<\/li>\n<li><strong>Game Programming Gems<\/strong>. Charles River Media (2000) \u2013 Zbi\u00f3r praktyk in\u017cynierii oprogramowania i optymalizacji w grach<\/li>\n<li><strong>Game Coding Complete<\/strong>. Course Technology PTR (2012) \u2013 Architektura gry, modu\u0142owo\u015b\u0107, separacja logiki od prezentacji<\/li>\n<li><strong>Patterns of Enterprise Application Architecture<\/strong>. Addison-Wesley (2002) \u2013 Wzorce architektoniczne, por\u00f3wnanie z aplikacjami biznesowymi<\/li>\n<li><strong>Clean Architecture: A Craftsman&#039;s Guide to Software Structure and Design<\/strong>. Pearson (2017) \u2013 Warstwowanie, separacja domeny, kryteria jako\u015bci architektury<\/li>\n<\/ul>\n<p><em><\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Poznaj praktyczne zasady architektury kodu gry, kt\u00f3re uchroni\u0105 Tw\u00f3j projekt przed chaosem w ko\u0144cowej fazie tworzenia.<\/p>\n","protected":false},"author":11,"featured_media":12899,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[49],"tags":[],"class_list":["post-12898","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-game-development"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/excelraport.pl\/index.php\/wp-json\/wp\/v2\/posts\/12898","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/excelraport.pl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/excelraport.pl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/excelraport.pl\/index.php\/wp-json\/wp\/v2\/users\/11"}],"replies":[{"embeddable":true,"href":"https:\/\/excelraport.pl\/index.php\/wp-json\/wp\/v2\/comments?post=12898"}],"version-history":[{"count":1,"href":"https:\/\/excelraport.pl\/index.php\/wp-json\/wp\/v2\/posts\/12898\/revisions"}],"predecessor-version":[{"id":12901,"href":"https:\/\/excelraport.pl\/index.php\/wp-json\/wp\/v2\/posts\/12898\/revisions\/12901"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/excelraport.pl\/index.php\/wp-json\/wp\/v2\/media\/12899"}],"wp:attachment":[{"href":"https:\/\/excelraport.pl\/index.php\/wp-json\/wp\/v2\/media?parent=12898"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/excelraport.pl\/index.php\/wp-json\/wp\/v2\/categories?post=12898"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/excelraport.pl\/index.php\/wp-json\/wp\/v2\/tags?post=12898"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}