Jak zacząć tworzyć gry w Unity: praktyczny przewodnik dla początkujących graczy i twórców

0
26
Rate this post

Z tego artykuły dowiesz się:

Od gracza do twórcy – zmiana perspektywy

Różnica między „lubię grać” a „umiem tworzyć gry”

Gracz śledzi akcję, twórca widzi pod spodem mechanikę. Gdy grasz w FPS-a, myślisz o tym, czy broń „dobrze się czuje”, czy przeciwnik nie jest zbyt mocny. Gdy zaczynasz tworzyć gry w Unity, zaczynasz patrzeć inaczej: jak działa system strzelania, w jaki sposób liczona jest celność, co powoduje, że wróg reaguje po określonym czasie. Ten sam ekran, ale całkiem inny sposób myślenia.

Różnica jest podobna jak między oglądaniem filmu a jego kręceniem. Odbiorca widzi fabułę, reżyser wyłapuje ustawienie światła, kadry, montaż. Jako przyszły twórca gier musisz zacząć „rozbierać” rozgrywkę na elementy składowe: sterowanie, zasady, interfejs, feedback dla gracza (dźwięki, animacje, komunikaty).

Przy pierwszych podejściach do Unity sporo osób czuje lekkie rozczarowanie: to wcale nie jest taki „magiczny kreator gier”, który wszystko zrobi sam. Unity daje narzędzia, ale puzzle nadal trzeba ułożyć ręcznie. Za to dokładnie dzięki temu możesz tworzyć coś naprawdę swojego, a nie tylko „klikane” szablony.

Czego oczekiwać po kilku miesiącach nauki Unity

Po 2–3 miesiącach regularnej nauki (kilka godzin tygodniowo) osoba, która naprawdę zaczęła od zera, jest zwykle w stanie:

  • zrobić prostą grę 2D typu „klikacz” albo nieskończony runner,
  • zrozumieć i samodzielnie zmodyfikować podstawowe skrypty w C#,
  • korzystać z komponentów takich jak Rigidbody, Collider, SpriteRenderer,
  • zbudować (Build) grę na PC i uruchomić ją poza Unity,
  • dodać prosty interfejs: menu startowe, licznik punktów, ekran „Game Over”.

W tym czasie raczej nie zbudujesz sieciowego MMO ani „własnego Wiedźmina” – i to jest zupełnie normalne. Dobrym celem jest natomiast mała, grywalna produkcja, którą pokażesz znajomym lub wrzucisz na itch.io.

Największa różnica między osobą, która się rozwija, a tą, która porzuca temat, wynika z nastawienia. Ktoś, kto zakłada, że „za miesiąc zrobię hit na Steam”, bardzo szybko się frustruje. Ktoś, kto mówi: „co tydzień dopiszę jedną małą funkcję i nauczę się jednej nowej rzeczy”, po kilku miesiącach ma już kilka prostych prototypów.

Typowa ścieżka początkującego twórcy

Najczęstszy scenariusz wygląda podobnie: trafiasz na pierwszy film „Unity dla początkujących”, odpalasz gotowy projekt i robisz wszystko krok w krok. Po godzinie masz grę, ale nie do końca wiesz, dlaczego to działa. Kolejny etap to modyfikacja: zmieniasz prędkość postaci, kolory, dodajesz nowy przeszkadzajnik. Nagle kod przestaje działać i pojawia się pierwszy prawdziwy problem do rozwiązania.

Tu zaczyna się właściwa nauka. Zamiast kopiować linijki bez zrozumienia, czytasz, co to jest Update(), czemu zmienna musi być publiczna, dlaczego kolizje nie wywołują się bez Rigidbody. Ktoś na forum radzi, aby użyć Debug.Log i sprawdzić, czy funkcja w ogóle się uruchamia – poznajesz kolejne narzędzie.

Po kilku takich pętlach (tutorial → własna modyfikacja → błąd → szukanie rozwiązania) powoli przechodzisz z poziomu „odtwarzam” na poziom „projektuję”. Zamiast szukać gotowego filmiku „jak zrobić skakanie”, zaczynasz samodzielnie myśleć: „potrzebuję siły w górę po wciśnięciu spacji i sprawdzenia, czy stoję na ziemi”. To moment, w którym zaczyna się prawdziwe tworzenie gier w Unity.

Nastawienie: zgoda na brzydotę i iteracje

Prototyp gry prawie zawsze wygląda fatalnie: kwadratowe postacie, zielone tło, przypadkowe dźwięki. I bardzo dobrze. Pierwszym celem nie jest piękno, tylko grywalność. Dopiero gdy mechanika „niesie” i testujący faktycznie bawią się przy Twoim projekcie, ma sens inwestowanie czasu w grafiki i efekty.

Dobrym nawykiem jest szybkie iterowanie: zamiast planować przez tygodnie, zrób najprostszy działający wariant, przetestuj, popraw jedną rzecz i znowu zagraj. Taka metoda działa zarówno przy małych projektach, jak i przy większych, komercyjnych grach. Nawet jeśli marzy Ci się kiedyś własne studio, opanowanie nawyku częstych, małych iteracji będzie ogromnym atutem.

Czasem pomaga metafora szkicownika. Rysownik potrafi stworzyć dziesiątki brudnych szkiców, zanim pokaże światu jeden dopracowany obraz. Prototypy w Unity to właśnie takie szkice. Im więcej ich zrobisz, tym szybciej się uczysz.

Co właściwie robi Unity i z czego się składa

Silnik gry jako reżyser: scena, aktorzy i komponenty

Unity jest silnikiem gry, ale można o nim myśleć jak o reżyserze teatralnym. Masz scenę (Scene), czyli miejsce akcji; masz aktorów (GameObjecty), którzy pojawiają się na scenie; masz też ich umiejętności i cechy, czyli komponenty (Components). W trakcie „przedstawienia” reżyser dba, aby wszystko działo się w odpowiednim czasie i kolejności.

