Unity3d FPS Tutorial, czyli tworzymy własną grę FPS od podstaw z wykorzystaniem silnika Unity3d.

Temat: Kamera z bronią i strzelanie

Spis treści

Jeżeli nie używałeś do tej pory Unity3d:

#0 – Podstawy Podstaw

FPS Tutorial:

#1 – Tworzenie nowego projektu i narzędzie terenu

#2 – Sterowanie postacią

#3 – Życie, pancerz i wytrzymałość postaci

#4 – Regeneracja życia i energii. Efekty trafienia

– Kamera z bronią i strzelanie

#6 – Przeładowanie broni i amunicja

#7 – Zbieranie przedmiotów

#8 – Druga broń

#9 – Rzut granatem i seria z karabinu

#10 – Celowanie i dziury po kulach

#11 – Przeciwnik z prostym AI, sztuczna inteligencja

#12 – Animacja postaci przeciwnika. Animator

#13 – Menu główne gry. GUI

#14 – Ostatnie szlify i budujemy projekt

Teoria

Mamy już poruszającą się, żywotną postać. Czas sprawić, żeby mogła strzelać! Teoria jest tak oczywista, że szkoda tekstu na nią.

Przygotowanie

Potrzebujemy modelu broni, dźwięku wystrzału i tekstury celownika. Aby twoje życie było piękniejsze, paczkę z tym “ekwipunkiem”, możesz pobrać stąd:

Tutorial_05_assets

Paczka particles z Unity 4.0

Zaimportuj wszystkie pliki do gry, umieszczając je w odpowiednich folderach. Zwróć uwagę na to, żeby pliki pistol.dae i texture.jpg zaimportować razem, ponieważ dotyczą modelu broni.

Ostatnia rzecz, to import paczki Particles ze standardowych assetów, jeśli jeszcze tego nie zrobiłeś. Można to zrobić przez: [Assets -> Import Package -> Particles]

Przygotowanie broni

Pierwszy krok, to dodanie modelu broni do sceny. Ustawiamy go od razu jako child obiektu MainCamera, który jest już childem obiektu FirstPersonController. Wystarczy przeciągnąć nazwę obiektu na drugi obiekt, aby to zrobić.

Ustawienie obiektu Gun jako childa obiektu MainCamera
Ustawienie obiektu Gun jako childa obiektu MainCamera

Teraz zresetuj ustawienia broni, aby to zrobić, klikamy na koło zębate przy komponencie transform i wybieramy reset. Teraz trzeba ustawić broń tak, by wyglądała naturalnie i tak, jak przyzwyczaiły nas do tego gry FPS.

Ustawienia położenia broni
Ustawienia położenia broni

Teraz z folderu Standard Assets/Particles/Misc, wybieramy efekty cząsteczkowe o nazwie Sparks. Przypisujemy go jako Child obiektu Gun, czyli naszej broni. Znów musimy zmienić ustawienia komponentu transform dla obiektu Sparks, tak aby iskry leciały z lufy broni. Najlepiej zrobić to sówkami z podglądem z gry, bo nie ma to być wartość co do centymetra, a dobrze wyglądająca optycznie. Dodatkowo w komponencie Elipsolid Particle Emiter zmieniamy wartość Max Energy na 0.1, oraz zaznaczamy Play One Shot, co zablokuje zapętlenie się emisji. Ogólnie ustawienia cząsteczek powinny wyglądać tak, oczywiście jeśli korzystasz z dostarczonych przeze mnie assetów:

Ustawienia emisji efektów cząsteczkowych
Ustawienia emisji efektów cząsteczkowych

Gry mamy to wszystko, czas utworzyć skrypt. Nazywamy go Shooting.cs i od razu dodajemy do obiektu Gun. Wchodzimy w edycję skryptu.

Strzelanie

Zaczynamy od deklaracji zmiennych:

public AudioClip pistolShot;
   
private float range = 10.0f;
private GameObject pistolSparks; 
private Vector3 fwd;
private RaycastHit hit;
  •  pistolShot – będzie przetrzymywać dźwięk wystrzału broni. Jest to zmienna publiczna, więc dźwięk wybierzemy z poziomu Unity.
  • range – Zasięg broni
  • pistolSparks – Przetrzymuje obiekt efektu cząsteczkowego
  • fwd – Wektor, określający przód, czyli gdzie gracz patrzy
  • hit – jest to zmienna typu RaycastHit, czyli pozwoli przetrzymywać informacje na temat kolizji spowodowanych rzucaniem promienia.

