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 ovládal naše animace.
V dnešním Unity 3D tutoriálu budeme programovat střelbu. Při stisku levého tlačítka spustíme animaci výstřelu a zároveň necháme posunout zasažený objekt:
Způsoby implementace střelby
Střelba se v Unity 3D může implementovat mnoha způsoby. Představíme si dva základní a jeden si vybereme.
Kulka se skriptem
První možností je 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 přidával sílu ve směru výstřelu. Tato možnost je složitější. Pracuje se v ní hodně s rotacemi objektu a získáváním směru.
Raycast
My si vybereme druhou možnost, spočívající v polopřímce vycházející ze zbraně a mířící na místo, kam se hráč dívá:
Pro tuto
možnost se používá metoda Raycast()
ze třídy
Physics
. Z možných parametrů metody využijeme pouze tři:
- pozice - odkud má vycházet naše polopřímka,
- naše proměnná typu
RaycastHit
, do které se budou ukládat informace o objektu, který naše polopřímka trefí, - směr - 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.
Směr, kterým "se dívá" naše kamera, získáme z
objekt.transform.forward
, kde objekt
bude naše
kamera.
Příprava na programování
Nejdříve potřebujeme mít na něco střílet. Vytvoříme si nový objekt
kostky Cube a přichytíme na něho komponentu
Rigidbody
. Díky tomu pak kostce můžeme přidat sílu ve směru
našeho výstřelu a budou se na ni 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 otevření nabídky zvolíme možnost 3D Object => Cube:
Nově vzniklý objekt si pojmenujeme například 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!
Klikneme levým tlačítkem na záložku Transform a vložíme
souřadnice, např: 5
, 1
, 5
:
V nově přidané komponentě Rigidbody neměňme žádné hodnoty. Jednotlivé kolonky v této komponentě, jako například Mass (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é přejdeme na
Prefabs/Example_P…/Bullet_Imp…/
a zde dvakrát klikneme na
soubor Metal Imp…
, což je úder na kov.
Vedle objektu Metal Impact Prefab klikneme na šipečku, aby se nám zobrazily 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 v objektu nehezký model "díry po výstřelu". Nám stačí mít zde pouze aktivovaný první podobjekt, který zajišťuje jiskry a zvuk zásahu.
Je možné si nechat aktívní oba podobjekty a případně deaktivovat objekt Metal Bullet Hole Particle až později.
Skript Shoot
Nejprve si vytvoříme nový skript a poté ho začneme upravovat.
Vytvoření skriptu Shoot
Levým tlačítkem klikneme na náš objekt s názvem
Assault_Rifle01_FPSController. Poté v záložce
Inspector klikneme na tlačítko Add Component a napíšeme
Shoot
. Klikneme na tlačítko New Script => Create
and Add:
Úprava skriptu Shoot
Na náš skript Shoot
dvakrát klikneme a tím ho otevřeme.
Upravíme ho tak, aby se při stisknutí levého tlačítka myši provedl
výstřel.
Proměnné
Na začátek třídy Shoot
přidáme tyto proměnné:
hitInfo
- pro ukládání informací o "paprsku",objectwithAnim
- pro instanci typuAnimator
,dostrel
- pro dostřel zbraně,poskozeni
- pro poškození zasaženého nepřítele,sila
- pro sílu působící na nepřítele,efekttrefy
- pro efekt zasažení.
Kód je následující:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Shoot : MonoBehaviour { RaycastHit hitInfo; Animator objectwithAnim; public float dostrel; public float sila; public float poskozeni; public GameObject efekttrefy; ... }
Metoda Start()
Dále v metodě Start()
nastavíme instanci proměnné
objectwithAnim
:
void Start() { objectwithAnim = GameObject.FindGameObjectWithTag("Animobject").GetComponent<Animator>(); }
Metoda Update()
Do metody Update()
přidáme dvě podmínky:
void Update() { if (Input.GetMouseButtonDown(0) && !objectwithAnim.GetBool("Run") && !objectwithAnim.GetBool("Holster") && !objectwithAnim.GetCurrentAnimatorStateInfo(0).IsName("Inspect")) { InvokeRepeating("ShootBullet", 0, 0.25f); } if (Input.GetMouseButtonUp(0)) { CancelInvoke("ShootBullet"); } }
V první podmínce hlídáme stisknutí levého tlačítka
myši, běh, schování zbraně a spuštění animace prohlížení. Pokud bude
podmínka splněna, zavoláme metodu InvokeRepeating()
s
parametry:
ShootBullet
- název metody, která se má zavolat (za okamžik si ji napíšeme),0
- okamžité zavolání metodyShootBullet()
s nulovou prodlevou,0.25f
- opakované volání metodyShootBullet()
každých0.25
sekund.
Pokud je v druhé podmínce levé tlačítko myši
vyhodnoceno jako uvolněné, v těle podmínky zrušíme opakované volání
metody ShootBullet()
.
Pro metody InvokeRepeating()
a
CancelInvoke()
se jako první parametr zadává název
metody bez závorek.
Metoda ShootBullet()
Nakonec si do skriptu Shoot
napíšeme novou metodu
ShootBullet()
. Metoda bude kontrolovat, jestli jsme něco zasáhli.
Pokud ano, tak se na konci vytvoří efekt a udělí zasaženému nepříteli
poškození:
void ShootBullet() { if (Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hitInfo, dostrel)) { GameObject trefa = Instantiate(efekttrefy,hitInfo.point, Quaternion.LookRotation(hitInfo.normal)); Destroy(trefa, 1); if (hitInfo.transform.GetComponent<Rigidbody>()) { hitInfo.transform.GetComponent<Rigidbody>().AddForce(Camera.main.transform.forward * sila); } if (hitInfo.transform.GetComponent<EnemyHealth>()) { hitInfo.transform.GetComponent<EnemyHealth>().TakeDamage(poskozeni); } } }
První podmínka
V první podmínce hlídáme zasažení objektu. Voláme metodu
Physics.Raycast()
s návratovou hodnotou typu
RaycastHit
, které předáme tyto parametry:
Camera.main.transform.position
- místo, odkud půjde polopřímka,Camera.main.transform.forward
- směr, jakým má jít polopřímka,out hitInfo
- kam se má ukládat informace o zasažení,dostrel
- vzdálenost, kam až povede polopřímka.
V těle podmínky si nejprve necháme vrátit objekt typu
GameObject
z metody Instantiate()
, které
předáme:
- efekt zasažení
efekttrefy
, - definované pozice
hitInfo.point
, - rotaci
Quaternion.LookRotation(hitInfo.normal)
.
Hodnotou normal
typu Vector3
u rotace definujeme,
že se nám má vrátit směr kolmý k zasaženému objektu:
Poté v těle podmínky zavoláme metodu Destroy()
s
parametry:
trefa
- objekt ke zničení,1
- doba v sekundách, za kterou se má objekt zničit.
Druhá podmínka
Druhou podmínku napíšeme do těla první podmínky za volání metody
Destroy(trefa, 1)
. V podmínce zjišťujeme, zda zasažený
objekt má komponentu typu Rigidbody
. Pokud ano, tak
přidáme sílu objektu ve směru, kterým se díváme.
Třetí podmínka
Také třetí podmínku si napíšeme do těla první podmínky a to za tělo
druhé podmínky. V podmínce zjišťujeme, zda zasažený
objekt má skript EnemyHealth
. Pokud ano, tak objektu
udělíme poškození pomocí metody TakeDamage()
.
Metodu TakeDamage()
si definujeme v dalších
lekcích.
Skript EnemyHealth
Nyní našemu objektu Target přidáme ještě nový skript
EnemyHealth
. Ve skriptu zjistíme, kolik životů má nepřítel,
na kterém je náš skript. Pokud nebude mít žádný život, tak objekt
nepřítele zničíme 😀
Vytvoření skriptu
EnemyHealth
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 napíšeme název našeho skriptu EnemyHealth
. Klikneme na
tlačítko New Script => Create and Add a skript je
přidán.
Úprava skriptu
EnemyHealth
Ve skriptu nebudeme vůbec používat metodu Start()
a
Update()
, které odstraníme. Do skriptu si přidáme proměnnou
health
:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyHealth : MonoBehaviour { public float health; }
Metoda TakeDamage()
Nejprve z životů odečteme poškození damage
. V podmínce
otestujeme, zda health<= 0
a případně zničíme objekt
nepřítele transform.gameObject
metodou
Destroy()
:
public void TakeDamage(float damage) { health -= damage; if (health <= 0) { Destroy(transform.gameObject); } }
Metodu budeme chtít volat z jiných skriptů, proto jsme ji
nastavili modifikátor přístupu public
.
Inicializace
public
proměnných v Unity Editoru
Proměnným obou skriptů nastavíme hodnoty.
Proměnné skriptu Shoot
Klikneme levým tlačítkem na objekt
Assault_Rifle01_FPSController. V záložce
Inspector se nám zobrazí komponenty přiřazené objektu
Assault_Rifle01_FPSController. Vybereme komponentu
Shoot, která představuje náš skript Shoot
:
V komponentě Shoot vidíme čtyři políčka se shodnými názvy proměnných našeho skriptu. Nastavíme jim například tyto hodnoty:
- pro Dostrel hodnotu
20
, - pro Sila hodnotu
100
, - pro Poskozeni hodnotu
20
.
V políčku Effekttrefy musíme zvolit náš dříve upravený objekt, v němž máme efekty. 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é.
Alternativně klikneme na kolečko ve volném poli s nápisem
None (Game Object) a napíšeme do vyhledávacího okénka :
Metal Impact Prefab
. Poté na vyhledaný objekt klikneme levým
tlačítkem.
Proměnné skriptu
EnemyHealth
Klikneme levým tlačítkem na našeho nepřítele, který jsme si nazvali
Target. V záložce Inspector se přesuneme do oddílu
Enemy Health (Script). Do políčka Health vložíme hodnotu
100
:
Políčko Health reprezentuje naši proměnou
health
. Čím vyšší ji dáme hodnotu, tím více výstřelů
nepřítel vydrží.
Zkouška střílení
Nyní máme vše nastaveno a můžeme spustit hru:
Zkusme si měnit hodnoty u komponenty Rigidbody přichycené na našem nepříteli a sledovat, co se bude dít
V následujícím kvízu, Kvíz - Animace zbraně a střelba na nepřítele v Unity3D, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 229x (1.74 kB)
Aplikace je včetně zdrojových kódů v jazyce C# .NET