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

0
54
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