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

Temat: Przybliżenie i dziury po kulach

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

#5 – Kamera z bronią i strzelanie

#6 – Przeładowanie i amunicja

#7 – Zbieranie przedmiotów

#8 – Druga broń

#9 – Rzut granatem i seria z karabinu

#10 – Przybliżenie 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

W dzisiejszym odcinku, dopieścimy naszą broń i zostawimy już temat dopracowywania elementów. Co zrobimy dzisiaj? Dwa elementy, finalizujące broń. Zoom po naciśnięciu prawego klawisza myszki, oraz efekt dziur po kulach.

Do wykonania tej części, potrzeba tylko tekstury dziury po kuli. Ja używam tego:

Dziura po kuli
Dziura po kuli

Przycelowanie – zoom

Tutaj sprawa jest prosta, bo wystarczy manewrować odpowiednim elementem kamery, by uzyskać efekt przybliżenia. Ponownie operować będziemy na skrypcie Shooting.cs. Żeby nic się nie posypało zapisujemy sobie zmienne pomocnicze:

Nie są to wartości znikąd. Jeśli wjedziesz do Unity i zaznaczysz obiekt Main Camera, to w komponencie Camera znajdziesz wartość: Field Of View. Zmienna defaultFieldOfView, to wartość, która jest ustawiona domyślnie, druga wartość jest odpowiednio pomniejszona, by uzyskać efekt przybliżenia. Wartość zooma najlepiej dobrać doświadczalnie, czyli ustawiać jakieś wartości i zobaczyć, jaka najlepiej wygląda.

Teraz, przechodzimy do funkcji Update, gdzie dodajemy taki kodzik:

Przeanalizujmy linia po linii. Pierwszy if, sprawdza czy rodzin naszego obiektu (w tym wypadku broni) posiada komponent Camera. Jeżeli tak jest, zapisujemy go sobie do zmiennej cam. Następnie rozważamy dwa przypadki, gdy naciśnięty jest przycisk Fire2 (czyli prawy klawisz myszki – można to zmienić w ustawieniach Input: [Edit -> Project Settings… -> Input]). Jeżeli przycisk jest naciśnięty, chcemy przybliżyć, jeśli nie, oddalić. Robimy to odpowiednio zmniejszając lub zwiększając fieldOfView, do którego mamy łatwy dostęp dzięki zmiennej cam.

Zostaje kwestia ifów wewnątrz. Są one po to, żebyśmy mogli zmniejszać/zwiększać parametr co 1, dzięki czemu uzyskamy efekt płynnego przejścia. Tutaj swoje zastosowanie mają nasze zmienne pomocnicze, dzięki którym nie przekroczymy ustalonych wartości.

Tyle! Zoom działa!

Dziury po kulach

Póki jesteśmy w skrypcie, możemy najpierw dodać kod. Znów zaczynamy od zmiennej pomocniczej:

Będzie to prefabrykant naszej dziury. Teraz samo pojawienie dziury, dodajemy go w warunku trafienia w ścianę po strzale:

Tworzymy sobie obiekt, dzięki znanej nam funkcji instantinate. Ciekawe jest tutaj jedynie użycie hit.point i hit.normal do określenia rotacji i położenia dziury. Dzięki temu, dziura pojawi się tam, gdzie padł promień strzału broni, oraz zawsze będzie ustawiona wektorem Y prostopadle do powierzchni. Daje nam to tyle, że dziura nie pojawi się na ścianie np. bokiem. W sumie tyle kodu, czas przygotować dziurę. Wracamy do Unity.

Schemat jest prosty. Tworzymy sobie Cube: [GameObject -> 3D Object -> Cube] – mój się nazywa Hole.  Spłaszczamy go, ustawiając Scale.y na 0. Nakładamy teraz na niego teksturę dziury. Zmieniamy jeszcze Shader na Transparent/Bumped Diffuse, dzięki temu dziura będzie miała przeźroczyste tło, jeśli takowe będzie posiadał plik.

Poprawny obiekt Hole
Poprawny obiekt Hole

Teraz tworzymy pusty GameObject [GameObject -> Create Empty] – mój się nazywa BulletHole. Obiekt Hole ustawiamy jako child pustego gameObjectu. Ostatni krok, to ustawienie, dla obiektu Hole wartości transform position y na 0.1. Dzięki temu manewrowi, dziura zawsze będzie na wierzchu.

