Lekce 8 - 3D střílečka v Unity - Střelba na nepřítele
V minulé lekci, 3D střílečka v Unity - Ovládání animací, jsme si upravili skript Move.cs
tak, aby nám ovládal naše animace.
V dnešní lekci budeme programovat střelbu. Když zmáčkneme levé tlačítko, tak se nám spustí animace výstřelu a zároveň se posune objekt, na který míříme, ve směru našeho výstřelu. Vše bude vypadat nějak takto:

Způsoby implementace střelby
Střelba se v Unity 3D se dá implementovat mnoha způsoby. Pojďme si představit ty nejzákladnější a vybrat pro nás ten nejlepší.
Kulka se skriptem
Jako příklad si uveďme možnost vytvořit ("spawnout") kulku po stisknutí levého tlačítka myši. Tato kulka by měla na sobě přichycený skript, který by ji okamžitě po vzniku přidával sílu ve směru, kterým je namířena. Tato možnost je složitější a komplexnější pro naši hru. Pracuje se v ní hodně s rotacemi objektu a získáváním směru.
Raycast
Druhá možnost, kterou Unity 3D nabízí a je často využívána, je udělat si polopřímku, která vychází ze zbraně a míří na místo, kam se hráč dívá:
Užívá se k tomu metoda
Raycast()
,
kterou bychom mohli do češtiny přeložit jako "vyšli paprsek" nebo "vyšli
polopřímku". Tato metoda má mnoho parametrů a nachází se
ve třídě Physics
. My zadáme pouze tři
parametry:
- pozice, odkud má vycházet naše polopřímka
- směr - již jsme si řekli, že bude směřovat na místo,
kam míříme. Tento směr je stejný jako směr, kterým se díváme. Nebo-li
stejný směr, jaký má naše kamera. A jak získat směr, kterým "se dívá"
naše kamera? Pomocí
objekt.transform.forward
, kdyobjekt
zde bude naše kamera. - naše proměnná, do které se budou ukládat informace o
objektu, který naše polopřímka trefí. Tato proměnná je typu
RaycastHit
.
Nyní se můžeme vrhnout na reálné činy, když už víme jak to funguje a co potřebujeme udělat.
Příprava na programování
Nejdříve potřebujeme na něco střílet. Vytvoříme si nový objekt
Cube a přichytíme na něj komponentu Rigidbody
.
Díky tomu ji pak můžeme přidat sílu ve směru našeho výstřelu a na
objekt se budou aplikovat fyzikální zákony.
Nejdříve ze všeho klikněme pravým tlačítkem někde na volnou oblast v záložce Hiearchy, po rozrolování nabídky zvolíme možnost 3D Object a pak možnost Cube. Nově vzniklý objekt si můžete pojmenovat jakkoliv, název nebude mít žádný vliv na náš kód:

Já jsem si svou kostku pojmenoval Target
. Nyní klikneme na
kostku levým tlačítkem a podíváme se do záložky
Inspector. Zde klikneme na tlačítko Add
Component, napíšeme Rigidbody
a klikneme na
Rigidbody
ve výsledcích vyhledávání.
Pozor, nevyberte omylem Rigidbody2D
, které je
určené pro 2D
hry! Jinak vám pohyb nebude fungovat.
Klikneme levým tlačítkem na záložku Transform a
vložíme souřadnice, např: 5
, 1
, 5
nebo jaké si vy sami zvolíte, aby byla kostka někde příhodně
umístěna:

V nově přidané komponentě Rigidbody
neměňte žádné
hodnoty. Pokud si s tím budete chtít pohrát, tak doporučuji až po tvorbě
našeho skriptu pro střelbu. Jednotlivé kolonky v této komponentě jako
například Mass nebo-li hmotnost ovlivní, jaký bude mít
vliv náš výstřel na tento objekt.
Poslední, co nám zbývá, je upravit vzor objektu, který budeme vytvářet vždy po výstřelu. Tento objekt nám bude tvořit efekt zásahu. Efekt je již hotový a máme ho naimportovaný spolu se všemi věcmi z našeho balíčku. Stačí kliknout levým tlačítkem myši na složku Low Poly F… v záložce Project, poté kliknout na Prefabs -> Example_P… -> Bullet_Imp… a zde dvakrát kliknout na soubor Metal Imp…, což je úder na kov.
Vedle objektu Metal Impact Prefab
klikneme na šipečku a tím
rozrolujeme podobjekty. Vybereme podobjekt
Metal Bullet Hole Particle
a deaktivujeme celý podobjekt
kliknutím na čtvereček vedle názvu. To proto, že když bychom podobjekt
nechali aktivní, po výstřelu by se nám objevil nehezký model "díry po
výstřelu" v objektu. Nám stačí mít zde pouze aktivovaný první podobjekt,
který zajišťuje jiskry a zvuk zásahu. Schválně si můžete nechat
podobjekty aktivní oba a rozhodnout se, jestli se vám efekt líbí a nebo
ne:

Skript EnemyHealth
Nyní našemu objektu Target
přidáme ještě nový skript
EnemyHealth
, který bude na každém našem kdy vytvořeném
nepříteli. Tento skript bude zjišťovat kolik má daný nepřítel, na
kterém je náš skript, životů a pokud bude mít nulu, tak se ten daný
objekt zničí.
Levým tlačítkem klikneme na objekt Target
a podíváme se do
záložky Inspector. Zde klikneme na tlačítko Add
Component a vepíšeme název našeho skriptu EnemyHealth
.
Klikneme na tlačítko New Script a pak už jen na
Create and Add a skript je přidán.
Skript shoot
Levým tlačítkem klikneme na náš objekt s názvem
Assault_Rifle_01_FPSController
. Poté v záložce
Inspector klikneme na tlačítko Add Component
a napíšeme shoot
. Klikneme na tlačítko New
Script pak už jen na Create and Add a máte
hotovo:

Následně už jen dvakrát klikneme na náš skript shoot
a
tím ho otevřeme.
Kód
Obsah skriptu bude následující:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; public class shoot : MonoBehaviour { RaycastHit hitInfo; Animator objectwithAnim; public float dostrel; public float sila; public float poskozeni; public GameObject efekttrefy; void Start() { objectwithAnim = GameObject.FindGameObjectWithTag("Animobject").GetComponent<Animator>(); } // Update is called once per frame void Update() { if (Input.GetMouseButtonDown(0)&&!objectwithAnim.GetBool("Run") && !objectwithAnim.GetBool("Holster") && !objectwithAnim.GetCurrentAnimatorStateInfo(0).IsName("Inspect")) // pokud stiskneme levé tlačítko, neběžíme, nemáme schovanou zbraň a ani není spuštěna animace prohlížení { InvokeRepeating("Shoot", 0, 0.25f); // opakuje metodu Shoot(), začíná okamžitě bez prodlevy, opakuje se každých 0.25 sekundy } if (Input.GetMouseButtonUp(0)) { CancelInvoke("Shoot"); // přestává se volat metoda Shoot() } } void Shoot() // námi nově vytvořená metoda { if (Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hitInfo, dostrel)) // pokud něco trefíme, parametry jsou: místo, odkud půjde polopřímka, směr, kam má ukládat informace o tom, co se zasáhlo, a dálka, kam až povede. { GameObject trefa= Instantiate(efekttrefy,hitInfo.point, Quaternion.LookRotation(hitInfo.normal)); Destroy(trefa, 1); if (hitInfo.transform.GetComponent<Rigidbody>()) // pokud objekt, který jsme trefili, má komponentu Rigidbody { hitInfo.transform.GetComponent<Rigidbody>().AddForce(Camera.main.transform.forward * sila); // přidáme sílu ve směru, kterým se díváme } if (hitInfo.transform.GetComponent<EnemyHealth>()) // pokud objekt, který jsme trefili, má komponentu EnemyHealth { hitInfo.transform.GetComponent<EnemyHealth>().GetDammage(poskozeni); // spouštíme metodu v jiném skriptu, parametrem jsme si nastavili množství poškození } } } }
Kód je okomentovaný, projděte si jej. Opět zde máme několik věcí k podrobnějšímu vysvětlení.
RaycastHit.normal
normal
je proměnná typu Vector3
. Objekt, kdyby
byl kolmý k tomu, co jsme pomocí neviditelné polopřímky ray trefili, by
měl směr stejný jako je hodnota proměnné normal
(je to tedy
kolmice). Následující obrázek by vám to měl pomoci pochopit:
Tuto proměnnou má každá polopřímka
ray.
LookRotation()
nám vrátí hodnotu ve formě
Quarterion(rotace), kterou by se tím směrem daný objekt díval.
Skript EnemyHealth
Uveďme si i druhý skript:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyHealth : MonoBehaviour { // Start is called before the first frame update public float zivoty; void Start() { } // Update is called once per frame void Update() { } public void GetDammage(float poskozeni) // nová metoda musí být public, abychom ji mohli zavolat z jiného skriptu { zivoty -= poskozeni; // odečte jednorázově poškození od životů if (zivoty <= 0) { Destroy(transform.gameObject); // metoda, která ničí herní objekty, jako parametr můžete nastavit čas od zavolání této metody, než se zničí } } }
Inicializace
public
proměnných v Unity Editoru
Teď, když jsme si vytvořili kód, který nám vše řídí, nastavíme
ještě hodnoty jednotlivým public
proměnným. U našeho
nepřítele je to hodnota životů a u našeho skriptu pro střelbu to jsou:
- dostřel zbraně
- síla, která působí na nepřítele
- vzor efektu
- poškození, které mu udělí
Proměnné skriptu shoot
Klikneme levým tlačítkem na objekt
Assault_Rifle_01_FPSController
. V záložce
Inspector se nám zobrazí vše, co je na tomto objektu
přichyceno za komponenty. Nás zajímá komponenta shoot
, která
je náš skript. Zde vidíme čtyři od sebe oddělená políčka s názvy:
Dostrel, Sila, Poskozeni, Efekttrefy. Tato políčka
představují stejnojmenné proměnné v našem skriptu. Podle toho, jaké jim
nastavíte hodnoty, se hra bude chovat. Když nastavíte proměnnou
Sila na 5000
, tak nám objekt, na který
vystřelíme a má Rigidbody
, odletí ze zorného pole:

Já jsem zvolil hodnoty:
- Dostrel:
20
, - Sila:
100
, - Poskozeni:
20
.
Pro proměnnou Effekttrefy musíme zvolit náš dříve upravený objekt v němž máme efekty. Jako první ho najdeme opět v záložce Project. Poté ho myší přetáhneme do volného pole s nápisem None (Game Object) vedle názvu Efekttrefy. Tím se nám herní objekt přiřadí do této proměnné.
Druhý způsob je kliknout na kolečko ve volném poli s
nápisem None (Game Object) a napsat do vyhledávacího
okénka, které nám vyskočí: Metal Impact Prefab
a poté na
vyhledaný objekt kliknout levým tlačítkem.
Proměnné skriptu
EnemyHealth
Klikneme levým tlačítkem na našeho nepřítele, v mém případě
pojmenovaného Target
. V záložce Inspector
následně uvidíme náš skript, který je na našem nepříteli přichycen.
Skript se jmenuje EnemyHealth
. Skript by měl mít viditelnou
proměnnou Zivoty. Tato proměnná, jak jste již pochopili,
určuje nepřítelovo zdraví. Čím vyšší hodnota, tím více výstřelů
vydrží. Já mám nastavenou hodnotu 100
:

Zkouška střílení
Nyní máme vše nastaveno a můžeme spustit hru:

Zkuste si schválně měnit hodnoty u komponenty Rigidbody
přichycené na našem nepříteli a sledujte, co se bude dít
V příští lekci, 3D střílečka v Unity - Efekty střelby, si uděláme efekt střelby, zvuk výstřelu a přidáme si mířidla.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkamiStaženo 184x (2.21 kB)