GameObject sam z siebie jest jak pusta kukiełka – nie robi nic. Dopiero dodanie komponentów nadaje mu sens: Transform określa położenie, Rigidbody – fizykę, Collider – kolizje, Renderer – widoczność na ekranie. Skrypt w C# to kolejny komponent, który opisuje zachowanie: ruch, strzelanie, znikanie po czasie.

Ta kompozycyjna filozofia jest sercem pracy w Unity. Zamiast pisać od zera gigantyczne klasy „Gracz” czy „Wróg”, budujesz zachowanie z klocków – komponentów, które można łączyć w różnych konfiguracjach.

Podstawowe okna i ich rola

Po uruchomieniu Unity widzisz kilka kluczowych okien. Poznanie ich przeznaczenia oszczędza mnóstwo czasu i frustracji:

  • Hierarchy – lista wszystkich obiektów znajdujących się na aktualnej scenie; tu widać strukturę „drzewka” (rodzic–dziecko).
  • Scene – widok edytora, w którym przesuwasz, obracasz i skalujesz obiekty; taki „podgląd od kuchni”.
  • Game – to, co widzi gracz; podgląd z kamery w czasie uruchomienia gry.
  • Inspector – panel z ustawieniami zaznaczonego obiektu; tutaj dodajesz, usuwasz i konfigurujesz komponenty.
  • Project – struktura plików projektu: sceny, skrypty, grafiki, dźwięki, prefaby.
  • Console – komunikaty z gry: błędy, ostrzeżenia i własne logi z Debug.Log.

Dobrym nawykiem jest częste spoglądanie na Console. Gdy coś nie działa, pierwszym krokiem jest sprawdzenie, czy nie pojawił się czerwony błąd. W większości przypadków to tam znajdziesz wskazówkę, co poszło nie tak.

Projekt 2D a projekt 3D – co wybrać na start

Przy zakładaniu nowego projektu Unity pyta, czy chcesz użyć trybu 2D, czy 3D. Różnica nie ogranicza się tylko do kamery. W zależności od wyboru domyślne ustawienia dotyczące światła, kamery i fizyki są inne. W projektach 2D Unity korzysta z fizyki 2D (Rigidbody2D, Collider2D), a w 3D z klasycznych komponentów 3D.

Dla początkujących bezpieczniejszym wyborem jest 2D. Łatwiej zrozumieć poruszanie się po płaskiej planszy, mniej jest problemów z kamerą i oświetleniem. Do tego dochodzi prostsze tworzenie assetów – wiele darmowych grafik 2D działa od razu po podpięciu.

3D kusi efektownym wyglądem, ale wymaga większej liczby elementów do ogarnięcia: modele, światła, cienie, kolizje w trzech wymiarach, praca z kamerą. Warto zacząć od małej gry 2D, a dopiero później przenieść te same zasady do świata 3D.

Frame, pętla gry i cykl życia obiektów

Podczas uruchomionej gry Unity działa w pętli. Każde odświeżenie obrazu to jeden frame (klatka). Dla każdej klatki wywoływana jest między innymi metoda Update() we wszystkich aktywnych skryptach. Dzięki temu możesz napisać: „w każdej klatce przesuń gracza trochę w prawo” i uzyskać płynny ruch.

Cykl życia obiektów w skryptach opiera się na specjalnych metodach (tzw. eventach):

  • Awake() – wywoływana, gdy skrypt jest inicjalizowany; dobre miejsce na ustawianie referencji.
  • Start() – uruchamia się tuż przed pierwszą klatką; tu zwykle konfigurujesz wartości początkowe.
  • Update() – wywoływana raz na klatkę; tu trafia większość logiki reagującej na czas i wejście gracza.
  • FixedUpdate() – wywoływana w stałych odstępach czasu; przeznaczona do logiki fizycznej.
  • OnDestroy() – wywoływana, gdy obiekt jest niszczony.

Zrozumienie różnicy między Update a FixedUpdate oraz świadomość, kiedy obiekt powstaje, a kiedy znika, pozwala uniknąć wielu trudnych do znalezienia błędów, np. „dlaczego pocisk czasem przechodzi przez ścianę” albo „czemu ruch gracza jest różny na różnych komputerach”.

Zespół e‑sportowy przy komputerach podczas intensywnej rozgrywki
Źródło: Pexels | Autor: Ron Lach

Pierwsze kroki techniczne – instalacja, ustawienia, pierwszy projekt

Wybór wersji Unity i rola Unity Hub

Unity udostępnia wiele wersji silnika. Dla początkujących najlepszą opcją jest wydanie z oznaczeniem LTS (Long Term Support). To stabilna linia, która przez kilka lat dostaje poprawki błędów, ale nie wprowadza gwałtownych zmian rozbijających projekty. W Unity Hub możesz zainstalować kilka wersji jednocześnie, ale na start w zupełności wystarczy jedna, aktualna LTS.

Unity Hub pełni rolę zarządcy: stąd instalujesz kolejne wersje silnika, tworzysz i otwierasz projekty, ustawiasz platformy docelowe (PC, Android itd.). Dobrą praktyką jest trzymanie różnych projektów w osobnych folderach, tak aby łatwo było przenosić je lub tworzyć kopie zapasowe.

Konfiguracja środowiska programistycznego

