Platformowa gra 2D w Unity5 na urządzenia mobilne (Android, iOS, Windows Phone)


#1

Jest to krótki artykuł jak rozpocząć tworzenie platformówki 2D. Wiele kwestii zostało omówionych pobieżnie. Wiele początkujących chce szybko stworzyć coś działającego, co później można rozwijać.

1. Tworzenie nowego projektu
Po uruchomieniu środowiska Unity pojawia się okno w którym możemy otworzyć istniejący projekt lub stworzyć nowy. Aby stworzyć nowy projekt należy kliknąć przycisk NEW PROJECT.

W pole tekstowe z etykietą Project Name możemy wpisać nazwę projektu, a niżej wybrać ścieżkę – gdzie będzie on zapisany. Dalej są opcje 2D oraz 3D. Dla gry platformowej, która będzie tworzona wybierzmy 2D. Można jeszcze wybrać jakie Assety mają być zaimportowane na starcie, ale to nie jest na razie potrzebne. Wszystko można zaimportować potem w edytorze. Po ustawieniu wszystkiego klikamy przycisk Create project.

2. Nawigacja po edytorze Unity
Po utworzeniu projektu jesteśmy w oknie edytora. Naciskamy skrót klawiaturowy CTRL+S, aby zapisać scenę. Jako nazwę dajmy level1.unity.

Będzie to pierwszy poziom tworzonej gry platformowej. Niektórzy zaczynają tworzenie gry od ekranu menu, ale to chyba nie do końca dobry pomysł :wink: Dlatego zacznijmy od pierwszego poziomu.

3. Importowanie grafiki
Do gry platformowej w 2D potrzebna jest jakaś grafika. Grafika nie powinna odstraszać. Jak nie za dobrze idzie nam rysowanie lepiej poszukać czegoś gotowego na licencji, która pozwala na użycie tego we własnej grze. Różne grafiki można znaleźć na stronie http://opengameart.org/. Wpisując w wyszukiwarce słowa „platform” lub „tile” można coś znaleźć. Użyję kafelków na platformy spod tego adresu:
http://opengameart.org/content/platformer-tiles-1
Bohatera, pułapki, przeszkody i wrogów dla celów edukacyjnych możemy zrobić sami. Postanowiłem, że bohaterem będzie znak @ narysowany w Paint.NET i zapisany jako obrazek PNG z przezroczystym tłem.

Wrogowie to będą cyferki, a przeszkody to narysuje się np. jakieś kolce. Całą grafikę w postaci obrazów PNG z przezroczystym tłem skopiujmy do folderu Assets/Images w plikach projektu.

4. Projektowanie poziomu (wrogowie, pułapki, przeszkody)
Teraz można przejść do czegoś ciekawszego niż wcześniejsze czynności. Zaprojektujmy testowy poziom pierwszy. Na dole w edytorze Unity można przeglądać Assety. Wejdźmy do folderu z obrazkami. Układamy je na scenie bardzo prosto – przeciągając je po prostu myszą. W górnym menu wybierzmy GameObject > Create Empty. Zaznaczmy go w oknie Hierarchy i w oknie Inspector wpiszmy mu nazwę Ground. Teraz trzymając CTRL zaznaczmy wszystkie kafelki, które są podłożem i przeciągnijmy do obiektu Ground. W ten sposób w oknie Hierarchy zrobił się porządek.
Ułożony przeze mnie poziom wygląda następująco:

Zanim zaczniemy pisać skrypt poruszania i inne dodajmy kolizje z terenem (Collider) oraz sprawmy, że postacie będą ciałem fizycznym (Rigidbody). Zaznacz kafelki, które są podłożem (kolce też) i wybierz z górnego menu: Component > Physics 2D > Box Collider 2D. Teraz zaznacz same kolce i w oknie Inspector zaznacz Is Trigger. Podłoże będzie normalnie kolidowało, a kolce będą tzw. wyzwalaczem. To znaczy, że po kolizji z kolcami można wykonać jakiś kod np. odtworzyć dźwięk, odjąć jedno życie lub pokazać ekran Game Over. Zaznacz teraz obiekt gracza (@) i wybierz z górnego menu: Component > Physics 2D > Polygon Collider 2D. W ten sposób kolider gracza nie będzie kwadratem (Box Collider) tylko będzie miał taki kształt jak postać. Tak samo zrób z postacią wroga (6). Dodatkowo dla postaci wroga, również zaznacz Is Trigger w oknie Inspector. Teraz do postaci gracza dodajmy ciało fizyczne (Rigidbody). Zaznacz obiekt gracza i wybierz z górnego menu: Component > Physics 2D > Rigidbody 2D. Teraz po uruchomieniu gry zauważysz, że gracz opadnie i stanie na podłożu, czyli działa na niego grawitacja oraz działają kolizje z podłożem.

5. Dotykowe GUI
O nowym interfejsie użytkownika w Unity można napisać całą serię artykułów. Postaram się tutaj tylko opisać podstawy, które wystarczą do tworzenia prostych gier. W tworzonej przez nas grze będzie poruszanie w lewo/w prawo, skok oraz strzelanie. Potrzebujemy zatem przycisków z odpowiednią grafiką. Wpisując „arrow png” w wyszukiwarkę Google Grafika można znaleźć ładne ikony strzałek, które użyjemy jako ikon przycisków sterowania.
Wybierz z górnego menu: GameObject > UI > Button aby dodać przycisk.
Zaznacz obiekt Canvas w oknie Hierarchy i w oknie Inspector ustaw Render Mode na Screen Space – Camera. Następnie przeciągnij obiekt Main Camera do pola Render Camera. Aby przyciski były przed grafiką gry w pole Order In Layer wpisz wartość 1.
Skopiuj grafiki przycisków do folderu Assets/Images w plikach projektu. W oknie Hierarchy rozwiń Canvas i zaznacz przycisk (Button), który został dodany. W oknie Inspector w polu Source Image wybierz obrazek przycisku z Assetów. Dodaj resztę przycisków i ustaw je odpowiednio.
U mnie wszystko prezentuje się następująco:

Jeśli chcemy by przyciski miały odpowiednie ułożenie podczas zmiany rozmiaru ekranu (np. różne rozdzielczości) musimy zaznaczyć przycisk w oknie Hierarchy i ustawić mu tak zwany Anchor.

Na rysunku widać, że przycisk ma ustawiony anchor jako lewy-dolny. Mimo zmiany rozmiaru ekranu przycisk będzie w lewym dolnym rogu.

6. Poruszanie postaci
Wejdź do folderu Assets w edytorze Unity i kliknij prawym przyciskiem myszy i wybierz Create > Folder. Nazwę folderu dajmy Scripts. Wejdź do folderu Scripts i prawym przyciskiem myszy wybierz Create > C# Script. Skrypt nazwij Player.cs. Kliknij na niego dwukrotnie, aby go otworzyć.
Dodaj nowe publiczne metody jak poniżej:

public void MoveLeft()
{
    this.GetComponent<Rigidbody2D>().AddForce(new Vector2(-150f, 0f));
}
    
public void MoveRight()
{
	this.GetComponent<Rigidbody2D>().AddForce(new Vector2(150f, 0f));
}

public void Jump()
{
	if(this.GetComponent<Rigidbody2D>().velocity.y == 0f)
	{
		this.GetComponent<Rigidbody2D>().AddForce(new Vector2(0f, 500f));
	}
}