[stextbox id=”info” defcaption=”true”]Raycasting

Jest to metoda wykrywania kolizji, która polega na tym, że “wystrzeliwujemy” promień z pewnego punktu na pewną odległość. Jeżeli promień trafi na jakiś obiekt, mamy kolizję. Jeżeli nie, kolizji nie ma.

Jest to jego główna różnica względem typowych metod wykrywania kolizji, polega właśnie na tym, że nie mamy do czynienia z obszarem, a jedynie promieniem.[/stextbox]
Zauważyłeś pewnie, że wykorzystujemy AudioClip, ale nie dodaliśmy nigdzie źródła dźwięku. Dlatego na samym początku skryptu – przed deklaracją klasy – dodajemy takie coś:

[RequireComponent(typeof(AudioSource))]
public class Shooting : MonoBehaviour

Ta jedna prosta linijka, sprawia, że skrypt wymaga od obiektu, do którego jest przyłączony posiadania komponentu AudioSource. Jeżeli go nie ma, zostanie automatycznie dodany.

Jeszcze nie koniec przygotowań. W funkcji Start, potrzebujemy ustawić kilka opcji:

void Start()
{
	Screen.showCursor = false;
		
	pistolSparks = GameObject.Find("Sparks");
	pistolSparks.particleEmitter.emit = false;
	audio.clip = pistolShot;
}

Po pierwsze chowamy kursor myszy. Nie będzie to widoczne w edytorze, ale po zbudowaniu gry. Robimy to dlatego, że ja osobiście nie przypominam sobie gry FPS, w której mieliśmy widoczny kursor myszy. Następnie odnajdujemy nasze efekty cząsteczkowe, od razu zatrzymując ich emisję. Gdybyśmy tego nie zrobili, rozbłyski wystrzału migałby od samego początku gry w nieskończoność. Ostatnia rzecz, to ustawienia clipu na naszą zmienną, publiczną. Oznacza to, że nasze AudioSource, w przypadku uruchomienia, odtworzy właśnie ten dźwięk.

Czas na samo strzelanie:

void Update () 
{
	fwd = transform.TransformDirection(Vector3.forward);
	
	if(Input.GetButtonDown("Fire1")) {
		pistolSparks.particleEmitter.Emit();
		audio.Play();
		
		if (Physics.Raycast(transform.position, fwd, out hit)) {
			if(hit.transform.tag == "Enemy" && hit.distance < range) {
				Debug.Log ("Trafiony przeciwnik");
				
			} else if(hit.distance < range) {
				Debug.Log ("Trafiona Sciana");
			}
		}
	}
}

Po pierwsze określamy gdzie jest przód. Przyda się to przy rzucaniu promienia.

Następnie, mamy klasycznego ifa, sprawdzającego czy nacisnęliśmy przycisk strzału. Jeżeli się to stało, to pierwsze dwa kroki to emisja cząsteczek i odtworzenie dźwięku.

Kolejny if to rzucenie naszego promienia. Pierwszy parametr to położenie startowe, czyli nasza kamera, a dokładniej jej środek. Drugi to kierunek wystrzału (dlatego, potrzebowaliśmy zmienną określającą położenie), ostatnia zmienna to zmienna RaycastHit, która przetrzymuje dane o kolizji. Zwróć uwagę na słowo kluczowe out, które jest wymagane w C#.

Teraz, gdy wiemy, że pojawiła się kolizja, czas sprawdzić z czym kolidujemy. My na tą chwilę dopuszczamy dwa typy. Po pierwsze, gdy trafiony obiekt, ma tag enemy i jest w zasięgu, zakładamy, że trafiliśmy przeciwnika. Jeżeli trafiliśmy coś będącego w zasięgu, ale innego niż z tagiem “enemy”, zakładamy że trafiliśmy ścianę. W przeciwnym wypadku, nie reagujemy.

Wróćmy teraz do Unity. Zaznacz obiekt broni i uzupełnij zmienną PistolShot dźwiękiem wystrzału (np. tym dostarczonym przeze mnie na początku). Wystarczy przeciągnąć.

Użyliśmy tagu Enemy, ale w sumie go nie ustawiliśmy. Wchodzimy w menu: [Edit -> Project Settings -> Tags and Layers]. Teraz zwracamy naszą uwagę na penel Inspector, gdzie pojawiły się nowe opcje. Najpierw rozwijamy pozycję Tags, klikając w trójkąt przy nim. Klikamy w pierwszy wolny input i wpisujemy tam tag Enemy.