Skrypty w C# najlepiej pisać w wygodnym edytorze z podpowiadaniem kodu (IntelliSense). Unity dobrze współpracuje z:

  • Visual Studio (pełne IDE, dużo funkcji, cięższe, ale kompletne),
  • Rider (płatny, bardzo dopracowany, popularny wśród zawodowców),
  • VS Code (lekki edytor, po doinstalowaniu odpowiednich rozszerzeń do C#).

Po zainstalowaniu edytora trzeba w Unity przejść do Edit → Preferences → External Tools i wskazać wybrany program jako External Script Editor. Dzięki temu podwójne kliknięcie skryptu w Unity otworzy go w odpowiednim środowisku, a błędy kompilacji będą poprawnie podpinane pod linie kodu.

Jeśli korzystasz z polskiej klawiatury, zadbaj o poprawne działanie nawiasów, średników i cudzysłowów – w C# używa się ich bardzo często. Przydaje się też automatyczne formatowanie kodu (np. skrót Ctrl+K, Ctrl+D w Visual Studio), które ustawia wcięcia i nawiasy w czytelny sposób.

Struktura projektu i porządek w plikach

Świeży projekt Unity tworzy domyślnie katalog Assets, w którym będziesz przechowywać wszystkie zasoby. Warto od razu zadbać o podstawowy porządek, bo późniejsze sprzątanie bywa bolesne. Prosty, ale skuteczny układ na start może wyglądać tak:

  • Assets/Scenes – wszystkie sceny (np. MainMenu, Game, GameOver),
  • Assets/Scripts – skrypty C#,
  • Assets/Sprites – grafiki 2D,
  • Assets/Prefabs – gotowe obiekty do wielokrotnego wykorzystania,
  • Assets/Audio – dźwięki i muzyka,
  • Assets/UI – elementy interfejsu użytkownika.

Gdy projekt rośnie, można dodawać bardziej szczegółowe podfoldery (np. Scripts/Player, Scripts/Enemies). Taki układ przypomina dobrze utrzymany plecak: gdy wiesz, gdzie leży dany przedmiot, mniej czasu spędzasz na szukaniu, a więcej na faktycznym działaniu.

Pierwsza scena i podstawowe skróty

Po utworzeniu projektu warto od razu zapisać pierwszą scenę. Wybierz File → Save As i zapisz jako Main w folderze Scenes. Nie zostawiaj sceny jako „Untitled” – to prosta droga do przypadkowego nadpisania lub utraty zmian.

Przy poruszaniu się po oknie Scene przydają się skróty:

Jeśli chcesz pogłębić temat i zobaczyć więcej przykładów z tej niszy, zajrzyj na więcej o Lanckorona.

  • Q – zaznaczanie,
  • W – przesuwanie obiektu (Move),
  • E – obracanie (Rotate),
  • R – skalowanie (Scale),
  • prawy przycisk myszy + WASD – latanie kamerą po scenie (w 3D).

Przy pracy z obiektami pomaga też znajomość kilku trików: podwójne kliknięcie nazwy obiektu w Hierarchy centrowuje kamerę na tym obiekcie w Scene, klawisz F robi to samo dla aktualnie zaznaczonego elementu, a przytrzymanie Alt podczas obracania widoku pozwala obracać kamerę wokół punktu zaznaczenia. Po godzinie takiej „nawigacji” czujesz się już o wiele pewniej, a sama edycja sceny przestaje być walką z kamerą.

Na start dobrze jest po prostu pobawić się przestrzenią: dodać kilka obiektów (GameObject → 3D Object → Cube/Sphere albo 2D Object → Sprite), poprzesuwać je, poskalować, poustawiać w Hierarchy relacje rodzic–dziecko. To trochę jak ustawianie klocków Lego na biurku – bez presji, że już teraz wszystko musi być idealną grą. Dzięki temu szybciej oswajasz się z tym, jak Unity „myśli” o scenie i obiektach.

Gdy podstawowe ruchy w edytorze wchodzą w nawyk, łatwiej przejść do kolejnych kroków: pisania prostych skryptów, dodawania komponentów fizyki czy budowania pierwszego poziomu. Zamiast walczyć z interfejsem, skupiasz się wtedy na faktycznej rozgrywce, a każdy kolejny projekt powstaje szybciej i z mniejszą liczbą irytujących pomyłek.

Najważniejsze, żeby ruszyć z miejsca: zainstalować Unity, utworzyć projekt, zapisać pierwszą scenę i od razu coś w niej postawić, choćby jeden prosty obiekt. Z tej pierwszej, niepozornej sceny bardzo często rodzi się gra, o której kiedyś marzyłeś jako gracz, a dziś krok po kroku budujesz ją już jako twórca.

Podstawy C# dla kompletnie zielonych w programowaniu

Skrypt to „instrukcja obsługi” obiektu

Skrypt w Unity to po prostu plik tekstowy z rozszerzeniem .cs, w którym zapisujesz zasady działania obiektu. Trochę jak karteczka przyklejona do maszyny: „po naciśnięciu czerwonego przycisku – uruchom, po pięciu sekundach – wyłącz”.

Gdy w Unity wybierzesz Create → C# Script, powstaje nowy plik z domyślną zawartością:

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    void Start()
    {
        
    }

    void Update()
    {
        
    }
}

To szkielet. Nazwa klasy (tu: PlayerController) musi być identyczna z nazwą pliku. Dziedziczenie po MonoBehaviour oznacza, że skrypt może działać jako komponent w Unity: możesz go dodać do obiektu, korzystać z Start, Update itd.

Zmienne – miejsce na przechowywanie danych

Jeśli gra ma coś „pamiętać”, potrzebujesz zmiennych. W C# deklarujesz je, podając typ i nazwę:

public float speed = 5f;
private int health = 3;
  • int – liczba całkowita (0, 1, 2, -5),
  • float – liczba z przecinkiem (1.5, 0.1), w C# zapisujesz ją z kropką i literą f na końcu,
  • bool – prawda / fałsz (true / false),
  • string – tekst w cudzysłowach ("Hello").

Słowa public i private określają, czy zmienna jest widoczna na zewnątrz. Dla ciebie na start ważne jest to, że publiczne pola pojawią się w Inspectorze, więc możesz je zmieniać bez dotykania kodu.

public class PlayerController : MonoBehaviour
{
    public float speed = 5f;
    public int maxHealth = 3;
}

Po zapisaniu pliku i powrocie do Unity zobaczysz te pola w Inspectorze przy obiekcie, do którego przypniesz skrypt. Chcesz, żeby gracz poruszał się szybciej? Wpisujesz 8 zamiast 5 – bez rekompilowania projektu.

Instrukcje warunkowe – jeśli to, to tamto

Żeby gra reagowała na sytuacje, używasz if. Schemat jest prosty: „jeśli warunek jest spełniony, wykonaj ten blok kodu”.