Przeciągnij skrypt Player.cs na obiekt player w oknie Hierarchy. W ten sposób skrypt zostanie dodany jako komponent do obiektu gracza.
Teraz trzeba podpiąć metody pod akcje przycisków. Na razie zajmiemy się tylko chodzeniem i skakaniem, bo strzelanie jest trochę bardziej skomplikowane. Zaznacz przycisk poruszania w lewo w oknie Hierarchy i w OnClick na dole (w oknie Inspector) nacisnij znak „+”. W polu w którym jest napisane: „None (GameObject)” przeciągnij obiekt gracza (player). Teraz tam gdzie jest lista rozwijana z napisem No Fuction można wybrać metode, która ma się wykonać po naciśnięciu przycisku. Wybierz metode Player.MoveLeft. Analogicznie dołącz metodę poruszania w prawo oraz skok do odpowiednich przycisków. Zmieniając wartości wektora podawanego metodzie AddForce możesz zwiększyć siłę skoku lub poruszania.
Na koniec ustaw w komponencie Rigidbody2D obiektu player właściwość Freeze Rotation Z. Aby obiekt gracza nie obracał się podczas poruszania.

7. Strzelanie
Strzelanie w grze można zrobić tworząc pocisk i dodając mu siłę. Stworzyłem dla celów testowych czerwoną kulkę jako obrazek PNG. Dodajmy go do assetów do folderu Images. Przeciągnij ją myszą i ustaw na scenie. Pocisk powinien być zaznaczony. Z górnego menu wybierz Component > Physics 2D > Circle Collider 2D. Ustaw Is Trigger we właściwościach Circle Collider 2D. Teraz ze sceny przeciągnij ją do folderu Images (w edytorze). I usuń ze sceny. Stworzony został prefab, czyli obiekt, który ma zapisane odpowiednie ustawienia.
Do skryptu Player.cs dodaj kod odpowiedzialny za strzelanie.

public GameObject bullet;

public void Shoot()
{
	GameObject clone = GameObject.Instantiate(bullet, this.transform.position, bullet.transform.rotation) as GameObject;
	clone.AddComponent<Rigidbody2D>();
	clone.GetComponent<Rigidbody2D>().AddForce(new Vector2(900f, 0f));
}

W powyższym kodzie tworzony jest pocisk, a następnie jest mu nadawana siła co powoduje, że obiekt zaraz po utworzeniu porusza się w określonym kierunku tak jakby był wystrzelony. Zaznacz obiekt gracza (player) i do publicznego pola bullet przeciągnij prefab pocisku (bullet.prefab).
Pozostało zrobić, żeby postać wroga znikała po kolizji z pociskiem. W tym celu zaznacz prefab pocisku i w oknie Inspector wybierz Tag > Add Tag. Dodaj nowy tag „bullet”. Zaznacz ponownie obiekt pocisku i wybierz tag „bullet” z listy tagów. Teraz w folderze Scripts stwórz nowy skrypt Enemy.cs. Przeciągnij skrypt na obiekt wroga w oknie Hierarchy. Do skryptu Enemy.cs dodaj metodę:

void OnTriggerEnter2D(Collider2D other)
{
	if(other.tag == "bullet")
		GameObject.Destroy(this.gameObject);
}

Teraz gdy pocisk uderzy we wroga – obiekt wroga zniknie.
Finalny prototyp gry prezentuje się następująco:

Pozostało zrobić poruszanie kamery razem z postacią gracza. W oknie Hierarchy przeciągnij obiekt Main Camera na obiekt player. W ten sposób obiekt gracza będzie rodzicem dla obiektu kamery. Zmiana pozycji obiektu gracza, będzie zmianą pozycji kamery.

8. Dalszy rozwój gry
Do gry można dodać dźwięki. Do ich obsługi służy komponent AudioSource. Menu polecam zrobić jak osobną scenę, dodawanie przycisków zostało pokazane, więc stworzenie menu nie powinno być problemem. Mając sterowanie dotykowe gra jest gotowa na Android, iOS i Windows Phone. Pozostaje kwestia rozdzielczości ekranu. Dlatego wymagane będzie ustawienie odpowiedniej wielkości przycisków zależnie od tego na jaki system mobilny będziemy budować grę. Przeszkody takie jak kolce powinny mieć Collider z ustawieniem Is Trigger. Analogicznym kodem jak przy kolizji pocisku z wrogiem można podczas kolizji gracza z kolcami odejmować jedno życie lub całkowicie kończyć grę.