Zostało już tylko zrobić z obiektu BulletHole prefabrykant (przenosimy go do panelu Project), a następnie dodać ten prefabrykant do odpowiedniego pola w obiektach broni (te przygotowane wcześniej publiczne pola).

Jeżeli po pojawieniu się, rozmiar dziury jest za duży, wystarczy zmniejszyć parametr Scale dla komponentu Transform, naszego prefabrykantu.

Podsumowanie

Dziś nie zrobiliśmy wiele, ale dzięki temu gra uzyskała nieco uroku. Tak jak wspominałem, dalej nie będziemy się już bawić za bardzo tym co mamy, a zrobimy coś nowego.

Z racji, że w skrypcie Shooting.cs mieszaliśmy już bardzo dużo, udostępniam pełny skrypt:

 

Poprzednia część <- #9 – Rzut granatem i seria z karabinu

Następna część-> #11 – Przeciwnik z prostym AI, sztuczna inteligencja

  • Maciej

    Mam problem z tymi dziurami, dopiero jak podejdę pod samego cube’a w którego strzelam, to się na nim pojawiają dziury, ale po wielu strzałach i w całkowicie losowych miejscach z tego co widzę.

    • Wynikać może z dwóch rzeczy.
      1) Możesz mieć ustawiony dystans na dość niski.
      2) Promień strzału może być ustawiony w dziwną stronę.
      Aby rozwiązać problem dodaj sobie linijkę z funkcję Debug.DrawRay:
      https://docs.unity3d.com/ScriptReference/Debug.DrawRay.html
      Gdy odpalisz grę w okienku Scene będziesz widział jak pada linia strzału. Będzie od razu wiadomo w czym jest błąd. :)

    • Maciej

      Faktycznie, linia strzału jest wręcz prostopadła do linii, która powinna być. Co z tym zrobić, skoro kod skryptu mam z poradnika i nic nie zmieniałem?

    • Kopiowales fragmentami czy masz ten koncowy? Jak fragmentami to mozesz sprobowac koncowy.
      Jesli koncowy to moze byc zla hierarchia obiektow albo skrypt zle przypisany. Skrypt powinien byc dodany do broni, a sama bron byc childem kamery wewnatrz First Person Controllera.
      Jezeli uzywasz kontrolera z Unity 5, moze tam byc inaczej i wtedy jest to nieznany mi blad ktory musze sprawdzic.

    • Maciej

      Kopiowałem fragmentami, bo nie implementowałem wszystkiego, ale tak jak napisałem wyżej, działa po przestawieniu skryptu bezpośrednio na kamerę. Po prostu z tego co widzę to skrypt korzysta z „przodu” obiektu do którego jest przypisany a że model pistoletu w pozycji default’owej jest nieodpowiednio ustawiony to po rotacji wychodzą takie kwiatki. Chyba, że jest jakiś sposób by zmienić ten przód obiektu?
      Korzysta z ostatniej wersji Unity 3.x.x

    • w kompletnym skrypcie jest zmienna fwd. Poniera ona przod komponentu kamery. I wtedy wszystko dziala.

    • Maciej

      Dobra, już wiem w czym tkwi problem, skrypt strzelania, był przypisany do broni, która swój przód ma gdzie indziej niż kamera/postać. Przypisałem skrypt do głównej kamery i jest dobrze. Dzięki ;)

  • Vindict

    Mój promień strzału idzie co prawda do przodu jak trzeba ale jest przesunięty w dół (zaczyna się niżej niż kamera) przez co strzały zawsze trafiają za nisko. Wszystko mam jak w poradniku

    • Jeżeli wszystko jest w zgodzie z poradnikiem, to promień powinien być rzucany bezpośrednio z kamery (zmienna tf, to pobranie lokalizacji rodzica broni, którym powinien być obiekt Main Camera). Czyli rzucany promień powinien być niezależny od broni.
      Hierarchia powinna wyglądać tak:
      – FPC
      – Main Camera
      – Bron1 <- ze skryptem
      – Bron2 <- ze skryptem

      Jeżeli skrypt jest np. w childzie obiektu broni, wtedy lokacja może się przesuwać. Ogólnie: Bezpośrednim rodzicem obiektu ze skryptem musi być obiekt Main Camera, w przeciwnym wypadku, skrypt nie zadziała poprawnie.

    • Vindict

      Heh jak zwykle po godzinie szukania mam błąd. Nie zauważyłem, że zamiast „tf.transform.position” w strzelaniu miałem „transform.position” XDD Oczywiście teraz wszystko działa jak trzeba

  • Barti

    Dzięki temu Efektowi Zoom stworzyłem efekt lornetki tylko musiałem dodać włączanie/wyłączanie textury lornetki (czyli czrnego tła z dwiema dziurami obok siebie :D) którą stworzyłem w Gimpie xD (I najlepiej zmienić wartość w private float zoomFieldOfView = 40.0f; na mniejszą ;) )

  • Pingback: Unity3d FPS Tutorial #13 - Menu główne gry. GUI | mWin()

  • Skydrovski

    Da się zrobić tak żeby broń podążała za ruchem myszki jak w innych grach ???

    • Skydrovski

      Dobra poradziłem już sobie.

  • bartezz

    Mam problem z efektem zoomu. Mianowicie sam zoom nie działa tak jak powinien (przybliża i oddala), ale często gdy poruszam się ‚sprintem’ z włączonym zoomem gra zamraża się w dziwny sposób, słychać strzały gdy kliknę myszką lub to że idę ale obraz jest jest zamrożony (widać to na co była skierowana kamera w danym momencie). Czasem po kilku sekundach ‚odwiesza się’ a czasem trzeba wyłączyć Unity lub już zbudowany projekt

    • Szczerze nie wiem skąd mógł się wziąć problem. :/

    • bartezz

      Bo dodatkowo czasem w trakcie tego problemu wyświetla się błąd ‚Screen position out of view frustum’ przy czym tych błędów jest od 400 do 800

    • Przeglądnąłem trochę sieć pod względem tego błędu i niestety jego pochodzenie jest niejasne. Niektórym wystarczy, że zamkną okienko Scene i otworzą je od nowa i wszystko działa. W innych przypadkach problemem są błędy matematyczne w obliczeniach, które wywalają obliczenia przesunięcia postaci po za skalę, czy powodują dzielenie przez 0.

      Jeżeli błędu nie znajdziesz, to możliwe, że jedyną opcją będzie zablokowanie przybliżenia w czasie biegu.

    • bartezz

      O zablokowaniu przybliżenia nie pomyślałem (spróbuję zrobić). Sam myślałem nad tym żeby skończyć robić tą grę bez możliwości zoomu w Unity które aktualnie mam zainstalowane (v. 5.4.3), a potem zaktualizować do najnowszej wersji,dodać możliwość przybliżania i zobaczyć czy problem dalej będzie występował

  • Jakub Kartkowski

    Niewiem czy ja coś źle robię czyco, ale przybliżenie nie działa poprawnie, bo skrypt nie uwzględnia kamery odpowiedzialnej za nieprzenikanie broni, co powoduje komiczny efekt rozdwojenia broni.

    • Tylko jedna kamera powinna wyświetlać warstwę na której masz broń. :)

  • Jarek Chrobak

    Mam problem ponieważ po strzale bullethole koliduje w jakiś sposób z FPSControllerem i dziury pojawiają się w powietrzu z wyjątkiem momentu gdy szybko biegnę i strzelam.

    • Czy masz do swojej postaci dodany jakiś collider który jest dużo większy od niej (np. jakaś sfera ogarniająca całą postać)? Jeżeli tak, to Raycast zatrzymuje się na tym colliderze i trzeba go przełączyć w tryb IsTrigger, albo usunąć wykrywanie kolizji na warstwie z tym colliderem.

    • Jarek Chrobak

      Właśnie nie. Mam dołączony obiekt capsule aby było widać gracza, ale usunięty z niej jest collider. Jest podpięty tylko transform, character controller, rigidbody, skrypty i audio

    • Jarek Chrobak

      Zauważyłem że strzelam do siebie tylko wtedy gdy patrzę się w dół. Gdy patrzę się w ścianę lub do góry to wszystko działa

    • Jarek Chrobak

      Wiem już w czym problem ale nie wiem jak go rozwiązać, a mianowicie strzały blokują się na colliderze character controllera. Można zmniejszyć heigh i radius ale wtedy kamera jest bardzo nisko :/ Da się zrobić tak aby Raycast był wysyłany trochę dalej od postaci?

    • W kodzie podajesz punkt startowy RayCasta, więc możesz go lekko odsunąć w kodzie od modelu postaci i wszystko powinno być git.