if (health <= 0)
{
    Debug.Log("Gracz nie żyje");
}

Można dodać również ścieżkę alternatywną:

if (health <= 0)
{
    Debug.Log("Gracz nie żyje");
}
else
{
    Debug.Log("Gracz żyje, zdrowie: " + health);
}

Najczęstsze operatory porównań:

  • == – równe (np. x == 5),
  • != – różne,
  • <, >, <=, >= – mniejsze, większe itd.,
  • &&i (oba warunki muszą być prawdziwe),
  • ||lub (wystarczy, że jeden warunek jest prawdziwy).

Przykład z gry: gracz może otworzyć drzwi tylko jeśli ma klucz i stoi blisko zamka:

if (hasKey && isNearDoor)
{
    OpenDoor();
}

Pętle – powtarzanie czynności

W grach wiele rzeczy się powtarza: odliczanie punktów życia przeciwników, tworzenie serii przeszkód, sprawdzanie listy obiektów. Zamiast kopiować ten sam kod kilka razy, używasz pętli.

for (int i = 0; i < 10; i++)
{
    Debug.Log("Licznik: " + i);
}

Pętla for wykona się 10 razy (od 0 do 9). Inna często spotykana wersja to foreach, która przechodzi po elementach kolekcji:

Do kompletu polecam jeszcze: Jak przygotować się do premiery gry, aby w pełni cieszyć się rozgrywką od pierwszego dnia — znajdziesz tam dodatkowe wskazówki.

foreach (GameObject enemy in enemies)
{
    enemy.SetActive(false);
}

W Unity pętle przydają się np. do ustawiania serii platform jedna za drugą albo ukrywania całej grupy wrogów po wygraniu poziomu.

Funkcje – porządkowanie logiki

Gdy w Update() zaczyna robić się tłoczno, przenosisz fragmenty do własnych metod. Dzięki temu łatwiej czytać kod i ponownie używać tych samych zachowań.

public class PlayerController : MonoBehaviour
{
    public float speed = 5f;

    void Update()
    {
        HandleMovement();
    }

    void HandleMovement()
    {
        float horizontal = Input.GetAxis("Horizontal");
        Vector3 movement = new Vector3(horizontal, 0f, 0f);
        transform.Translate(movement * speed * Time.deltaTime);
    }
}

Teraz wiesz, że Update() tylko koordynuje, a szczegóły ruchu siedzą w HandleMovement(). Łatwiej też wprowadzać zmiany: jeśli zmienisz sposób poruszania, dotykasz jednego miejsca.

Młody mężczyzna projektuje grę na kilku monitorach w ciemnym pokoju
Źródło: Pexels | Autor: UMUT 🆁🅰🆆

Myślenie „komponentowe” – serce pracy w Unity

Obiekt jako „pudełko” na komponenty

W Unity każdy GameObject to jak puste pudełko, do którego dokładasz kolejne „moduły” – komponenty. Samo pudełko niewiele potrafi, ale jeśli dorzucisz SpriteRenderer, zobaczysz grafikę; dodasz Rigidbody2D – obiekt zacznie reagować na fizykę; dopniesz własny skrypt – zacznie wykonywać twoją logikę.

Typowy obiekt gracza w prostej grze 2D może mieć:

  • Transform – pozycja, rotacja, skala (jest zawsze),
  • SpriteRenderer – wyświetlanie grafiki,
  • Rigidbody2D – fizyka (grawitacja, siły),
  • BoxCollider2D – kształt do wykrywania kolizji,
  • PlayerController (skrypt) – twoja logika sterowania.

Zamiast jednego „wielkiego” skryptu robiącego wszystko, dzielisz zachowania na mniejsze komponenty. To jak z samochodem: masz osobno silnik, hamulce, światła – łatwo wymienić jedną część bez budowania wszystkiego od nowa.

Dodawanie i usuwanie komponentów w praktyce

Żeby zrozumieć moc komponentów, dobrze jest przez chwilę je dodawać i usuwać jak klocki:

  • stwórz obiekt (np. kwadrat w 2D),
  • dodaj Rigidbody2D – od razu zacznie spadać w dół,
  • usuń Rigidbody2D – obiekt zastygnie w miejscu,
  • dodaj BoxCollider2D do podłogi i do gracza – nagle gracz nie spada w nieskończoność, tylko ląduje na platformie.

Każdy komponent odpowiada za „jeden wycinek rzeczywistości”: grafika, fizyka, dźwięk, logika wejścia, AI, UI. Im bardziej to rozdzielasz, tym łatwiej później diagnozować problemy (czy to fizyka, czy logika, czy może renderowanie?).

Relacja rodzic–dziecko i złożone obiekty

Często jeden GameObject to za mało. Postać złożona z kilku elementów (ciało, broń, wskaźnik życia nad głową) może być zorganizowana jako drzewko:

  • Player (rodzic)
  •   ↳ Weapon (dziecko)
  •   ↳ HealthBar (dziecko)

Gdy przesuwasz rodzica, dzieci jadą razem z nim. Kiedy obrócisz gracza w lewo, broń i pasek życia odwrócą się razem. Dzięki temu możesz traktować całą strukturę jak jeden organizm, a jednocześnie osobno zmieniać szczegóły (np. podmienić broń bez ruszania reszty).

Prefaby – „formy” do odlewania obiektów

Jeśli jakiś typ obiektu ma pojawiać się wielokrotnie (pocisk, przeciwnik, moneta), nie chcesz za każdym razem klikać wszystkiego ręcznie. Do tego służą prefaby.

Tworzysz obiekt w scenie, dokładasz mu komponenty, ustawiasz parametry, a potem przeciągasz go do folderu Prefabs. Powstaje niebieski „wzór” – prefab. Teraz możesz:

  • wstawić kolejne kopie prefabów do sceny,
  • instancjonować (tworzyć) je w locie ze skryptu, np. gdy gracz strzela,
  • zmienić ustawienie w prefabie i automatycznie zaktualizować wszystkie jego kopie.