9. Budowanie projektu gry na dane platformy

Aby zbudować grę na określoną platformę mobilną wybieramy z górnego menu File > Build Settings.

Następnie w oknie, które się pojawiło wybieramy platformę z listy.

I klikamy przycisk Build. Jednak zanim się to zrobi, trzeba wiedzieć czy ma się odpowiednie rzeczy takie jak:

Budując dla iOS potrzebujemy konto developera Apple. Jak je zdobyć nie jest w ramach tematycznych tego artykułu. Potrzebujemy też środowisko Xcode, ponieważ Unity wygeneruje nam projekt Xcode, który po otwarciu i zbudowaniu w środowisku Xcode da nam docelowy plik gry.

Budując dla Android potrzebujemy Android SDK. Po instalacji SDK można zbudować projekt w Unity. Środowisko Unity zapyta o lokalizację Android SDK i stworzy paczkę z grą (.apk) dla systemu Android.

Budując dla Windows Phone 8/8.1. potrzebujemy mieć środowisko Microsoft Visual Studio z komponentem odpowiedzialnym za tworzenie dla Windows Phone. Po zbudowaniu projektu, Unity wygeneruje nam plik solucji dla Visual Studio. Budując solucję w Visual Studio otrzymamy gotową paczkę z grą (.xap) dla systemu Windows Phone.

10. Projekty w Unity a system git
Projekty w Unity mają binarną naturę. Stąd nie jest tak prosto używać do nich systemu git. Dobrym sposobem jest wysyłanie do repozytorium tylko tych assetów, które są już gotowe. Jeśli chodzi o skrypty to są to pliki tekstowe, więc możemy je normalnie zmieniać i wysyłać zmiany. Natomiast gdy mamy np. plik dźwiękowy, lub model 3D to najlepiej wykonać go do końca i jak jest wersja finalna, która nie będzie zmieniana to wtedy ją wysłać i gotowe.
Tryb tekstowy dla Assetów włącza się (w górnym menu) poprzez Edit › Project Settings › Editor › Asset Serialization Mode i tutaj wybieramy Force Text.

Jeśli chcemy, aby na serwer git nie były wysyłane niepotrzebne pliki możemy użyć pliku gitignore, którego treść jest pod tym linkiem.

11. Zakończenie
Artykuł jest krótki i ciężko byłoby opisać wszystko dokładnie i ze szczegółami. Jeśli nie znasz za dobrze języka C# możesz zajrzeć na kurs pisania skryptów C# na stronie Unity. Jest tam też więcej kursów o różnych tematach związanych z grami.

Jeśli masz jakieś środki na cel jakim jest nauka tworzenia gier, możesz zaopatrzyć się w kurs video np. Unity. Kurs video. Tworzenie gry 2D. Według mnie jeśli chodzi o Unity to wolę obejrzeć wideo niż czytać tekstowe instrukcje.

Download projektu:
Unity2DPlatformGameExample.zip (127.5 KB)


Jaki język programowania ?
#2

Mam jakieś problemy ze skryptem ( nie umiem za bardzo C#)using UnityEngine;
using System.Collections;

public class gracz.cs : MonoBehaviour {

// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {

}

}
public void MoveLeft()
{
this.GetComponent().AddForce(new Vector2(-150f, 0f));
}

public void MoveRight()
{
this.GetComponent().AddForce(new Vector2(150f, 0f));
}

public void Jump()
{
if (this.GetComponent().velocity.y == 0f)
{
this.GetComponent().AddForce(new Vector2(0f, 500f));
}
}

Czy to ma tak wyglądać?


#3

}
public void MoveLeft()
{
this.GetComponent().AddForce(new Vector2(-150f, 0f));
}

public void MoveRight()
{
this.GetComponent().AddForce(new Vector2(150f, 0f));
}

public void Jump()
{
if (this.GetComponent().velocity.y == 0f)
{
this.GetComponent().AddForce(new Vector2(0f, 500f));
}
}

// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {

}
tak ma wyglądać