Rozwijamy też pozycję Layers. Również w pierwszym wolnym miejscu dopisujemy warstwę Guns. Będzie to nam potrzebne później.

Ustawienia tagów i warstw
Ustawienia tagów i warstw

Możesz teraz dodać do sceny dwa cuby i jednemu ustawić tag “enemy”. Uruchom grę i postrzelaj w obiekty, patrząc na to co zwraca konsola. Powinny się pojawić odpowiednie komunikaty, które ustawiliśmy w kodzie.

Przenikanie broni

Bawiąc się grą, mogłeś zauważyć, że broń przenika przez ściany. Możemy temu zaradzić prostym trikiem. Dodaj do sceny nową kamerę. [GameObject -> Create Other -> Camera]. Nową kamerę nazywamy GunsCamera i ustawiamy jako child MainCamery. Resetujemy jej ustawienia dla komponentu transform (Koło zębate -> Reset). Teraz czas zmienić kilka parametrów samej kamery:

  • Clear Flags -> Depth Only – Dzięki temu, kamera rysuje tylko elementy gry, pomijając np. skybox czy kolor tła.
  • Culling Mask -> Wybieramy tylko naszą warstwę Guns. Dzięki temu, kamera rysuje wszystko co znajduje się na tej warstwie i nic po za tym.
  • Depth -> 80 – De facto, nie ważne jaka będzie to liczba, byleby była wyższa od tego parametru dla MainCamera. Jest to jak by priorytet kamer. Czyli im wyższy, tym obiekty z tej kamery będą renderowane bardziej z przodu.

[stextbox id=”info” defcaption=”true”]Depth – Przykład

Gdy nasza kamera z Depth 0 ma narysować drzewo, a w tym samym miejscu kamera z Depth 80, ma rysować broń, wyrenderowana zostanie broń, bo ta kamera ma wyższe Depth.[/stextbox]

Ustawienia obiektu GunsCamera
Ustawienia obiektu GunsCamera

Skoro GunsCamera ma rysować broń, to MainCamera nie powinna tego robić, aby nie było duplikatów. Dlatego wybieramy obiekt MainCamera i w opcji Culling Mask, odznaczamy warstwę Guns.

Ostatni krok, to wybranie obiektu broni i wybranie mu warstwy Guns.

Warstwa dla broni
Warstwa dla broni

Celownik

Tutaj sprawa jest banalnie prosta. Na chwilę wracamy do skryptu. Dodajemy dwie zmienne na samym początku:

public Texture2D crosshairTexture;
public AudioClip pistolShot;

private Rect position;   
private float range = 10.0f;
private GameObject pistolSparks; 
private Vector3 fwd;
private RaycastHit hit;

Pierwsza to tekstura 2D, samego celownika. Druga, określa pozycję celownika.

Kolejny krok, to wyśrodkowanie celownika:

void Start()
{
	Screen.showCursor = false;
	position = new Rect((Screen.width - crosshairTexture.width) / 2,
	                    (Screen.height - crosshairTexture.height) /2,
	                    crosshairTexture.width,
	                    crosshairTexture.height);
	
	pistolSparks = GameObject.Find("Sparks");
	pistolSparks.particleEmitter.emit = false;
	audio.clip = pistolShot;
}

Dzięki zabiegowi w pierwszych linijkach otrzymujemy środek ekranu. Gdybyśmy wzięli samą połowę ekranu gry, wtedy na środku mielibyśmy lewy górny róg tekstury. Dlatego odejmujemy też połowę szerokości i wysokości samej tekstury.

Zostało narysować teksturę, dlatego dodajemy:

void OnGUI()
{
	GUI.DrawTexture(position, crosshairTexture);
}

Chyba nie trzeba tutaj nic tłumaczyć, pierwszy parametr to pozycja, drugi to sama tekstura.

Wracamy do Unity i znajdujemy naszą teksturę celownika. Zaznaczmy mu opcję Alpha Is Transparent, klikamy Apply i przeciągamy do zmiennej w skrypcie.

Dodanie tekstury celownika
Dodanie tekstury celownika

W tej chwili system strzelania z celownikiem powinny działać perfekcyjnie.

 Poprzednia część <- #4 –  Regeneracja życia i energii. Efekty trafienia

Następna część -> #6 – Przeładowanie broni i amunicja