Przykładowo, jeśli do prefabów przeciwnika dodasz nowy komponent „EnemyAI”, wszystkie istniejące instancje w poziomie zaczną go używać. To ogromna oszczędność czasu przy większych mapach.

Komponenty „mówią” do siebie przez referencje

Częstym zadaniem jest to, żeby jeden skrypt odwołał się do innego komponentu na tym samym obiekcie lub na obiekcie obok. Robisz to albo przez Inspector, albo programistycznie.

Przykład: skrypt pocisku, który po trafieniu zmniejsza zdrowie przeciwnika:

public class Bullet : MonoBehaviour
{
    public int damage = 1;

    private void OnCollisionEnter2D(Collision2D collision)
    {
        EnemyHealth enemy = collision.gameObject.GetComponent<EnemyHealth>();
        if (enemy != null)
        {
            enemy.TakeDamage(damage);
        }

        Destroy(gameObject);
    }
}

Metoda GetComponent<T>() szuka komponentu konkretnego typu na danym GameObjekcie. Jeśli go znajdzie, można zawołać jego metody, np. TakeDamage. Gdy go nie ma, wynik to null, więc dobrze dodać sprawdzenie, żeby uniknąć błędu.

Pierwsza prosta gra krok po kroku – od pustej sceny do grywalnego prototypu

Pomysł: prosty „endless runner” w 2D

Żeby przejść od teorii do praktyki, posłużymy się przykładem gry, którą da się złożyć z kilku elementów: prosty biegacz 2D z widokiem z boku. Gracz biegnie w prawo, przeskakuje przeszkody, zbiera punkty. Tyle wystarczy, żeby dotknąć kluczowych elementów Unity.

Przygotowanie sceny: tło, podłoga, gracz

W projekcie 2D możesz zaczynać od czystych kształtów, bez dopracowanej grafiki. Wystarczą proste sprite’y – kolorowe prostokąty i kwadraty. Takie „prototypowe” kształty pozwalają skupić się na działaniu.

  1. Utwórz nową scenę (np. Runner) w folderze Scenes.
  2. Dodaj obiekt „Ground” (2D Object → Sprite → Square), rozciągnij go w poziomie i ustaw lekko poniżej środka ekranu.
  3. Dodaj do „Ground” komponent BoxCollider2D, zaznacz Is Trigger jako odznaczone (to ma być zwykła, stała podłoga).
  4. Stwórz obiekt „Player” z małego kwadratu, ustaw nad podłogą.
  5. Dodaj do „Player”: Rigidbody2D oraz BoxCollider2D.

Po wciśnięciu Play gracz powinien spaść i wylądować na podłodze. Jeśli przelatuje przez nią, coś jest nie tak z colliderami (brak jednego z nich, złe ustawienie lub zła warstwa).

Skrypt poruszania i skakania

Następny krok to dodanie prostego sterowania. Biegacz może poruszać się sam w prawo, a gracz kontroluje wyłącznie skok.

using UnityEngine;

public class RunnerController : MonoBehaviour
{
    public float moveSpeed = 5f;
    public float jumpForce = 5f;
    public Transform groundCheck;
    public float groundCheckRadius = 0.1f;
    public LayerMask groundLayer;

    private Rigidbody2D rb;
    private bool isGrounded;

    void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        // Stały ruch w prawo
        rb.velocity = new Vector2(moveSpeed, rb.velocity.y);

        // Sprawdzanie podłoża
        isGrounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayer);

        // Skok po wciśnięciu spacji, tylko gdy stoimy na ziemi
        if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
        {
            rb.velocity = new Vector2(rb.velocity.x, jumpForce);
        }
    }
}

Do poprawnego działania tego skryptu przyda się mały „czujnik podłoża”:

  • dodaj pusty obiekt jako dziecko „Player” (prawo klik → Create Empty), nazwij go GroundCheck,
  • ustaw go tuż pod stopami postaci,
  • w Inspectorze przeciągnij ten obiekt w pole groundCheck w skrypcie,
  • ustaw warstwę gruntu (np. nowa warstwa „Ground”) i przypisz ją do podłogi oraz do groundLayer w skrypcie.

Dobrze jest też na chwilę „pobawić się” parametrami: zwiększ moveSpeed, zmniejsz jumpForce, zmień promień groundCheckRadius. Zobaczysz, jak bardzo te kilka liczb wpływa na odczucie sterowania. To pierwsze spotkanie z tym, że game design to w dużej mierze kręcenie gałkami, a nie tylko pisanie kodu.

Przeszkody, punkty i warunki przegranej

Skoro gracz już biega i skacze, potrzebuje przeszkód i nagród. Najprościej złożyć je z tych samych klocków, których już używasz: sprite + collider + prosty skrypt. Możesz stworzyć prefab „Obstacle” (np. słupek) z BoxCollider2D i ustawić go jako „Obstacle” na osobnej warstwie. Do gracza dodaj skrypt, który reaguje na zderzenie z tą warstwą: zatrzymuje ruch, wyświetla komunikat „Game Over” albo resetuje scenę.

Z punktami jest jeszcze prościej. Utwórz prefab monety: mały sprite, CircleCollider2D ustawiony jako Is Trigger oraz skrypt, który w OnTriggerEnter2D sprawdza, czy dotknął go gracz. Jeśli tak – zwiększa licznik punktów i niszczy monetę. Na początku zamiast rozbudowanego UI wystarczy wypisać wynik w Konsoli lub prostym napisie na ekranie, żeby widzieć, że logika działa.

Poruszająca się „taśma produkcyjna” przeszkód

Endless runner żyje z tego, że przed graczem ciągle coś się pojawia. Można to zrobić na dwa sposoby: przesuwać gracza i cały świat, albo zostawić gracza mniej więcej w miejscu i przesuwać tło oraz przeszkody w lewo. Na start wygodniejsza jest druga opcja – łatwiej wtedy kontrolować kamerę. Wystarczy prosty skrypt na prefabie przeszkody, który w Update() przesuwa obiekt w lewo transform.Translate(Vector2.left * speed * Time.deltaTime); i niszczy go, gdy minie określoną pozycję poza ekranem.

