Matematikai és Informatikai Intézet
Unity Programozás
Készítette:
Témavezető:
Dósai László
Bíró Csaba
programtervező informatikus
adjunktus
Eger, 2015
Tartalomjegyzék 1. 3D modellezés
5
1.1. Alapok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
1.2. Alakzatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
1.3. A modellalkotás folyamata . . . . . . . . . . . . . . . . . . . . . . . .
6
1.4. A modellezés előnyei . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
2. Blender
8
2.1. Története . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
2.2. Kezelő felület . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.2.1. Eszközök . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.2.2. Módok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
2.3. A repülőgép elkészítése Blenderben . . . . . . . . . . . . . . . . . . . .
15
2.3.1. Modell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
2.3.2. Modellezés . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
2.3.3. Anyag és textúra . . . . . . . . . . . . . . . . . . . . . . . . . .
19
2.3.4. Exportálás . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
3. Unity
23
3.1. A Unity Leírása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
3.2. A szakdolgozatom leírása . . . . . . . . . . . . . . . . . . . . . . . . .
23
3.3. A repülőgép irányítása . . . . . . . . . . . . . . . . . . . . . . . . . .
24
3.4. A környezet kialakítása . . . . . . . . . . . . . . . . . . . . . . . . . .
25
3.4.1. Terrain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
3.4.2. Víz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
3.4.3. Környezeti objektumok . . . . . . . . . . . . . . . . . . . . . .
27
3.4.4. Repülőgép . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
3.4.5. Kijelző . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30
3.4.6. Fakészítés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
3.5. Scriptek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
3.5.1. Mozg . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
3.5.2. crash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
3.5.3. Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
2
3.5.4. Compass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.5.5. Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4. Összegzés
46 47 48
3
Bevezetés Szakdolgozati témámnak a Unity programozást választottam, aminek segítségével egy „Free Fly ” típusú repülőgép szimulátort írtam. A munkám tulajdonképpen 2 nagy részre bontható szét. Először vehetjük azt, amikor az alapvető modellek és objektumok készültek el. Ebben a Blender program segített, későbbiekben majd részletezem. Ebben a szoftverben készült el maga géptest, és annak részei, kerekek, szárnyak,gép test stb. Továbbá szintén ebben a program készült el a gép textúrája is. A dolgozat elkészítésének második lépcsője a Unity programozás volt. Ebben a fejlesztői környezetbe lett be importálva a gépünk, és itt lettek köré írva scriptek, amiknek segítségével lett az egyszerű objektumból, egy mozgó, és egy közel életszerű szimulátor, aminek segítségével, átélhetjük a repülés élményét otthonról a fotelból is.
4
1. fejezet 3D modellezés 1.1. Alapok A számítógépes grafikában 3D modellezésnek nevezzük azt a folyamatot, amikor egy tetszőleges objektumot ábrázolunk matematikai modellek segítségével. Ezen modellek készülhetnek manuális úton és teljesen automatikusan.[4] Ennek eredményét nevezzük 3D modellnek. Egy 3D képből bármikor készíthetünk 2D képet a renderelés eljárás segítségével. Viszont ez a folyamat egy dimenzióvesztő eljárása ahol, ugye elveszítjük a modellünk Z koordinátáit és csak az X és Y marad. Ez tulajdonképpen egy pillanatkép a 3D objektumunkról, amit egy előre beállított szögből készítünk. Egyetemesen elmondható, hogy minden 3D objektum pontokból áll ezeket a pontokat kössük össze vonalakkal és 2D alakzatok segítségével, pl. négyzetek, háromszögek, körök, és szakaszok segítségével. Ezekből az alapvető alakzatokból elkészíthető szinte minden 3D objektum, még akár a gömb is, hiszen gondoljunk csak bele abba, hogyha veszünk egy gömböt és az megfelelő kicsi négyzetekből vagy háromszögekből építjük fel, akkor az már egy bizonyos nagyságban kellően sima felületű alakzatot eredményez.
1.2. Alakzatok Minden modell besorolható, 2 nagy alapvető kategóriába: Héj. Ennél az ábrázolásnál az alakzatnak csak a felszínét hozzuk létre, hogy hogyan néz ki kívülről, de az alakzaton belül, egy „légüres” tér van tehát, nincs benne semmilyen kitöltő anyag. Ezekkel az objektumokkal sokkal egyszerűbb dolgozni, és ez a legelterjedtebb a számítógépes grafikában. [4] Tömör. Ezen objektumok ábrázolása meglehetősen körülményes, ugyanis itt nem csak egy felszínt, hanem a belső teret is meg kell tervezni, tehát valós fizikai anyagokat, és fizikai mutatókat kell hozzáadni az objektumhoz. Gondolok itt a sűrűségre, 5
tömegre, az anyag szerkezeti felépítésére, esetlegesen rugalmasságára. Ezt az eljárást ritkán használatos, elsősorban fizikai szimulációknál, ahol számítanak az előbb felsorolt mutatók, de elterjedt, a gyógyászatban is. Ennek a módszernek a segítségével készít képet, és alkot modellt, az MRI gép is ahol kimondottan fontos, hogy mi van a felszín alatt.[4]
1.3. A modellalkotás folyamata A modelleket, több fajta módon készíthetjük el, a legalapvetőbb ezek közül talán a poligonhálós modellezési mód, aminek segítségével, elhelyezünk pontokat a 3D térben, és azokat kötjük össze szakaszokkal az így létre jött felületek alkotják a poligon hálót.[4] Ezek rugalmasan és könnyen használható felületek, könnyű őket alakítani. Tökéletes példa erre, ha mondjuk, elkészítünk egy jó modellt, ami közel azonos egy négylábú állattal, arra mindegy ,hogy tigris vagy oroszlán kinézetet húzunk, mindegyiknek ugyanolyan a mozgása. A poligonháló meglehetősen hasonló. Ebben a modellezési eljárásban is van azért automatizmus, amit manapság már a tervező programok elkészítenek helyettünk. Sok olyan számítást nem is látunk, amikor futás közben egyes poligon részek nem látszanak, de olyanok igen, amiket mi nem terveztünk meg, viszont a program ott újra írja poligont, hogy a lehető legjobb hálót adja vissza a felhasználónak. A másik elterjedt modellalkotási folyamat az a NURBS1 modellezés. Ennél a modellalkotási technológiánál a modell súlyozott kontrollpontokba, vagy közelükbe húzott spilne függvények segítségével jön létre.[4] A spline függvények görbe függvények, amiket polinomok segítségével adunk meg. A leggyakoribb polinomok, amit használnak a programok az Hermit-polinomok, Bernstein polinomok, és a Bezier görbék.[4] És végezetül a Primitívmodellezés[4] maradt, ez leginkább a vektorgrafikus ábrázolásra hasonlít, ugyanis itt is alapvető primitívekből, kockák, hengerek, kúpok, tóruszokból épülnek fel az objektumok. Ez egy meglehetősen pontos modellt ad vissza eredményül, a háttérben matematikai definíciók vannak. Könnyű velük dolgozni, és egyszerű leíró nyelvet használnak. A Blender ezen utolsó kategóriába tartozik, tehát ezen alapvető primitívekből épülnek fel az alakzatok, mint ahogy az én repülőm is.
1.4. A modellezés előnyei A modellezés előnyeit elsősorban abban kell keresni, hogy milyen dologra fogjuk használni a modellünket, és annak a modellnek az elkészítése a valós világban mekkora befektetésnek minősül. Gondolok itt, egyértelműen anyagi, fizikai, megvalósíthatósági 1
Non- Uniform Rational B-spline Surfaces, nem uniform racionális B-spline görbékkel definiált felület
6
korlátokra egyaránt. Az esetek döntő többségében, amikor is elkezdődik egy tervezési folyamat, sokkal logikusabb döntés egy számítógépes modellel kezdeni a tervezést. Ezeknek a modelleknek rengeteg előnye van egy tervezési folyamat alatt, részletesen meg tudunk adni olyan adatokat, amik közel valóságos eseteknek felelnek meg. Az objektumoknak tudjuk vizsgálni fizikai szerkezetét és azt, hogy bizonyos fizikai hatások következtében az objektum hogyan viselkedne, ha mondjuk szélviharba kerülne vagy esetleg egy árhullám csapódna neki. Az ilyen modelleknek különösen nagy haszna van a járműtervezésben és építészetben. Egy repülő tervezésénél, rengeteg időt vesz igénybe pl., a tökéletesítés, az egyes felületek görbülete és, hogy a felületek hogyan érintkeznek a levegővel. Ebben az esetben nem kell minden egyes alkalommal újra és újra megépítenünk a modellünket, hanem pár kattintással, könnyedén módosítani tudjuk az objektumunkat. Így és ilyen eszközök segítséggel születnek egyre jobb és jobb technikai vívmányok. Manapság már a finommechanikában és a mikro alkatrészek megtervezésénél, is fontosak a modellek, ugyanis, ha létezik is a technika arra, hogy mikro eszközöket gyártsunk, mégis bonyolult volna megtervezni ezeket a valós világban tollal és ceruzával. Ekkor hívják újfent segítségül a 3D modelleket, megtervezik, és ha kell, akkor akár ki is tudjuk nyomtatni az objektumot vagy esetleg legyártjuk egy CNC marógéppel. A jövőt mindenképpen abban látom, hogy minden háztartásban elérhetővé válik egy 3D nyomtató, és ha kell egy eszköz, egy szerszám, egy letört kis alkatrészdarab, vagy netalán egy új mobil csak fogjuk és kinyomtatunk magunknak egy eszközt.[4]
7
2. fejezet Blender 2.1. Története A Blender egy 3D tervező program. A programot először egy belső használatra tervezett programnak szánták. A fejlesztője egy Ton Roosendaal nevű férfi. 1998-ban megalapította saját cégét amit Not a Number Technologies nevezett el. Itt a Blender fejlesztésével szeretett volna foglalkozni, kezdetben a program shareware volt tehát egy fizetős program, egészen 2002-ig, amikor is a cég tönkre ment, és el kellett adni a programot. Innen vált a program nyílt forráskódúvá. Ez tulajdonképpen azt jelenti, hogy a program teljes forrás kódja megtalálható az interneten és bárki aki szeretné, módosíthatja azt, akár saját használatára vagy elküldheti a Blender Alapítványnak, akik jelenleg felügyelik a szoftvert. Így lehetőság van arra ,hogy az esetleges hivatalos verzió frissítés esetén kerüljön bele az ő kódrészlete is a programba.[1] Érdemes megemlíteni Suzanne (2.1), ő egy csimpánz arc, ami minden Blenderben megtalálható. Olyan ő, mint a szövegszerkesztő programoknak a lorem ipsum1 , ezen jól beállíthatók és próbálgathatók a fények és viszonyok. Jól lehet hozzá anyagot vagy textúrát adni.
2.1. ábra. Suzanne - Blender egyik primitívje 1
Szögszerkesztők ezen a szövegen próbálják, ki az egyes formázási beállításokat.Ez egy értelmetlen szöveg viszont benne van az összes olyan betű kombináció amin jól látszanak az egyes formázási beállítások
8
2.2. Kezelő felület 2.2.1. Eszközök A Blender program megnyitásakor egy letisztult, bár első ránézésre kissé bonyolult kezelő felület jelenik meg. Alapvetően, be van importálva nekünk egy kocka, ez a kezdő felületünk. Baloldalon találhatók az eszközök, amiknek segítségével, alakzatokat tudunk létre hozni.Ebben a verzióban a 2.75 kiadásban baloldalon fel vannak osztva az eszközök a könnyebb kezelés érdekében.(2.2)
2.2. ábra. A Blender nyítóképe
Tools. Legfölül található a Tools, ezen belül pedig a Transform, legördülő menü, itt a legalapvetőbb transzformációk vannak: Translate. (G billentyű parancs). Ha rávezetjük az egérmutatónkat, egy funkció elemre, a Blender egy címkét dob fel, amiben röviden leírja, hogy mit is csinál az a funkció és mi a gyors billentyű parancsa. Ennek a segítségével, tudjuk mozgatni az alakzatokat, szabadon a 3D tervező térben. Ha csak simán rányomunk a Translatre akkor, szabad mozgatás történik abba az irányba amerre a mutatónk mozog. Tulajdonképpen egy 2D vásznon történik az esemény, viszont ha már billentyű kombinációt is használunk úgy már precíziósabb mozgatást érünk el. Ha ráklikkelünk a Translate gombra, és megnyomjuk az X, Y vagy Z billentyűt akkor az adott tengely mentén, mozgatjuk az objektumot. 9
Rotate. (R) Ez a funkció a forgatás, testek forgatása szabadon a test geometriai középpontja körül. Hasonló elven működik, mint a Translate, ugyanis ha csak simán rákattintunk a gombra, akkor szabad forgatás történik a 2D vásznon, abba az irányba ahol a mutatónk áll. Viszont ha alkalmazzuk a fenti billentyűket, akkor már a kiválasztott tengely körül történik meg a forgatás. Scale. (S) E funkció segítségével, tudjuk, nagyítani vagy kicsinyíteni az alakzatunkat, a működési elve teljesen megegyezik, az előző funkciókkal. Ezek az alapfunkciók még a fentiken kívül 3 helyen is elérhetőek, a legalapvetőbb, ha parancssorban megírjuk ezeket a funkciókat és így kerül sor a transzformációra. Lehetőség van még a jobb oldali alapból elrejtett sávot, megjelenítenünk és ott legfelül szintén a Transform rész alatt megtalálhatóak ezek a funkciók. Ez azért jobb, mert itt pontos értékeket is meg tudunk adni, és precízebb beállításokat is készíthetünk. Végezetül találunk egy vékony sávot alul, ami a fenti képen is látszik(2.2). A Global test mellett található 4 ikon, nekünk ebben az esetben az utolsó 3-ra lesz szükségünk. Ezeknek a kiválasztásával szintén tudjuk transzformálni az alakzatunkat. Ha rákattintunk valamelyikre, akkor megváltozik az objektumunkon lévő vezérlő. A Transformation Manipulator(nyilas vezérlő) segítségével tudjuk mozgatni, az alakzatunkat, a megfelelő tengely körül húzzuk az alakzatunkat. A 3 irányba mutató és a végén ki kockával ellátott vezérlővel tudjuk nagyítani vagy kicsinyíteni alakzatunkat. Végezetül a félkörívre kattintva, megjelenik, a forgatás segítő gömb alak, itt tudjuk a megfelelő körív mentén forgatni az alakzatunkat. Edit. A következő legördülő menünk az Edit, itt a legfontosabb eszközök: Duplicate. Ami azt csinálja, amit a neve is elmond róla, megduplázza a kijelölt objektumot. Pontosan arra koordinátára illeszti be a másolatot ahol az eredeti is található volt. Ennek a billentyű kombinációja, Shift+D. Delete. Megtalálható még itt a Delete parancs is, ami törli a kiválasztott objektumot, ennek a gyors billentyűje, az X. Join. Van itt egy fontos parancs a Join ez azt csinálja, hogy összekacsol objektumokat. Itt arra kell gondolni, hogy vannak pl. kockák és azt szeretnénk, hogy ez a két kocka mindig egyszerre változzon, ha transzformálom, nagyítom, forgatom, vagy elmozdítom. Ha az objektumok össze vannak kapcsolva, akkor ezek a műveletek mind a 2 alakzatra egyszerre végbe menni. Ez egy fontos funkció mivel, egy bonyolultabb alakzat, nyilván nem egy primitívből fog állni, hanem akár sok százból. Amikor esetlegesen, exportáljuk, az alakzatunkat akkor jó lenne, ha nem sok száz darabban lenne, hanem egy nagy összefüggő alakzatba. 10
Create. Ugorjunk a következő fülre a Create, fülre, ahol is azok az alakzatok, találhatók, amikkel a Blender dolgozni tud, itt, ha rákattintunk bármely alakzatra, akkor az rögtön bekerül a tervező térbe és dolgozhatunk vele. Mesh. A Mesh rész alatt megtalálhatók azok a primitívek, amiket a Blender használni tud. Megtalálható itt, a 2D négyzet, a kocka, a kör, a gömb, kúp, henger, tórusz, az ikozaéder is. Curve. Vannak itt még görbék a ,Bezier görbe, olyan kör, aminek csak az íve látszik, de nincs felülete, Félkörök és irányított irányú szakaszok is. Lamp. A Lamp alatt találjuk a fényeket, közül is sok áll rendelkezésünkre. Egy pont fény, ami csak a maga kis pontjában világít és nincs neki nagy kiterjedése. Ellenben mondjuk a Sun vagy az Area light-al. A Sun fénynek nem tudom állítani az irányát az mindig minden felé, világít, nem tudok neki megadni olyan attribútumot, hogy csak egy pontot világítson meg. Nagy intenzitású, tehát megvilágítja az egész jelenetet, nem kell egyéb fényforrást hozzáadni. Az Area light ezzel szemben azért jobb mert, irányítható a fény iránya, tehát ha azt adom meg, hogy csak egy bizonyos szint alatt legyen világos,akkor csak ott lesz világos. A beállított szint felette nem, ellenben a nappal ahol minden irányba terjed a fény. A Spot light is hasonló elven működik, csak itt nem lehet akkora területet megadni, mint az Area lightnál sokkal kisebb a megvilágítható terület. Other. Az Other rész alatt az egyéb kiegészítő vezérlők találhatók meg. Itt van, pl. a Text ezzel a funkcióval tudunk feliratokat és szövegeket adni, az alakzatokhoz, ennek a funkciónak nincsenek nagy beállítási lehetőségei. Lehet állítani a betű stílust és a betűk formáját, és persze az alap transzformációk megtalálhatók ennél is. Armature. Ez egy fontos elem, ha mozgó alakzatokat szeretnék elkészíteni, gondoljunk itt akár egy gömbcsuklóra vagy akár egy emberre. Ezzel az eszközzel tulajdonképpen forgási és csuklási pontokat tudunk hozzáadni egy alakzathoz. Le tudunk modellezni egy teljes emberi kart a könyökkel és csuklóval. Ezzel az eszközzel, több ilyen kis alakzatot összekapcsolhatunk, és akkor azok együtt tudnak mozogni. Ugyanakkor vannak csuklási pontjaik, hogy pl. egy emberi ujjat is tudjunk csinálni, vehetjük úgy, hogy ezeknek az objektumoknak a gömbös rész, az emberben a porcoknak felelnek meg. Legutolsó elemként itt van a Camera is, ami fontos ha renderelt animációkat vagy alakzatokat akarunk létre hozni, ha nincs a jelenetben kamera, akkor a renderelés alatt semmi nem fog látszani. Ennek is lehet állítani a nagyságát, így állítódik az, hogy mekkora legyen a kamera betekintési szöge. 11
Relations. Ha tovább megyünk a füleken a következő a Relations, vagyis kapcsolatok. Itt tudunk megadni szülő gyerek kapcsolatokat, és képesek vagyunk csoportokat kialakítani. Ez nagy projekteknél tud hasznos lenni hogyha össze akarunk foglalni több alakzatot egy nagyobb alakzat alá, és azt nevesíteni szeretnék. Tökéletes példa erre, ha egy emberi testet készítünk, akkor érdemes az egyes testrészeket egy csoportba foglalni a kéz mondjuk biztos állni fog minimum 10-15 armatureből. Ezeket utána sokkal egyszerűbb egy csoport alatt kezelnünk. Viszont itt még érdemes beállítani egy szülő gyerek kapcsolatot, az alkar és a felkar között, a fel kar lesz a szülő, az alkar pedig annak a gyerek eleme. Animation. A 4. fülnek a neve Animation, ezzel a menü ponttal tudunk létre hozni, animációkat az egyes alakzatokra. Insert. Az Insert funkcióval be tudunk szúrni jeleneteket, a filmsávba (ez a sáv legalul található meg itt megtalálható a hozzá való alap gombok is a lejátszás, a szünet, és az ugrások bármely irányba). Ennek segítségével tudja a Blender hogy, itt egy animáció fog kezdődni. Számtalan típusú animációt tudunk beszúrni egy jelenetbe, a legegyszerűbbek nyilván valóan, transzformációs animációk tehát, hogy egy alakzatot, arrébb tolunk vagy megforgatjuk, a tengelyek körül. Ennél a résznél még érdemes megemlíteni a Motion Capture, funkciót, a Blender ezzel a funkcióval is fel van szerelve. A Motion Capture azt jelenti, hogy rögzítjük, valaminek a mozgását, és azt a mozgás sémát ültetjük rá, egy tetszőleges modellre. Ezt a funkciót általában a filmeknél szokták, alkalmazni. Úgy kell elképzelni, hogy van egy színészünk, akire rászerelnek, jó sok szenzort ezek rögzítik a színész mozgását, hogy egy kis képet is tudjuk hozzá képzelni, vegyük Davy Jones karakterét a Karib tenger kalózaiból. Ő teljesen Motion Capture animációval jött létre. Volt egy színész, akire rátettek egy nagy adag érzékelőt, és utána, rögzítették a mozgását, és az arcának minden egyes grimaszát, gesztusát. Azután rá lettek húzva a polip karok, amik felvették azt a mozgást, amit az érzékelők rögzítettek. Persze ennek is vannak hátrányai és nem minden esetben alkalmazható. Az állatok mozgása nem vagy nehezen modellezhető, és abszurd fizikával ellenes mozgásokat nem tudnak rögzíteni vele A határ kb. ott van, amit egy ember meg tud csinálni, azt le lehet Mocap animációval is modellezni. Physics. Az utolsó előtti fül a Physics fül, amin a testekhez tudunk rendelni fizikai anyagokat, és fizikai testeket. Rigidbody. Itt tudjuk megadni, hogy az egyes elemek hogyan, viselkedjenek egy fizikai ráhatás következtében. Gondolok itt arra, hogy hogyan viselkedjen az 12
elem, ha zuhan, vagy ha ütközik, egy másik testtel. Rengeteg előre megadott fizikai anyagot tudunk hozzáadni a testünkhöz. Arany, vas, fa, rugós felületű anyagok. Ki tudjuk választani, hogy az a test milyen alakú Rigidybodyval rendelkezzen. Tehát egy kockához adhatunk akár henger alakú Rigidbodyt. Én a szakdolgozatom írása alatt nem alkalmaztam ezt a funkciót. A Blenderben kizárólag az objektumot csináltam meg és a fizikai jellemzőket, a Unity programban adtam hozzá. Könnyebb volt ott, mivel akkor már a Unityben könnyebb volt hivatkozni egyes alakzatokra és egyszerűbb volt vizsgálni bizonyos fizikai érintkezéseket. Grease Pencil. Az utolsó fül a Grease Pencil. Itt vannak azok a funkciók, amik segítségével szabad kézzel tudunk alakzatokat lére hozni. Megtalálható itt, az alap ecset, ami teljes szabad kezű rajzolást segíti, de rajzolhatunk akár polinomot, vagy egyenes szakaszokat is, de természetes van radír is.
2.2.2. Módok
2.3. ábra. A Blender - Edit mode Ebben részben arról lesz szó, hogy milyen különböző tervező módok állnak rendelkezésre a Blenderben. Azt, hogy jelenleg milyen módban vagyunk, azt alulról a harmadik sorban látjuk. A Blender alapból Object módban nyílik meg. Ilyenkor nem nagyon lehet az alakzatokat részletesen szerkeszteni csak 1 nagy egészként. A fent részletezett funkciók nagy része elérhető Object módban. Egy fontos billentyű, ami megkönnyíti a munkát a Blenderrel az a TAB. Ezzel a gombbal tudunk váltani a másik nagyon fontos 13
mód között,ezt úgy hívják, hogy Edit mód (A TAB gomb csak e 2 mód között tud váltogatni.). Amikor át megyünk Edit módban újra számos új funkció válik elérhetővé számunkra. (2.3) A Blenderben hasznosak lesznek a különböző nézetek.Ezzel azt tudjuk beállítani, hogy hogyan szeretnénk látni az alakzatunkat. Ez a funkció rögtön az Edit mode jobb oldalán található meg. Alapból a Solid van, beállítva ez egy alap textúrát húz az objektumra, és minden ugyanúgy fog kinézni. Van itt még Material mód ahol ha anyagot adtunk az objektumhoz annak a felületét látjuk későbbiekben még szó lesz az anyagokról. A Textura módban a feltextúrázott testeket fogjuk látni. Az Edit mód szempontjából fontos még a Wireframe. Ez a dróthálós felépítését mutatja. Ahhoz hogy kielégítően tudjunk az Edit módban dolgozni fontosak még a kiválasztok. 3 kis ikon, amin 3 kis kocka van. Elhelyezkedés, a lenti soron ahol előbb taglalt ikonok is találhatók. Edit módban tudjuk ugye módosítani az alakzatunk kinézetét, ezt több féle módon tudjuk megtenni, pl. kiválasztjuk a modellünk 1 pontját. Ez az első ikon, egy dinamikus módosítási forma tehát ha elkezdjük elmozdítani az alakzatunk 1 pontját a pontra kapcsolódó szakaszok is követni fogják azt a pontot tehát azok a szakaszok megnyúlnak. A szakasz kiválasztó, ennek segítségével, tudunk szakaszokat módosítani az alap transzformációk erre is használhatóak csak úgy, mint az előző kiválasztónál. Szerintem a legfontosabb kiválasztó, az a felület választó itt az alakzatunk bizonyos, lapjait tudjuk módosítani. Szerintem ez a legsokoldalúbb. Ezzel a kiválasztóval könnyedén tudunk a kockából, téglatestet csinálni, de ha kombináljuk későbbi eszközökkel akár több mindent is. A következő néhány eszköz segítségével, az alap primitívekből szinte minden alakzat létrehozható, amire csak szükségünk lehet. Extrude Region. A példa kedvért mondjuk azt, hogy szükségünk van egy görbe csőre. Ha azt vesszük, egy cső tulajdonképpen egy henger tehát mindenképpen ebből kell kiindulnunk. Viszont akár, hogy is forgatom, a henger tetejét sehogy sem tudjuk kivitelezni azt ,hogy szép görbe, csövet készítsünk. Ekkor használhatjuk, ha Edit módban vagyunk a baloldalon a Tools fülön egy olyan rész, hogy Add és az alatt az Extrude Region. Ez a funkció azt csinálja, hogy veszi az eredeti lapunkat, és oda berak egy új szakasz határolót, ennek segítségével már nem az egész alakzatunk fordul, hanem kaptunk 1-el több törés pontot. Ha kellően sok ilyen Extrude Region használunk, akkor kivitelezhető akár milyen görbe alakzat. Ennek a funkciónak a gyors billentyűje a E gomb. Insert Faces. A következő funkció segítségével, újabb lapot tudunk beszúrni egy már meglévő lapra. Ennek segítségével, egy egyszerű lap is felosztható 4 felé, és így 4 irányba tudjuk széthúzni a lapunkat, ezt a funkciót úgy hívják, hogy Insert Faces. Make Edge/Faces. A Make Edge/Faces funkció talán a leghasznosabb dolog a Blenderben nagyban segíti a munkánkat. Tulajdonképpen nevezhetjük azt a funkciót 14
kitöltésnek is. Azt csinálja, hogy kitölti a kijelölt szakaszok közötti részt akár egy szakasszal, de ha kell akár egy egész felülettel is. A dolog úgy működik, hogyha kiválasztunk a választók segítségével 2 pontot és lenyomjuk az F gombot, akkor egy vonal jön létre a két pont között, ha 3 pontot választunk ki, akkor, egy háromszög. Viszont ha szakaszokat választunk és ekkor nyomunk F-et, akkor már nem szakaszok fognak létre jönni, hanem oldalak, amik ki vannak töltve felülettel. Ez egy roppant fontos funkció és nagyon kényelmes vele dolgozni. Számtalan estben alkalmaztam a szakdolgozatom elkészítése alatt. Több esetben is volt olyan, hogy 2 felület nem ért össze és ugye ott akkor lyuk keletkezett, ami ugye nagyon feltűnő a renderelt képen. Ilyenkor alkalmaztam ezt a funkciót. Viszont van neki egy hátránya is, mégpedig az, ha görbe felületekkel dolgozunk, és ki akarunk tölteni egy részt akkor sok felesleges belső irány pontot, hoz létre automatikusan, ami a későbbiekben nagyon zavaró lehet. Ekkor az alakzatunk dróthálós modellje egy nagy összegabalyodott, halmaz. Subdivide. A Subdivide segítségével feloszthatjuk az alakzatunk egyik lapját több egyenlő részre, ez mindig arányosan osztja fel a lapokat, és minden alakzat esetében tartja az arányokat. Minél többször nyomunk a gombra annál több felé osztja. Ez akkor jó amikor nagyon részletes dolgokat szeretnénk készíteni. Például ha egy gömbből akarunk arcot csinálni ott tényleg nagyon sok részlet szükséges és minél több lappból áll egy gömb annál jobb. A Sclupt módban annál szebben tud vele dolgozni. Loop Cut and Slide. A Loop Cut and Slide funkció hasonló mint a Subdivide csak itt nem automatikus a felosztás hanem szabad kézzel tudjuk felosztani az alaktanunk egy lapját. Amikor rákattintunk erre az eszközre és rávisszük a kurzorunkat az alakzat egy lapjára először meghatározzunk, hogy függőlegesen vagy vízszintesen fogjuk osztani a lapunkat. A következő kattintásra pedig, hogy mekkorát akarunk abból a részből kimetszetni.
2.3. A repülőgép elkészítése Blenderben 2.3.1. Modell A kiválasztott gép, ami a szakdolgozatomban szerepel egy Antonov AN-2(2.4) dupla szárnyú, egymotoros repülőgép. A gép történetéről annyit érdemes tudni, hogy 1948ban kezdték gyártani az akkori Szovjetunióban. Eredetileg mezőgazdasági feladatkora szánt könnyű szállító gép volt. A géptest fémborítású, míg a szárnyak vászonborításúak. Műszaki alapadatok szintjén még azt kell tudni, hogy a gép hossza 12,74 m, a szárnyak fesztávolsága pedig, 18,18 m. Az üresjárati tömege 3450 kg. A motor egy 9 hengeres 15
2.4. ábra. Az Antonov An-2 majd, 30000 cm3 csillagmotor melynek teljesítménye, közel 1000 LE. A legnagyobb utazási sebessége 258 km/h. A maximális hatótávolsága a gépnek egy tankolással 854 km, melyet akár 4500 m magasságban is képes megtenni.
2.3.2. Modellezés Ahhoz hogy el tudjuk kezdeni a modellezést, legelőször kellett egy három nézeti rajz az Antonovról. Amin szerepel egy elől nézeti kép, szükség volt egy oldalnézeti képre, és egy felülnézeti nézeti képre. A 3 képnek külön kell szerepelnie. A Blender programban, jobb oldali sávban van egy olyan rész, hogy Background Image, ide kell be tallóznunk az egyik képet. Először vegyük az oldalnézeti képet, Add Image gombra kattintva kiválasztjuk a képet és az Axis funkciónál kiválasztjuk, hogy milyen szögben szeretnénk látni a be tallózott képet. Ezt megtesszük a fennmaradó többi képpel is, csak a látási szögeket változtassuk.(2.5) A Lényeg ennél a résznél az, hogy hogyan skálázzuk be a képeinket. Itt arra gondolok, hogyha húzunk egy vonalat akkor, amikor felülnézetben vagyunk, pl. meghúzzuk a szárnyfesztávolságot, akkor az a vonal ugyanolyan hosszú legyen, az elölnézeti képen is. Ez egy rettentő aprólékos feladat, és nagy precizitást igényel. Az egész gép tulajdonképpen négyzetekből épül fel, mégpedig olyan módon, hogy a fenti, alapfunkciókat alkalmaztam. A forgatás, skálázás és mozgatás. Ezekkel a funkciókkal elkészíthető a repülő. Van még egy okos megoldás a modellezésnél, ami megkönnyíti a munkánkat. A Tükrözés azt csinálja, hogy ahhoz az elemhez, amihez hozzá van adva ez a módosító, 16
2.5. ábra. Az Antonov Előznézeti képe a háttérképpel azok tükröződnek egy tengely mentén. Ezek után, minden az objektumra alkalmazott, módosítás a tükörképén is végrehajtódik. Ez az én esetemben egy teljesen jó funkció, ugyanis a gép szimmetrikus alakzat tehát, elég volt csupán a gép felét megcsinálni, mert a másik rész a módosító segítségével automatikusan elkészül. Ezt a funkciót a Blender ablak Jobb oldalán található menüben tudjuk hozzáadni, a csavarkulcs ikon alatt kiválasztjuk a Mirror funkciót. Be kell még állítanunk a tükrözés tengelyét hogy x,y, vagy z tengely menti tükrözést szeretnénk. Továbbá a tengely közétől való távolságot, ez az én esetemben a gép közepe a tengelyközép felülnézetben, és a gép széle ahol rajzolni fogjuk a vonalakat. Lerakunk egy Planet az oldalnézetben a gép farkához olyan közel amennyire csak tudjuk. Hozzá formázzuk a gép alakjához. Amikor tovább haladtam nem egy új Planet raktam hozzá, hanem használtam az E gombot, ami ugye az Extrude Region. Ennek segítségével rajta maradt a módosító is az objektumunkon elhúztam az újonnan létrejött részt a gép eleje felé. Így haladok egészen addig, amíg el nem érjük a gép elejét. A légcsavart még nem formázzuk, azt majd egy későbbi alkalommal. Minél többször alkalmazzuk az Extrudeot annál szebb géptestet tudunk létre hozni. Azért mert sokkal több kisebb felületből fog állni a géptest, amit sokkal több féle képpen tudunk alakítani. Szebb görbületi ívet tudunk adni a géptestnek, mert ugye nem egy nagy merev felületből fog állni a gépünk, amit csak a középpontja körül tudunk forgatni, hanem több kicsiből, így lesz tökéletes a géptest. Érdemes még egy Subdivide funkció segítségével, félbe osztani a géptestet ugyanis lefele, is görbülni is fog, a géptest így ott, lesz egy törés a géptestben így sokkal szebb géptestet fogunk kapni. 17
A Tükrözés funkcióra visszatérve, van egy fontos funkció, ami megkönnyíti a munkánkat. Mint azt említettem géptest oldala lapokból fog állni. Van egy olyan funkció, ami a Clipping, ez azt tudja, hogy ha kijelölünk egy vonalat, és elkezdjük egymás felé húzni a vonalakat, akkor egyesíti őket így kapjuk meg a géptestünk alját és tetejét. Tulajdonképpen összeolvasztja a felületeket. Ezután a gép orrát csináltam meg az elv ugyanaz volt, mint az oldalánál, extrudáljuk a szakaszokat és húzzuk a lapokat addig, amíg a 2 oldalt össze nem olvasztja a Clipping metódus. Ha van olyan rész, amit nem tudunk tökéletesen, összeolvasztani, arra ott a kitöltés metódus, aminek segítségével az üres részekre is felület kerül. A géptest kialakítása után a következő lépés a vízszintes szárny kialakítása miből az én modellemnél 2 db is van. Itt is alkalmazom a tükrözés metódust, a gép szárnya egy kockából lesz kialakítva, csak a gépszárny fele készül el a másik részét a tükrözés metódus végzi. Itt ki kell alakítani a csűrőlapokat ezek végzik, a repülőnél az orsózó mozgást ettől tud forogni a gép a hossztengelye körül. A későbbiek során, ehhez animációt fogunk adni és egy mozgó alkatrészt láthatunk. Az előbb részletezett eljárással alakítjuk a szárnyakat. Ennél a résznél fontos megint az elől nézeti kép, ehhez mérve tudjuk belőni a szárny hosszát, az ívét és elhelyezkedését, a géptesthez képest. Az oldalnézeti képen pedig, a gép szárnyának vastagságát. Az alsó szárny, csak másolás és beillesztéssel készült kicsit kisebb, de ez könnyen kialakítható a felső szárnyból, némi skálázással, transzformációval. Továbbá még annyi a különbség, a felső szárnytól hogy alul nincsenek csűrő lapok. Ablakok kialakítására nem volt szükség, ugyanis a gép csak hátulnézeti szögből fog látszani. A farok rész kialakítása nem túl egyszerű, a vízszintes vezérsík a testtől külön álló, ugyanis ennek is mozogni kell. Kellően vékonynak kell lennie, hogy megtartsa a gép az áramvonalasságát. Ez a rész felel, azért, hogy a gép tudjon mozogni a z tengelye körül. Kialakítás egy kockából indul, amit addig osztunk és transzformálunk, amíg egy kielégítő farok részt kapunk, ehhez sincs szükség semmilyen egyéb funkcióra csupán, az Extrudra, Subdividera, és a Kitöltésre, plusz az alap transzformációkra. A függőleges vezér sík egy fontos mozgató alkatrész, ez felel a gép magasságának emelkedésért és a süllyedésért. Tehát ez egy y tengely menti, mozgás. Ez a rész is 2 részből áll van egy fix rész és egy mozgó. Ezzel nagyjából kész is vagyunk, a gép testtel. Már csak egy pár alkatrész van hátra. A légcsavar vagy más néven a Rotor. Az Antonov An-2 egy 4 ágú középen kúpos rotorral van felszerelve. A kúprészt egy hengerből és egy gömbből hozom létre ehhez, használok egy módosítót, amit úgy hívnak, hogy Boolean. Ehhez a művelethez 2 objektum kell, és be lehet állítani, hogy mit csináljon a 2 objektummal, olvassza össze vagy az egyik objektumból vágja ki a másikat. Én az Union funkciót alkalmaztam ezzel olvasztottam össze az objektumokat, tehát mint a halmazműveletnél a közös rész nem látszik, csak ahol nem ér össze a 2 alakzat. A rotort is kockából alakítjuk ki, itt sajnos nem tudjuk alkalmazni az tükrözés metódust 18
ugyanis a rotor 2 része ellentétes irányba csavarodik, ettől a csavartól tud a gép előre mozdulni. Sokkal erősebb lesz a rotor lapátjai mellet a légáramlás. A másik rotor az első pontos mása, csupán el van forgatva, 90 fokkal. Végezetül pedig, összekapcsoljuk az elkészült elemeket, hogy egy egész objektumot alkossanak ez a programozásnál lesz fontos, amikor is a rotor majd forogni fog. Már csak néhány apró részlet maradt a szárny stabilizátorok és a kerekek. A szárny stabilizátorok és a keréktartók is hengerekből vannak kialakítva. A kerekek pedig tóruszok amik úgy lettek tele karikák, hogy a belső köríven lévő vonalat extrudáltuk, és befelé haladva skáláztuk addig, amíg össze nem értek a vonalak a középpontban. A gépünknek 3 kereke van, de alap állásban a repülő nem vízszintesen, van a földön, hanem egy 20-25 fokos szöget zár be a földel, ez azért van, mert a gép keréktartói, elérő hosszúak. A hátsó kerék jóval rövidebb az elsőnél. Ezzel el is készültünk a gépünk testével, és alkotó részeivel, Ezek után jön a textúrázás, aminek segítésével, valamilyen mintát tudunk adni a gépünknek.
2.3.3. Anyag és textúra A következő lépésben elkészítjük a gépünkön lévő textúrát, és a hozzá tartózó anyagokat is. Alapvetően 3 képet használtam fel ahhoz, hogy elkészítsem a textúrát. Mielőtt elkezdetem dolgozni nyitottam, még egy ablakot Blenderben ezt úgy tudom megtenni, hogy a jobb felső sarokban lévő 3 keresztbe lévő vonalra, kattintva kihúzok még egy ablakot, ezzel a funkcióval akárhány ablak megjeleníthető, ami megkönnyíti a munkát. A második ablakban a bal alsó sarokban lévő funkció nézetekből kiválasztjuk az UV/Image Editor, ez első nyitáskor csak egy üres 2 dimenziós koordináta rendszer. Szükségünk lesz egy beállításra, amit Edit módban az U gomb megnyomásával tudunk, előhozni, ez az UV Mapping. Itt pedig az a beállítása kell, hogy Project From View. Ezzel azt érjük el, ha kijelölünk egy felületet az objektumunkban, akkor az meg fog látszódnia az UV/Image Editor ablakban és ott pontosan be tudjuk majd pozícionálni, hogy a kép melyik részén helyezkedjen el a kijelölt felülte. Adjunk hozzá egy új Materialst a projektünkhöz ezt a jobb oldalon tudjuk elérni, középen, a kis karikát kell keresni, a kockás felülettel. Itt kattintsunk a New gombra, ha ezzel kész vagyunk, akkor az előbbi ikon mellet helyezkedik el a textúrának az ikonja, is. Itt tudjuk be tallózni a képet, amire szükségünk van. Ha betallóztuk, akkor abban az ablakban, amiben az Image Editor van, az alsó soron ki tudjuk választani az általunk létre hozott anyagot. Ekkor ez megjelenik az ablakunkban, és ha a projektünkből is kijelölünk egy felületet, akkor annak a felületnek a drót váza megjelenik a képen és be tudjuk pozícionálni arra, részre, amit kinéztünk az adott, felületnek.(2.6) Érdemes olyan nevekkel elnevezni a felülteket, amikről a későbbiekben is tudni fogjuk, hogy, oldalsáv, szárny, stb. Minden egyes új alkatrészhez, amihez létre hozzuk a textúrát, 19
2.6. ábra. Az UV/Image Editor ahhoz új Materialt is adjunk hozzá, ez a későbbiekben nagy segítség lesz. A Blender minden pozicionálásnál, kivág a képből egy részt és azt hozzá köti az alkatrészünkhöz. A háttérben egy adatbáziskötés jön létre az anyag és a kiválasztott felület között. És amikor exportáljuk az objektumunkat és be importáljuk majd a Unity ebben az adatbázisban benne lesz, hogy mi hogyan rendeztük el a felületeinket a képen és egyszerűen csak rá kell majd húzogatnunk egy egyes Materiálokat a megfelelő alkatrészre. A kötés miatt a Unity tudni fogja, hogy hogyan is rendezze el a azt az anyagot, a felületen. Egyébként a kötéseket meg tudjuk nézni a Blenderben ha kiválasztjuk a funkció nézetekből a Node Editort,akkor itt láthatjuk a kötéseket, és mi is tudunk új rétegeket beszúrni pl. árnyékolásokat, vagy gamma színcsatornát.
2.3.4. Exportálás Ezzel el is készült a Blender modellünk alkalmas arra, hogy ki exportáljuk.(2.7) Mivel én Unitybe szeretném ezt az objektumot ezért én az .fbx formátumot választottam [5]. Ez tartalmazza az egész gépet és textúrákat is, és nagyon jól kezeli a Unity. Érdemes exportálás előtt beállítani azt az opciót, hogy az objektum középpontja a geometriai középpontban legyen. Így szebb mozgásokat lehet elérni, az én esetemben a gépnél a geometriai középpont közelebb került a farok részhez ugyanis, az irányítás a gép farkánál lesz így egy nagyobb ívben lévő forgást kapunk eredményül. Amikor beimportáltam a repülőt a Unitybe azt vettem észre ,hogy valami probléma van a modellel ugyanis bele látok a modell belsejébe valamiért lyukas volt. 20
2.7. ábra. Az elkészült modell A probléma oka a normál vektorokban keresendő ezek a vektorok mutatják meg, hogy hogyan áll egy bizonyos lap abból a szögből, amiből éppen a kamera látja. Az én modellemnél az volt a baj, hogy egyes vektorok iránya a gép belseje felé nézett, ebből következett az, hogy olyan volt mintha lyukas lenne a géptest. A befelé álló vektorok akkor jöhettek lére amikor a gép az ellentétes oldalról készült, mint ahogy a kamerán látszott, és más lett a lap iránya. A Blender azt hitte, hogy mivel arról nézem azt a lapot az lesz a külső oldala. A hiba javítása elég egyszerű tulajdonképpen először meg kellett keresni azokat a vektorokat, amik, rossz irányba néznek viszont alapból a Blender nem mutatja ezeket a vektorokat. Megjelenítésükre Edit módban van lehetőség, a jobb oldali ablak sávban megkeressük a Mesh Displayt és ott van egy olyan menüpont, hogy Normals ott kiválasztjuk azt, hogy a lapok normál vektorait szeretnék látni, és egy kicsit megnöveljük a méretüket. Ekkor azt kell látni, hogy a modellünkből vonalak, mutatnak kifele. Így már könnyű szerrel ki tudjuk választani a rossz normálvektorokat. A W gombot, lenyomva megfordítja a normálvektorokat, ez a Flip Normals. (2.8) Ezután ha újra exportáljuk a modellünket a Unitybe és bemásoljuk arra helyre ahol a Unity projektünkben elhelyezkedik a rossz objektum és felül írjuk akkor a Unity automatikusan újra importálja a gépet és megvan a tökéletes Antonov An-2.
21
2.8. ábra. Az helyes irányú normálvektrok
22
3. fejezet Unity 3.1. A Unity Leírása A Unity egy videójáték-motor, amit a Unity Technologies fejleszt. [2] A program nyelve angol. Ez a program tökéletes alkalmas arra, hogy háromdimenziós játékokat és három dimenziós tereket hozzunk létre. Tudja, kezeli a valós idejű animációkat és fel van szerelve, geometriai tervező csomaggal. Létre tudunk hozni benne, tereket, fizikai metódusokat, gondolok itt zuhanásokra, esésekre, forgásokra, képesek vagyunk fákat tervezni a program segítségével. A program egységeket jelenetként kezeli, és jelenetek egyes elemeihez scripteket írhatunk, amik segítik elérni az automatikus működés látszatát. A program 2 fajta programozási nyelvet támogat a C# és a Java. Van neki saját fejlesztői környezet is amit Mono Developernek hívnak. Egy hátránya van talán a programnak, hogy nem tudunk létrehozni vele 3 dimenziós alakzatokat1 , ehhez szükségünk van egy külső programra, pl. Blenderre ami képes olyan formátumba exportálni az adatokat amit a Unity felismer. A könnyebb kezelés érdekében, ha egy beimportált, alakzatot frissítünk fájlszinten akkor azt a Unity automatikusan frissíti a felületünkön. Több platformra is fejleszthetünk a segítségével, többek között Android, Black Berry, Windows és IOS. A fejlesztői környezet viszont csak a Windowson és IOS operációs rendszereken érhető el.
3.2. A szakdolgozatom leírása A program alap koncepciója egy olyan, repülőgépes játék elkészítése, amelyben a játékos közel valósághű körülmények között, próbálhatja ki, hogy milyen a repülőgéppel fel és leszállni, és irányítani, még ha csak a billentyűzet segítségével. A programom1
Az alap primitívek bele vannak építve csak nem tudjuk olyan részletesen szerkeszteni őket mint a Blenderben
23
ban megtalálhatók azok az alapvető irányítási funkciók, amik egy valódi repülőgépen. Gondolok itt a gyorsításra, és lassításra, a vízszintes és függőleges mozgásra. Ebbe ugye bele tartozik a süllyedés és emelkedés, valamint az orsózó mozdulatokra, amiket a csűrőlapok segítségével, érhetünk el. Végezetül egy kis játék is beépítésre került a programba, aminek keretein belül, ha sikerül minden elrejtett objektumot megtalálni a területünkön, akkor nyerjük meg a játékot. A problémák megoldásához a már előzetesen elkészített Antonov An-2 objektumomat fogom felhasználni, ez lesz a repülőgép modellem. Ezt a modellt fogom beimportálni Unitybe és itt fogom megcsinálni, hozzá a repülési és egyéb scripteket. Továbbá a környezetet, amiben a gépünk működni fog, egy felszálló pályát, egy területet, amin belül repkedhetünk valamint egy üzemanyagtöltő állomást is. A repülés az egy scripten belül fog működni, valamint nyilván, ha lezuhanunk valamilyen indokból, vagy egy veszélyesebb manőver következtében, vagy neki repülünk valaminek akkor sajnos a gépünk fel is fog robbanni, és elég a tűzben. A folyamatos repülés következtében, az üzemanyaguk el tud fogyni, viszont erre ki van, alakítva egy rész ahol fel tudjuk tankolni a gépünket. Mivel a gépünk nem mehet a végtelenségbe és tovább, ezért amikor a repülőgép eléri, a határokat akkor a program automatikus visszafordítja a gépet a területünk közepe felé. A játék rész abból áll a programnak, hogy a pálya különböző részein el vannak rejtve piros golyók, amiket meg kell találnunk és fel kell szednünk, tehát át kell repülnünk rajta, 2-szer nem tudjuk felszedni ugyanazt a golyót. Összesen 10 darab ilyen objektum van elhelyezve a pályán, vannak olyanok is, amit nem minden szögből lehet felszedni, csak ha egy bizonyos irányba haladunk. A játék addig tart, amíg meg nem találtuk az összes objektumot. Közben a kijelezőn követhetjük, hogy eddig hány objektumot szedtünk fel, jelenleg milyen sebességgel haladunk. Ez egy arányszám, tehát ha mutató középen áll, akkor haladunk a maximális sebesség felével, ez elmondható a többi kijelző elemre is. Meg van még jelenítve az üzemanyag szintünk is és a jelenlegi magasságunk. A jobb alsó sarokban pedig van egy kis nyíl, ami mindig a benzinkút felé mutat, ez azt segíti, hogy könnyen vissza tudjunk találni a felszállóhelyünkre.
3.3. A repülőgép irányítása A repülőgép irányítása azzal kezdődik, hogy be kell indítanunk a motort. Ezt az I gomb folyamatos lenyomásával tudjuk elérni, egy hangeffektus fogja, kísérni. Az indítási gombot addig kell nyomva tartani, amíg a rotor el nem kezd pörögni. Azért van erre szükség, mert az Antonov indításánál van egy úgynevezett előgyújtási folyamat, egy segédmotor fogja végezni az önindító szerepét tehát ez a motor fogja elindítani a rotort. A gép sebességet az R betű segítségével tudjuk növelni, míg lassítani az F betű lenyomásával tudunk. Az emelkedés, az S betű hatására következik be, ettől fog a 24
gépünk feljebb menni, míg süllyedni a W betűvel tudunk, ettől a gép orra lefele mozdul és abba az irányba fog tovább haladni. Amikor lenyomjuk, a W vagy S betűt a függőleges vezérsík el mozdul attól függően, hogy süllyedünk vagy emelkedünk. Szintén ez a helyzet abban az esetben ha, a Q vagy E betűt nyomogatjuk ez a vízszintes vezérsík mozgatója. Ezekkel a gombokkal tudunk vízszintesen jobbra vagy balra fordulni. Az orsózó mozgás az A és a D gomb nyomására következik be ennél is le van az programozva, hogy a csűrőlapok mozogjanak. Az egyik utolsó funkció az M gomb, aminek segítéségével le tudjuk állítani a gépünket tehát a motor, leáll, és nem repül tovább. Végül már csak egy funkció maradt ki az ESC gomb. Ennek segítségével tudunk kilépni a menübe ahol új játékot, tudunk kezdeni vagy, kiléphetünk, és a program bezáródik.
3.4. A környezet kialakítása 3.4.1. Terrain A program elkészítését a környezet kialakításával kezdtem, el kell készítenünk a Terraint. Ehhez a Unity a megnyitáskor létrehoz egy struktúrálatlan, 3D teret amiben alapból semmi nincs betöltve, ez lesz a fő jelentünk Main lett a neve. Létre kell hozni a környezetet, a bal oldali listában legfelül van egy Create gomb, amiben van egy olyan menü pont, hogy 3D Object és azon belül a Terrain. A jobb oldalon láthatjuk az adott elemre vonatkozó lehetséges beállításokat. Ennél az objektumnál van egy olyan rész, hogy Terrain.Az alatta lévő 6 db gomb balról jobbra, a következő funkciókra szolgálnak.(3.1) Ezzel a funkcióval tudunk kihúzni részeket a Terrainből, tehát így tudunk hegyeket és dombokat csinálni. Változtatni tudjuk az ecset mintáját, a méretét és azt, hogy milyen erős legyen a húzása. Itt tudjuk visszanyomni és kisimítani a területeket, a fenti funkciók itt is megtalálhatók viszont, itt van egy plusz funkció, aminek segítségével azt tudjuk beállítani, hogy mi legyen az a minimális magasság, ameddig vissza lehet nyomni. Tökéletesen alkalmas arra, hogy szakadékokat vagy tó medreket alakítsunk ki. A Smooth Heightel le tudjuk kerekíteni az éleket, és a durvább húzásokat így sokkal szebb dombokat lehet létrehozni. A Paint Texture egy ecset funkció itt tudunk szabad kézzel festeni, textúrát, tehát ha azt akarjuk, hogy a hegyünknek a teteje havas legyen itt, tudunk hozzáadni a fehér textúrát. Én konkrétan ott használtam, hogy a tó fenekét egy kicsit más fajta textúrával rajzoltam ki. A fák ecsetbe rakása. Ide be kell tölteni egy elkészített 3D fát, erre funkcióra később visszatérek még, egyelőre csak azt kell tudni róla, hogy itt az általunk elkészített fa lesz az ecset mintája tehát így tudunk fákat rajzolni a Terrainbe. 25
3.1. ábra. A Unity Terrain készítője A következő fülön a Paint Details alatt tudunk alap textúrát hozzáadni a Terrainhez. Vannak ingyenesen importálható textúrák amit be tudunk tölteni, de akár a Unity Asset Storeban akár vehetünk is különlegesebb textúrákat, én egy alap fű textúrát használtam. A legutolsó fülön a beállításokat tudjuk megadni. Meg tudjuk adni azt, hogy milyen erősségű szél, legyen a területen, és annak mekkora legyen sebessége. Itt tudom beállítani azt is, hogy mekkora legyen a Terrain. Én egy 4000 x 4000-es méretű környezetet hoztam létre. Aminek 600 egységnyi a magassága. Ezekkel az eszközökkel elkészíthetjük a Terrainünket, itt tulajdonképpen csak az ember képzelőereje szabhat határt, hogy mennyi dombot és egyéb alakzatot hozunk létre a területünkön. Én úgy csináltam, hogy a Terrain széle egy magas hegysáv legyen, tehát egy medence szerűségben van a repülőnk. Vannak benne szurdokok, és az egyik sarokban egy tó is helyet kapott az előbb részletezett eljárás segítségével először kihúztam egy szintre a Terraint, hogy meg legyen a partfal majd a medret visszasimítottam. [7]
3.4.2. Víz A vizet szerencsére nem kell leprogramoznunk, hanem be tudjuk importálni. Sok komponens alapból nincs betöltve a Unitybe ezeket nekünk kell betöltenünk, ilyenek a textúrák, a különböző anyagok, fizikai hatások, a kamerák, az egyes effektusok. Az importálás az Assets menüben, az Import Packages menüpontban érhető el, nekünk most 26
az Enviroment csomag kell, ebben vannak benne a vízfelszínek. Betöltjük a csomagot, ez meg fog jelenni a Standard Assets Enviroment menüben. A vizek a Water mappában lesznek. Amit én használtam az a Water4 és a Prefabs mappában lesz megtalálható, ezek a szögletes vízfelszínek. A WaterSimple nevű víz effektet, csak egyszerűen behúzzuk a jelenetünkbe és ott a megfelelő méretűre alakítjuk. Két helyen használtam ezt a
3.2. ábra. A tó csomagot, egyrészt a lake(3.2) rész elkészítésénél másrészt pedig a Terraint körül vevő vízfelületek kialakítására. A Unity 5 először tudja valós időben kezelni az árnyékokat, így amikor elrepülünk a vízfelszín felett látni fogjuk a tükörképünket. A lake objektumhoz hozzá kell adnunk egy box collidert, ez egyszerűen az add component segítségével tudjuk megtenni. Ennek segítségével tudjuk majd azt érzékelni, hogy ehhez a felülethez hozzá-e ért valami más objektum. A Size tulajdonság, segítségével, megfelelő méretűre alakítjuk a collidert. Ezzel készen is vagyunk a vizes felületek kialakításával.
3.4.3. Környezeti objektumok Itt azokra az elemekre gondolok, amik nem rögös részei a terrainnek, viszont mégis része a környezetnek. Konkréten a petrol station nevű objektum az, ami egy üzemanyag állomás. Ezt a Blenderben raktam össze tulajdonképpen egyszerű egységekből áll, téglalapok, gömbök és hengerek. Tényleges funkciója nincs csak, megjelenés. Az anyagokat a Blenderben raktam rá, és amikor beimportáljuk az objektumot a terrainbe , akkor az anyagok alapból nincsenek rajta, ezek nekünk kell ráhúznunk.(3.3) Viszont az adatbáziskötés miatt tudja a program, hogy hogyan nézzenek ki az egyes elemek. A road, 27
3.3. ábra. Az üzemanyag állomás ami a felszállópálya a repülőgép csak innen tud felszállni, el kell helyeznünk rajta egy mesh collidert, ez is azt szolgálja, hogy az érintkezést tudjuk vizsgálni. A colliderek azért is kellenek, hogy, az egyes objektumok ne essenek át egymáson. Ha nincs collider az objektumon, például a terrain vagy a repülőgépen akkor a gép egyszerűen átesik a terrainen és zuhan a semmibe. A petrol objektum, egy lap, amin el van helyezve egy mesh collider, ez majd azért kell, hogyha a gép hozzáér akkor a gép feltankolódjon üzemanyaggal. Ehhez a részhez tartoznak, még a Wall objektumok, ebből 4 db van.(3.4) Ezek egyszerű üres objektumok, amihez csupán egy komponens van hozzá rendelve, ami egy Box Collider. Ezeken az objektumok trigger is el van helyezve. A trigger egy olyan egyszerű metódus, ami akkor fut le, ha egy másik gameobject hozzáér a felületéhez([9]). Ennek majd az lesz a funkciója, hogy visszafordítsa a repülőt, a terrain közepe felé, ha hozzáért a falhoz.
3.4.4. Repülőgép Ez a Plane objektum(3.5). Beimportáljuk az objektumot a jelenetünkbe. Szépen ráhúzogatjuk a textúrát. Mivel a gépünknek a hátsó kerek rövidebb, mint az első, azért aprólékos mozdulatokkal be kell forgatnunk a gépeket arra a pozícióra, hogy minden kerék, érje a talajt. Mivel ez a központi elemünk, ezért szinte az összes script is ehhez az objektumhoz lesz hozzárendelve. A Unityben ki tudjuk nyitni, az objektumunkat és ott látjuk, hogy milyen elemekből épül fel az objektum. A repülőgép minden eleméhez 28
3.4. ábra. A falak collidert kell adni, az előbb leírt okok miatt. Én ehhez az objektumhoz adtam hozzá
3.5. ábra. A repülőgép a Main Camerát, ez lesz a fő kameránk tehát ezen keresztül fogunk látni mindent, és ehhez kell hozzáadnunk egy új komponenst a SkyBoxot, ami az égbolt lesz. Én itt is az alap importált égboltot használtam, több fajtát lehet kiválasztani a sötét csillagos égtől a napos felhőmentes fajtáig. A Main Camera alá van rendelve a Compass ami egy kis 29
nyíl, szintén a Blenderben készült, ez lesz az iránytű. Azért is kell, hogy a Plane alatt legyen a kamera, hogyha elkezd mozogni a gép, akkor a kamera vele együtt, mozogjon. Ez a folyamat úgy van a Untyiben , hogyha van egy fő objektumunk és ahhoz tartozik számos más objektum és a főhöz adunk hozzá egy scriptet akkor az al-összetevőkre is vonatkozni fognak az események amik a scriptben le van írva.
3.4.5. Kijelző Itt olyan 2D elemeket találunk meg, információként szolgálnak nekünk. Van itt egy magasság mérő egy sebességmérő és egy üzemanyag szintmérő.(3.6) Ezek az objektumok, csúszkák, amiket a scriptek vezérelnek. Létrehozásuk nem bonyolult folyamat csupán a Create gombra kattintunk , és ott a UI menüből kiválasztjuk a ScrollBar objektumot. Ebben, menüpontban minden 2D elem megtalálható, a gombtól kezdve a feliratokon
3.6. ábra. A kijelző keresztül egészen a 2D képek felhelyezésének lehetőségéig. Amikor felrakjuk az elemeket a jelenetünkre, akkor, a program automatikusan létrehoz neki egy Canvas-t egy vásznat. Minden új elemet ez alá kell bepakolni, és akkor egységes lesz a kijelzőnk. Most már csak, be kell pozícionálni a vásznat, úgy, hogy az a kamera előtt legyen. Így végig láthatjuk az értékeinket. Tovább a Canvasnál ki kell Render Modenál, a Screen Space Camera opciót, és a Render Cameránál pedig a Main Camerát, így tudja a Unity, hogy hozzá vannak ezek az elemek kötve a fő kameránkhoz. 30
A főmenü(3.7) az teljesen így készült létrehoztam egy új jelenetet abba van egy vászon. Betallóztam egy 2D képet, és azon van elhelyezve 2 gomb, ami egy metódust hív meg. Végezetül van egy kamera, hogy megjelenítsük a vásznat. A gombok működése kicsit érdekes a Unityben, létrehozzuk őket és felrakjuk a vászonra, megvan neki az OnClick() metódusuk, ami azt vizsgálja, hogy rányomtak-e a gombra. Amikor elkészült
3.7. ábra. A Fő Menü a kívánt script, akkor, azt egy üres GameObjecthez adjuk hozzá, és a gombhoz behúzzuk ezt az objektumot, akkor már ki lehet választani, hogy az objektumhoz, tartozó, elemek közül esetünkben a scriptek közül melyik metódust szeretnénk meghívni.
3.4.6. Fakészítés A fák készítése, egy bonyolult folyamat, és jó kézügyességet kíván. Úgy kezdődik, hogy létrehozzuk a fánkat, ez a Create gombnál a 3D objektumok közül kiválasztjuk a Tree elemet. Ekkor létrejön egy fa, ami alapból csak egy vesszőből áll ezt kell majd alakítgatnunk. A Unity fakészítőjében jól követhető, hogy hogyan is néz ki a fánk, egy szép fa gráfon keresztül.(3.8) Értelemszerűen legalul van a törzs és abból indul ki minden ág, továbbá az ágakból jönnek az ágon lévő levelek. Új ágat hozzáadni a kis + jelel, tudunk, ugyanitt tudunk új levelet is hozzáadni, az ághoz. Amikor hozzáadunk egy új ágat akkor azt szabad kézzel is tudjuk mozgatni, viszont akkor a unity valamiért nem tudja bekonvertálni, és jó pár funkció nem lesz elérhető. A másik lehetőség a Group Seed, itt majdcsak 100000 féle képpen tudja a Unity felrakni az ágat, a másik ágra, 31
3.8. ábra. A fa abból a szempontból, hogy a másik ág hol helyezkedjen el a gyökér elemén. A Growth Scale arra szolgál, hogy beállítsuk az águnk hosszát, míg az Angle-el az ág dőlés szögét tudjuk megadni, a gyökér eleméhez képest. A Lengthel, azt csinálja, hogy a gyökérhez közeli résztől kezdve vékonyodva milyen vastag legyen az ág. Azt, hogy egy ág mennyire csavarodjon azt a Crinkliness funkcióval tudjuk beállítani, ha 0 az értéke, akkor teljesen egyenes az ág ha 1 akkor nagyon görbe. A Branch Materiálnál a fánk törzyének az anyagát adhatjuk meg. A levélkészítés nem bonyolult, itt viszont van még egy fontos tulajdonság a Frequency, ezzel tudjuk azt beállítani, hogy milyen sűrűen legyenek a levelek, a fán. Ugyanúgy a Materialnal, tudjuk megadni a levelünk mintáját. A Size tulajdonság pedig a levél nagyságát befolyásolja([9])
3.5. Scriptek Összesen 5 db script tartozik a programhoz: – mozg, – menu, – crash, – collection, – compass. 32
A mozg a Plane objektumhoz van hozzárendelve, ez tartalmazza mozgásokat, és az irányításokat, valamint azokat a funkciókat, amik a repüléshez kellenek. A crash-ben azok a feltételek vannak megfogalmazva, hogy mikor robbanjon fel, vagy törjön össze a repülőgép, ez is szintén a Planehez van hozzárendelve. A collection tartalmazza a játékot, tehát azt, hogy össze kell gyűjteni a gömböket a pályán, ez is a Plane objektumon van rajta. A compass az a kis nyíl, ami iránytűként szolgál, ez a Plane belül van a Main Camera azon belül pedig a Compass, ahhoz van hozzárendelve. Minden Unity script alapból 2 metódusból épül fel. Az első a Start(), ez csak egyszer fut le akkor ,amikor a script meghívódik, viszont ami nagyon fontos, azaz Update(). Ez minden framen belül egyszer fut így biztosítsa azt, hogy miden bekövetkezett eseményt vizsgálni tudjon. Fontos még azt megjegyezni, hogyha egy konkrét dologra akarunk vonatkoztatni egy kódrészt pl. azt, akarjuk, hogy forogjon a rotor, az akkor ugye csak 1 alkatrészre kell mozgatnunk. Ezt úgy tudjuk elérni, hogy publikus változót hozunk létre, így tudjuk azt megcsinálni, hogy csak bele húzzuk a kívánt elemet, oda ahol a Unity a definiálást mutatja.(3.9)
3.9. ábra. A mozg metódus publikus változói
3.5.1. Mozg Változók
33
Listing 3.1. Az mozg metódus változói 1 2 3 4 5 6 7
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
32
f l o a t speed =0; public GameObject rotor ; public GameObject v i z s z i n t e s _ v e z e r s i k ; public GameObject f u g g o l e g e s _ v e z e r s i k ; public GameObject bal_szarny ; public GameObject jobb_szarny ; // Ezek az objektumok , a z e r t k e l l e n e k , hogy a r e p u l o e g y b i z o n y o s r e s z e t t u d j u k i r a n y i t a n i v a l a m i l y e n formaban , // a z e r t p u b l i k u s a k , mert i g y tudunk n e k i tulajdonkeppen e r t e k e t adni a f e l u l e t e n , t e h a t ra k e l l huznunk a m o z g a t n i k i v a n t // o b j e k t u m o t . public bool alapjaratv = f a l s e ; // Az a l a p j a r a t s z a b a l y o z a s a r a , s z o l g a l o l o g i k a i v a l t o z o , a l a p b o l hamis , ugye mert mikor b e l e p u n k , a gep nem megy . public Scrollbar public Scrollbar public Scrollbar tajekoztatni
speedbar ; heightbar ; fuelbar ; // Ezek az objektumok , a c s u s z k a k , amiknek e s e g i t s e g e v e l tudom a j a t e k o s t a gep a l l a p o t a r o l .
f l o a t speedsize = 0 ; f l o a t heightsize = 0 ; f l o a t fuelsize = 1 ; // Ezeknek s e g i t s e g e v e l a l l i t o m be a c s u s z k a k e r t e k e t . i n t interval = 1 ; f l o a t nextTime = 0 . 0 F ; f l o a t push_down =0.0 F ; f l o a t rate = 0 . 5 F ; f l o a t audio_rate = 0 . 0 F ; // Ezek az i d o v a l t o z o k , t e h a t hogy v a l a m i b i z o n y o s i d o s z a k o n k e n t t o r t e n j e n meg , a gep nem t u d j o n g y o r s a n f e l s z a l l n i , e r r e p e l d a u l a push_down s z o l g a l . //Vagy hogy a motor a d d i g ne i n d u l j o n be amig , l e nem ment az i n d i t o hang , e z az audio_rate . public AudioSource au_start ; public AudioSource au_engine ; // A hangok , az , a u _s t a r t , az i n d i t a s i hang , amig az au_engine p e d i g , a motorhang . // Az AudioSoruce komponenseket h o z z a k e l l a d n i a f e l u l e t e n a r e p u l o g e p h e z . // I g y a z o k a komponensek l e t t e k b e h u z v a a p u b l i k u s v a l t o z o h o z . Fontos m e g j e g y e z n i hogy c s a k . wav formatumot tamogat a Unity . // Tovabba van e g y h a s z n o s t u l a j d o n s a g a az Audio Sourcenak a Loop , e z a z t c s i n a l j a hogyha i g a z a k k o r f o l y a m a t o s a n i s m e t l i a hangot , ha hamis a k k o r c s a k // 1− s z e r j a t s z o d i k l e . // Nallam az au_engine az i s m e t l o d i k a s t a r t p e d i g c s a k 1− s z e r j a t s z o d i k l e .
A kód nagyrész az Updateben van, továbbá van kiszervezve 2 metódus, ami a megall()(3.3), alapjarat()(3.2) és van még egy OnCollosionEnter(). Talán érdemes úgy lekövetni a kódot, ahogy az a felhasználás szempontjából lefut. A Start() metódusom nekem üres. Az Update() az úgy kezdődik, hogy meghívja az alapjárat metódust. Alapjarat Minden gombnyomást az Input.GetKey(KeyCode.[Gomb neve]) függvénnyel vizsgálunk, egy ha függvényben. Ha lenyomták azt a gombot, akkor történjen meg az esemény, itt most az van, ha lenyomjuk az I gombot, akkor több minden történik. Ugyanis a gombnak abba a részében is kód van, ahol lenyomjuk a gombot, ahol felengedjük a 34
gombot, és csak ha megnyomjuk a gombot. Ha lenyomjuk az I betűt és a alapjaratv értéke hamis akkor, elindul a gyújtási hang.
Listing 3.2. Az Alapjárat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
void alapjarat ( ) {
i f ( Input . GetKeyDown ( KeyCode . I ) && alapjaratv == f a l s e ) { au_start . Play ( ) ; } i f ( Input . GetKeyUp ( KeyCode . I ) && alapjaratv == true ) { au_start . Stop ( ) ; au_engine . Play ( ) ; } i f ( Input . GetKey ( KeyCode . I ) ) { i f ( audio_rate > 1 7 . 0 F ) { return ; } else { audio_rate += Time . deltaTime ; i f ( audio_rate > 1 7 . 0 F ) { alapjaratv = true ; } } } }
Ezzel egy időben, mivel le lett nyomva a gomb, ezért a GetKey[10] metódus is elindul. Ebben ha audio_rate változó nagyobb, mint 17 (azért pont 17, mert itt indul el a motor a hang fájlban.) akkor tulajdonképpen nem csinál semmit. Ha viszont kisebb, akkor az audio_rate értékét megnöveli a Time.deltatime értékével (ez az érték azt mutatja, meg hogy mennyi másodperc telt el amióta lefutott az előző frame.) Ezzel körül belül 17 másodpercig vár a program, amíg megy a hang. Itt van még egy vizsgálat szintén az, hogyha az audio_rate nagyobb, mint 17, akkor viszont már az alapjaratv váltson igazra, tehát ezzel elindítjuk az Update() metódusunkat, is. Megall 35
Ez a metódus a gép megállítására szolgál, amikor ez a metódus meghívódik, akkor alapjáratot hamisra állítom, ha rotor nem null akkor a rotor forgása megáll. A gép sebességét szintén 0-ra állítom úgy, mint a sebesség kijelző értékét is lenullázom.
Listing 3.3. A megall 1 2 3 4 5 6 7 8 9 10 11 12 13 14
void megall ( ) { alapjaratv = f a l s e ; i f ( rotor != n u l l ) { rotor . transform . Rotate ( 0 , 0 , 0 ) ; } speed = 0 ; speedbar . value = 0 . 0 F ; au_engine . volume = au_engine . volume − 0 . 4 F ; au_engine . Stop ( ) ; audio_rate = 0 ; }
36
A motorhang hangerejét először kicsit lejjebb veszem, majd, teljesen megállítom a hang lejátszását. Végül az audio_rate visszaállítom 0-ra ez azért fontos, mert ha újra be akarják indítani a gépet nem, indulna be ugyanis az audio_rate, jelenlegi értéke annyi amennyinél felengedtük az I gombot. Update()
Listing 3.4. A mozg metódus első rész 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
void Update ( ) { i f ( Input . GetKey ( KeyCode . Escape ) ) { Application . LoadLevel ( "main_menu" ) ; } alapjarat ( ) ; i f ( alapjaratv == true && rotor != n u l l ) { rotor . transform . Rotate ( 0 , Time . deltaTime ∗ 6 0 0 , 0 ) ; } i f ( rotor == n u l l ) { speed = 0 ; speedsize = 0 ; } i f ( alapjaratv == true ) { i f ( fuelbar . value == 0 ) { megall ( ) ; } i f ( Time . time >= nextTime && fuelsize >0) { nextTime += interval ; fuelsize = fuelsize − 0 . 0 0 1 F ; fuelbar . value = fuelsize ;
Az Update() (3.4) függvényen belül az első sorban várunk egy Escape gombot, ha megkapjuk, tehát ha valaki ki akar lépni, akkor betöltöm a main_menu jelenetet. Ez azért van az alapjárat igaz vizsgálaton, kívül mert, bármikor ki lehet lépni a játékból nem, kell, ahhoz elindítani a gépet. Ezután hívódik meg ugye az alapjárat metódus. A következő vizsgálat elindítja a rotor forgását, méghozzá úgy hogyha az alapjáratv igaz és a rotor nem null akkor, forgassa meg a rotort, kb. 600 fordulattal (Time.deltaTime * 600)[10]. A null vizsgálatnak a későbbiekben lesz jelentősége, majd amikor elpusztulnak a gép összetevői akkor ugye az Update() futna tovább, de nem fogja megtalálni, a rotor komponenst így hibára fut, ezzel a vizsgálattal védem ki a hibát. 37
Ha a rotor null vizsgálat szintén a robbanás miatt kell, ha elpusztult az összetevő, akkor a gép ne menjen tovább. A következő vizsgálattal azt érem el, hogy, amíg a gép nem indult el addig, ne lehessen, használni ezeket a funkciókat, amik ebben a kódrészben találhatók meg. Ez pedig csak azt vizsgálja, hogy az alapjárat igaz-e? A kódrészben rögtön azt vizsgálom meg először, hogy van-e üzemanyagom, ha nincs, akkor hívja meg a megáll metódust. Ha a gép alapjáraton működik, akkor is fogyaszt üzemanyagot, minden esetben fut a következő feltétel. Ha az idő nagyobb, mint a nextTime változó értéke és az üzemanyag kijelző értéke nagyobb, mint 0 akkor, fusson le a feltétel mag, ami azt csinálja, hogy a nextTime értékét megnöveli az interval értékével (1), így minden másodpercben csökkentem az üzemanyag mennyiségét, 0.001 értékkel. A fuelbar.Value tulajdonság segítségével, lehet beállítani, a csúszka értékét.
Listing 3.5. A mozg metódus második rész 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
i f ( Input . GetKey ( KeyCode . R ) && speed < 200 && Time . time > push_down ) { push_down = Time . time + rate ; GetComponent
() . drag += 0 . 0 5 F ; speed = speed + 1 0 ; speedsize = speedsize + 0 . 0 5 F ; speedbar . value = speedsize ;
} i f ( Input . GetKeyDown ( KeyCode . M ) ) { megall ( ) ; } i f ( speed > 50 && alapjaratv == true && rotor != n u l l ) { rotor . transform . Rotate ( 0 , Time . deltaTime ∗ 1 0 0 0 0 0 , 0 ) ; } i f ( Input . GetKeyUp ( KeyCode . F ) && speed > 0 && GetComponent() . drag >= 0 ) { GetComponent() . drag −= 0 . 0 5 F ; speed = speed − 1 0 ; speedsize = speedsize − 0 . 0 5 F ; speedbar . value = speedsize ; }
transform . position −= transform . right ∗ Time . deltaTime ∗ speed ;
38
A kódrészben(3.5) az első vizsgálat a gyorsításra szolgál, ami akkor fut le ha megnyomjuk az R betűt és a sebességünk nem nagyobb mint 200 (ez a gép maximális sebessége,), és a Time.time2 nagyobb mint a push_down. Ezt a vizsgálatot azért kellett bele vennem, hogy lassítsam a felszállást, ugyanis túl gyors volt, így nem lehet lenyomni a gombot, csak minden 1,5 másodpercben. Ha teljesülnek a feltételek, akkor a push_down értékét megnövelem a rate értékével. A GetComponent.drag [10] azt csinálja, hogy ahhoz az objektumhoz amihez a script hozzá van adva annak a komponensei között meg keresi a rigidbodyt és annak a drag tulajdonságát növeli meg. Ez az ellenállás, minél gyorsabban megy a gép annál nagyobb legyen a rá ható levegő ellenállása. Minden lenyomásnál a sebesség az nőjön 10-zel és a sebesség jelző értéke is növekedjen 0.05-tel. Ha lenyomjuk, az M gombot tehát megállítjuk, a gépet akkor meghívódik, a megáll metódus. A következő sor a rotor forgásának beállítására szolgál, ha a sebesség nagyobb, mint 50 és az alapjáratv egyenlő igazzal, továbbá a rotor nem null akkor forgassuk meg a rotort az Y tengely körül méghozzá, 10000 fordulattal. Az F gomb lenyomásával a lassításnál nagyjából az ellenkezője történik, mint a gyorsításnál. Ha a sebesség és az ellenállás nagyobb, mint a 0 akkor a csökkentsük az ellenállást,a sebességet, és a csuszka értékét. Egy sor van itt, talán ami a legfontosabb ezt végzi a mozgást méghozzá úgy, hogy mozogjon a gép az x tengelye mentén méghozzá akkor sebességgel, mint amekkora, speed szorozva a Time.deltaTimeal.
2
Ez egy számláló ami akkor indul el amikor a kód is meghívódik tehát az első másodperctől fogva.
39
Listing 3.6. A mozg metódus harmadik rész 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
i f ( v i z s z i n t e s _ v e z e r s i k != n u l l ) { i f ( Input . GetKeyDown ( KeyCode . E ) ) { v i z s z i n t e s _ v e z e r s i k . transform . Rotate (new Vector3 ( 1 , } i f ( Input . GetKeyUp ( KeyCode . E ) ) { v i z s z i n t e s _ v e z e r s i k . transform . Rotate (new Vector3 ( 1 , ; } i f ( Input . GetKey ( KeyCode . E ) ) { transform . Rotate (new Vector3 ( 0 , 1 , 0 ) , 0 . 5 F ) ; } i f ( Input . GetKey ( KeyCode . Q ) ) { transform . Rotate (new Vector3 ( 0 , 1 , 0 ) , −0.5 F ) ; } i f ( Input . GetKeyDown ( KeyCode . Q ) ) { v i z s z i n t e s _ v e z e r s i k . transform . Rotate (new Vector3 ( 1 , ; } i f ( Input . GetKeyUp ( KeyCode . Q ) ) { v i z s z i n t e s _ v e z e r s i k . transform . Rotate (new Vector3 ( 1 , } } i f ( f u g g o l e g e s _ v e z e r s i k != n u l l ) { i f ( Input . GetKey ( KeyCode . W ) ) { transform . Rotate (new Vector3 ( 0 , 0 , 1 ) , 1 ) ; } i f ( Input . GetKeyDown ( KeyCode . W ) ) { f u g g o l e g e s _ v e z e r s i k . transform . Rotate (new Vector3 ( 0 , } i f ( Input . GetKeyUp ( KeyCode . W ) ) { f u g g o l e g e s _ v e z e r s i k . transform . Rotate (new Vector3 ( 0 , ; heightsize = transform . position . y / 6 0 0 ; heightbar . value = heightsize ; } i f ( Input . GetKeyDown ( KeyCode . S ) ) { f u g g o l e g e s _ v e z e r s i k . transform . Rotate (new Vector3 ( 0 , ; } i f ( Input . GetKeyUp ( KeyCode . S ) ) { f u g g o l e g e s _ v e z e r s i k . transform . Rotate (new Vector3 ( 0 , } } i f ( Input . GetKey ( KeyCode . S ) && transform . position . y <600) {
40
0 , 0) , 15.0 F ) ;
0 , 0 ) , −15.0 F )
0 , 0 ) , −15.0 F )
0 , 0) , 15.0 F ) ;
1 , 0) , 15.0 F ) ;
1 , 0 ) , −15.0 F )
1 , 0 ) , −15.0 F )
1 , 0) , 15.0 F ) ;
55 56 57 58
transform . Rotate (new Vector3 ( 0 , 0 , 1 ) , −1) ; heightsize = transform . position . y / 6 0 0 ; heightbar . value = heightsize ; }
A következő kódsorok(3.6) a vízszintes, és a függőleges mozgásokat szimulálják. Ezek egy sémára épültek, úgyhogy nem részletezem mindegyiket. Vegyük most a süllyedést. Ezt ugye W gombbal tudjuk elérni. Itt is a W minden gombnyomását vizsgálom. Ha csak megkapja a W gombot akkor, forogjon a gép a Z tengelye körül méghozzá 1 fokot lefelé. A gomb felengedése és lenyomása, arra szolgál hogy animáljuk a farok szárnyak mozgását, ha lenyomjuk a gombot akkor a függőleges vezérsík az Y tengely mentén, forduljon el felfelé 15 fokot, ha pedig felengedjük a gombot akkor menjen vissza az eredeti pozíciójába. Az emelkedés ugyanígy működik csak ott minden az ellenkező irányba mozdul el. A kód úgy van megírva hogy a gép ne tudjon 600 egységnél magasabbra repülni, ezt vizsgálom egy ha függvénnyel, és beállítom az emelkedésnél a magasságmérő értékét.
41
Listing 3.7. A mozg metódus negyedik rész 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
i f ( bal_szarny != n u l l | | jobb_szarny != n u l l ) { i f ( Input . GetKeyDown ( KeyCode . A ) ) { bal_szarny . transform . Rotate (new Vector3 ( 0 , 1 , 0 ) , jobb_szarny . transform . Rotate (new Vector3 ( 0 , 1 , 0 ) } i f ( Input . GetKeyUp ( KeyCode . A ) ) { bal_szarny . transform . Rotate (new Vector3 ( 0 , 1 , 0 ) , jobb_szarny . transform . Rotate (new Vector3 ( 0 , 1 , 0 ) } i f ( Input . GetKey ( KeyCode . A ) ) { transform . Rotate (new Vector3 ( 1 , 0 , 0 ) , −1) ; heightsize = transform . position . y / 6 0 0 ; heightbar . value = heightsize ; }
i f ( Input . GetKeyDown ( KeyCode . D ) ) { bal_szarny . transform . Rotate (new Vector3 ( 0 , 1 , 0 ) , jobb_szarny . transform . Rotate (new Vector3 ( 0 , 1 , 0 ) } i f ( Input . GetKeyUp ( KeyCode . D ) ) { bal_szarny . transform . Rotate (new Vector3 ( 0 , 1 , 0 ) , jobb_szarny . transform . Rotate (new Vector3 ( 0 , 1 , 0 ) } i f ( Input . GetKey ( KeyCode . D ) ) { transform . Rotate (new Vector3 ( 1 , 0 , 0 ) , 1 ) ; heightsize = transform . position . y / 6 0 0 ; heightbar . value = heightsize ; }
15) ; , −15) ;
−15) ; , 15) ;
−15) ; , 15) ;
15) ; , −15) ;
Az orsózó mozgást szimuláló kódok(3.7) is ugyanarra sémára épültek, mint az előzőek, csak itt, nem azokat az elemet állítgatom, hanem a baloldali és jobboldali vízszintes vezérsíkot. Itt is állítom a magasság mérő értékét.
Listing 3.8. A mozg metódus ötödik rész 1 2 3 4 5 6 7 8 9
void O n C o l l i s i o n E n t e r ( Collision other ) { i f ( other . gameObject . name == " p e t r o l " ) { fuelsize = 1 ; fuelbar . value = fuelsize ; } }
Már csak egy metódus maradt hátra(3.8), az OnCollisionEnter(), ez egy paraméteres metódus és ez szolgál a tankolásra. Az azt vizsgálja, hogy érintkezik e gép valamivel, 42
a másik objektumon nem kell triggernek lennie, ez anélkül is érzékeli az objektumot. Ha annak az objektumnak, amivel érintkezik, az a neve hogy petrol, akkor töltse fel a gépet üzemanyaggal tehát a fuelsize értéket állítsa 1-re és csúszkát is maximalizálja. Ezzel végeztünk is a mozg scriptel most már elértük, hogy mozog a gépünk. Jöjjön a crash, ami a gép felrobbanásáért felel.
3.5.2. crash Változók
Listing 3.9. A crash metódus változói 1 2 3 4 5 6
public GameObject repulo ; //Ez az elem a r e p u l o g e p u n k i d e be van huzva az e g e s z gep . public GameObject explosion ; // I g y van d e f i n i a l v a az , hogy m i l y e n t i p u s u r o b b a n a s t szeretnenk . public GameObject [ ] d es tr o y_ el e me n t ; //Ez e g y o l y a n tomb ami g a m e o b j e c t e k e t t a r t a l m a z , nem i t t k e l l d e f i n i a l n i a m e r e t e t hanem , a f e l u l e t e n . public Text mestext ; // Ez UI t e h a t e g y s z o v e g d o b o z , aminek s e g i t s e g e v e l , u z e n e t e t irok ki jatekosnak . public AudioSource audio_s ; //Az p e d i g u j f e n t a motorhang , s z u k s e g l e s z i t t i s , ra mert a l l i t a n i k e l l . 2 d o l o g van l e k e z e l v e e b b e n a kodban a r o b b a n a s e s az , // hogyha a gep e l e r i h a t a r o k a t , a k k o r f o r d u l j o n v i s s z a a palya kozepe f e l e .
Robbanás
Listing 3.10. A robbanás 1 2 3 4 5 6 7 8
void O n C o l l i s i o n E n t e r ( Collision other ) { i f ( other . gameObject . name != " road " && other . gameObject . name != " Wall1 " && other . gameObject . name != " Wall2 " && other . gameObject . name != " Wall3 " && other . gameObject . name != " Wall4 " && other . gameObject . name != " p e t r o l " && other . gameObject . name != " gy_obj1 " && other . gameObject . name != " gy_obj2 " && other . gameObject . name != " gy_obj3 " && other . gameObject . name != " gy_obj4 " && other . gameObject . name != " gy_obj5 " && other . gameObject . name != " gy_obj6 " && other . gameObject . name != " gy_obj7 " && other . gameObject . name != " gy_obj8 " && other . gameObject . name != " gy_obj9 " && other . gameObject . name != " gy_obj10 " )
9 10 11 12 13 14 15 16 17 18 19
{ audio_s . volume = 0 ; f o r ( i n t i = 0 ; i < d es tr o y_ e le me n t . Length ; i++) { Destroy ( d es tr o y_ e le me n t [ i ] ) ; } Instantiate ( explosion , repulo . transform . position , repulo . transform . rotation ) ; mestext . text= "You d i e , i f you want r e s t a r t t h e game p l e a s e push t h e ESC" ; } }
43
Ez is(3.10) egy nagy OnCollisionEnter(Collision other) metódussal kezdődik csak it nagyobb, azoknak a száma, amikkel ha a gép érintkezik is akkor mégsem kell felrobbannia. Ilyenek például az út, a falak, az üzemanyag állomás, és azok az objektumok, amiket, össze kell szednünk a játék alatt. Ha ezeken kívül más objektummal érintkezik, akkor, a hangerőt állítsuk 0-ra vagyis némítsuk el. Ez egy kicsit érdekes rész, ugye nem pusztíthatom el az egész repülőt, mert tartalmazza a kamerát is, és ha az elpusztul, akkor, hibára fut a program. Így az lett a megoldás, hogy létrehoztam egy tömböt, amibe bele pakoltam a repülő minden komponensét kivéve a kamerát, és egy ciklus segítésével végig megyek a tömb elemein és egyesével pusztítom el azokat a Destroy() metódussal. Ha ezzel végeztünk, akkor lejátszódik a robbanás (egy alapból beépített robbanási formát használtam, amit csak be kellett húznom az explosion gameobjecthez.). Ezt az Instantiate [8] függvény segítségével megy végbe, 3 paramétere van, neki, az első maga a robbanás, amit le kell játszania, a második az, hogy hol, nálam ugye ott ahol a gép is van erre a transform.position kód szolgál, és kell a gép forgása is. Ezek után már csak egy hiba üzenetet kell dobni, hogy a felhasználót tájékoztassuk arról, hogyan kezdhet új játékot.
Listing 3.11. A fallal való értintkezés 1 2 3 4 5 6 7 8 9
void OnT rigger Enter ( Collider other ) { i f ( other . gameObject . name == Wall1 other . gameObject . name == Wall2 gameObject . name == Wall3 other . gameObject . name == Wall4 ) { repulo . transform . Rotate (new Vector3 ( 0 , 1 , 0 ) , 1 8 0 . 0 F ) ;
other .
} }
A falakkal való találkozást(3.11) nem Collision segítségével vizsgálom, hanem ugye mikor létre lettek hozva a falak el lettek rajta fejezve triggerek. Most azt megvizsgálom az OnTriggerEnter()[6] segítségével, hogy a gép bele-e lép ebbe a triggerbe. Ha igen, akkor, a repülőt forgassa meg az Y tengely körül 180 fokkal.
3.5.3. Collection Változók
44
Listing 3.12. A Collection Metódus változói 1 2 3
public Text scoore ; public Text message ; f l o a t szamlalo= 0 ; //Az e l s o 2 v a l t o z o az c s a k t a j e k o z t a t a s u l s z o l g a l , a f e l h a s z n a l a f e l e , az u t o l s o p e d i g az o s s z e g y u j t o t t e l e me k szamat m u t a t j a .
Listing 3.13. A játek 1 2 3 4 5
void OnT rigger Enter ( Collider other ) {
i f ( other . gameObject . name == " gy_obj1 " | | gy_obj2 " | | other . gameObject . name == " gy_obj3 " gy_obj4 " | | other . gameObject . name | | other . gameObject . name == " gy_obj6 " gy_obj7 " | | other . gameObject . name | | other . gameObject . name == " gy_obj9 " gy_obj10 " ) {
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
other . gameObject . name == " || == || == ||
other . gameObject . name == " " gy_obj5 " other . gameObject . name == " " gy_obj8 " other . gameObject . name == "
other . gameObject . SetActive ( f a l s e ) ; szamlalo = szamlalo + 1 ; scoore . text = szamlalo . ToString ( ) ; Destroy ( other . gameObject ) ; i f ( szamlalo == 1 0 ) { message . text = "You have found a l l o f t h e i t e m s " ; Application . LoadLevel ( 0 ) ; } } } }
Mivel minden elemen, amit össze kell gyűjtenünk trigger van azért az OnTriggerEnter()(3.13) metódust használom, megvizsgálom, hogy az érintkezett objektum neve benne van-e a listámban, ha igen akkor lefut a feltételmag. Azt az elemet amivel érintkezett, a gép deaktiváljuk , ez azért kell mert a gépnek több része is átrepül a gömbön , és lehet, hogy akár 5 pontot is felszámolna a program holott csak 1 elemet talált meg. A szamlalo értékét megnöveljük 1-gyel, mert megtaláltunk egy elemet. Kiírjuk a felhasználónk a szamalo eredményét, de előtte Stringé konvertáljuk a ToString() függvénnyel. Végezetül elpusztítjuk a megtalált elemet, hogy ne lehessen újra felszedni. Ha elérjük a 10 pontot, akkor ki ír egy üzenetet, és betölti újra a menüt. 45
3.5.4. Compass Ez egy nagyon egyszerű script, csak azt csinálja, hogy afelé az objektum felé mutat a nyíl, amit mi behúztunk neki, erre a transform.LookAt() [6] metódus képes, 1 paraméter van a kívánt metódus pozíciója. (3.14)
Listing 3.14. Az iránytű 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
public c l a s s compass : MonoBehaviour {
public Transform target ;
// Use t h i s f o r i n i t i a l i z a t i o n void Start ( ) { }
// Update i s c a l l e d once p e r frame void Update ( ) {
transform . LookAt ( target . position ) ;
} }
46
3.5.5. Menu Végezetül a menu script(3.15), ami 2 metódust, tartalmaz, amik publikusak csak így fognak látszódni a felületen és csak így tudjuk kiválasztani azt, hogy melyik fusson le a gombnyomáskor. A Start_game betölti, a fő jelenetünket, a maint. A másik a quit_game, ami bezárja programot. Ehhez azonban le kell állítanunk a futást, az isPlaying tulajdonságot hamisra kell állítani, és csak utána tudunk kilépni.
Listing 3.15. A menü 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
public c l a s s menu : MonoBehaviour {
public void start_game ( ) { Application . LoadLevel ( " main " ) ; } public void quit_game ( ) { UnityEditor . E d i t o r A p p l i c a t i o n . isPlaying = f a l s e ; Application . Quit ( ) ; } }
47
4. fejezet Összegzés Ezzel el is készültünk a repülőgépes játékunkkal. Most már, nem maradt más hátra, mint játszani egy kicsit. Bizonyára vannak a programban hibák, amikor abból adódnak, hogy nem találtam rájuk jó megoldást a Unityben. Ilyen például, a lendület, ami azért volna jó, hogyha lecsökkentem a gépemnek a sebességét, akkor ne csak szépen lassan lessen, hanem még szálljon egy darabig, és létre jöjjön a siklás, mint a valódi repülőknél. A programot bőven lehet tovább fejleszteni, kezdetnek lehetne hozzá még készíteni, több pályát is, amiken máshol vannak elhelyezve a gyűjthető elemet. Tovább azt is meg lehetne még írni, hogy az el lehessen menteni az aktuális állást. A program elmentené egy. txt formátumba, a repülőgép éppen aktuális adatait, a pozícióját, sebességét, a pontok állását, üzemanyag szintjét, és ezeket a program beolvasná. Végezetül pedig azt szeretném még elmondani, hogy remélhetőleg egy használható programot, sikerült elkészítenem, amivel az ember mikor unatkozik, akkor egy kicsit kikapcsolódhat, és repkedhet, ha akar szabadon, de ha egy kis játékra is vágyik, akkor az se okozzon neki csalódást.
48
Irodalomjegyzék [1] A Blender program weboldala: http://www.blender.org/ [2] Unity weboldala: https://unity3d.com/ [3] John M. Blain: The Complete Guide to Blender Graphics, Second Edition: Computer Modeling and Animation 2nd Edition ,2014,A K Peters/CRC Press [4] Lance Flavell: Beginning Blender: Open Source 3D Modeling, Animation, and Game Design, 2010, Apress [5] Alan Thorn: Practical Game Development with Unity and Blender,2014,Cengage Learning PTR [6] Alex Okita: Learning C# Programming with Unity 3D,2014,A K Peters/CRC Press [7] Will Goldstone: Unity 3.x Game Development Essentials, 2011,Packt Publishing [8] Volodymyr Gerasimov, Devon Kraczla:Unity 3.x Scripting, 2012,Packt Publishing [9] Sue Blackman: Beginning 3D Game Development with Unity: All-in-one, multiplatform game development,2011,Apress [10] Unity API: http://docs.unity3d.com/Manual/index.html
49