Do tego dorzuć mały „spawner” – pusty GameObject stojący poza prawą krawędzią ekranu z prostym skryptem, który co kilka sekund instancjonuje prefab przeszkody na losowej wysokości (w rozsądnym zakresie). Kilka linii kodu, a nagle masz coś, co rzeczywiście przypomina grę: biegniesz, omijasz przeszkody, zbierasz punkty, możesz przegrać. Potem już tylko szlif: inna grafika, dźwięki, płynniejsze animacje, lepsze kolizje.

Po zbudowaniu takiego prostego prototypu Unity przestaje być abstrakcyjnym zestawem okienek, a zaczyna działać jak warsztat, w którym naprawdę coś powstaje pod rękami. Od tej chwili każdy kolejny projekt – czy to spokojna gra logiczna, czy dynamiczny shooter – będzie już tylko rozwijaniem tych samych podstawowych klocków: scen, GameObjectów, komponentów, skryptów i prefabów.

Świat 2D i 3D w praktyce – co wybrać, jak mieszać

2D kontra 3D – nie tylko kwestia „ładniejszej grafiki”

Na początku kusi, żeby od razu rzucić się na pełne 3D – w końcu większość dużych gier tak wygląda. Tyle że z perspektywy osoby uczącej się Unity to trochę jak nauka jazdy od razu na motocyklu wyścigowym. W 3D dostajesz w pakiecie dodatkowy wymiar problemów: modelowanie, oświetlenie, perspektywa kamery, zderzenia w trzech osiach. W 2D część z tych zagadnień po prostu znika lub jest dużo prostsza.

Świat 2D w Unity to nadal „prawdziwa” gra: masz fizykę, wejście z klawiatury/pada, UI, dźwięk, logikę. Różnica polega na tym, że używasz Rigidbody2D, Collider2D, kamery ustawionej „na wprost” i płaskich sprite’ów zamiast modeli 3D. Możesz więc skupić się na projektowaniu mechaniki i zrozumieniu narzędzia, a nie na walce z technikaliami.

Tryb 3D pokazuje pełnię możliwości silnika. Dochodzą jednak pytania: jak ustawić światło, żeby scena nie była „płaska”? Jak nie zgubić gracza w przestrzeni? Jak zoptymalizować ilość trójkątów (poligonów), żeby gra nie zamieniła się w pokaz slajdów? To wszystko są fascynujące tematy, ale łatwiej się w nie wchodzi, mając już za sobą kilka małych projektów 2D.

Kiedy zacząć od 2D, a kiedy od razu skakać w 3D

Dobrym filtrem jest proste pytanie: co tu jest najważniejsze – przestrzeń czy mechanika? Jeśli sednem pomysłu są reakcje, skoki, zręczność, łamigłówki, a widok z boku lub z góry spokojnie to ogarnia – 2D będzie szybsze w produkcji i nauce. Platformówki, proste RPG z widokiem z góry, gry logiczne, tower defense, „match-3” – to naturalni kandydaci.

Jeśli natomiast pomysł kręci się wokół eksploracji przestrzeni, układu pomieszczeń, widoków z różnych stron – 3D staje się sensowne. Strzelanki FPP/TPP, gry wyścigowe, eksploracyjne „chodzone” przygodówki, symulatory – tu trudno oszukać trójwymiar.

Czasem warto też spojrzeć na swoje zasoby. Nie masz skąd wziąć modeli 3D, nie umiesz ich robić, nie chcesz na razie kupować assetów w sklepie? Proste kształty 3D (sześciany, kapsuły) oczywiście wystarczą do prototypu, ale jeśli wizualny pomysł mocno siedzi w głowie, 2D może zwyczajnie mniej frustrować, bo łatwiej tam coś narysować lub „pożyczyć” z darmowych paczek.

Jak Unity „przełącza się” między 2D a 3D

Przy tworzeniu nowego projektu wybierasz szablon 2D lub 3D, ale to nie jest wyrok do końca życia. Ten wybór głównie ustawia domyślną kamerę, typy nowo tworzonych obiektów i kilka predefiniowanych ustawień. W samym edytorze masz przycisk 2D w widoku sceny – przełącza sposób patrzenia na świat, ale nie zmienia tego, jak gra działa w czasie rzeczywistym.

Silnik fizyki dla 2D (Physics2D) jest oddzielny od tego dla 3D (Physics). Dlatego komponenty Rigidbody i Rigidbody2D nie „widzą się” nawzajem; to zupełnie osobne systemy. Jeśli na jednej scenie postawisz obiekt 2D i obiekt 3D, można je wyświetlić jednocześnie, ale nie zderzą się ze sobą w sensowny sposób, dopóki nie będą używać spójnego zestawu komponentów.

Hybrdy: 2,5D, czyli 2D w świecie 3D

Bardzo popularnym podejściem jest tzw. 2,5D: graficznie wygląda to jak 3D (kamera może delikatnie się poruszać, obiekty są „grube”), ale rozgrywka jest w zasadzie 2D – poruszasz się po jednej osi (lewo–prawo, góra–dół). Przykład? Platformówka, w której postać biega po „mostku” 3D, ale nie ma swobody chodzenia w głąb ekranu.

Technicznie możesz to zrobić na co najmniej dwa sposoby:

  • Logika 2D, grafika 3D – ruch i fizyka liczone w 2D (np. Rigidbody2D i collidery 2D), ale modele wyświetlane przestrzennie, np. przyklejone do płaszczyzny X-Y. Dzięki temu wszystko zachowuje się jak gra 2D, tylko inaczej wygląda.
  • Logika 3D, ruch ograniczony do jednej osi – używasz komponentów 3D, ale w skryptach blokujesz ruch na niektórych osiach. Np. po każdej klatce ustawiasz transform.position.z = 0;, dzięki czemu postać nie odjedzie „w ekran”.

Tu wchodzi w grę kwestia wygody: mechaniki bardziej „platformowe” zwykle łatwiej ogarnąć w 2D, natomiast jeśli później chcesz dać choć odrobinę swobody w przestrzeni (np. delikatne odchodzenie w głąb planszy), sensowne jest od razu oparcie się na fizyce 3D.

Typowe pułapki przy przechodzeniu z 2D na 3D

Przesiadka na 3D często boli w trzech miejscach naraz: kamera, skalowanie i kolizje. Kamera nagle ma obrót w trzech osiach, więc drobna pomyłka w ustawieniu potrafi sprawić, że postać wygląda, jakby biegała po ścianie. Z kolei skalowanie modeli z różnych źródeł prowadzi do sytuacji, w której „metr” u jednego twórcy to zupełnie inna jednostka niż u innego – i nagle kapsuła gracza ma dwa piętra wysokości.

Kolizje w 3D to też inny świat. Zamiast BoxCollider2D i CircleCollider2D dochodzą MeshCollider, CapsuleCollider, SphereCollider oraz kwestia generowania tzw. siatek kolizyjnych. Dla prostoty na starcie najlepiej budować otoczenie z prostych brył – ścian z BoxCollider, postaci z połączenia kapsuły i kilku boxów. Dopiero później, gdy baza działa, można się bawić dokładniejszymi colliderami.

W tym miejscu przyda się jeszcze jeden praktyczny punkt odniesienia: Excel dla początkujących i zaawansowanych: praktyczne triki, dzięki którym szybciej zbudujesz profesjonalny dashboard.

Przykładowa strategia nauki: trzy małe gry zamiast jednego „dzieła życia”

Zamiast próbować od razu zbudować „swoje RPG marzeń w 3D”, łatwiej się rozwinąć, składając kilka mniejszych projektów, każdy w trochę innym stylu świata:

  1. Mały projekt 2D – coś w rodzaju prostego runnera, platformówki albo gry logicznej. Celem jest ogarnięcie komponentów, podstaw fizyki 2D, inputu i UI.
  2. Prosty prototyp 2,5D – ten sam typ gry (np. platformówka), ale z użyciem prostych modeli 3D i innego ustawienia kamery. Uczysz się, jak wygląda praca z materiałami, światłem, kamerą w perspektywie.
  3. Mała scena 3D – nie musi to nawet być „pełna” gra. Wystarczy poziom, po którym możesz się przejść, podnieść przedmiot, wcisnąć przycisk, który coś uruchomi. Liczy się obycie z przestrzenią 3D.

Takie stopniowanie ma tę zaletę, że wiele problemów zdążysz „przerobić” w prostszej konfiguracji, zanim zaczną się nawarstwiać w dużym projekcie. To trochę jak z nauką instrumentu: łatwiej grać pełną piosenkę, gdy palce są już przyzwyczajone do prostych ćwiczeń.

Mieszanie 2D i 3D w jednym projekcie

Nie ma zakazu, który mówi, że gra 3D nie może mieć interfejsu złożonego z 2D sprite’ów, albo że platformówka 2D nie może korzystać z trójwymiarowego tła. Unity bardzo dobrze dogaduje się z takim miksowaniem, byle robić to z głową.

Najczęściej spotykane kombinacje to:

  • UI 2D na wierzchu świata 3D – standardowy przypadek. Kamera 3D patrzy na świat, a interfejs leży w warstwie UI (Canvas). Nie potrzebujesz tu żadnych sztuczek, to domyślny sposób działania.
  • 2D tła do 3D akcji – np. daleki horyzont narysowany jako płaska tekstura, która przesuwa się wolniej niż reszta sceny (paralaksa). W praktyce to zwykłe quady (płaskie prostokąty) z teksturą, ustawione daleko od kamery.
  • Elementy 3D w grze 2D – świat jest 2D, ale co jakiś czas pojawia się „efekt specjalny” w 3D: obracające się logo, wybuch, który ma głębię, statyczny model budynku w tle. Takie akcenty potrafią wizualnie podbić nawet prostą grę.

Kluczem jest konsekwencja: gracz powinien mieć jasny sygnał, co jest tylko dekoracją, a co częścią rozgrywki. Jeśli element tła 3D wygląda jak platforma, ale wcale nią nie jest, rodzi to frustrację. Z drugiej strony, gdy wszystkie elementy „grywalne” mają np. jasny kontur albo trzymają się jednej palety barw, od razu łatwiej się połapać.

Optymalizacja – 2D i 3D zużywają moc w inny sposób

Przy małych projektach możesz się tym specjalnie nie przejmować, ale z czasem pojawia się pytanie: czemu to tak przycina? 2D i 3D obciążają sprzęt trochę inaczej. W 2D największy problem to często ogromne tekstury (sprity) i duża liczba przezroczystości. W 3D dochodzą liczba trójkątów, ilość świateł, post-processing (efekty na kamerze).

W praktyce częściej usłyszysz: „za dużo wybuchów i cząsteczek na ekranie naraz” niż „za dużo linijek kodu”. Optymalizacja skryptów oczywiście też ma znaczenie, ale pierwszym miejscem do porządków zwykle jest grafika i fizyka: za dużo aktywnych rigidbody, za dużo colliderów obliczanych w każdej klatce, niepotrzebnie włączone dynamiczne cienie.

Przekładanie doświadczeń z 2D na 3D (i odwrotnie)

Dobra wiadomość jest taka, że to, czego nauczysz się przy projektowaniu prostej gry 2D, w ogromnej części przenosi się na 3D. Zmieniasz komponenty fizyki, bryły kolidujące i sposób ustawienia kamery, ale myślenie zostaje to samo: sceny, obiekty, komponenty, prefaby, skrypty i komunikacja między nimi.

Mechaniki też zwykle da się przełożyć. Skok biegacza 2D? To samo równanie prędkości pionowej w platformówce 3D. Zbieranie monet? Ten sam OnTriggerEnter, tylko w trzech wymiarach. System punktów, licznik żyć, logika przegranej – to wszystko nie dba o to, czy obiekt porusza się po osi X/Y, czy X/Z.

Dlatego, gdy przyjdzie moment przesiadki, warto traktować 3D nie jako „coś zupełnie nowego”, a raczej jak rozszerzenie znanego już zestawu narzędzi. Nagle okazuje się, że większość kodu, który pisałeś wcześniej, da się skopiować niemal linijka w linijkę – różni się tylko to, gdzie stoi kamera i w ilu kierunkach może pobiec postać.

Najczęściej zadawane pytania (FAQ)

Od czego zacząć naukę tworzenia gier w Unity jako kompletny początkujący?

Najprościej zacząć od bardzo małego projektu 2D, np. „klikacza” albo prostego endless runnera. Wybierz jeden kurs wideo dla początkujących i przejdź go od początku do końca, nawet jeśli na początku bardziej „odtwarzasz” niż rozumiesz. Chodzi o to, żebyś zobaczył cały proces: od pustego projektu do gotowej mini-gry.

Drugi krok to modyfikacja gotowego tutoriala: zmień prędkość postaci, kolory, dodaj przeszkodę. Gdy coś się zepsuje – super, zaczyna się prawdziwa nauka. Szukaj błędu w Console, używaj Debug.Log, zadawaj pytania na forach. Taki cykl „tutorial → przeróbka → błąd → rozwiązanie” najszybciej buduje zrozumienie.

Czy muszę umieć programować w C#, żeby tworzyć gry w Unity?

Na starcie wystarczy znajomość absolutnych podstaw: zmienne, instrukcje warunkowe, pętle, proste funkcje. Tyle, żebyś wiedział, co się dzieje w prostym skrypcie i potrafił coś w nim zmienić. Resztę spokojnie dociągniesz „po drodze”, rozwiązując konkretne problemy z gry, zamiast wkuwać suchą teorię.

Unity traktuj jako kontekst do nauki programowania. Pisząc skrypt ruchu czy skakania, od razu widzisz efekt na ekranie, więc łatwiej zrozumieć, po co jest dana linijka. Po kilku tygodniach takich małych kroków będziesz w stanie samodzielnie pisać proste komponenty zamiast tylko kopiować cudzy kod.

Jakiego projektu w Unity powinienem się podjąć jako pierwszej gry?

Najlepiej sprawdza się mała gra 2D z jedną główną mechaniką: kliknięcie, skakanie, omijanie przeszkód. To może być endless runner, prosty „clicker” albo platformówka na jednym ekranie. Jeden przycisk, jeden cel, kilka przeszkód – taką grę da się ukończyć w rozsądnym czasie.

Dobrą zasadą jest: „gra do pokazania znajomemu po weekendzie”. Niech prototyp będzie brzydki, z kwadratami zamiast bohaterów, ale grywalny. Jeśli ktoś po minucie chce zagrać jeszcze raz, znaczy, że kierunek jest dobry i można to rozwijać.

Po jakim czasie nauki Unity mogę zrobić własną, grywalną grę?

Przy regularnej nauce (kilka godzin tygodniowo) po 2–3 miesiącach większość osób jest w stanie stworzyć prostą, samodzielną grę 2D: klikacz, runner, małą platformówkę. Taka gra nie będzie „hitem na Steam”, ale można ją pokazać znajomym albo wrzucić na itch.io.

Kluczowe jest nastawienie. Jeśli ustawisz sobie cel „co tydzień dodam jedną funkcję i nauczę się jednej nowej rzeczy”, po kilku miesiącach będziesz mieć kilka prototypów i kupę doświadczenia. Jeśli celem od razu jest „własny Wiedźmin”, frustracja pojawi się bardzo szybko.

Czy lepiej zacząć w Unity od 2D czy od 3D?

Dla początkujących znacznie łatwiejszy jest start w 2D. Poruszasz się po płaskiej planszy, masz mniej kłopotów z kamerą i światłem, a do tego prościej ogarnąć fizykę i kolizje (Rigidbody2D, Collider2D). Wiele darmowych assetów 2D działa od razu po wklejeniu do projektu.

3D kusi efektem „wow”, ale dorzuca kolejne warstwy złożoności: modele, oświetlenie, cienie, kamerę w trzech wymiarach. Rozsądny plan to: mała gra 2D → druga gra 2D trochę ambitniejsza → dopiero potem pierwsze 3D, najlepiej jako przeniesienie znanej sobie mechaniki do trzech wymiarów.

Dlaczego mój pierwszy prototyp w Unity wygląda brzydko i czy powinienem od razu inwestować w grafika?

Pierwszy prototyp z definicji wygląda brzydko i to jest w porządku. Twoim celem na początku jest grywalność, a nie ładne obrazki. Tak jak rysownik zaczyna od dziesiątek szkiców, tak samo Ty w Unity robisz „brudne” wersje gry: kwadraty zamiast postaci, jeden dźwięk zamiast całej ścieżki audio.

Dopiero gdy mechanika działa, a ludzie faktycznie bawią się przy Twoim projekcie, ma sens szukanie lepszych assetów albo współpracy z grafikiem. Dzięki temu nie spędzisz tygodni na dopieszczaniu elementu, który później i tak wyrzucisz, bo sama rozgrywka nie „niesie”.

Co właściwie robi Unity podczas działania gry i czym jest Update()?

Unity działa w pętli, klatka po klatce. Każde odświeżenie obrazu to tzw. frame i przy każdej takiej klatce wywoływana jest metoda Update() we wszystkich aktywnych skryptach. To właśnie tam najczęściej umieszcza się logikę typu: ruch gracza, sprawdzanie wciśnięć klawiszy, odliczanie czasu.

Możesz myśleć o Unity jak o reżyserze, który co klatkę wydaje aktorom (GameObjectom) polecenia: „teraz się przesuń”, „teraz sprawdź kolizję”, „teraz odtwórz animację”. Skrypty w C# są jednym z komponentów tych aktorów i opisują, jak mają się zachowywać w czasie trwania „przedstawienia”.