Tehnici de inteligenta artificiala folosind motorul grafic Unity [620969]
UNIVERSITATEA DIN CRAIOVA
FACULTATEA DE AUTOMATICA , CALCULATOARE SI
ELECTRONICA
Departamentul de Automatica si Electronica
SPECIALIZARE INGINERIA SISTEMELOR MULTIMEDIA
LUCRARE DE LICEN TA
Tehnici de inteligenta artificiala folosind motorul grafic Unity
Coordonator:
s.l. dr. ing Ionut Cristian Resceanu
Absolvent: [anonimizat] 2015
2
Cuprins
Industria jucurilor ……………………………………………………………………………………………. ……………… 3
Motorul grafic Unity3 D pentru jocuri…. …………………………………………………………………………… ..7
Modul de lucru cu motorul grafic Unity…………………….. ……………….. ………………………… ..8
Joc de strategie in Unity. ……………….. ……………………………………………………………………. 16
Tehnici de Inteligenta Artificiala………………………………………………………………….. …………………..24
Logica fuzzy …………………………… ……………….. ……………………………………. …………………..27
Inteligenta artificiala impartita pe agenti ……………… ……………….. …………………………….37
Exemple scripturi in Unity……………… ……………………………………………………………………………….48
3
T ehnici de inteligen ta artificial a folosind
motorul grafic Unity
Industria jocurilor video a aparut in 1971 cu primul joc arcade “Computer Space”.La
scurt timp Atari a lansat prima consola de jocuri “Magnavox Odysey”. La inceputul anilor 1980
industria jocurilor video a cunoscut un progres spectaculos, in America vanzarea de console
crescand de la 50 milione de dolari in 1978 la 900 milione de dolari in 1981. Putin mai tarziu au
inceput sa apara inovatii si pe partea hardware care a u ajutat dezvoltarea industriei jocurilor ,
inovatii cum ar fi stocarea informatie i pe CD(compact disc), aparitia p lacilor video cu suport
pentru grafica 3D si aparitia unor procesoare cu o viteza mai mare. Un alt factor care a
influentat dezvoltarea jocurilor video a fost si aparitia internetului.
La inceput echipele care lucrau la un joc erau compuse din cateva pers oane, insa acum la
creerea unui joc echipele sunt formate din zeci de persoane cu roluri predefinite cum ar fi:
Designer
Aceste persoane au rol ul de a creea design ul unui joc, de la poveste pana la mecanicile
de baza ale a cestuia. Tot aceste persoane realiz eaza si inter fata jocului.
Artisti
Aceste persoane se im part la randul lor in doua categorii. Artisti 2D , care se ocupa in
general de crearea texturi lor si concepte lor pentru personaje cat si pentru intreaga lume in care
are loc actiunea jocului. O alta categorie sunt ar tisitii 3D care se ocupa de crea rea obiectelor
tridimensionale din jocuri pornind de la personaje, inamici pana la cea mai mica pietricica din
lumea jocului.
Programatori
Rolul unui programator in industria jocului nu difera foarte mult de alt programator
dintr -o alta industrie, in fond un joc este doar o alta aplicatie , mai complexa in general , cu care
jucatorul interactioneaza. In zilele noastre insa doarece jocurile sunt complexe din punct de
vedere al programarii, programatori s unt si ei impartiti in mai multe categorii in functie de
domeniul in care lucreza, dupa cum urmeaza:
IA (inteligenta artificial)
4
Acestia se ocupa de creerea modului in care personajele care nu sunt controlate de
jucator interactioneaza cu acesta dar si anumite parti din mediul inconjurator cu care jucatorul
poate intractiona .
Fizica
O componenta foarte des intalnita in jocurile moderne este fizica care cu c at este mai
complexa cu atat universul jocului pare mai real, mai credibil.
Grafica
Chiar daca modelele pentru un joc sunt create de un artist 2D sau 3D pentru a ajunge in
joc acestea au nevoie de un suport din programare. Pe langa suportul pentru modele mai exista
si lumini care trebuie introduse in scena. Oricat de realiste ar fi modelele create de un artist
fara o iluminare adecvata acestea nu pot fi puse in evidenta.
Unelte pentru joc
Pentru a putea lucra la un joc anumite persoane cum ar fi designerii si artistii nu sunt
obligati sa stie programare si astfel , pentru ca si ei sa poata lucre, se creaza anumite programe.
Modul de Joc
Acesti programatori se ocupa de creerea anumitor reguli dupa care jucator sa poata juca. Ce
poate jucatorul sa faca pe parcursul jocului, cu cine poate interactiona sau cum poate personajul
lui sa evolueze.
Interfata
5
Pentru ca jucatorul sa poate juca i se creeaza o interfata cu care poate interactiona sau pe care
sa fie afisat e anumite info rmatii cum ar fi viata, punctajul , gloa ntele sau arma pe care o are
selectata.
Testari
Acestia trebu ie sa se asigure ca jocul nu are probleme si ca orice ar face jucatorul nu
apar greseli vizuale sau de programare care ar face c a jucatorul sa aiba o experienta neplacuta .
Testarii sunt in general angajati pe o perioada determinata de timp deoarece ei nu testeaza
aplicatiile decat in momentul in care aceastea sunt intr -un stadiu jucabil.
In prezent media de varsta a jucatorilor es te de 30 de ani cu o usoara crestere. Daca la
inceput jucatorii erau prodominat baieti acum procentajul este destul de apropiat cu 58% baieti
si 42% fete. Un motiv pentru care media de varsta este in creste poate fi cauzat de faptul ca acei
copii care au j ucat primele jocuri acum doar s -au mutat la o alta platforma pe care sa se joace.
Jocurile video pot fi jucate atat de catre o singura persoana sau de mai mute persoane
simultan cum ar pe pe internet sau pe LAN(retea locala). In cadrul jucului intr -o rete a locala
jucatori se intalnesc intr -un loc si se creeaza asa zisele 'LAN Party -uri'.
Mai exista si evenime nte organizate unde jucatorii pot ven i sa participe la competitii
contra altor jucatori dar pot sa si joace de la mare distanta unul fata de altul cu ajutorul
internetului.
Cu dezvoltarea industriei jocurilor au aparut si noi cuvinte care au devenit populare.
Multe din jocurile pe internet incurajeaza folosirea unor cuvinte sau expresii prescurtate sau
chiar inventate pentru a descrie o actiune sau un eveniment. Printre cele mai intalnite gasim “lol”
(care provine da la prescurtarea expresiei “a rade cu pofta”), “noob”(este dat unei persoane
care nu stie sa joace acel joc sau care joaca foarte prost), “AFK”(plecat de la tastatura, cand un
jocator tre buie sa lipseasca o perioada scurta de timp), “GLHF”(mult noroc si distractie placuta)
sau ”gg”(joc bun). Folosirea acestor cu vinte este in general criticata pentru ca deformeaza
modul de a vorbi al persoanei respective in societate. O parte dintre jucator i folosesc acest
limbaj si in afara jocurilor unde celelalte persoane nu o sa inteleaga mare lucru. Sunt intalnite
persoane care in loc sa rada la o gluma o sa le auziti zicand “lol”.
Odata cu dezvoltarea jocurilor video a fost nevoie de impartirea acesto ra dupa anumite
categorii . In funct ie de modul in care se pot juca , de tipul in care personajul este vazut de catre
jucator, de zona in care are loc actiunea jocului, de tipul actiunilor pe care le poate face
jucatorul in cadrul jocului sau chiar de publi cul caruia ii este adresat jocul.
6
Vom discuta acum de impartirea jucurilor pe categroii in functie de tipul actiunilor pe
care le poate face un jucator in cadrul jocului, asfel jocurile se pot imparti in jocuri de :
Actiune
In acest ti p de jocuri, jucat orul trebuie sa se foloseeasca de reflexe foarte bune, de o
sincronizare buna ca sa treca de anumite obstacole. Acest tip de joc este foarte des intalnit si in
general pune foarte mult accent pe luptele jucatorului cu alte personaje.
Aventura
Jucatorul t rebuie sa gaseasca raspunsuri la anumite ghicitori si sa rezolve anumite
cerinte care i se dau de catre persoane din joc. Este un tip de joc ca re il pune pe jucator sa se
simta ca un detectiv care trebuie sa rezolve mai multe cazuri.
Strategie
Jucatorul este pus in general in rolul unui comandat care are in subordine o armata sau
care este nevoit sa isi faca o armata pentru a putea distruge inamicii sai care pot fi alti jucatori
sau o inteligenta artificiala.
Role Playing Game (Jocuri video de rol)
In acest tip de joc jucatorul este un aventurier sau va deveni un aventurie r . Acest ti p de
joc este inspirat din jocurile mai vechi cu tabla de joc. Personajul principal este bazat pe mai
multe abiltati pe care jucatorul poate sa le creasca in funtie de modul in care ii place sa joace(sa
isi faca un personaj care sa se lupte bine cu sabia sau cu arcul in fuctie de stilul sau de joc).
Jucatorul este nevoit sa treaca prin tot felul de orase, pesteri, castele pentru a salva un popor, o
persoana sau fel de fel de creaturi . In fuctie de cum este dezvoltat personajul, jucatorul poate
urmari anumite statistici ca sa vada cat de bun este.
Simulare
Aceste jocuri incearca sa se apropie cat mai mult de realitate si sa ii dea jucatorului
impresia ca asa se intampla si i n realitate. Simulatoare incearca sa reproduca de exemplu bordul
unei masini si regulile dupa care aceasta se misca.
Inafara de aceste tipuri de baza au mai aparut si alte tipuri de jocuri care combina doua
sau mai multe tipuri principale, cel mai intal nit tip de acest gen este:
7
Actiune si Aventura
Acest e tipuri de jocuri combina cele doua tipuri mari de jocuri aventura si actiune.
Jucatorul trebuie sa rezolve anumite 'puzzle' dar si sa se confrunte cu inamici.
Pentru a cre a un joc se folosesc p rograme numite motoare de jocuri. Fiecare motor de
jocuri are anumite avantaje cat si dezavantaje. In functie de proiectul la care lucrezi iti selectezi
motorul care te ajuta. Noi vom discuta in special despre programarea unui joc in Unity 3D.
Unity a apa rut pe piata in 2005 si a inceput sa se extinda rapi d din cauza faptului ca tot
ce faci in el este in timp real iar insterfata era usor de inteles. Fara a citi vreun document poti
deschide editorul si sa incepi sa lucrezi. La scurt timp Motoarele de jocuri mai mari au i nceput
sa il puna in calcul ca u n potential concurent. Putin mai tarziu Unity 3D a avu t suport si pentru
android lucru care motoarele mai mari nu il aveau. Din cauza multitudinii de platforme pe care
le putea avea si a faptului ca era destul de accesibil pentru oricine a acaparat rapid piata
dezvoltatorilor mici de jocuri. Fata de celelalte motoare cum ar fi UDK sau Cry Engine acesta
avea o versiune gratuita care iti permite a sa faci jocuri destul de complexe. Dupa o perioada
pana si cei de l a UDK au abordat aceeasi startegie si au facut o versiune gratuita a motorului.
Am ales Unity deorece fata de alte motoare de jocuri cum am fi Cry Engine sau UDK,
acesta are un editor de programanre incorporate (“Mono Dev”). Fata de celelalte doua Unity 3 D
te lasa sa alegi intre trei limbaje de programare : c#, unity script(care este un fel de Java Script )
si Boo(in ultimele versiuni de Unity se incearca renuntarea la Boo) , pe cand de exemplu in UDK
esti obligat sa lucrezi cu limbajul UDK , plus ca nu au un editor de programare si esti nevoit sa
lucrezi intr -un program care nu stie sa interpreteze codul (In UDK 4 este precizat ca se va trece la
programe in C#) . Codul scris de programatori ajunge in Unity sub forma unui script care este
ulterior atasat de cate un obiect ca si componenta. Orice script creat este automat introdus in
librarie si compilat, nu este nevoie sa inchizi motorul si sa il repornesti ca sa vezi ca nu ai erori.
In afara de modul in care se poate programa Unity mai are avantajul ca este usor de
folosit de catre oricine chiar daca nu cunoaste programare, Totul se foloseste pe principiul 'drag
and drop'.
Un alt avantaj din punctul meu de vedere destul de mare este faptul ca Unity are libraria
care se actualizeaza in timp real. Daca un fisier se modifica in directorul in care are proiectul
libraria , de exemplu o textura se modifica, aplicatie a o vede automat ca modifica ta si se
actualizeaza imediat si in joc. In alte motoare de jocuri trebuie inchis programul ca sa actualizeze
resursele.
8
Un dezavantaj fata de celelalte motoare mentionate este faptul ca nu vine cu o mare
librarie de modele si resurse, plus faptul ca in “UDK” sau in “Cry Engine” iluminare a este mul t
mai buna di n start fara a umbla la setari 'shadere' sau alte optiuni.
Ca mod de lucru Unity foloseste metoda cu atasare de componente fata de “UDK” care
foloseste clase care extind alte clase.
Orice motor de joc are doua ‘pipeline’ -uri , un pipeline pe GPU si unul pe CPU. Aceste
pipeline -uri merg in paralele si se asteapta unul pe celalalt. Din aceasta cauza poate aparea
fenomenul de ingatuire, care se produce cand pe unul din pipelineuri este mult mai multa
informatie si celalalt trebuie sa il astepte.
Pentru ca o aplicatie sa releze in mod optim trebuie sa avem cel putin 30 de cadre pe
secunda, asta insemnand ca pe oricare din pipeline -uri trebuie sa fie executat in jur de 33 de
milisecunde (33 ms* 30 = 990 ms aproximativ o secunda). Daca avem probleme de perform anta
intai trebuie localizata problema si dupa aceea rezolvata deoarece spre exemplu incercam sa
optimizam cod care se executa pe CPU dar ingatuirea este pe GPU , nu vom castiga performanta
deoarece cadrele pe secunda sunt date de cel mai mare timp de execu tie intre GPU si CPU.
Jocul in Unity este structurat in scene. Fiecare scena din Unity este echivalentul unui
nivel de joc. Meniul si el este considerat un nivel de joc.
Interfata
“Default” Unity este impartit in patru ferestre: fereastra de Joc(“Game View”),fereastra
Proiect(Project View),fereastra Scena(“Scene View”), fereastra Ierarhie( “Hieraechy View”) si
fereastra Inspector(“Inspector View”),f ereastra Consola (“Console View”).
9
Fereastra de Joc (“Game View”)
O data ce apasam butonul de pornit jocul putem vedea jocul ruland in aceasta fereastra.
Se poate seta in aceasta fereastra rezolutia la care vrem sa rulam jocul cat si daca vrem sa fie
rulat pe tot ecranul. Rezolutia poate fi atat stantard 16×9 sau 4×3 cat si o rezolutie personalizata.
Fereastra Proiect (“P roject View”)
Aceasta fereastra mai poate fi numita si librarie. Aici se gasesc toate resursele pe care le
foloseste proiectul respectiv. Atat resursele grafice cum ar fi modele sau texturi cat si shadere
sau pur si simplu scripturile facute de catre programatori. Orice resursa poate fi adaugata in
proiect ori prin copierea ei in directorul in care se afla proiectul ori prin adaugarea ei direct in
fereastra Proiect iar Unity automat o va copia in directorul proiectului. Daca o resursa e ste
modificata in directorul sursa , automat va aparea modificata si in fereastra Proiect.
10
Fereastra Scena(“Scene View”)
Asematoare cu fereastra de Joc in aceasta fereastra este afisat jocul dar si cand nu este
dat drumul. In aceasta fereastra se construieste nivelul propriu -zis. Un mare avantaj al acestei
ferestre este ca o data ce am dat drumul la joc putem depana in timp real tot ce este in nivel
deoarece aici putem modifica proprietatile obiectelor in timp real. De exemplu un obiect a ajuns
intr-o pozitie care nu am vrea si ramane blocat. Daca il selectam vedem in fereastra Inspector
propritatile acestui obiect, sau daca vrem chiar putem sa ii schimbam pozitia in lume.
11
Fereastra Ierarhie (“Hierarchy”)
Aici apar toate obiectele care se afla in scena deschisa momentan,
mai exac t o sa apara toate obiectele care se afla intr -un nivel. Daca dam
dublu click pe unul din obiecte suntem automat mutati in fereastra Scena
pe obiectul selectat.Unity foloseste ierarhie de tip parinte copil cu
obiectele din scena.Un obiect poate avea mai multi copii care isi modifica
pozitia si rotatia in fuctie de parintele lor . Aceste legaturi pot fi distruse
chiar si in timpul rularii jocului.
Fereastra Inspector(“Inspector View”)
In aceasta fereastra apar toate proprietatile unui obiect
selectat, de la ce componente are atasate pana la toate
proprietatile acestor componente facut e globale in scripturi.
Aceste proprietati se pot vedea si in timpul rularii aplicatie i si isi
schimba valorile in timp real. Valorile afisate pot fi modificate de
catre utilizator pentru a vedea anumite efecte in timp real de
exemplu daca vrem ca lumina sa isi schimbe culoarea sau
intensitatea nu trebuie sa iesim din aplicatie sa o modificam si sa
intram la loc pur si simplu o modificam pe loc si vedem diferenta.
Daca o proprietate este modifcata in timp ce aplicatia ruleaza
aceasta proprietate revine la valoarea initiala dupa ce aplicatia este
oprita.
12
Fereastra Consola(“Console View”)
Toate erorile, avertismentele sau chiar comentarii le care sunt puse de catre
programatori in scripturi apar afisate in aceasta fereastra. Daca dam dublu click pe una dintre
erorile aparute in fereastar ni se deschide automat editorul in care este scris codul si suntem
dusi in scriptul respectiv la linia c u probleme.
Alte ferestre pot fi adaugate din meniu de la Ferestre. Toate ferestrele pot fi marite sau
micsorate dupa placul utilizatorul. Ferestre pot fi si mutate cu totul. O fereasta dstul de
importanta este si :
Feresatra de Etichete si Straturi (“Tag and Layer View”)
Aici se pot seta etichete noi pe langa cele cu care vine Unity din start si care pot fi
atribuite obiectelor din scena. Aceste etichete sunt folositoare mai ales atunci cand trebuie sa
gasim un anumit obiect in scena si nu vrem sa tr ecem prin toate obiectele deoarece ar dura mai
mult. O alta utilizare a acestor etichete este si pentru verificare coli ziunilor intre obiecte. Pentru
ca fizica sanu faca foarte multe calcule anumite obiecte sunt excluse din start.
Orice obiect in Unity es te considerat “GameObject”. Acesta poate fi un obiect static sau
dinamic, o lumina , un efect sau doar un obiect care nu contine nimic (“Empty Object”) care nu
are decat o pozitie in lume. Pe aceste obiecte se pot adauga componente.Pentru a adauga o
componenta unui obiect nu trebuie decat luata componenta din librarie sau de la meniul
Com ponente si trasa peste obiectul caruia vrem sa ii adaugam aceasta componenta. Aceste
componente contin noi proprietati care sunt adaugate intregului obiect, de exemplu daca vrem
ca obiectul nostru sa fie un obiect dinamic care sa fie influentat de fizica n u trebuie decat sa ii
adaugam o componenta numita “Rigid Body” (corp rigid). Aceasta componenta ii da propieta tea
de a fi influentat de forte pe una sau mai multe axe. Odata adaugata o componenta unui obiect
aceasta apare in fereastra Inspector cu toate pro prietatile setate ca si globale de catre
programator in momentul in care a scris scriptul.
Dupa ce am creat un obiect caruia i -am adaugat anumite componente si am modificat
proprietatile lor ar fi neplacut daca ar trebui sa refacem pasii pentru un alt obi ect asemanator
13
asa ca unity vine cu conceptul de “Prefab”. Acest “Prefab” salveaza obiectul cu toate satarile
facute si cand avem nevoie de un obiect identic sau putin modificat dacat creem obiectul nu din
acel “Prefab” si facem micile modifcari. Marele av antaj il constituie faptul ca odata facut prefab
putem creea ace l obiect cu ajutorul scripturilor . De exemplu la un joc de startegie o fabrica
trebuie sa creeze unitati, acele unitati sunt d e fapt prefab -uri care sunt cre ate de catre un script
atasat de fa brica resectiva.
Alte proprietati importante care pot fi modificate sunt si cele de la meniul editare/setari
de proiect/jucator unde putem seta cum se numeste compania care face programu l, cum arata
cursorul, re zolutii acceptate de program sau ce directx foloseste aplicatia. Dupa ce am setat
toate aceste proprietati si aplic atia noastra este gata de testat putem cre a un executabil pentru
platforma dorita. Acest lucru se face din meniu de la fisier/ setari de contruire unde selectam
platforma care o dorim si ce scene vrem sa fie folosite in aplicatia noastra. Scena cu care incepe
aplicatia este intotdeauna scena 0.
In programare stim ca avem si variabile globale, care pot fi apelate in program unde
avem nevoie, Unity foloseste variabile globale doar in ca drul unui script(componenta). Aceste
variabile sunt considerate globale doar in cadrul scriptului respectiv si nu pot fi apelate direct de
catre un alt script. Pentru a putea fi apelate de catre alta componenta, acea componenta
trebuie sa faca referire la scriptul in care variabilele sunt declarate de ex:
Daca avem scriptul “properties.js” care contine proprietatile unui unitati cum ar fi viata
“HP” sau armura “armor” dar noi avem nevoie de aceste valori in alt script de exemplu “IA.js”,
acel script trebu ie sa faca referire la scriptul din care ii trebuie variabilele. Acestu lucru se face
cu ajutorul instructiunii “GetComponent”.
Props = GameObject.Find(“obiectul care contine scriptul”).GetComponent(“properties”);
In orice joc avem nevoie ca la trecerea de la un nivel la altul sa pastram anumite valori
cum ar fi puctajul, sau nive lul personajul nostru, poate ch iar obiectele pe care le avea la e l la
sfarsitul nivelului, insa in Unity l a iesirea dintr -un nivel (scena) toate obiectele care compun acea
scena dispar , astfel dispar si proprietatile lor .
In cazul in care avem nevoie de o proprietate care sa se pastreze de la un nivel la altul se
folosesc obiecte care sa nu se distruga la incarcarea unui nivel nou. Aceste obiecte au
prorietatea “@DontDestroyOnLo ad”. Aceata proprietate se poate da din orice script atatasat de
acest o biect. Daca un script contine a ceasta proprietate tot obiectul si toate componentele
atasate acestuia nu se vor sterge la incarcarea unui nivel nou. Astfel putem crea variabile care s a
fie globale pe parcursul intregului program. Putem creea un script de exemplu “globals.js” care
sa contina proprietatea “@DontDestroyOnLoad” si in care sa punem toate variabilele sau
functiile care ne trebuie permanent. Problema care apare cu aceasta pro prietate este ca atunci
14
cand ne intoarcem in nivelul in care acest obiect a fost creat vor aparea duplicate. Pentru a
preveni aceasta problema trebuie sa avem intotdeauna o list a cu obiecte care nu se distrug si sa
le distrugem manual atunci cand este nevo ie.
Pe langa functiile pe care le crea m noi , Unity are functii predefenite care sunt
interpretate sau apelate cand anumite contditi i sunt indeplinte. Cele mai des folosite functii
sunt:
Awake (‘Trezire’ )
Aceasta functie este apelata o singura data in mom entul in care scriptul este initializat
adica atunci cand obiectul nostru a fost creat in scena. Aici se pot declara variabilele de inceput
ale unui obiect cum are fi cu ce viata incepe, care jucator il detine.
Start (Pornire )
Este asemanatoare functie A wake insa diferenta o face faptul ca aceasta functie nu este
apelata decat in momentul in care scriptul este activat. Daca un script este atasat de un obiect
el nu este neaparat si activ. Toate componentele au proprietatea de a fi activate sau dezactivate.
Update (Actualizare )
Aceasta functie este apelata o data pe parcursul fiecarui cadru. Timpul in care este
apelata este aleator pe parcursul unui cadru. Daca vrem anu mite instructiuni sa fie apelate la
sfarsitul unui cadru sau la inceputul acestuia putem folosi functiile “FixedUpdate (Actualizare
Imbunatatita )” care este apelata la inceputul unui cadru sau functia “LateUpdate (Actualizare
Tarzie )” care este apelata la sfarsitul fiecarui cadru. De evitat sa facem verificari multe in aceasta
functie, orice verificare per cadru reduce performanta.
OnGUI (Pornire Interfata Grafica cu Utilizator )
Aceasta functie este apelata de mai multe ori per cadru. Este folosita pentru a desena
interfata in ge neral. Din cauza faptului ca se apeleaza de multe ori pe cadr u trebuie sa contina
foarte pu tine instructiuni.
OnTriggerEnter(Collider)
Aceasta functie este apelata atunci cand un obiect intra intr -un ‘trigger’ (declansator) .
Variabila de tip “Collider” este de fapt componenta de coliziune a obiectului care a intrat in
‘trigger’ . Alte functii asemanatoare acestei functii sunt “OnTriggerExit(Collider)” care este
apelata atunci cand un obiect iese din ‘trigger’ nu si atunci cand un obiect este distrus in
interiorul ‘trigger -ului’ si functia “OnTriggerStay(Collider)” care este epelata per cadru atat timp
cand in interiorul unui ‘trigger’ este un obiect care are o componenta de tip “Collider”. Atentie
15
deoarece aceasta functie din urma se apeleaza per cadru pen tru fiecare obiect care contine un
“Collider” si poate fi foarte costisitoare, de exemplu daca sunt 11 obiecte care se afla reciproc in
vecinatatea lor functia se va apela de 100 de ori per cadru.
OnDestroy (Distrugere )
Este apelata O singura data in cadru l in care obiectul este distrus. Mai este apelata si
atunci cand se schimba o scena deoarece toate obiectele sunt distruse automat. Nu este indicat
sa crea m alte obiecte din aceasta funct ie deoarece atunci cand schimbam scena se vor crea
obiecte care o sa fie in memorie dar nu si in nivel si avem pierderi de memo rie. Daca suntem
nevoiti sa crea m obiecte de exemplu particule sau alte efecte cand o unitate este distrusa ne
putem folosi de o alta proprieta a obiectului de exemplu in cazul nostru prorpietatea
“dead” (mort) care ne spune daca obi ectul nostru este mort, distrus de catre altceva sau daca
este distrus la schi mbarea nivelului, astfel nu crea m obiecte decat in cazul in care distrugem noi
un obiect nu cand se schimba nivelul.
Unity are si anumite tipu ri de variabile proprii. Cele mai intalnite sunt:
GameObject
Contine indicativul obiectului care ajunge in sce na.Este clasa din care sunt cre ate toate
obiectele din Unity.
Transform
Contine pozitia si rotatia cat si scalarea obiectului din scena.
Collider
Contine componenta cu care obiectul poate interactioneaza cu alte obiecte. Aceasta este
clasa de baza de la care sunt create celelate collider -e. Un collider este o forma geometrica
simpla in general (cub, plan,cilindru, sfera,capsula) cu care motorul isi face calculele de fizica si
cu care verifica ‘trigger -ele’ . Un collider mai diferit este ‘mesh’ collider care ia un model 3d si il
transforma in collider . Avantajul acestui tip de collider este faptul ca el creeaza o coliziune mai
precisa in sa este mai costisitor .
Color
Acest tip de variabila este de fapt un structura cu patru variabile in care este trecuta
valoarea unei culori in RGBA. Fiecare valoare poate fi apelata cu Color .r, Color .g,Color .b,Color .a ;
Variabilele globale apar in fereastra Inspector in functie de tipul lor . De exemplu
variabilele de tip ‘intre ’ apar cu un camp unde scrie valoarea, variabilele de tim boolean apar cu
16
o casuta pe care o bifam daca sunt adevarate sau false, sau o variabila d e tip enumerator care
apare ca un meniu din care alegem ce valoare poate sa ia acel enumerator .
Daca vrem totusi ca o variabila sa fie globala dar sa nu apara in Inspector ca sa poata fi
modificata o putem declara cu ”@HideInIspector” inai nte.
@HideInInsp ector
var enemyLastPos : int = 0;
Pentru o mai buna intelegere a modului in care se lucreaaza in Unity i n conti nuare vom
discuta pe un exemplu concret si anume un joc de startegie in Unity 3D , insa o sa punem accent
pe inteligenta artificiala .
Jocul nostru contine trei rase, fiecare cu modul ei de a se dezvolta. Singurul lucru in
comun intre cele trei rase este ti pul resurselor pe care trebuie sa le colecteze, insa modul cum
sunt acestea folosite difera. Diferenta majora intre aceste trei rase este faptul cum se
construiesc unitatile si cladirile. Fiecare are un mod special de a construi de ex:
– Rasa NOVA
o Aceasta va construi unitatile si cladirile in modul standard. Exista anumite
cladiri fabrici care construies alte cladiri sau unitati daca au resursele
necesare pentru acestea.
– Rasa YX
o Aceasta rasa extraterestra isi creeza totul cu ajutorul unor celule. Ori ce
Cladire sau unitate este cre ata daca exista un numar necesar de celule care se
vor compune si se vor transforma in acea cladire sau unitate. Daca o cladire
sau o unitate nu mai este necesara se poate descompun e la loc In celule care
pot cre a altceva.
– Rasa HU MANS
o Aceasta rasa nu construieste decat o platforma in modul standard ca si rasa
NOVA, insa pe aceasta platforma se pot pune atasamente. Atasamentele
modifica platforma dand -ui un nou rol, de exemplu un atasament o poate
transforma intr -o cladire ca re con struieste unitati de atac sau ii putem pune
un atasament care o face un tun pentru a apara baza. Toate platformele
17
comunica intre ele pentru ca atunci cand anumite atasamente sunt contruite
pe mai multe platforme sa se deblocheze unitati sau cladiri noi.
Problema care apare cand rasele au anumite actiuni diferite cum ar fi in cazul nostru
modul de a contruii unitati este ce face inteligenta artificiala?
Pentru el actiunea va fi tot construi rea unei unitati insa in functie de rasa pe care o are
trebuie sa i si faca pregatir ile necesare pentru a putea face acest lucru. Degeaba are resurse ca
sa construiasca o cladire daca nu are celulele necesare pentru aceasta.
Primul lucrul cu care un proiect trebuie inceput este sa cre am scriptul care sa contina
variabile le globale si anumite functii cu care o sa lucram frecvent. Pentru a face acest lucru se
adauga un obiect gol in scena , prima scena cu care incepe un proiect este intotdeauna scena in
care se afla si meniul . Acest obiect nu contine decat o pozitie si un nume, nu are coliziune s au
forma. De acest obiect atasa m scriptul nostru cu variabile globale. Acest lucru face ca atunci
cand noi incarcam prima scena si anume meniul jocului, aplicatia noastra isi incarca toate
variabilele globale de care are nevoie. Pe ntru a stii ce face scriptul nostru ii vom da un nume
adecvat , de ex emplu obiectul de care il atasam se va numi “globals” iar scriptul nostru se va
numi “globals.js” , astfel putem avea o variabila care contine toate functiile si variabilele globale .
De exemplu putem declara variabila “globa l” care sa contina acest script:
var global : globals;
global = GameObject.Find(“globals”).GetComponent(“globals”);
Numele script -urilor trebuie sa fie unice deoarece orice script creat devine automat tip
de variabil a.
Dupa cum am precizat anterior acest scr ipt va contine si proprietatea
“@DontDestroyOnLoad ” ca sa nu se distruga atunci cand incarcam alta scena.
Am precizat ca in acest script apar si functii apelate frecvent. Cateva exemple de functii
de acest fel po t fi :
DistToGround( Transform,Vector3,Vector3,boolean )
Aceasta functie intoarce distanta de la un obiect la pamant( prin pamant intelegem
suprafata de nivel pe care o unitate merge sau zboara, in cazul apei se ia distanta pana la nivelui
apei) . Acesta functie mai poate sa intoarca si inaltimea terenului in punctul in care este calculata
distanta.
ArrangeMyUnits (Aranjarea Unitatilor )
18
Cu ajutorul acestei functii avem intotdeauna o lista ordonata o tuturor obietelor pe care
un jucator le detine. Acest l ucru face ca o cautare a unui anumi t obiect sa fie mult mai rapida,
deoarece obiecte detinute de catre un jucator nu pot fi clasificate dupa un anumit criteriu, dat
fiind faptul ca ele pot fi orice tip de cladire sau de unitate si au tot felul de proprieta ti. Asfel
ordonarea se va face aleator incepand cu unitatile existente si cu unitatile posibile . De exemplu :
Ca o cautare sa fie rapida cautam intr -un vector pana cand dam de o pozitie goala(null)
deoarece vectorul in care se stocheaza indicativele unitat ilor este mare(500 – 1000 de pozitii) si
ar dura foarte mult sa parcurgem tot vectorul.
Presupunem ca jucatorul ar avea 20 de unitati din care 4 au fost distruse la un
momendat. La inceput vectorul nostru ar fi avut primele 20 de pozitii ocupate cu indic ativul
obiectelor dar acum unele dintre ele au disparut iar in vectorul nostru exista 4 pozitii goale , iar
daca am incerca sa cautam o unitate anume din vector si am da de pozitia goala cautarea s -ar
opri si ar returna ca nu exista acel obiect chair daca e l este posibil sa fi existat . Pentru a evita
acest lucru functia noastra are ca scop eliminarea acestor goluri si astfel avem tot timpul un
vector in care primele pozitii sunt ocupate de catre indicativele obiectele pe care jucatorul le
detine.
In afara d e functii putem avea si clase. O clasa care va fi folosita pe tot parcursul
proiectului este clasa ”Teck” care contine toate informatiile despre ce unitat i si cladiri fiecare
jucator poate contruii si ce depend ente are fiecare obiect pentru a fi construit .
Dupa ce am stabilit in mare cam ce ne trebuie de inceput ca variabile si functii globale
trebuie sa stabilim ce clase mari de obiecte o sa avem in scena.
Prima Clasa de obiecte ar fi obiectele din care este alcatuit nivelul ca visual. Marea parte
din ele o sa fie obiecte statice care o sa fie impartite in trei mari categorii: obiecte statice peste
care mergi, obiecte statice de care doar te lovesti si obiecte care sunt doar de decor fara
coliziune.
Pentru ultima categorie nu trebuie sa facem nimc deo arece cand importam un obiect in
Unity acesta vine fara coliziune doar cu ‘mesh’ -ul provenit din programul in care modelam,
astfel el nu influenteaza cu nimic scena.
Ca sa deosebin primele doua categorii o sa ne folosim de strat -uri si de sistemul de
“Nav Mesh” din Unity. Ca sa stim la ce distanta ne aflam de teren si pentru a optimiza calculele o
sa trecem toate obiectele care le folosim ca teren pe un strat special pe care il putem
numi ”terr” , asfelt fizica va face calcule doar cu obiectele de pe acest s trat.
19
Ca obiectele sa aiba o coliziune se adau ga un tip de collider . Deoarece terenul nostru are
o forma neregulata si deoarece nu vrem sa avem unitati care o sa mearga prin aer o sa ii
adaugam un collider de tip mesh ca sa ia forma terenului.
Daca vrem sa optimizam acest mesh de coliziune se poate face un obiect cu mai putine
detalii al terenului si se poate incarca acesta, asfel avem o performanta mai buna insa se
mareste memoria RAM folosita deoarece avem inca un mesh incarcat.
Sistemul de “NavMesh” cr eeaza un mesh pe deasupra tuturor obiectelor care sunt puse
sa creeze acest mesh, la un anumit unghi stabilit de noi. Cu acest mesh avem o suprafata peste
care unitatile noastre pot merge. Toate obiectele care nu sunt incluse sa faca un mesh vor fi
conside rate obstacole si in locul acestora ne se va genera un mesh.
“NavMesh” sau mesh de navigatie este de fapt un mesh bidimensional care este creat
din poligoane convexe pe care se calculeaza ruta unui obiect dupa un algoritm de cautare.
Deoarece poligoanele sunt convexe , pentru a st rabate un poligon dintr -un punt in altul se poate
merge in linie dreapta iar asfel se poate calcula cel mai scurt traseu de la un punct la altul.
O alta categorie o constituie obiectele jucatorului. Aceste obiecte in cazul nostru pot fi
impartite la randul lor in doua clase: cladiri si unitati.
Toate obiectele cu care interactionezi intr -un nivel trebuie identificate pentru a le da
anumite proprietati , astfel cre am un script universal pentru toate pe care il vom numi
“properties.j s” in care punem proprietati pe care majoritatea obiectelor pe care le selectam sa
le aiba. Acest script mai contine si proprietati care ne pot spune cui ii apartine un obiect, daca
este neutru sau inamic cat si tipul obiectului , daca este unitate , cladir e, resursa sau orice obiect
cu care jucatorul poate sa interactioneze.
Chiar daca acest script ne spune ce tip de obiect avem selectat nu este de ajuns
deoarece daca avem o cladire selectata aceasta are alte proprietati fata de resursa. Putem
adauga in sc ript toate proprietatile pentru cladiri, unitati si alte obiecte insa de ce sa incarcam
un script cu proprietati inutile pentru alte obiecte, de ce sa incarcam proprietatile unei cladiri pe
o unitate care nu o sa le foloseasca niciodata. Pentru a rezolva a ceasta problema daca cream
scripturi c u proprietati diferite pentru cladiri pe care il vom numi ”building_properties.js” si
pentru unitati altul numit ”unit_properties.js”.Nu exista o regula in cate scripturi sa impartim
proprietatile pe un obiect, nu este neaparat bine sa fie multe scripturi pe un obiect doar ca sa
impartim noi codul. Trebuie facut un compromis intre cate scripturi avem pe un obiect si cat cod
scriem intr -un script, nu vrem sa ne pierdem in scripturi cautand cate ceva.
Asadar pentru ca unitatea noastra sa fie o cladire ii adugam un script cu proprietati
standard pentru toate obiectele plus scriptul cu proprietati pentru cladiri.
20
Ce facem daca avem proprietati care ne trebuie intre tipurile de obiecte, de exemplu ce
facem daca vrem ca o anumita unitate sa construiasca ca o cladire? Incarcam aceasta
proprietate pe toate unitatile?
Pentru a rezolva aceasta problema putem crea un script cu proprietati specific. De
exemplu in cazul nostru avem nevoie ca o unitate sa creeze alte u nitati. Ca sa poata face acest
lucru cre am un script cu aceasta proprietate si il adaugam doar unitatii respective. Deci ca
unitatea noastra sa contruiasca ii vom adauga scriptul “can_build.js”.
Daca mai avem alte proprietati specifice si nu le vrem pe to ate obiectele doar cre am cate
un script cu acea proprietate. Un alt exemplu de astfel de script este “dismatle.js” care face ca
unitate a de care este atasat atuci cand moare sa se distruga in mai multe bucati care sa fie
afectate de fizica.
Dupa ce am st abilit si clasele mari de obiecte urmeaza sa cre am alte mecanici de care
avem nevoie in joc, cum ar fi solutia de cautare a drumului unei unitati sau ceata pentru a
acoperi zonele in care nu am fost.
Chiar daca folosim sistemul de “NavMesh” pe care il ofe ra Unity nu este de ajuns. Acest
sistem doar ofera o ruta catre un punct , daca este posibil , si seteaza o viteza si o acceleratie
obiectului, insa modul in care obiectul parcurge aceasta ruta nu este precizat. Exista unitati care
zboara sau unitati care pl utesc. Astfel trebuie sa stabilim si modul in care o unitate merge si mai
ales, in fu nctie daca unitatea merge sau zboara sa ii setam mesh -ul pe care se deplaseaza.
In general la un proiect exista programatori care lucreaza doar la o categorie de cod,
astfel vom imparti si noi scripturile pe mai multe categorii.
Mecanicine generale ale jocului
In aceasta categorie se incadreaza toate script -urile care fac ca obiectele sa
interactioneze intre ele si sa poata fi controlate de catre jucator . Un script important pe langa
cele mentionate mai sus care face parte din aceasta categorie este si manager -ul de animatii.
Ca o unitatate sa se miste credibil ea trebuie sa aiba o animatie pentru fiecare miscare
pe care o poate face. Pentru aceast lucru avem nevoie de un manager care sa gestioneze toate
animatiile pe care un obiect le poate rula si sa o aleaga pe cea de care are nevoie la un moment
dat.
Pentru a realiza acest lucru avem doua variante in Unity 3D. Cu ajutorul componentei
“Kismet” care este un sistem c reat de Unity in care fiecare stare a unui obiect este redata vizual
printr -un bloc cu anumite proprietati. Trecerea dintr -o stare in alta este specificata prin creerea
21
unor lagaturi intre blocuri. Pentru a trece dintr -o stare in alta trebuie indeplinite a numite
conditii pe care le specificam cu ajutorul blocurilor .
O alta varianta este sa cre am propriul nostru manager . Ca sa cre am un manager propriu
vom crea un script pe care il atatasam de obiectul pe care vrem sa gestionam animatiile. O
metoda de manager este cu ajutorul starilor prin care poate trece un obiect. Putem declara stari
pe obiecte iar la trecerea dintr -o stare in alta sa cerem manager -ului sa ruleze o animatie.
Acesta verifica din ce stare a plecat obiectul si in ce stare va ajunge pentru a ii seta o anumita
animatie din lista.
Scripturi pentru Camera
In orice joc camera are un rol foarte important. In functie de cat de bine este realizata
miscarea acesteia joc ul poate deveni bun sau prost. Oricat de bun ar fi un joc daca avem
dificultate a ne deplasa cu camera sau este pusa in asa fel incat tot timpul sa ne incurce o sa
avem o experienta neplacuta. La un joc de startegie camera va avea o orientare de sus in jos si
se va putea misca cu ajutorul ta stelor sau daca avem cursorul la marginea ecranul ul. Ca sa
provocam neplaceri jucatorului camera va trebui sa se miste cu o mica acceleratie initiala sa nu
plece brusc de pe loc.
Alta proprietate pe care o putem adauga camerei este ‘zoom’ -ul. Pentru a realiza zoom
avem doua posibilitati:
– Mutam camera ma i aproape de unitati si astfel acestea par mai mar i insa apar
probleme. Ce se intampla daca avem intre noi si unitate un obstacol? Camera va
trece prin acesta si vom vedea prin el.
– Modificarea FOV -ului. Daca midificam Fov -ul producem efectul de apropiere s au de
indepartare a obiectelor insa si de data aceasta apar probleme deoarece la
modficarea mai agresiva a acestuia o sa se distorsioneze obiectele(spatiile o sa para
mai mici sau mai mari).
Sunet
Ca si in cazul animatiilor si pentru sunete este nevoie de un manager .
Sunetele se pot imparti in mai multe categorii in functie de cum sunt incarcate, acestea
putand fi sunete care sunt ‘streemate’ adica din cauza ca sunt de dimensiuni mai mari nu vrem
sa le avem incarcate tot timpul in memorie si se incarca atun ci cand avem nevoie de ele. Din
aceasta categorie fac parte sunetele ambiectale.
22
O alta categorie sunt sunetele nestreemabile care sunt incarcate tot tim pul in memorie.
Acestea sunt sunetel e pe care le folosim in mod frecvent si nu vrem sa le incarcam si descarca
intruna din memorie. Din aceasta categorie fac parte sunetele pe care le produc obiectele la o
anumita actiune pe care o intreprind.
Deoarece nu ne trebuie in general sunete de trece re dintr -o stare in alta putem atasa
sunete de stari ale obiectului. Daca merge dam drumul la un sunet de mers pe acea unitate.
Pentru fiecare sunet trebuie setat daca acesta este un sunet Stereo sau 3D. Daca sunetul
este 3D trebuie sa ne asiguram ca este setata pozitia de la care se aude cum trebuie. La un sunet
3D mai trebuie setata si distanta de atenuare.
Scriptul atasat de obiect are rolul de a face o lista cu sunetele necesare pentru acel
obiect pentru ca atunci cand obiectul se afla intr -o an umita st are sa i se dea un anumit sunet.
Sunetele se mai pot imparti si dupa modul in care sunt folosite. Acestea pot fi :
– Sunete ambie ntale
Acestea sunt sunetele pe care le produce mendiul in care ne aflam de exemplu
ciripitul pasarilor intr -o padure sau melodia de fundal pe care o auzi m cand jucam.
– Sunete produse de efecte speciale
Atunci cand un obiect ataca un alt obiect , arma cu care trage va trebuii sa produca
un anumit sunet.
– Dialog
Toate replicile pe care la gasim intr -un joc.
Efecte speciale
Acesta categor ie este asemanatoare din punct de vedere al programarii cu cea pentru
sunete. Exista insa doua mari deosebiri:
– Efectele pot exista de sine statatoare in lume nefiind atasate de un obiect. Putem
astfel avea particule de praf prin n ivel.
In acest caz manage r-ul de efecte trebuie sa le declanseze doar in momentul in care
jucatorul se afla cu camera in aproprie re pentru a nu consuma din performanta
degeaba.
23
– Efectele nu trebuie sa dispara neaparat cand obiectul isi schimba stare a sau acel
obiect de care sunt at asate este distrus. Un exemplu poate fi o racheta care lasa in
urma sa o dara de fum. In mom entul in care racheta este distrusa inca mai vrem sa
vedem dara de fum care dispare treptat nu o data cu racheta.
In acest caz manager -ul are ca rol detasarea efect ului de obiectul de care este atasat
pentru a nu disparea o data cu acesta si de a seta un timp dupa care sursa care emite
particule sa se opreasca.
Interfata grafica cu utilizatorul (GUI)
Chiar daca acum exista un trend de a se renunta cat mai mult la int erfata sau de a o
integra pe obiectele din scena, anumite tipuri de jocuri au nevoie extensiv de aceasta.
La un joc de strategie trebuie sa afisam o multime de actiuni pe care le poate face
jucatorul cu o anumita unitate sau unitati selectate. De la cum o misca pana la ce poate construi
cu aceasta. Toate posibilitatile pe care le poate executa jucatorul la un moment dat trebuie sa
fie verificate cu arborele tehnologic. Nu trebuie sa poata construi anumite unitate fara sa fi
contruit altele inainte.
O compon enta majora de pe interfata o constituie harta.Pe acesata trebuie afisat in timp
real atat obiectele jucatorului cat si cele ale inamicilor sau aliatilor in caz ul in care au fost
descoperite. Pentru a nu le veadea pe toate se foloseste efectul de ceata car e dispare in locurile
in care jucatorul detine obiecte.
Aceasta se realizeaza in cazul nostru cu ajutorul unei masti de trasparenta de 256×256
pixeli dupa care desen am o textura care contine culoarea cetei. Deoarece scrierea unei texturi
de 256×256 in timp real per cadru este costisioare se scrie doar o parte din ea per cadru iar cand
am scris toata textura o citim (4 linii din textura per cadru).
Retea
Aceasta categorie are ca scop cre area unei legaturi intre doi sau mai multi utilizatori si de
a sincroniza aplicatiile acestora, nu vrem ca un jucator sa vada alte pozitii ale inamicului.
Metoda dupa care se face acest lucru este metoda server client. O aplicatie este considerata
server ia r celelalte care se conecteaza la aceasta sunt considerate clienti.
Server -ul poate fi atat un jucator cat si o aplicate dedicata doar pentru a fi server si care
nu joaca propriu -zis, ea avand rol doar de a gestiona actiunile care sunt trimise pe retea. I n cazul
nostru serverul este un jucator .
24
Ca un client sa se poata conecta la un server el trebuie sa stie atat adresa acestuia cat si
portul la care sa se conecteze. Acest lucru poate fi incomod pentru jucatori, acestia fiind nevoiti
sa distr ibuie adresa la fiecare jucator care vor sa se conecteze. Pentru a evita inconvenietele se
folosete un server stapan care are rolul de a face o lista cu toate adresele si port -urile celor care
fac un server si de al afisa celor care vor sa se conecteze. In acest fel se ascunde si adresa celor
care fac server deoarece serverul stapan nu afiseaza adresa ci doar anumite informatii despre
acel server cum ar fi nume le si alte proprietati ale serverului .
Pentru a putea trimite actiuni obiectelor prin retea trebuie sa cunoast em numele acelor
obiecte carora le trimitem actiunea. Oricarui obiect intr -un motor de joc i se da un indicativ unic
insa acesta poate sa difere de la o aplicatie la alta asfel ca obiectul 14327 de pe server nu este
acelasi si pe client. Ca sa putem face s incronizare obiectelor fiecare client cand a creat un obiect
va trimite la server un mesaj cu obiectul pe care la cr eat iar server -ul ii va da un indicativ unic la
fel ca cel de pe server .
Problema majora care apare la un joc care este rulat pe retea este timpul in care serverul
raspunde la clienti. Daca timpul este foarte mare ap ar probleme de sincronizare deoarece
obiectele se misca mult mai repede pe server decat pe clienti care inca nu au primit comanda
de a se misca sau invers, acest lucru poate duce la un avantaj al anumitor jucatori. Ca sa evitam
aceasta problema se cre aza un manager de instructiuni trimise pe retea. Acest manager
stocheaza toate instructiunile care trebuie trimise si l e va trimite la un interval de timp
prestabilit (in general la 2 00 de milisecunde).
Daca timpul de raspun s al serverului cu clientii este mai mare decat cel al managerului
va aparea o latenta deoarece actiunile nu o sa fie trimise decat la urmatorul interval.
Pentru a rezolva nesincronizarile care pot aparea pe rete a (o unitate a mers mai mult
decat pe server) serverul verifica pozitiile unitatilor pe care le are el cu cele de pe clienti.
IA
Toate script -urile care constituie aceasta categorie au ca scop functionarea Inteligentei
artificiale. Ele constituie cre ierul inteligentei artificiale. Trebui e totusi facuta o distinctie in tre
inteligenta artificiala studiata academic si cea folosita in industria jocurilor .
Academic , inteligenta artificiala este ipartita in doua categorii:
– Inteligenta artificiala puternic a
25
Aceasta incearca sa imite mimica si gandirea umana, incearca sa umanizeze o
aplicatie.
– Inteligenta artificial slaba
Aceasta nu incearca decat sa gaseasca o sulutie la probleme curente pe care le are.
Din cauza resurselor pe care le avem la dispozitie ca nd lucram la o aplicatie inteligenta
artificiala foloseste algoritmi mai complexi sau cum se intampla frecvent in industria jocurilor se
incearca imitarea unei inteligente. Daca o asa zisa inteligenta artificiala se comporta si face
aceleasi actiuni pe car e un jucator le -ar face putem sa nu zicem ca este o inteligenta artificiala?
Exista mai multe tehnici de implemetare a unei inteligente artificiale. Printre cele mai
intalnite gasim:
Retele Neuronale Artificiale(ANN)
Acestea sunt constituite dintr -o serie de algoritmi. Acesti algoritmi sunt inpirati de catre
retelele neuronale din biologie. Aceste retele sunt alcatuite din mai multe sisteme numite”
neuroni” care sunt interconectate intre ele.
Scopul acestor neuroni este de a recunoaste anumite modele si de a le interpreta.
Aceasta tehnica de inteligenta artificiala are avantajul ca poate invata. ANN invata din greseli,
pentru fiecare actiune pe care au interprins -o, isi stabilesc daca a fost bine sau nu si daca o sa o
repete.
Un neuron primeste mai multi s timuli (informatii) cu o anumita importanta stabilita de la
inceput sau pe care o dobandesc prin antrenarea acelei legaturi si dupa ce stabileste importanta
actiuni pe care o are de indeplinit hotaraste daca o face sau nu. Importanta unei informatii este
definita ca un numar real acesta putand fi si negativ. Daca suma importantei tuturor stimulilor
este mai mare decat un prag definit in neuron acesta trimite rezultatul mai departe.
Retelele neuronale au o invatare supravegheata, adica atat informatiile de intrare cat si
cele de iesir e sunt cunoscute de la inceput.
Algoritmi Genetici (GA)
Acest tip de inteligenta artificiala este inspirat din teoria despre evolutie a lui Darwin
(premis, selectie natura si pasi marunti). "…Natural selection acts only by taking advantage of
slight successive variations; she can never take a great and sudden leap, but must advance by
short and sure, though slow steps. “
26
Algoritmi genetici folosec un spatiu de cautare in care se afla solutii (populatie) viabile
pentru a rezol va o problema. Pe masura ce aplicatia ruleaza apar si alte solutii in acest spatiu.
Cautarea in acest spatiu poate fi lunga deoarece nu stim de unde sa inceapa cautarea unei
solutii.
Dintre aceste solutii sunt luate cateva care sunt mai viabile si se form eaza o alta
populatie.Aceasta noua populatie va genera alte solutii (crossover) din care se vor lua iar cele
mai viabile si se va crea un nou spatiu de solutii . La creerea de noi solutii apare fenomenul de
mutati e in cadrul caruia solutiile noi obtinute au noi proprietati . Pasii se repeta pana sunt
indeplinite anumite conditii.
Ca parametri mai importanti intalnim :
– Probabilitatea de crossover
In functie de acest procentaj noile solutii pot avea proprietati din ambii parinti.
– Probabilitatea de mutatie
Aces t procentaj specifica daca noile solutii pot contine proprietati care nu apartin
niciunui parinte.
– Marimea populatiei
Cate solutii se gasesc intr -o populatie. Cresterea acestui numar face ca timpul de
cautare al unei solutii viabile sa creasca.
Acest tip de inteligenta are o invatare nesupravegheata deoarece solutiile generate nu
sunt cunoscute. Invatare se face din greseli.
‘Reinforcement Learning ’ (Invatare prin consolidare)
Aceasta teh nica merge pe principiul de rec ompensa si pedeapsa. Inteligenta a rtificiala
determina daca actiunea pe care o interprinde este benefica sau nu in functie de cum se
schimba nivelul din jurul sau. Experienta pe care o acumuleaza este impartasita de toti agentii
care alcatuiesc aceasta inteligenta si nu trebuie ca doi agen ti sa faca aceeasi greseala.
La fel ca si algoritmii genetici aceasta tehnica are o invatare nesupravegheata deoarece
nu se cunoaste de la inceput daca o actiune este benefica sau nu, in schimb aceasta nu trebuie
sa greseasca ca sa isi dea seama ca a gresi t deoarece actiunile pe care le ia sunt influentate de
actiunile precedente.
Greutatile intampinate la acest mod de inteligenta ar fi:
– Explorarea solutiilor
27
Daca IA a mers pe o solutie care pana acum a fost benefica, ce va face in continuare?
Continua pe acesata cale si nu mai cauta o alta solutie sau incearca sa gaseasca si
alte solutii?
– Atribuirea recompensei si a pedepsei
Cum stabileste daca o actiune interprinsa este benefica sau nu? Recompensa pe care
a primit -o in cadrul acestei actiuni nu este neces ara din cauza acestei actiuni si poate
este din cauza unei actiuni petrecute anterior .
– Schimbarea lumii inconjuratoare
Se poate ca nivelul din jurul entitatii sa nu se schimbe imediat. Se poate ca un numar
de cateva actiuni sa schimbe aceasta lume astfel actiunea pe care a indeplinit -o nu se
stie pe un termen mai lung daca este benefica sau nu.
Urmatoarele tehnici nu invata pe parcursul rularii aplicatiei.
Masina cu stari finite (FSM)
Este una dintre cele mai intanlnite tehnici de IA din industria jocuri lor deoarece sunt
usor de implementat si de depanat plus ca au avantajul ca sunt mult mai putin costisitoare ca si
performanta. Sunt intuitive si flexibile, oricand se pot adauga alte stari de care IA sa tina cont si
se poate usor combina cu alte tehnici de IA cum ar fi logica fuzzy sau retele neuronale.
Acest principiu are la baza impartirea unui comportament al unei entitati in mai multe
stari finite in cazul nostru o unitate trebuie sa stie sa se miste sa atace sa apare alte uniti sau
chiar sa stranga resurse. In functie de anumite conditii IA hotarast e daca sa schimbe starea unei
entitati sau sa pastreze starea in care se afla pana cand alte conditii sunt indeplinite.
Deoarece nu stie daca o actiune este buna sau nu si nici nu are posibilitatea de a invata
actiunile pe care le ia o entitate tind sa f ie de fiecare data la fel.
Logica Fuzzy
Oamenii pot interpreta anumite reguli care pentru calculator nu ar avea prea mult sen s.
Un exemplu de acest fel ar fi cand vorbim cu o persoana si ii zecem sa vina mai aproape sa u sa
mearga mai departe. Termenii apr oape sau departe un calculator nu ar putea sa ii interpreteze.
Pentru el acesti termeni sunt vagi si nu stie ce sa faca.
28
set concret
set concret Logica fuzzy incearca sa traduca acesti termeni pentru a fi intelesi si de catre calculator .
Pentru calculator se poate seta un interva l de valori pe care el sa il interpreteze si cu care sa
definim ce inseamna aproape si ce inseamna departe si care este distanta medie.
Ex: hotaram sa folosim ca distanta minima 10m, 50m distanta medie si 100 distanta
mare.
Deoarece dupa analizarea tuturor regulilor calculatorul va intoarce o valoare, aceasta
poate fi incadrata intr -una din cele categorii de distate, insa ce se intampla daca aceata valoare
ar fi 49,99?
Calculatorul ar incadra obiectul ca fiid la o distanta mica insa daca un om ar interpret a
aceasta valoare ca fiind incadra ta altfel?
Logica fuzzy inventata de catre Lotfi Zadeh reuseste sa interpreteze termeni ca aprope,
putin mai apropate si sa incadreze o valoare ca si un om, in exemplul de mai sus din cauza unui
centimetru calculatorul ar fi facut incadrarea ca si cand ar fi aproape. In logica fuzzy conceptul
de aproape sau departe nu este reprezentat ca o valoare discreta ci ca un set fuzzy. Cu aceste
setury fuzzy calculatorul interpreteaza un set de reguli si returneaza un alt set de valo ri care
sunt tot fuzzy insa dupa un proces numit defuzificare aceste valori devin din nou concrete.
Principiul de functionare al unei logici fuzzy ar fi:
Seturi Concrete
Seturile de valori concrete sunt multimi de numere. Fiecare element din multime avand
o apartenenta la multime (grad de apartenenta) care poate fi adevarat sau fals(1 sau 0). Un
numar neputand fi in doua multimi(un numar neputand fi aproape par).
Fuzzificare
Reguli Fuzzy
Defuzzificare
29
Deoarece aceste seturi de valori sunt multimi matematice, operatorii folositi sunt tot
aceeasi ca pentru multimi si anume intersectare, uniune, si complement.
Complement
Complement -ul unei multimi de valori este acea multime de valori care nu sunt
incluse in multime. In programare complementul este echivalent cu operatia NOT
A’ = B
Ᾱ = B
Set Fuzzy
Pentru a exemplifica probleme care apar folosind seturile concrete de valori vom folosi
exemplu prezentat mai sus cu declararea c elor trei distante, apr oape, mediu, departe.
Aproape = {0,1,2,…49}
Medie = {50,51,52 ,…,99}
Departe = {100,101,102,…150}
Problema apare le intersectia dintre tipuri deoarece in cazul valorii 49 si 50 una va fi
considerata apropae iar alta departe dar diferenta dintre ele este doar de 1 m. Daca se folosesc
seturi de valori fuzzy figurile nu vor mai fi dreptunghiulare de ex: 01
010 20 30 40 50 60 70 80 90100 110 120 130 140 150 160Apartenenta
Distanta
Aproape Medie Departe
30
Astfel o valoare nu apartine neaparat unei grupe departe sau aprope. Punand exemplul
nostru cu valori fuzz y va rezulta:
Deci daca avem valoarea 45m aceasta este 20% aproape si 90% la o distanta medie .
Aceasta valoare reprezentand fradul de apartenenta. Functia ar arata de genul:
𝑉𝑎𝑙𝑜𝑎𝑟𝑒 = 𝐹(𝑎𝑝𝑟𝑜𝑎𝑝𝑒 )(45) = 0.2; 𝑉𝑎𝑙𝑜𝑎𝑟𝑒 = 𝐹(𝑀𝑒𝑑𝑖𝑒 )(45) = 0.9
Logica fuzzy foloseste si operatori numiti ‘Hedges’ . Cei mai des intalniti ar fi:
“Foarte”
𝐹𝑓𝑜𝑎𝑟𝑡𝑒 (𝐴)=(𝐹𝐴(𝑥))2; 01Apartenenta
Distanta 01Apartenenta
trapezoidal
01Apartenenta
Curba
0 0.2 0.9
00.10.20.30.40.50.60.70.80.91
0 25 50 75 100 125 150Apartenenta
Distanta
Aproape Medie Departe valoarea noastra
31
“Destul de”
𝐹𝑑𝑒𝑠𝑡𝑢𝑙𝐷𝑒 (𝐴)=√𝐹(𝐴)(𝑥);
Categoriile apr oape, mediu si departe sund de fapt variabile lingvistice fuzzy iar
impreuna constituie un domeniu. Ex:
Distanta = {aproape,mediu,departe};
Miscarea = {PePamant,Pluteste,Zboara};
Importanta = {neiportant,putinImportant,important};
Viteza = {mica, medie,mare};
Forta = {slab, moderata,puternic};
Reguli Fuzzy
Intel igenta fuzzy functioneaza cu ajutorul unor reguli. Daca regulile sunt indeplinite se
apeleaza o anumita functie.
Daca reguli Atunci functii;
Cu cat numarul de reguli este mai mare cu atat actiunea luata de catre un sistem este
mai corecta insa o data cu adaugarea de reguli durata in care ia o decizie creste. Pentru ca
unitatea noastra sa ia decizia daca urmareste o alta unitate ar trebuii sa aiba urmatoarele reguli:
Daca Forta_slab Atunci Urmareste
Daca Forta_destulDeModerata Atunci NuUrmari
Daca Forta_purtnic Atunci NuUrmari
Daca Viteza_mica Atunci Urmareste
Daca Viteza_medie si Forta_slab Urmareste
Daca Viteza_medie sau Forta_puternic Atunci NuUrmari
Daca Viteza_mare Atunci NuUrmari
Pentru calcularea vitezei unei unitati fata de alta unitate se va face un grafic dupa
procentajul dintre vitezele celor doua obiecte. Daca avem inamicul cu viteza de 6m/s si unitatea
noastra cu 8m/s rezulta urmatorul tabel.
32
6/8 = 0.75
Pentru a calcula forta se procedeaza la fel si se ia in calcul tot un procent int re
forta inamicului si unitatea noastra. Luand atacul inamicului ca fiind 7 si al nostru ca fiind
12 avem:
7/12 = 0.58
Deci rezultatul va iesi ca fiind 10% puternic 68% slab si moderat
Operatorul “si” intre conditii este considerat AND si se ia valoarea minima dintre cele
doua, iar operatorul “sau” este considerat OR si in cazul sau se ia valoarea cea mai mare dintre
cele doua.
Cu ajutorul acestor grafice se va analiza fiecare regul: 0 0.6
00.10.20.30.40.50.60.70.80.91
0 25 50 75 100 125 150Apartenenta
Procentaj
mica medie mare valoarea noastra
0 0.1 0.68
00.10.20.30.40.50.60.70.80.91
0 25 50 75 100 125 150Apartenenta
Procentaj
slab moderat puternic valoarea noastra
33
Regula 1) 68% Urma reste
Regula 2) 8.24% NuUrmareste
Regula 3) 10% NuUrmareste
Regula 4) 0% Urmareste
Regula 5) 0% Urmareste
Regula 6)10% NuUrmareste
Regula 7) 60% NuUrmareste
In cazul in care functie a este apelata de mai multe ori se va folosi un operator AND sau
OR in func tie de cum alegem. In cazul nostru vom alege OR. Valorile de 0 fiind ignorate.
Pentru Urmareste avem 68% iar pentru NuUrmareste vom avea :
8.24 OR 10 OR 60 = 60
Defuzzificarea
Aceasta este ultima etapa, care este de fapt inversul fuzzificari, deoarece
calculatorul are nevoie de valori concrete, face actiunea sau nu. Pentru acest lucru exista
mai multe metode prin care se poate face. 01
0 25 50 75 100Apartenenta
Procentaj Urmareste Valoare
01
0 20 40 60 80 100Apartenenta
Procentaj Urmareste
01
0102030405060708090100Apartenenta
Procentaj NuUrmareste Valoare
01
0102030405060708090100Apartenenta
Procentaj NuUrmareste
34
Media Maximelor (MOM)
Aceasta metoda face media dintre maximele valorilor functiilor .
(65+100)/2 = 82.5
La Ac easta metoda apare problema ca luandu -se in calcul doar maxi mele se
igmora partea din grafic care nu este de maxim.
Centroid
Se calculeaza valoarea concreta cu ajutorul centrului de masa al figurii rezultate.Pentru a
face acest lucru se ia figura, se imparte in intervale egale (putem seta noi cat de dese sa
fie intervalele, cu cat sunt mai multe intervale cu atat calculul valori concrete va fi mai
greu dar mai precis) si se ia valoarea din acel interval (DOM) .
Formula dupa care se calculeaza centrul de masa este:
Valoare =∑ 𝑘 𝑥 𝐷𝑂𝑀 (𝑘)𝑘=𝑑𝑜𝑚𝑒𝑛𝑖𝑢𝑀𝑎𝑥𝑖𝑚
𝑘=𝑑𝑜𝑚𝑒𝑛𝑖𝑀𝑚𝑖𝑛𝑖𝑚
∑ 𝐷𝑂𝑀 (𝑘)𝑘=𝑑𝑜𝑚𝑒𝑛𝑖𝑢𝑀𝑎𝑥𝑖𝑚
𝑘=𝑑𝑜𝑚𝑒𝑛𝑖𝑀𝑚𝑖𝑛𝑖𝑚
Nu se calculeaza suma tutoror DOM -urilor de pe interval si doar un numar din ele in
general 10, 15 valori.
66 100
01
0 20 40 60 80 100Apartenenta
Procentaj Urmareste
35
DOM(0) = 0.6;
DOM( 10) = 0.6;
DOM( 20) = 0.6; ∑ 𝑘𝑥𝐷𝑂𝑀 (𝑘)𝑘=100
𝑘=0 = 364.5
DOM( 30) = 0.6;
DOM( 40) = 0.48 + 0.15 ;
DOM( 50) = 0.35 + 0.3 ;
DOM( 60) = 0.56 + 0.1 ;
DOM( 70) = 0.68; ∑ 𝐷𝑂𝑀 (𝑘)𝑘=100
𝑘=0 = 7.06
DOM( 80) = 0.68;
DOM( 90) = 0.68;
DOM( 100) = 0.68; 00.10.20.30.40.50.60.70.80.91
0 10 20 30 40 50 60 70 80 90 100Apartenenta
Procentaj Urmareste NuUrmareste
36
Valoare =∑ 𝑘 𝑥 𝐷𝑂𝑀 (𝑘)𝑘=100
𝑘=0
∑ 𝐷𝑂𝑀 (𝑘)𝑘=100
𝑘=0 = 364 .5
7.06 = 51.62
Media Maxima
Aceasta metoda calculeaza media fiecarui platou si face media acest ora. Formula dupa
care se calculeaza este urmatoarea.
Valoare =∑𝑝𝑟𝑜𝑐𝑒𝑛𝑡𝑎𝑗 𝑥 𝐷𝑂𝑀
∑𝐷𝑂𝑀
Maximele celor doua forme care c onstituie figura noastra ar fi 0.6 la procentaj de 16.5 si
0.68 la procentaj de 82.5 de unde rezulta valoarea noastra. Pozitia la care sunt
considerate dupa ce se calculeaza media este la jumatatea platformei a carei medie a
fost calculata.
Valoare =16.5𝑥0.6:0.68𝑥82.5
0.6: 0.68 = 66
1.28 = 51.56 0.6 0.6 0.68 0.68 0.6 0.68
00.10.20.30.40.50.60.70.80.91
0 10 20 30 40 50 60 70 80 90 100Apartenenta
Procentaj Urmareste NuUrmareste
37
Dupa cum se observa aceasta valoare este foarte apropiata de cea calculata cu metoda
Centroid dar in schimb aceasta metoda este mult mai eficienta din punct de vedere al resurselor
consumate.
Dupa ce am calculat aceasta valoare unitatea noastra a ajuns la concluzia ca 51% nu este
bine sa urmareasca unitatea inamica.
Noi pentru un j oc de strategie in Unity vom folosi trei metode de IA:
– IA impartit pe agenti
– Masina cu stari finite (FSM)
– Inteligenta Fuzzy
IA impartit pe agenti
Aceasta metoda functioneaza ca si gradele din armata. Fiecare agent are un set de
instructiuni pe care trebui e sa le indeplineasca. In cazul nostru exista trei grade dupa care sunt
impartiti agentii. Un mare avantaj al acestei metode este faptul ca putem folosi doar o parte din
IA deoarece fiecare agent se ocupa de ceva anume si poate fi oprit oricand.
Gradul I
In aceasta categorie avem un singur agent, n ucleul IA -ului (“coreAI.js”). Scopul acestui
agent este de a verifica daca ceilalti agenti sunt activi si daca nu sunt , in functie de setarile pe
care le -am facut inainte , sa ne apucam de joc sa porneasca anumiti agenti.
function Update()
{
if (activated && Application.load edLevel != 0 && myBase != null)
{
if (resourceAgent.activated && !resourceManager.activated)
{
resourceManager.activated = true;
resourceManager.GetTasks (resourceAgent.extractorNR,
resourceAgent.minimumResources);
resourceManager.enabled = true;
}
if (attackAgent.activated && !attackManager.activated)
{
attackManag er.activated = true;
38
attackManager.enabled = true;
}
if (buildAgent.activa ted && !buildManager.activated)
{
buildManager.activated = true;
buildManager.enabled = true;
}
If (scoutA gent.activated && !scoutManager.activated)
{
scoutManager.activated = true;
scoutManager.enabled = true;
}
}
}
Pe langa faptul ca el porneste ceilalti agenti le seteaza si o lista de operatii pe care sa le
indeplineasca. De exemplu pentru agent -ul care se ocupa cu strangerea de resurse ii trimite si
numarul maxim de extractoare pe care sa il construiasca cat si resursele minime pe care trebuie
sa le aiba stranse pentru a se apuca de construit .
class ResourceBrain
{
var activated : boolean = true;
var extractorNR : int = 1;
var minimumResources : int = 0;
}
O alta functie pe care o indeplineste este de a colecta toate informatiile de pe harta de
care ar putea avea nevoie ceil alti agenti cum ar fi poztia unde se gasesc mineralele, locurile in
care a descoperit inamicul, nu marul inamicilor . El este atot stiutor insa nu trimite celorlalti agenti
decat informatia pe care se presupune ca o stiu. Pentru a putea strange informatii des pre toate
unitatile care se construiesc in timpul jocului si deoarece nu putem sa verificam permanent
daca se construieste ceva sau nu pentru ca ar consuma multe resurse, fiecare obiect care se
construieste va trimite un eveniment prin care ii spune necleu lui ca sa construit. Acesta ia toate
informatiile necesare despre acesta cum ar fi echipa care la construit sau modul in care merge,
prin aer sau pe jos si il incadreaza intr -o lista de obiecte.
@HideInInspector
var myLandUnits : GameObject[];
39
@HideInInspector
var enemyLandUnits : GameObject[];
@HideInInspector
var myAirUnits : GameObject[];
@HideInInspector
var enemyAirUnits : GameObject[];
Gradul II
In aceasta categorie intra toti agentii pe care ii controleaza dir ect nucleul. Ei iau toate
deciziile mari despre ce se construiest e, ce unitati trebuie sa faca, daca ataca sau nu.
Pentru a indeplini toate functiile necesa re unui joc de strategie am cre at patru agenti.
Agent de Resurse
Acesta are scopul de a se asigura c a in orice moment al jocului exista un numar stabilit
de extractoare care strang resurse. Singura informatie de care dispune el este cate extractoare
are momentan si cate dintre ele fac ceva.
function FixedUpdate()
{
if(Timer(2) && activated)
{
if(extractorNR != -1 && builtext < extractorNR && !genExOnGoing )
GenerateExtractor();
if(idlescv > 0)
GetToWork();
}
}
O data la un interval stabilit el verifica daca numar de e xtractoare pe care l e are este cel
pe care nucleul l -a pus sa il construiasca si daca nu este se apuca sa creeze extractoare. Crea rea
extractorului nu o face acest agent, el decat trimite evenimentul ca are nevoie de un extractor si
asteapta sa primeasca un eveniment ca acesta a fost construit.
GenerateExtractor();
Tot atunci verifica daca un extractor nu are ce sa faca, daca a terminat re sursele din acea
zona si daca gaseste ca nu are ce sa faca il trimite in alta parte.
GetToWork();
40
Agentul de Construit
Acesta are rolul de a construi toate obiectele de care au nevoie ceilalti agenti. Acesta
primeste o lista cu obiecte pe care trebuie sa le construiasca si le ia in ordine tinand cont de
depende ntele fiecarui obiect. Lista de obiecte este definita initial in nucleu.
function Update()
{
if(activated && Timer(4) && !bussy)
{
if(brain.myRace ==1 && brain.buildAgent.maintainedCells > cellBuilt)
BuildCell();
if(building == "")
building = NeedToBuild();
if(building != "")
CreateBuilding(building,"none");
}
}
De fiecare data cand trebuie sa construiasca un obiect verifica lista de la capat pentru ca
nu cumva un obiect construit mai inainte sa fie distrus si in cazul in care acesta este distrus va
trebui sa il refaca.
function NeedToBuild()
{
for (var i : int = 0; i <brain.buildAgent.toBuild[brain.myRace].buildingList.length; i +=1)
for (var j : int = 0; j <whatIHave.length; j +=1 )
if(whatIHave[j])
if(whatIHave[j].name ==
brain.buildAgent.toBuild[brain.myRace].buildingList[i].name)
if(whatIHave[j].howMany <
brain.buildAgent.toBuild[brain.myRace].buildingList[i].howMany)
return wha tIHave[j].name;
return "";
}
La inceput am discutat despre problema care apare atunci cand doua sau mai multe rase
au moduri total diferite de a contrui obiecte. Datorita faptului ca rasa “YX” construieste totul din
celule, atat unitati cat si cladiri, Agentul care le contruieste ar e o problema in a identifica ce tip
de obiect va iesi si din aceasta cauza atunci cand construim un obiect trebuie sa ii dam si tipul
41
acestuia. In functie de tipul obiectului pasii urmati pentru al construi difera . La o unitate se ia
pozitia unei celule si restul de celule necesare pentru a construi unitatea se indreapta spre
aceasta, pe cand la construirea unei cladiri se stabileste o pozitie unde se vrea cladirea si toate
celulele necesara se indreapta spre aceas ta, deoarece o cladire dupa ce a fost construita nu mai
poate fi mutata la aceasta rasa. Pe langa lista de obiecte care o primeste de la nucleu el poate
primi evemnimente prin care ii se cere sa cobnstruiasta un anumit obiect.
Agentul de Atac
Rolul acestui agent este de a gestiona toate unitatile create si sa decida daca trebuie sa
atace sau sa se apere. Actiunile pe care le ia sunt luate in functie de numarul si forta unitatilor
pe care le detine la un moment dat. Ca sa poata sa isi creeze o armata el imparte toate unitatile
in mai multe categorii.
Primele doua mari categorii dupa care le imparte ar fi in functie de modul in care merg si
anume unitati care merg pe pamant si unitati care zboara. In functie de aceste doua categorii el
ataca daca are co nstruite un numar stabilit de catre nucleu de unitati din fiecare categorie.
if(onFlyUnits >= neededAirUnits)
airUnitsReady = true;
else
CreateAir();
if(onLandUnits >= neededGroundUnits)
landUnitsReady = true;
else
CreateLand();
Aceste doua categorii nu sunt de ajuns deoarece un numar de unitati nu poate spune
daca armata creeata este si puternica deoarece el poate sa creeze toate unitatile cele mai sl abe
si chiar daca are mai multe decat inamicu l tot o sa ia bataie, astfel ca pentru a elimina acesata
problema el imparte fiecare categorie de unitati aeriene si pe pamant in subcategorii in functie
de puterea unei unitati. Acum el poate sa creeze unitati si in functie de puterea acestora
deoarece nu cleul ii va preciza clar ca are nevoie de un numar de unitati de putere x.
if(!onAttack)
{
if(creatingAir <= 0 && creatingLand <= 0)
if(flyUnits >= neededAirUnits && landUnits >= neededGroundUnits && prepared >=
neededAirUnits + neededGroundUnits)
{
prepared = 0;
42
onAttack = true;
attackNrOfUnits = flyUnits + landUnits;
GT1Units = 0;
GT2Units = 0;
GT3Units = 0;
A T1Units = 0;
A T2U nits = 0;
A T3Units = 0;
if(currentWave < brain.attackAgent.attackWave.length -1)
{
currentWave += 1;
GetRandomWave(currentWave);
}
DefendToAttack();
StartAttack();
}
}
else
if(attackNrOfUnits == 0)
onAttack = false;
Pentru ca armata sa creasca in putere de la atac la atac nucleul ii va trimite alti parametri
referitori la unitati le pe care sa le construiasca de la atac la atac. Acest lucru se face prin
stabilirea unor val ori din care nucleul va alege unele din ce in ce mai puternice.
Acest agent are si rolul de a trimite ajutor unor unitati sau cladiri daca acestea au nevoie.
Asa ca atunci cand primeste even imen tul prin car e o unitate are nevoie de ajutor el va trimite
toate unitatile care le are asignate pentru apar are sa ajute acea unitate.
Toate unitatile cr eate sunt trecute prima data ca unitati pentru aparare si numai in cazul
in care a strans armata necesara pentru a p utea ataca, o parte din aceste un itati asignate pentru
aparare vor trece ca unitati pentru atac si le va trimite sa atace.
function SendHelp(grp : String, en : GameObject)
Cand se da evenimentul ca are nevoie de ajutor o unitate se specifica si grupul care va fi
trimis sa ajute, cel de aparare sau cel de atac deoarece de exemplu o unitate de atac este
atacata vrem sa o ajute unitatile din grupul sau , nu sa vina cele din baza de aparare sa o ajute.
Agentul Cercetasi
Rolul acestui agent este de a descoperi harta si punctele de interes de pe aceasta cum ar
fi mineralele, baza inamicului, puncte strategice importante si altele.
43
De ce avem nevoie de acest agent daca nucleul stie toate aceste informatii?
Daca jucatorul ar vedea ca IA il ataca exact unde a facut el baza sau daca IA descopera
toate depozitele de minerale rapid s -ar simti inselat ca inamicul stie tot de la inceput asa ca
acest agent are rolul de al pacali pe jucator cum ca IA nu stie nimic si ca si el ca si jucatorul
descopera harta.
Singura informatie folositoare pe care o aduce acest agent este daca a fost sau nu intr -o
anumita zona sau nu, astfel nucleul va putea furniza informatii celorlalti agenti despre acea zona.
if(resBrain.extractorNR+aditionalRes s > known Res && scoutNr > 0 && Delay(5))
FindResources();
if(Timer(brain.scoutAgent.baseScoutInterval+brain.scoutAgent.firstScoutTimer) && scoutNr >0)
ScoutEnemy();
Acest agent va cerceta inamicul periodic ca sa ii dam impresia jucatorului ca tot timpul
are nevoie sa stie ce face.
Gradul III
Daca toti agentii din gradul II lucrau in general cu grupuri de unitati acest grad va lucra cu
unitatile in parte. Singurul agent din acest grad este:
Agentul Multime (Swarm)
Acesta este cel mai de jos tip de agent si el are ca scop sa interpreteze actiunile venite de
la ceilalti agenti pentru a fi utilizate de catre unitatea respectiva.
In afara de a interpreta actiunile venite de la ceilalti agenti el poate da actiuni proprii
unitatii de care este atasat . De e xemplu agentul de construit cre aza o cladi re dar aceasta dupa
ce este creata va sta in locul unde este create, asa ca dupa ce este cre ata si agentul Swarm este
activat va verifica daca acea cladire face ceva si daca nu face ii va da ca actiune sa aterizeze intr –
un loc. S au daca o unitate este atacata acesta este cel care trimite evenimentul prin care cere
ajutor agentului de atac.
function ImBuilding()
{
if(building.noDeploy == false && building.ignoreDeploy == false &&
props.state == "idle")
TryToLand();
if(props.attacked)
attackAI.SendHelp("deff",props.attacker);
}
44
In cazul in care este atasat de o unitate va incerca in functie de tipul de unitate , si anume
cercetasi, extractor sau rest ul de unitati sa ii dea o actiune in cazul in care aceasta nu face
altceva.
In cazul in care unitatea este cercetasi va verifica da ca este atacat si in cazul in care
acesta chiar este atacat il va trimite in baza deoarece cercetasii nu pot ataca.
if(pro ps.state == "attacked")
ReturnToBase();
Pentru extractoare are cam aceeasi functie insa in loc sa il trimita acasa va cere ajutor
fortelor asignate apararii.
if(group == "ext")
{
if(props.attacked)
attackAI.Se ndHelp("deff",props.attacker);
}
Pentru restul unitatilor are rolul de a le trimite pe fiecare la un punct in care sa se
intalneasca pentru a forma grupul de aparare din care atunci cand este necesar agentul de atac
sa isi faca armanta.
if(!prepared && group == "none" && props.state == "idle")
{
GoPrepare();
}
if(!prepared && group == "none" && props.state == "walk" && nav.speed <=0.1)
{
GoPrepare();
}
Dupa cum ati observat in exemple de cod de la f iecare agent in parte acestia sunt
construiti dupa tehnica unei masini cu stari finite(FSM).
Fiecare agent in parte este de fapt o masina cu stari finite care are o serie de valori
predefinite si care au un set de valori de iesire care in functie de anumite conditii va afisa una
dintre acestea.
Avantajul acestei metode combinata cu cea impartita pe agenti este faptul ca atunci
cand apare o problema de depanat este foarte usor . Daca o unitate nu se duce sa atace automat
45
ne gandim ca agentul de atac a intampinat o problema si incep de acolo. Se vor verifica toate
conditiile acestui agent si se poate gasi problema imediat.
Marele dezavantaj al acestei metode este faptul ca de fiecare data cand jucam contra
unui tip de IA vom observa ca va repeta aceeasi pasi tot timpul chiar daca sunt buni sau rai.
Pentru a diminua aceasta problema in continuare vom folosi Inteligenta Fuzzy care va
sparge un pic aceasta monotonie in gandirea IA -ului.
Pentru fiecare actiun e pe care un agent o va incerca rezultatul va fi calculat cu ajutorul
logici fuzzy.
Un exemplu bun ar fi atu nci cand agentul de atac trimite armata sa atace baza inamica si
pe traseu se intalneste cu inamicul care are armata mai puternica decat a lui sau din cauza
pozitionarii acesta ii distruge o parte din armata repede.
Datorita faptului ca acum parametrii s -au schimbat iar armata sa este mult mai mica
logica fuzzy ii va da ca este mai bine sa intrerupa aceasta actiune de atac si ca ar fi bine sa se
retraga.
Putem lua exemplul pentru calcularea fortei unei unitati cu logica Fuzzy si sa il extindem
la tot grupul nostrum. A stfel , daca la inceput forta grupului nostru de atac ar fi fost 20 si
inamicului 15 ar rezulta graficul :
15/20 = 0.75
Luand in calcul doar forta celor doua grupuri de unitati am avea urmatoarele
reguli:
Daca Forta_slab Atunci Ataca 0 0.33 1
00.10.20.30.40.50.60.70.80.91
0 25 50 75 100 125 150Apartenenta
Procentaj
slab moderat puternic valoarea noastra
46
Daca Forta_medie Atunci Ataca
Daca Forta_puternic Atunci NuAtaca
De unde avem :
Regula 1) 0% Ataca
Regula 2) 100% Ataca
Regula 3) 33% NuAtaca
Daca pastram graficele de la Urmareste si de la Nu Urmarteste pentru cazul nostru cu
Ataca sau NuAtaca ne rezulta graficul
Folosi nd metoda Media Maxima ne rezulta:
Valoare =16.5𝑥0.33:1𝑥82.5
0.33: 1 = 87.945
1.33 = 66.12
Daca pe parcursul luptei valoarea fortei noastre ar scadea la 12 si a inamicului ar ramane
constanta. Graficul s -ar schimba si ar rezulta.
0.33 0.33 1 1 0.33 1
00.10.20.30.40.50.60.70.80.91
0 10 20 30 40 50 60 70 80 90 100Apartenenta
Procentaj Ataca NuAtaca
47
Valoare =16.5𝑥0.1:0𝑥66.5
0: 1 = 16.5
1 = 16.5
In acest caz logica Fuzzy ne zice ca ar fi cazul sa nu mai atacam si sa ne retragem.
Pentr u simplificarea calculelor am luat in calcul doar forta dintre cele doua grupuri insa
se pot lua si alti parametrii in calcul pentru ca decizia pe care o luam sa fie mai acurata de
exemplu se poate lua in calcul viteza cu care se regenereaza cele doua arma te si astfel suntem
dispusi sa pierdem unitatile, daca stim ca inamicul nu mai are resurse si noi avem destule si ne
permitem sa facem schimb de unitati sau tipul unitatatilor, degeaba avem forta grupului mai
mare daca noi nu avem unitati cu care sa atacam aerian iar inamicul are unitati aeriene.
O alta utiliz are a logicii fuzzy este la crea rea de unitati. Daca la ultima intalnire cu
inamicul acesta a avut mai multe unitati aeriene deca IA -ul si nu a avut ce sa ii faca , logica fuzzy
va interveni si va supr ascrie numarul de unitati pe care sa le faca agentul de atack. 0 1
00.10.20.30.40.50.60.70.80.91
0 25 50 75 100 125 150Apartenenta
Procentaj
slab moderat puternic valoarea noastra
1 1
0 0 1
0
00.20.40.60.81
0 10 20 30 40 50 60 70 80 90 100Apartenenta
Procentaj Ataca NuAtaca
48
Implementarea logicii fuzzy este facuta in paralele cu celelalte metode astfel inteligenta
artificiala nu va astepta un raspuns de la logica fuzzy si va respecta setul sau de reguli pana va fi
suprascrisa de logica fuzzy.
Exemple scripturi in Unity :
“globals.js”
@script ExecuteInEditMode;
var release : boolean = false;
@HideInInspector
var debuger : boolean = false; // togle for debuger mode
@HideInInspector
var selectedUnits : int = 0; // units selected
@HideInInspector
var selected : T ransform = null; //current selected object or one of the group selected objects
@HideInInspector
var selection : GameObject[] = new GameObject[500]; //GameObject[];
@HideInInspector
var groups = new MultiDim.GOBJArray(10,500); //GameObject[]; control groups
@HideInInspector
var groupProps : int[] = new int[10];
@HideInInspector
var warrior = new Array(); //GameObject[];
@HideInInspecto r
var harvester = new Array(); //GameObject[];
@HideInInspector
var builders = new Array(); //GameObject[];
@HideInInspector
var buildersSelected : int = 0; // number of builders selected;
@HideInInspector
var showHealth : boolean = false; //togle for displaying hp bar
@HideInInspector
var unitType : String; // none ; unit ; building;
@HideInInspector
var markPos : Vector3; // market location clicked;
@HideInInspector
var ongui : boolean = false; // none ; un it ; building;
@HideInInspector
var markT err : boolean = false; // if player is markin terrain for something;
@HideInInspector
var createFog : boolean = false; // none ; unit ; building;
@HideInInspector
49
var ally = MultiDim.IntArray(33,33); // alligence between players
@HideInInspector
var serverPermision : boolean = false; // if server wants that
@HideInInspector
var enemyUnits = new Array(); // enemy units spawned on map
@HideInInspector
var myUnits = new Array(); // my units spawned on map
@HideInInspector
var enemyLastPos : int = 0; // enemy position on enemyUnits array
@HideInInspector
var teamGold : int[] = new int[12]; // starting gold per team
@HideInInspector
var myLastPos : int = 0; // my unit p osition on myUnits array
@HideInInspector
var startPosition : Vector3 = Vector3.zero; // my start position on level
//@HideInInspector
var pathHeight : float = 0.0f; // Flying unit path plane height (current level)
@HideInInspector
var myT eck : Pl ayerT eck[]; // nothing yet
@HideInInspector
var canNavigate : boolean = false; // nothing yet
@HideInInspector
var playerRace : int[] = new int[12]; // what race each player is 1) race 1 ; 2) race cells 3) race unknown
@HideInInspector
var enemyOnMap = MultiDim.IntArray(2000,2000); // position of enemies from meter to meter 0 : none ; 1 : someone there; 2 : enemies there
do something;
@HideInInspector
var lastBuilt : String;
@HideInInspector
var hideEnemy : boolean = true;
@HideInInspector
var constructTime : boolean = false;
@HideInInspector
var noDestroy : GameObject[] = new GameObject[10];
@HideInInspector
var EndGame : int = -1;
@HideInInspector
var globalAddons : glbAddons[];
var nrOfPlayers : pls[] ;
var my Buildings : int = -1; // number of buildings owned
var team : int = 1; // team of this player
var resourceViewDistance : float = 3.0f; // distance from units where you see resources
var pointer : GameObject; // type of pointer displa yed on ground
when moving
var fallHeight : float = -5; // distance where there is no land
var pointerOffset : Vector3; // distance above ground to display the pointer
var jumpT oLevel : boolean = false; // if level loading
var startingGold : int = 100; // player gold
var teamColors : Color[]; // colors for players
var unitTimeTillDestroy : float = 3; // time till the remains of units dissapear
var quePref : T ransform; // que plane transform
var defaultQue : T exture2D;
var defaultEmptySlot : T exture2D; // for buildings who need epty slots
var techT ree : T eck; // what every race can build
var cellName : String = "Cell";
var selectionHalos : selectionHLS; // chage halo depending aliance
50
var sounds : GlobalSound s;
private var cross : GameObject = null; // pointer object created on map (to know if exist)
private var FOW : fog_creator; // fog of war object
private var globalGui : global_gui; // global user interface
private var gameStarted : boolean = false; // at least one enemy has an unit
private var lights : Light[];
private var Snd : AudioSource;
private var spawnPoints : spawnPoint[];
class glbAddons
{
var addons :String[];
var addonNr : int[];
var plat forms : GameObject[];
function glbAddons()
{
addons = new String[20];
addonNr = new int[20];
platforms = new GameObject[200];
}
}
class pls
{
var team : int = 0;
var race : Races = Races.race1;
}
class GlobalSounds
{ var click : AudioClip;
var clickV olume : float = 1.0f;
var fxVolume : float = 1.0f;
var environmentVolume : float = 1.0f;
var voiceVolume :float = 1.0f;
}
class selectionHLS
{
var normalSelection : T exture2D;
var neutralSelection : T exture2D;
var enemySelection : T exture2D ;
}
class PlayerT eck
{
var reqBuilding : String[] = new String[50];
var reqBuildingNr : int[] = new int[50];
}
class T eck
{
var races : RaceUnits[];
}
class RaceUnits
{
var name : String;
var extractor : Unit;
var AirUnits : Unit[];
51
var GroundUnits : Unit[];
var SupportUnits : Unit[];
var Buildings : Unit[];
var Upgrades : Unit[];
}
class Unit
{
var name : String;
var tier : int = 1;
var build : boolean = true;
var needs : NeedUpgrades;
}
class NeedUpgrades
{
var buildings : Need Unit[];
var upgrades : NeedUnit[];
@HideInInspector
var units : NeedUnit[];
var addons : NeedUnit[];
function NeedUpgrades()
{
buildings = new NeedUnit[20];
upgrades = new NeedUnit[20];
addons = new NeedUnit[20];
for (var i : int = 0 ; i< 20;i +=1)
{
buildings[i] = new NeedUnit();
upgrades[i] = new NeedUnit();
addons[i] = new NeedUnit();
}
}
}
class NeedUnit
{
var name : String;
var global : boolean = false;
var need : boolean = false;
function NeedUnit()
{
name = "";
need = false;
}
}
function Awake ()
{
debuger = false;
lastBuilt = "null";
enemyLastPos = 0;
teamGold = new int[12];
playerRace = new int[12];
globalGui = this.gameObject.GetComponent("global_gui");
var tmpdbg : debugGUI;
tmpdbg = this.gameObject.GetComponent("debugGUI");
52
if(!release || Application.isEditor)
{
if(tmpdbg == null)
this.gameObject.AddComponent("debugGUI");
}
else
if(tmpdbg != null)
Destroy(tmpdbg);
if(!jumpT oLevel)
{
Destroy(GameObject.Find("cam") );
Destroy(this.gameObject);
}
if(Application.isEditor)
debuger = true;
FOW = this.transform.GetComponent("fog_creator");
//selection.length = 500;
warrior.length = 500;
builders.length = 500;
enemyUnits.length = 500;
myUnits.length = 500;
Don tDestroyOnLoad (this.gameObject);
for(var i : int = 0; i <= 499; i += 1) // initialize major unit classes
{
selection[i] = null;
warrior[i] = null;
harvester[i] = null;
builders[i] = null;
enemyUnits[i] = "";
myUnits[i] = "";
}
for(var j : int = 0; j <= 32; j += 1) // initialize alligence between players (enemy default)
for(var k : int = 0; k <= 32; k += 1)
ally[j,k] = 0;
for(var l : int = 0; l <= 11; l += 1)
{
teamGold[l]= startingGold;
playerRace[l] = 1;
}
for (var m : int = 0;m<10;m+=1)
noDestroy[m] = null;
GenerateAddons();
SetT echT ree();
Debug.Log("T eck T ree set");
}
function OnLevelWasLoaded (level : int)
{
yield WaitForSeconds (10);
if (level != 0 )
{
lastBuilt = " -1";
}
}
function Update ()
53
{
if(enemyLastPos > 0)
gameStarted = true;
if(Input.GetMouseButtonDown(0))
PlaySound(sounds.click,sounds.clickVolume);
if(Input.GetMouseButtonDown(1))
PlaySound(sounds.click,sounds.clickVolume);
if(EndGame > -1)
{
T estWinLoss(EndGame);
EndGa me = -2;
}
if(enemyLastPos == 0 && gameStarted)
{
gameStarted = false;
var pos : Vector2 = Vector2((Screen.width -100)/2,Screen.height/2);
var mess : String = "Player "+team.T oString()+" Was defeated";
var tm : float = 3;
globalGui.netwo rkView.RPC("ReceiveMessage",RPCMode.AllBuffered,pos.x,pos.y,mess,tm);
}
if(Input.GetMouseButtonUp(1) && !ongui) // if not on button create pointer on terrain
SetPointer();
if(selected == null) // reset unit Type if no object is
select ed
unitType = "none";
if(Input.GetKeyUp(KeyCode.Escape)) // quit application
Application.Quit();
if(Input.GetKeyDown(KeyCode.Q) && !release) // enable/disable debuger mode
debuger = !debuger;
if(debuger) //
debugger commands
DebugFunctions();
}
function DebugFunctions()
{
var i : int ;
if(Input.GetKeyDown(KeyCode.Minus))
if(team >1)
team -= 1;
if(Input.GetKeyUp(KeyCode.Keypad9))
hideEnemy = !hideEnemy;
if(Input.GetKeyUp(KeyCode.Keypad8))
Time.timeSca le += 0.5;
if(Input.GetKeyUp(KeyCode.Keypad7))
Time.timeScale -= 0.5;
if(Input.GetKeyDown(KeyCode.Plus))
if (team < 32)
team += 1;
if(Input.GetKeyDown(KeyCode.Alpha0))
teamGold[team] += 1000;
if(Input.GetKeyUp(KeyCode.Keypad0))
{
54
lights = FindObjectsOfType(typeof(Light)) as Light[];
Debug.Log("Got all the lights in the scene");
}
if(Input.GetKeyUp(KeyCode.Keypad1))
for(i = 0; i<lights.length;i+=1)
lights[i].intensity -= .2;
if(Input.GetKeyUp(KeyCode.Keypad4))
for(i = 0; i<lights.l ength;i+=1)
lights[i].intensity += .2;
if(Input.GetKeyUp(KeyCode.Keypad2))
for(i = 0; i<lights.length;i+=1)
lights[i].range -= .2;
if(Input.GetKeyUp(KeyCode.Keypad5))
for(i = 0; i<lights.length;i+=1)
lights[i].range += .2;
if(Input.GetKeyUp(KeyCo de.Keypad0))
constructTime = !constructTime;
}
function DistT oGround( tr : T ransform,offset : Vector3, dir : Vector3, point : boolean)
{
var fwd = tr.T ransformDirection (dir);
var hit : RaycastHit;
var mask = 1 << 8;
var pt : int;
var dist : int;
Debug.DrawLine(tr.position+offset,tr.position+Vector3(0, -100,0)+offset);
if (Physics.Raycast (tr .position + offset, fwd, hit, 100, mask))
{
dist = tr.position.y – hit.point.y;
pt = hit.point.y;
}
else
{
pt = 0;
dist = -1;
}
if(point)
retu rn pt;
return dist;
}
function SetPointer()
{
var hit : RaycastHit;
var mask = 1 << 8;
var mask2 = 1 << 10;
var heightOffset : float = 0;
var tmpobj : T ransform;
var tmpprp : properties;
var ray : Ray = Camera.main.ScreenPointT oRay (Input.mousePosition);
55
tmpobj = ClickSelect();
if(tmpobj)
tmpprp = tmpobj.GetComponent("properties");
if(!tmpprp)
if (Physics.Raycast(ray,hit,200,mask))
{
if(cross)
Destroy(cross);
//cross = Instantiate(pointer ,hit.point + pointerOffset,Quate rnion.FromT oRotation(Vector3.up,hit.normal));
cross = Instantiate(pointer ,hit.point + pointerOffset,Quaternion.identity);
if (Physics.Raycast(ray,hit,200,mask2))
if(hit.transform.GetComponent(ParticleSystem).isPlaying ||
hit.transform.GetComponent(Pa rticleSystem).isPaused)
{
cross.transform.position = ray.origin +ray.direction*5;
cross.transform.localScale = Vector3(.2,.2,.2);
}
else
cross.transform.T ranslate(0,2 + heightOffset,0);
}
}
function RightClickPosition()
{
var hit : RaycastHit;
var mask = 1 << 8;
var pt : Vector3;
var ray : Ray = Camera.main.ScreenPointT oRay (Input.mousePosition);
if (Physics.Raycast(ray,hit,200,mask))
pt = hit.point;
else
pt = Vector3.zero;
return pt;
}
function CastRay(start : Vector3,dir : Vector3, dist : float, msk : int)
{
var hit : RaycastHit;
var mask = 1 << msk;
var pt : Vector3;
if (Physics.Raycast(start,dir,hit,200,mask))
pt = hit.point;
else
pt = Vector3.zero;
return pt;
}
function RemoveFog(tr : T ransform, radius : float) // removes fog where ther are units
{
var hit : RaycastHit[];
var mask = 1 << 10;
56
var part : ParticleSystem;
var prop : fog_regenerate;
hit = Physics.SphereCastAll(tr.position+Camera.main.transform.forward* -200,radius,Camera.main.transform.forward, 300, mask);
Debug.DrawLine(tr.position,tr .position+Camera.main.transform.forward* -200);
for(var i : int = 0; i < hit.length; i += 1)
{
part = hit[i].transform.gameObject.GetComponent(ParticleSystem);
prop = hit[i].transform.gameObject.GetComponent("fog _regenerate");
if(part.isPaused || part.isStopped)
{
prop.once = true;
prop.hit = true;
part.Stop();
part.Clear();
}
}
}
function ClickSelect()
// returns the transform that it hit (if the coresponding layer is set to the t ransform)
{
var hit : RaycastHit;
var mask = 1 << 9;
var obj : T ransform;
var ray : Ray = Camera.main.ScreenPointT oRay (Input.mousePosition);
if (Physics.Raycast(ray,hit,200,mask))
obj = hit.transform;
else
obj = null;
return obj;
}
function CamGoT o(pos : Vector3)
{
var cam : camera;
var hdist : float;
var camProp : minimap;
cam = GameObject.Find("cam").GetComponent("camera");
camProp = this.gameObject.GetComponent("minimap");
hdist = cam.cameraHeight;
pos -= Camera.main.transform.forward *( hdist/Mathf .Sin(Mathf .Deg2Rad*(90 -cam.viewAngle)));
if(camProp )
{
cam.transform.position = pos;
}
else
cam.transform.position = pos;
}
57
function T estDeploy(obj : T ransform , offset : Vector3 , objectRadius : int ,rampHeightDiff : int , text : boolean)
{
var hit : RaycastHit;
var mask = ~(1 << 12);
var pt1 : int;
var pt2 : int;
var pt3 : int;
var pt4 : int;
var pt5 : int;
if (Physics.Raycast(obj.position + offset,Vector3.down,hit,100,mask))
{
if(hit.transform.gameObject.layer != 8)
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
pt1 = hit.point.y;
}
else
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
if (Physics.Raycast(obj.position + offset +Vector3(objectRadius,0,0),Vector3.down,hit,100,mask))
{
if(hit.transform.gameObject.layer != 8)
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy", 3);
return false;
}
pt2 = hit.point.y;
}
else
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
if (Physics.Raycast(obj.position + offset -Vector3(objectRadius,0,0),Vector3. down,hit,100,mask))
{
if(hit.transform.gameObject.layer != 8)
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
pt3 = hit.point.y;
}
else
{
58
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
if (Physics.Raycast(obj.position + offset +Vector3(0,0,objectRadius),Vector3.down,hit,100,mask))
{
if(hit.transform.gameObject.layer != 8)
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
pt4 = hit.point.y;
}
else
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
if (Physics.Raycast(obj.position + offset -Vector3(0,0,objectRadius),Vector3.down,hit,100,mask))
{
if(hit.transform.gameObject.layer != 8)
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
pt5 = hit.point.y;
}
else
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
if(Mathf .Abs(pt1 – pt2) > rampHeightDiff)
{
if(text)
globalGui.Sen dMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
if(Mathf .Abs(pt1 – pt3) > rampHeightDiff)
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
if(Mathf .Abs(pt1 – pt4) > rampHeightDiff)
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
59
}
if(Mathf .Abs(pt1 – pt5) > rampHeightDiff)
{
if(text)
globalGui.SendMessage(Vector2(Screen.w idth/2,Screen.height/2),"Unable to deploy",3);
return false;
};
if(Mathf .Abs(pt2 – pt3) > rampHeightDiff)
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
if(Mathf .Abs(pt2 – pt4) > rampHeightDiff)
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
if(Mathf .Abs(pt2 – pt5) > rampHeightDiff)
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
if(Mathf .Abs(pt3 – pt4) > rampHeightDiff)
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return f alse;
}
if(Mathf .Abs(pt3 – pt5) > rampHeightDiff)
{
if(text)
globalGui.SendMessage(Vector2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
if(Mathf .Abs(pt4 – pt5) > rampHeightDiff)
{
if(text)
globalGui.SendMessage(Vect or2(Screen.width/2,Screen.height/2),"Unable to deploy",3);
return false;
}
return true;
}
@RPC
function SetT echT ree()
{
60
var tmppos : int = 0;
myT eck = new PlayerT eck[12];
for(var j : int = 0; j < myT eck.length; j+=1 )
{
myT eck[j] = PlayerT eck();
myT eck[j].reqBuilding = new String[100];
myT eck[j].reqBuildingNr = new int[100];
}
for(var k : int = 0; k < myT eck.length; k+=1 )
{
tmppos = 0;
for(var l : int = 0; l < techT ree.races.length; l+=1 )
{
for(var i : int = 0; i < techT ree.rac es[l].Buildings.length; i+=1 )
{
myT eck[k].reqBuilding[tmppos+i] = techT ree.races[l].Buildings[i].name;
myT eck[k].reqBuildingNr[tmppos+i] = 0;
}
tmppos += techT ree.races[l].Buildings.length;
}
}
}
@RPC
function ArrangeEnemy(dead : int)
{
var enpos : properties;
enemyUnits[dead] = enemyUnits[enemyLastPos -1];
enpos = GameObject.Find(enemyUnits[enemyLastPos -1]).GetComponent("properties");
enpos.enPosition = dead;
enemyUnits[enemyLastPos] = null;
enemyLastPos -=1;
}
@RPC
function Arr angeMyUnits(dead : int)
{
var enpos : properties;
if(myLastPos > 0)
{
myUnits[dead] = myUnits[myLastPos -1];
enpos = GameObject.Find(myUnits[myLastPos -1]).GetComponent("properties");
enpos.enPosition = dead;
myUnits[myLastPos] = null;
myLastPos -= 1;
}
}
@RPC
function AddEnemy( en : String)
{
var enpos : properties;
enemyUnits[enemyLastPos] = en;
enpos = GameObject.Find(en).GetComponent("properties");
enpos.enPosition = enemyLastPos;
enemyLastPos +=1;
61
}
@RPC
function AddMyUnit( en : String)
{
var enpos : properties;
myUnits[myLastPos] = en;
enpos = GameObject.Find(en).GetComponent("properties");
enpos.enPosition = myLastPos;
myLastPos +=1;
}
function Dist2D(start : Vector3 , end : Vector3)
{
var dist : float;
dist = Vector2. Distance(Vector2(start.x,start.z),Vector2(end.x,end.z));
return dist;
}
function Dist2D(start : Vector2 , end : Vector2)
{
var dist : float;
dist = Vector2.Distance(start,end);
return dist;
}
function Planar( pos : Vector3)
{
return Vector2(pos.x,pos.z);
}
function PlaySound(sound : AudioClip, volume : float)
{
if(Snd == null)
Snd = this.gameObject.AddComponent(AudioSource);
Snd.volume = volume;
Snd.clip = sounds.click;
Snd.Play();
}
function AddSpawnPoints(sp : spawnPoint[])
{
spawnPoints = sp;
SpawnPlayers();
}
function SpawnPlayers()
{
var j : int = 0;
var k : int = 0;
var l : int = 0;
var tmp : int = 0;
var spp : spawnPoint[] = new spawnPoint[20];
62
var spp2 : spawnPoint[] = new spawnPoint[20];
for(i = 0; i< nrOfPlayers.length;i++)
{
k = 0;
l = 0;
spp = new spawnPoint[20];
spp2 = new spawnPoint[20];
for(j = 0; j<spawnPoints.length;j++)
if(spawnPoints[j].taken == false)
if(spawnPoints[j].race == nrOfPlayers[i].race || spawnPoints[j].race == spaw nPoints[j].race.none)
if(spawnPoints[j].team == nrOfPlayers[i].team || spawnPoints[j].team == 0)
{
spp[k] = spawnPoints[j];
k+=1;
}
for(j = 0; j<k;j++)
{
if(spp[j].team == nrOfPlayers[i].team && spp[j].race == nrOfPlayers[i].ra ce)
{
spp2[l] = spp[j];
l+=1;
}
}
if(l == 0)
for(j = 0; j<k;j++)
{
if(spp[j].team == nrOfPlayers[i].team && spp[j].race == spp[j].race.none)
{
spp2[l] = spp[j];
l+=1;
}
}
if(l == 0)
for(j = 0; j<k;j++)
{
if(spp[j].team == 0 && spp[j].race == nrOfPlayers[i].race)
{
spp2[l] = spp[j];
l+=1;
}
}
if(l == 0)
for(j = 0; j<k;j++)
{
if(spp[j].team == 0 && spp[j].race == spp[j].race.none)
{
spp2[l] = spp[j];
l+=1;
}
}
tmp = Mathf .Round(Random.Range(0,l));
spp2[tmp].PlaceBase(nrOfPlayers[i].team,nrOfPlayers[i].race);
spp2[tmp].taken = true;
}
for(j = 0; j<spawnPoints.length;j++)
Destroy(spawnPoints[j].gameObject);
}
63
function VectorGetPoint(p1 : Vector3, p2 : Vector3, dst : int)
{
var PT : Vector3;
PT = p1+(dst/100.0)*Vector3(p2.x -p1.x,p2.y -p1.y,p2.z -p1.z);
return PT ;
}
function RestartGame(delay : float)
{
yield WaitForSeconds (delay);
for(var i : int = 0; i < noDestroy.length; i += 1)
if(noDestroy[i] != null)
{
Debug.Log("Destroy Undestroyable "+noDestroy[i]);
Destroy(noDestroy[i]);
}
Destroy(this.gameObject);
}
function OnDestroy()
{
Application.LoadLevel(0);
}
function AddNoDestroy(ob : GameObject)
{
for(var i : int = 0; i < noDestroy.length; i += 1)
if(noDestroy[i] == null)
{
noDestroy[i] = ob;
break;
}
}
function T estWinLoss(tm : int)
{
//Debug.Log(tm +" ====== "+team);
if(tm != team)
{
yield WaitForSeconds (3);
globalGui.winDefeatMaterial.mainT exture = g lobalGui.winT exture;
globalGui.winT exture.Stop();
globalGui.victory = 1;
globalGui.winT exture.Play();
}
if(tm == team)
{
yield WaitForSeconds (3);
globalGui.winDefeatMaterial.mainT exture = globalGui.defeatT exture;
globalGui.defeatT exture.Stop();
globalGui.victory = -1;
globalGui.defeatT exture.Play();
}
64
}
function GlobalEvent(key : KeyCode)
{
var obj : properties[];
obj = new properties[2000];
if(key == KeyCode.H)
{
obj = FindObjectsOfType(properties);
if(obj)
for(var i : int = 0;i< obj .length;i+=1)
{
if(obj[i] == null || !obj[i])
break;
obj[i].KeyPressEvent(key);
}
}
}
function AddGlobalAddon(tm : int , adds : String)
{
for(var i:int=0;i<20;i+=1)
{
if(globalAddons[tm].addons[i] == "")
{
globalAddons[tm].addons[i] = adds;
globalAddons[tm].addonNr[i] += 1;
break;
}
else
if(globalAddons[tm].addons[i] == adds)
globalAddons[tm].addonNr[i] += 1;
}
}
function GenerateAddons()
{
globalAddons = new glbAddons[12];
var i : int = 0;
var j : int = 0;
for (i=0;i<12;i+=1)
{
globalAddons[i] = new glbAddons();
for (j=0;j<20;j+=1)
{
globalAddons[i].addons[j] = "";
globalAddons[i].addonNr[j] = 0;
}
for (j=0;j<200;j+=1)
globalAddons[i].platforms[j] = null;
}
}
function UseAddon(tm : int , obj : GameObject)
{
for(var i:int=0;i<200;i+=1)
65
if(globalAddons[tm].platforms[i] == null)
{
globalAddons[tm].platforms[i] = obj;
break;
}
}
function GlobalRequires(tm : int)
{
var bp : building_properties;
for(var i:int=0;i<200;i+=1)
if(globalAddons[tm].platforms[ i] !=null)
{
bp = globalAddons[tm].platforms[i].GetComponent("building_properties");
bp.Requires();
}
}
function RemoveAddon(tm : int , obj : String)
{
for(var i:int=0;i<20;i+=1)
if(globalAddons[tm].addons[i] == obj)
globalAddons[tm].addonNr[i] -= 1;
}
“pathfinder.js”
#pragma strict
/////////////////////////////////////////////////////////////////////
/// Creates a rout for the unit ///
/// and sets the walking/flying heig ht of the unit ///
/////////////////////////////////////////////////////////////////////
@HideInInspector
var selected : boolean = false; // if this object is selected
@HideInInspector
var tempHeight : float;
@HideInInspector
var mesh : NavMeshA gent; //navmesh on witch unit is walkin/flying
@HideInInspector
var canMove : boolean = true;
@HideInInspector
var mySpeed : float;
var target : GameObject ; // where to go
var hover : boolean = false; // if unit is flyer
var smoothHeight : boolean = true; // unit decend smooth if true
var movementHeight : float = 0; // height between nav mesh and object
var heightDecSpeed : float = 0.3; // smooth factor
var objectRadius : float = 4; // unit radius (boundin g box) for ahead rayhiting
private var tmp : float = 0;
66
private var global : globals; //global game variables and functions
private var mouseMovement : mouse_actions; // mouse actions script
private var unitScript : unit_properties; // null if its a building
private var buildingScript : building_properties; // null if its a unit
private var netAction : task_manager; // sends action through the network
private var minimap : minimap; // minimap properties
private var props : properties ; // core properties of objects
private var obstacle : NavMeshObstacle;
private var once : boolean = false;
function Awake ()
{
tempHeight = movementHeight;
}
function Start ()
{
// getting values from other scripts or components;
global = GameOb ject.Find("globals").GetComponent("globals");
mesh = this.GetComponent(NavMeshAgent);
mesh.radius = objectRadius;
mySpeed = mesh.speed;
mouseMovement = GameObject.Find("globals").GetComponent("mouse_actions");
unitScript = this.gameObject.GetComponent("unit_properties");
buildingScript = this.gameObject.GetComponent("building_properties");
netAction = GameObject.Find("globals").GetComponent("task_manager");
minimap = GameObject.Find("globals").GetComponent("minimap");
props = this.gameObject.GetComponent("properties");
}
function Update ()
{
if(props.objectType == 1 && !once)
{
once = true;
obstacle = this.gameObject.AddComponent(NavMeshObstacle);
obstacle.radius = objectRadius;
}
// testing distance till ground if unit is flyer
if (hover && this.GetComponent(NavMeshAgent).enabled)
{
if (global.DistT oGround(this.transform, this.transform.forward * (objectRadius + 2),Vector3.down,false) <
movementHeight )
{
tmp = heightDecSpeed;
if(smoothHeight)
this.GetComponent(NavMeshAgent).baseOffset += tmp;
else
this.transform.position = Vector3(this.transform.position.x, movementHeight +
global.DistT oGround(this.transform,this.transform.forward*2,Vector3.down,true), this.transform.position.z);
}
else
{
if(buildingScript)
if(movementHeight == 0)
67
if (global.DistT oGround(this.transform, Vector3.zero,Vector3.down,false) > movementHeight )
this.GetComponent(NavMeshAgent).baseOffset -= heightDecSpeed;
}
// if (global.DistT oGround(t his.transform,this.transform.forward * (objectRadius + 2),Vector3.down,true) > global.fallHeight
&& global.DistT oGround(this.transform, this.transform.forward * (objectRadius + 2), Vector3.down,false) > movementHeight &&
global.DistT oGround(this.transform, this.transform.forward, Vector3.down,false) > movementHeight)
if (global.DistT oGround(this.transform, Vector3.zero,Vector3.down,false) > movementHeight )
{
tmp = -heightDecSpeed;
if(smoothHeight)
this.GetComponent(NavMeshAgent).baseOffset += t mp;
else
this.transform.position = Vector3(this.transform.position.x, movementHeight +
global.DistT oGround(this.transform, this.transform.forward * 2,Vector3.down, true), this.transform.position.z);
}
}
if(canMove)
if(unitScript)
{
if(selected && unitScript.team == global.team )
if(props.spawn == false)
{
if(Input.GetMouseButtonDown(1) && !global.ongui)
{
netAction.networkView.RPC("Move",RPCMode.AllBuffered,this.gameObject.name,
mouseMovement.MouseT erPosition());
props.playerMoveOrder = true;
}
if(Input.GetMouseButtonDown(1) && global.ongui && minimap.onMinimap)
{
netAction.networkView.RPC("Move",RPCMode.AllBuffered,this.gameObject.name,
minimap.PosT oMap(Input.mousePosition));
props.player MoveOrder = true;
}
}
}
else
if(selected && buildingScript.team == global.team )
if(props.spawn == false)
{
if(Input.GetMouseButtonDown(1) && !global.ongui)
{
netAction.networkView.RPC("Move",RPCMode.AllBuffered,this.game Object.name,
mouseMovement.MouseT erPosition());
}
if(Input.GetMouseButtonDown(1) && global.ongui && minimap.onMinimap)
{
netAction.networkView.RPC("Move",RPCMode.AllBuffered,this.gameObject.name,
minimap.PosT oMap(Input.mousePosition));
}
}
}
function SetDestination(destination :Vector3)
{
var canMove : boolean = false;
68
if(unitScript)
{
canMove = true;
props.state = "walk";
}
if(buildingScript)
if(props.state == "idle" || props.state == "walk" || props.state == "fire1")
{
canMove = true;
props.state = "walk";
}
if(canMove && props.dead == false )
{
var nav : NavMeshAgent;
nav = this.GetComponent(NavMeshAgent);
nav.SetDestination(destination);
nav.speed = mySpeed;
if(unitScript)
{
if(unitScript .movementT ype != mv.Ground)
destination += Vector3(0,global.pathHeight,0);
}
else
{
if(buildingScript.movementType != mv.Ground)
destination += Vector3(0,global.pathHeight,0);
}
this.GetComponent(NavMeshAgent).SetDestination(destination); // setting destination and starts moving
yield WaitForSeconds(.2);
this.GetComponent(NavMeshAgent).SetDestination(destination); // setting destination and starts moving
}
if(unitScript)
{
canMove = true;
props.state = "walk";
}
if(buildingScript)
if(props.state == "idle" || props.state == "walk")
{
canMove = true;
props.state = "walk";
}
}
function SetDestinationSPD(destination :Vector3,spd : float)
{
var canMove : boolean = false;
if(unitScript)
{
canMove = true;
props.state = "walk";
}
if(buildingScript)
69
if(props.state == "idle" || props.state == "walk")
{
canMove = true;
props.state = "walk";
}
if(canMove && props.dead == false )
{
var nav : NavMeshAgent;
nav = this.GetComponent(NavMeshAgent);
nav.SetDestination(destination);
nav.speed = spd;
if(unitScript)
{
if(unitScript.movementT ype != mv.Ground)
destination += Vector3(0,global.pathHeight,0);
}
else
{
if(buildingScript.movementType != mv.Ground)
destination += Vector3(0,global.pathHeight,0);
}
this.GetComponent(NavMeshAgent).SetDestination(destination); // setting destination and starts moving
yield WaitForSeconds(.2);
this.GetComponent(NavMeshAgent).SetDestination(destination); // setting destination and starts moving
}
if(unitScript)
{
canMove = true;
props.state = "walk";
}
if(buildingScript)
if(props.state == "idle" || props.state == "walk")
{
canMove = true;
props.state = "walk";
}
}
“properties.js”
#pragma strict
@HideInInspector
var enPosition : int;
@HideInInspector
70
var attacker : GameObject;
@HideInInspector
var unitPrefab : GameObject;
@HideInInspector
var attacked : boolean = false;
//@HideInInspector
var state : String;
@HideInInspector
var attackMove : boolean = false;
@HideInInspector
var onHit : boolean = false;
@HideInInspector
var spawn : boolean = false;
@HideInInspector
var movement : mv = mv.none;
@HideInInspecto r
var type : tps;
@HideInInspector
var objectType : int = 0; // 0 = none ; 1 = building ; 2 = unit;
@HideInInspector
var helping : boolean = false;
71
@HideInInspector
var defaultSpeed : float = 0.0f;
@HideInInspector
var haloSelect : boolean = false;
@HideInInspector
var canRetaliate : boolean = true;
@HideInInspector
var enPositionMp : Vector3 = Vector3.zero;
@HideInInspector
var myT arget : GameObject = null;
@HideInInspector
var swrm : swarmAI;
@HideInInspector
var myLights : Component[];
@HideInInspector
var playerMoveOrder : boolean = false;
@HideInInspector
var playerAttackOrder : boolean = false;
@HideInInspector
var retaliating : boolean = false;
72
@HideInInspector
var resourceT arget : GameObject;
var myName : String = "";
var senzorArea : int = 20;
var team : int = -1;
var unitTier : int = 1;
var dead : boolean = false;
var extractor : boolean = false;
var support : boolean = false;
var imBase : boolean = false;
var imScout : boolean = false;
var visible : boolean = false;
var destroySound : GameObject;
private var global : globals;
private var min1 : Vector3;
private var unitAction : unit_actions;
private var detect : boolean = false;
private var brain : coreAI;
private var attackAI : attackingAI;
private var mouse : mouse_act ions;
private var lights : boolean = true;
private var fx : Component[];
private var inT rigger : boolean;
private var last : float;
private var getT eam : boolean = true;
private var myTime : int;
private var globalGui : global_gui;
private var played : boolean = false;
private var path : pathfinder;
73
private var obstacle : NavMeshObstacle;
private var unit_props : unit_properties;
private var building_props : building_properties;
private var once : boolean = false;
private var dbg : debugGUI;
function Aw ake ()
{
team = -1;
myTime = Time.frameCount;
if(GameObject.Find("globals"))
{
global = GameObject.Find("globals").GetComponent("globals");
brain = GameObject.Find("globals").GetComponent("coreAI");
mouse = GameObject.Find("globals").GetComponent ("mouse_actions");
globalGui = GameObject.Find("globals").GetComponent("global_gui");
swrm = this.transform.GetComponent("swarmAI");
attackAI = GameObject.Find("globals").GetComponent("attackingAI");
dbg = GameObject.Find("globals").GetComponent("d ebugGUI");
}
min1 = GameObject.Find("minimap1").transform.position;
unitAction = this.gameObject.GetComponent("unit_actions");
unit_props = this.gameObject.GetComponent("unit_properties");
building_props = this.gameObject.GetComponent("building_prop erties");
path = this.gameObject.GetComponent("pathfinder");
myLights = GetComponentsInChildren(Light);
fx = GetComponentsInChildren(T ransform);
if(building_props != null)
building_props.T estHp();
if(unit_props != null)
74
unit_props.T estHp();
}
function OnDrawGizmosSelected ()
{
// Draw a yellow sphere at the transform's position
Gizmos.color = Color .yellow;
Gizmos.DrawSphere (transform.position, senzorArea);
}
function Update()
{
once = true;
var others : Collider[];
if(destroySound && d ead && !played)
{
played = true;
Instantiate(destroySound,this.transform.position,Quaternion.identity);
}
if(Mathf .Round((Time.frameCount – myTime)%3) ==0)
{
if(getT eam)
{
if(team != -1)
{
var halo : T ransform;
getT eam = false;
T eckAdd();
global.lastBuilt = this.gameObject.name;
if(imBase)
if(team == brain.myT eam)
75
brain.SetBase(this.gameObject);
halo = this.transform.FindChild("select_halo");
if(halo && team != global.team)
halo.renderer .material.mainT exture = global.selectionHalos.enemySelection;
}
}
others = Physics.OverlapSphere(this.transform.position,senzorArea,LayerMask.GetMask("selectable"));
Senzors(others);
if(global.hideEnemy)
{
if(team != global.team && team != 0 && team != -1 && visible)
if(T est())
{
visible = false;
lights = true;
}
if(team == global.team && team != 0 && team != -1)
{
visible = true;
lights = false;
}
if(visible)
{
if(!lights)
T urnOn();
lights = true;
}
76
else
{
if(lights)
T urnOff();
lights = false;
}
}
else
{
T urnOn();
visible = true;
}
}
}
function Empty(pos : Vector3)
{
var posOnMx : int;
var posOnMz : int;
posOnMx = Mathf .Round(pos.x – min1.x);
posOnMz = Mathf .Round(pos.z – min1.z);
global.enemyOnMap[posOnMx,posOnMz] = 0;
}
function Senzors (others : Collider[])
{
if(myT arget == null || state == "idle")
{
77
playerAttackOrder = false;
}
for(var i : int = others.length -1;i>= 0;i -=1)
{
var props : properties;
props = others[i].gameObject.GetComponent("properties");
if(props)
if(props.team != team && team != 0 && team != -1)
{
if(props && unitAction && props.dead == false && !playerMoveOrder && !playerAttackOrder && !retaliating)
if(myT arget == null)
{
myT arget = others[i].gameObject;
if(attackMove == true || state == "fire1" || state == "idle" || state == "deployed")
if(unitAction.T estAttack(others[i].transform))
if(objectType != 1)
unitAction.StartAttack(others[i].transform);
else
{
if(unitAction.attackRange >
Vector3.Distance(this.transform.position,others[i].transform.position))
{
unitAction.StartAttack(others[i].transform);
if(swrm)
swrm.walkT arget = Vector3.zero;
}
}
}
else
78
{
if(attackMove == true || state == "fire1" || state == "idle" || state == "deployed")
if(unitAction.T estAttack(myT arget.transform))
if(objectType != 1)
unitAction.StartAttack(myT arget.transform);
else
{
if(unitAction.attackRange >
Vector3.Distance(this.transform.position,myT arget.transform.position))
{
unitAction.StartAttack(myT arget.transform);
if(swrm)
swrm.walkT arget = Vector3.zero;
}
else
myT arget = null;
}
}
props.visible = true;
props.last = 0;
}
}
}
function Retaliate(other : GameObject)
{
var props : properties;
if(other)
props = other .gameObject.GetComponent("properties");
if(props && unitAction)
79
if(props.team != team && team != 0 && team != -1)
{
if(unitAction.T estAttack(other .transform))
{
onHit = false;
// if(swrm)
// swrm.walkT arget = Vector3.zero;
unitAction.StartAttack(other.transform);
}
else
path.SetDestination(other.transform.position);
}
}
function OnDestroy()
{
var rsp : extractor_actions;
var ress : resource_properties;
if(dead)
{
brain.Destroyed(this.gameObject,team,objectType);
if(imBase)
{
brain.RemoveBase(this.gameObject);
if(global.EndGame == -1)
global.EndGame = team;
}
if(objectType == 1)
for(var i : int = 0; i < building_props.addons.length; i+=1)
if(building_props.addons[i].built)
80
{
global.RemoveAddon(team,bu ilding_props.addons[i].name);
global.GlobalRequires(team);
}
}
if(extractor == true)
{
rsp = this.transform.GetComponent("extractor_actions");
if(ress)
{
ress = rsp.resourceHarvested.GetComponent("resource_properties");
ress.useable = true;
}
}
if(swrm)
{
if(swrm.prepared && swrm.group == "deff")
attackAI.prepared -= 1;
if(swrm.prepared)
if(attackAI.attackSpeed <= path.mySpeed)
attackAI.attackSpeed = 0;
if(swrm.group == "attk")
attackAI.RemoveUnit(this.gameObject);
if(swrm.group == "def")
if(unit_props)
{
if(unit_props.movementT ype == mv.Air)
{
attackAI.flyUnits -= 1;
81
attackAI.onFlyUnits -= 1;
if(unitTier == 1)
attackAI.A T1Units -=1;
if(unitT ier == 1)
attackAI.A T2Units -= 1;
if(unitTier == 1)
attackAI.A T3Units -= 1;
}
if(unit_props.movementT ype == mv.Ground)
{
attackAI.landUnits -= 1;
attackAI.onLandUnits -= 1;
if(unitTier == 1)
attackAI.GT1Units -=1;
if(unitTier == 1)
attackAI.GT2Units -= 1;
if(unitTier == 1)
attackAI.GT3Units -= 1;
}
}
}
globalGui.RemoveUnit(myName);
ClearUnit(this.gameObject,type);
mouse.ClearSelection(this.gameObject);
ClearGroup();
}
function ResetT arget()
{
82
var coll : SphereCollider[];
coll = this.gameObject.GetComponents.<SphereCollider>();
for (var cl : SphereCollider in coll)
if(cl.isT rigger == true)
{
cl.enabled = false;
cl.enabled = true;
}
}
function ClearUnit(unit : GameObject, tp : tps)
{
var obj : GameObject;
var ind : int;
obj = null;
switch (tp)
{
case tps.warrior :
for (var i : int = 499 ;i >= 0; i -= 1)
{
if(global.warrior[i] != null && obj == null)
{
obj = global.warrior[i];
ind = i;
}
if(global.warrior[i] == unit)
83
{
global.warrior[i] = global.warrior[ind];
global.warrior[ind] = null;
break;
}
}
break;
case tps.harvester :
for (var j : int = 499 ;j >= 0; j -= 1)
{
if(global.harvester[j] != null && obj == null)
{
obj = global.harvester[j];
ind = j;
}
if(global.harvester[j] == unit)
{
global.harvester[j] = global.harvester[ind];
global.harvester[ind] = null;
break;
}
}
break;
case tps.builder :
for (var k : int = 499 ;k >= 0; k -= 1)
{
if(global.builders[k] != null && obj == null)
{
obj = global.builders[k];
ind = k;
84
}
if(global.builders[k] == unit)
{
global.builders[k] = global.builder s[ind];
global.builders[ind] = null;
break;
}
}
break;
}
}
function RegisterUnit()
{
var uprops : unit_properties;
var type : tps;
uprops = this.gameObject.GetComponent("unit_properties");
if(uprops)
type = uprops.type;
if(uprops)
if (global.team == uprops.team)
{
if(type == tps.warrior)
{
var k : int = 0;
while(global.warrior[k] != null && k < 499)
{
if(k < 499)
85
k += 1;
}
if(global.warrior[k] == null)
global.warrior[k] = this.gameObject;
}
if(type == tps.harvester)
{
var i : int = 0;
while(global.harvester[i] != null && i < 499)
{
if(i < 499)
i += 1;
}
if(global.harvester[i] == null)
global.harvester[i] = this.game Object;
}
if(type == tps.builder)
{
var j : int = 0;
while(global.builders[j] != null && i < 499)
{
if(j < 499)
j += 1;
}
86
if(global.builders[j] == null)
global.builders[j] = this.gameObject;
}
}
}
function T urnOff()
{
var lg : Light;
var fxs : T ransform;
for(lg in myLights)
lg.enabled = false;
for(fxs in fx)
{
if(fxs.name == "lightFX")
fxs.gameObject.SetActive(false);
if(fxs.GetComponent(Renderer))
fxs.renderer.enabled = fal se;
}
}
function T urnOn()
{
var lg : Light;
var fxs : T ransform;
for(lg in myLights)
lg.enabled = true;
87
for(fxs in fx)
{
if(fxs.name == "lightFX")
fxs.gameObject.SetActive(true);
if(fxs.GetComponent(Renderer) && fxs.name != "deploy" && fxs.name != "health" && fxs.name != "construction" &&
fxs.name != "select_halo")
fxs.renderer.enabled = true;
}
}
function T est()
{
if(last <= 1.5)
{
last += Time.deltaTime;
return false;
}
else
{
last = 0;
return true;
}
}
function T e ckAdd()
{
for(var i : int = 0; i< 50; i+= 1)
{
if(global.myT eck[team].reqBuilding[i] == myName)
{
global.myT eck[team].reqBuildingNr[i] += 1;
88
return;
}
if(global.myT eck[team].reqBuilding[i] == "" || global.myT eck[team].reqBuilding[i] == null)
return;
}
for(var j : int = 0; j< 50; j+= 1)
{
if(global.myT eck[team].reqBuilding[j] == "" || global.myT eck[team].reqBuilding[j] == null)
{
global.myT eck[team].reqBuilding[j] = myNam e;
global.myT eck[team].reqBuildingNr[j] += 1;
return;
}
if(global.myT eck[team].reqBuilding[j] == "" || global.myT eck[team].reqBuilding[j] == null)
global.myT eck[team].reqBuildingNr[j] = 0;
}
}
function ClearGroup()
{
}
funct ion HaloSelect()
{
var halo : T ransform;
var i : int = 0;
halo = this.transform.FindChild("select_halo");
haloSelect = true;
while(i<4)
89
{
halo.renderer .enabled = true;
yield WaitForSeconds(.1);
halo.renderer .enabled = false;
yield WaitForSeconds(.1);
i++;
}
haloSelect = false;
}
function PlaySound(snd : AudioClip, source : AudioSource, loop : boolean, volume : float)
{
if(source == null)
source = this.gameObject.AddComponent(AudioSource);
source.rolloffMode = AudioRolloffMo de.Linear;
source.volume = volume;
source.minDistance = 20;
source.maxDistance = 200;
source.loop = loop;
source.clip = snd;
source.Play();
}
function StopSound(source : AudioSource)
{
if(source != null)
source.Stop();
}
function KeyPressEvent(key : KeyCode)
90
{
if(key == KeyCode.H)
{
if(unit_props != null)
unit_props.T estHp();
if(building_props != null)
building_props.T estHp();
}
}
“minimap.js”
#pragma strict
var minimapLocation : mp = mp.Left;
var minimapScale : float = 25;
var min1 : Vector3 = Vector3.zero;
var min2 : Vector3 = Vector3.zero;
var mapHeight : float;
var mapWidth : float;
var mapLocation : Vector2;
var minimapT exture : T exture;
var border : T exture;
var onMinimap : boolean = false;
var viewWidth : float = 0;
var viewHeight : float = 0;
var fogOfWar : T exture2D;
var default_mask : T exture2D;
var material : Material;
var fog = MultiDim.IntArray(257,257);
var onMapPic : T exture2D;
var onMapPicEn : T exture2D;
var onMapPicRes : T exture2D;
var timeOffset : Vector2 = Vector2.zero;
var timeFont : int = 12;
@HideInInspector
var minimapLength : int = 250;
private var timeStyle : GUIStyle;
private var global : globals;
private var cam : camera;
private var oldPos : Vector3 = Vector3.zero;
private var txtr : T exture2D;
private var cl : Color[];
private var clr : Color;
91
private var global_gui : global_gui;
private var redraw : boolean = true;
enum mp {Left,Right};
function Awake ()
{
material.SetT exture("_AlphaMap",default_mask);
material.SetT exture("_MainT ex",fogOfWar);
global = GameObject.Find("globals").GetComponent("globals");
global_gui = GameObject.Find("globals").GetComponent("global_gui");
cam = GameObject.Find("cam").GetComponent("camera");
minimapLength = Screen.hei ght/(100/minimapScale);
fog = new MultiDim.IntArray(minimapLength,minimapLength);
timeStyle = new GUIStyle(global_gui.popupStyle);
txtr = material.GetT exture("_AlphaMap");
cl = txtr.GetPixels();
txtr = new T exture2D(minimapLength,minimapLength);
for(var k:int=0;k< minimapLength;k++)
for(var j:int=0;j< minimapLength;j++)
fog[k,j] = 1;
for (var i : int = 0; i<cl.Length; i++)
{
clr = cl[i];
clr.a = 255;
}
txtr.SetPixels(cl);
SetMapProperties();
SetMinimapProperties();
timeFont = Mathf .Round(timeFont*(Screen.width/1920.0));
timeStyle.alignment = T extAnchor.UpperLeft;
timeStyle.fontSiz e = timeFont;
}
function TimeElapsed()
{
var h : int;
var m : int;
var s : int;
var tmr : String;
var tm : int;
tm = Mathf .Floor(Time.time);
h = Mathf .FloorT oInt(tm/3600);
m = Mathf .FloorT oInt(tm/60);
s = Mathf .FloorT oInt(tm – (h*3600) – (m*60));
if(h> 9)
tmr = h.T oString();
else
tmr = "0"+h.T oString();
if(m> 9)
92
tmr += " : " + m.T oString();
else
tmr += " : 0" + m.T oString();
if(s> 9)
tmr += " : " + s.T oString();
else
tmr += " : 0" + s.T oString();
return tmr;
}
function Update()
{
if(redraw)
SetAlpha();
}
function SetAlpha()
{
redraw = false;
for(var i:int=0;i<minimapLength;i++)
{
for(var j:int=0;j< minimapLength;j++)
{
if(fog[i,j] == 0)
txtr.SetPixel(i,j,Color(0,0,0,0));
else
txtr.SetPixel(i,j,Color(255,255,255,255));
fog[i,j] = 1;
}
if(i % 4 == 0)
yield;
}
cl = txtr.GetPixels();
txtr.Apply();
// Debug.Log("Got Here");
material.SetT exture("_AlphaMap",txtr);
redraw = true;
}
function OnGUI()
{
GUI.depth = 3;
if(min1 != Vector3.zero && Camera.main.farClipPlane > 1)
{
GUI.Label(Rect( timeOffset.x -(timeOffset.x*(1 –
Screen.width/1920.0)),timeOffset.y*(Screen.height/1080.0),200,200),TimeElapsed(),timeStyle);
if(Event.current.type.Equals(EventType.Repaint))
{
Graphics.DrawT exture(Rect(mapLocation.x -2,mapLocation.y -2,minimapLength+4,minimapLength +4),border);
Graphics.DrawT exture(Rect(mapLocation.x,mapLocation.y,minimapLength,minimapLength),minimapT exture,Rect(0,0,1,1),0,0,0,0);
Graphics.DrawT exture(Rect(mapLocation.x,mapLocation.y,minimapLength,minimapLength),fogOfWar,Rect(0,0,1,1),0,0,0,0, material);
93
}
}
if(T estMouse(Rect(mapLocation.x,mapLocation.y,minimapLength,minimapLength)))
{
onMinimap = true;
global.ongui = true;
if(Input.GetMouseButton(0) && Vector3.Distance(Input.mousePosition , oldPos) > 3)
{
oldPos = Input.mousePosition;
if(T estPosOnMap(Input.mousePosition))
global.CamGoT o(PosT oMap(Input.mousePosition));
}
}
else
onMinimap = false;
}
function T estPosOnMap(pos : Vector3)
{
var rct : Rect;
rct = Rect(mapLocation.x+viewWidth/2,mapLocation.y+ viewHeight/2,minimapLength -viewWidth,minimapLength -viewHeight);
if(rct.Contains(Vector2(pos.x,Screen.height – pos.y)))
return true;
else
return false;
}
function T estMouse(bt : Rect)
{
if(bt.Contains(Vector2(Input.mousePosition.x, Screen.height – Input.mousePosition.y)))
return true;
else
return false;
}
function GetPosition(obj1 : GameObject)
{
var objPos : Vector2;
var normPos : Vector2;
if(min1 == Vector3.zero)
SetMinimapProperties();
objPos.y = obj1.transform.position.z – min1.z;
objPos.x = obj1.transform.position.x – min1.x;
normPos.y = objPos.y/mapHeight;
normPos.x = objPos.x/mapWidth;
return (mapLocation + Vector2(normPos.x * minimapLength, minimapLength – normPos.y * minimapLength));
}
function SetMapProper ties()
{
if(minimapLocation == mp.Left)
mapLocation = Vector2(5,Screen.height -5 – minimapLength);
else
94
mapLocation = Vector2(Screen.width – minimapLength – 20,Screen.height -20 – minimapLength);
}
function SetMinimapProperties()
{
if(Application.loadedLevel != 0)
{
min1 = GameObject.Find("minimap1").transform.position;
min2 = GameObject.Find("minimap2").transform.position;
mapHeight = Mathf .Abs(min2.z – min1.z);
mapWidth = Mathf .Abs(min2.x – min1.x);
}
}
function PosT oMap (mousePosition : Vector3)
{
var mapPos : Vector3;
var hit : RaycastHit;
if(Application.loadedLevel != 0)
{
mapPos = (Vector3(mousePosition.x,0,mousePosition.y) –
Vector3(mapLocation.x,0,Screen.height – mapLocation.y – minimapLength))/minimap Length;
mapPos.z = mapPos.z * mapHeight;
mapPos.x = mapPos.x * mapWidth;
mapPos.z = mapPos.z + min1.z;
mapPos.x = mapPos.x + min1.x;
mapPos.y = cam.cameraHeight;
var mask = 1 << 12;
if (Physics.Raycast (mapPos,Vector3.down,hit,100,mask))
mapPos = hit.point;
return mapPos;
}
}
“coreAI.js”
#pragma strict
@script RequireComponent(resourceAI);
@script RequireComponent(attackingAI);
@script RequireComponent(builderAI);
@script RequireComponent(scoutAI);
@HideInInspector
var myLandUnits : GameObject[];
@HideInInspector
var enemyLandUnits : GameObject[];
@HideInInspector
var myAirUnits : GameObject[];
@HideInInspector
var enemyAirUnits : GameObject[];
@HideInInspector
var myScvs : GameObject[];
95
@HideInInspector
var enemyScvs : GameObject[];
@HideInInspector
var myScouts : GameObject[];
@HideInInspector
var enemyScouts : GameObject[];
@HideInInspector
var myBuildings : GameObject[];
@HideInInspector
var enemyBuildings : GameObject[];
@HideInInspector
var mapResources : GameObject[];
@HideInIn spector
var mapResourcesIdle : int[];
@HideInInspector
var myRace : int;
@HideInInspector
var activated : boolean = true;
@HideInInspector
var resourceManager : resourceAI;
@HideInInspector
var attackManager : attackingAI;
@HideInInspector
var buildManage r : builderAI;
@HideInInspector
var scoutManager : scoutAI;
@HideInInspector
var targetedEnemy : GameObject;
@HideInInspector
var myBase : GameObject;
var myRaceName : String = "";
var myT eam : int ;
var resourceAgent : ResourceBrain;
var attackAgent : AttackBrain;
var buildAgent : BuildBrain;
var scoutAgent : ScoutBrain;
var raceNames : RacessNames[];
var enemyBase : GameObject[];
private var global : globals;
class ResourceBrain
{
var activated : boolean = true;
var extractorNR : int = 1;
var minimu mResources : int = 0;
}
class RacessNames
{
var name : String = "";
var extractor : String = "";
var scout : String = "";
var airUnits : String[];
var landUnits : String[];
var supportUnits : String[];
var buildings : String[];
}
96
class AttackBrain
{
var activated : boolean = true;
var attackWave : AttackLST[];
}
class BuildBrain
{
var activated : boolean = true;
var minimumResources : int = 150;
var maintainedCells : int = 15;
var toBuild : BuildNr[];
}
class ScoutBrain
{
var ac tivated : boolean = true;
var scoutNr : int = 1 ;
var priorityEnemy : boolean = false;
var scoutRange : int = 25;
var firstScoutTimer : int = 60;
var baseScoutInterval : int = 300;
var maxScoutsOnRes : int = 1;
var knownStartingRess : int = 2;
}
class BuildNr
{
var raceName : String = "";
var buildingList : bldLst[];
}
class bldLst
{
var name : String;
var howMany : int = 1;
}
class AttackLST
{
var nrOfAirUnits : int = 2;
var airTier1 : int = -1;
var airTier2 : int = -1;
var airTier3 : int = -1;
var nrOfLandUnits : int = 2;
var landTier1 : int = -1;
var landTier2 : int = -1;
var landTier3 : int = -1;
var wavePriority : int = 1;
}
function Awake ()
{
myT eam = 2;
global = GameObject.Find("globals").GetComponent("globals");
resourceM anager = GameObject.Find("globals").GetComponent("resourceAI");
attackManager = GameObject.Find("globals").GetComponent("attackingAI");
buildManager = GameObject.Find("globals").GetComponent("builderAI");
97
scoutManager = GameObject.Find("globals").GetComponent("scoutAI");
myLandUnits = new GameObject[200];
enemyLandUnits = new GameObject[200];
myAirUnits = new GameObject[200];
enemyAirUnits = new GameObject[200];
myScvs = new GameObject[200];
enemyScvs = new GameObje ct[200];
myScouts = new GameObject[200];
enemyScouts = new GameObject[200];
myBuildings = new GameObject[200];
enemyBuildings = new GameObject[200];
mapResources = new GameObject[200];
mapResourcesIdle = new int[200];
enemyBase = new GameObject[20] ;
GetMyRace();
for( var i : int = 0; i <200; i+=1)
{
myLandUnits[i] = null;
enemyLandUnits[i] = null;
myAirUnits[i] = null;
enemyAirUnits[i] = null;
myScvs[i] = null;
enemyScvs[i] = null;
myScouts[i] = null;
enemyScouts[i] = null;
myBuildings[i] = null;
enemyBuildings[i] = null;
mapResources[i] = null;
mapResourcesIdle[i] = 0;
}
}
function Update()
{
if(activated && Application.loadedLevel != 0 && myBase != null)
{
if(resourceAgent.activated && !resourceManager.activat ed)
{
resourceManager.activated = true;
resourceManager.GetT asks(resourceAgent.extractorNR,resourceAgent.minimumResources);
resourceManager.enabled = true;
}
if(attackAgent.activated && !attackManager .activated)
{
attackManager .activate d = true;
attackManager .enabled = true;
}
if(buildAgent.activated && !buildManager.activated)
{
buildManager.activated = true;
buildManager.enabled = true;
}
if(scoutAgent.activated && !scoutManager .activated)
{
98
scoutManager .activated = true;
scoutManager .enabled = true;
}
}
}
function CollectObject(obj : GameObject)
{
var props : properties;
var i : int;
var air : boolean = false;
var land : boolean = false;
var extractor : extractor_actions;
extract or = obj.GetComponent("extractor_actions");
props = obj.GetComponent("properties");
if(props.myName == global.cellName)
buildManager.GetUnitType(obj,global.cellName);
if(extractor)
if(props.team == myT eam)
resourceManager.AddSCV(obj,0);
else
resourceManager.AddSCV(obj,1);
if(props.imScout)
if(props.team == myT eam)
scoutManager .AddScout(obj,0);
else
scoutManager .AddScout(obj,1);
if(props.movement == mv.none)
Debug.Log("Movement was not initialized");
if(props.team == 0 || props.team == -1)
Debug.Log("T eam number was not initialized");
if(!extractor && !props.imScout)
{
////////////////Get all Objects that fly ////////////////////
if(props.movement == mv.Air && !props.support)
{
if(props.objectType == 2)
if(props.team == myT eam)
for(i = 0; i <200; i += 1)
{
if(myAirUnits[i] == null)
{
myAirUnits[i] = obj;
break;
}
}
else
for(i = 0; i <200; i += 1)
{
if(enemyAirUnits[i] == null)
{
enemyAirUnits[i] = obj;
break;
}
}
99
if(props.objectType == 1)
if(props.team == myT eam)
for(i = 0; i <200; i += 1)
{
if(myBuildings[i] == null)
{
myBuildings[i] = obj;
buildManager.BuildingAdded(props.myName);
break;
}
}
else
for(i = 0; i <200; i += 1)
{
if(enemyBuildings[i] == null)
{
enemyBuildings[i] = obj;
break;
}
}
}
//////////////// //////////////////////////////////////////////
////////////////Get all Objects that are on ground////////////
if(props.movement == mv.Ground && !props.support)
{
if(props.objectType == 2)
if(props.team == myT eam)
for(i = 0; i <200; i += 1)
{
if(myLandUnits[i] == null)
{
myLandUnits[i] = obj;
break;
}
}
else
for(i = 0; i <200; i += 1)
{
if(enemyLandUnits[i] == null)
{
enemyLandUnits[i] = obj;
break;
}
}
if(props.objectType == 1)
if(props.team == myT eam)
for(i = 0; i <200; i += 1)
{
if(myBuildings[i] == null)
{
myBuildings[i] = obj;
buildManager.BuildingAdded(props.myName);
break;
}
}
else
100
for(i = 0; i <200; i += 1)
{
if(enemyBuildings[i] == null)
{
enemyBuildings[i] = obj;
break;
}
}
}
//////////////////////////////////////////////////////////////
//////////////// Get all Objects that are hybrid///////////////
if(props.movement == mv.AirAndGround && !props.support)
{
if(props.objectType == 2)
if(props.team == myT eam)
{
for(i = 0; i <200; i += 1)
{
if(myLandUnits[i] == null && !land)
{
myLandUnits[i] = obj;
land = true;
}
if(myAirUnits[i] == null && !air)
{
myAirUnits[i] = obj;
air = true;
}
if(air && land)
break;
}
air = false;
land = false;
}
else
{
for(i = 0; i <200; i += 1)
{
if(enemyLandUnits[i] == null && !land)
{
enemyLandUnits[i] = obj;
land = true;
}
if(enemyAirUnits[i] == null && !air)
{
enemyAirUnits[i] = obj;
air = true;
}
if(air && land)
break;
}
air = false;
land = false;
}
if(props.objectType == 1)
if(props.team == myT eam)
101
for(i = 0; i <200; i += 1)
{
if(myBuildings[i] == null)
{
myBuildings[i] = obj;
buildManager.BuildingAdded(props.myName);
break;
}
}
else
for(i = 0; i <200; i += 1)
{
if(enemyBuildings[i] == null)
{
enemyBuildings[i] = obj;
break;
}
}
}
//////////////////////////////////////////////////////////////
}
}
function Destroyed(obj : GameObject, team : int, type : int)
{
var extractor : extractor_actions;
var unitpos : int = -1;;
var i : int;
var props : properties;
extractor = obj.GetComponent("extractor_actions");
props = obj.GetComponent("properties");
if(extractor)
if(props.team == myT eam)
resourceManager.RemoveSCV(obj,0);
else
resourceManager.RemoveSCV(obj,1);
if(props.imScout)
if(props.team == m yT eam)
scoutManager .RemoveScout(obj,0);
else
scoutManager .RemoveScout(obj,1);
if(team == myT eam)
{
if(type == 1)
{
for(i = 0; i <200; i += 1)
{
if(myBuildings[i] == obj)
{
unitpos = i;
buildManager.BuildingRemoved(props.myName);
}
if(myBuildings[i] == null && unitpos != -1)
if(i>0)
myBuildings[unitpos] = myBuildings[i -1];
102
else
myBuildings[unitpos] = null;
}
unitpos = -1;
}
if(type == 2)
{
for(i = 0; i <200; i += 1)
{
if(myLandUnits[i] == obj)
unitpos = i;
if(myLandUnits[i] == null && unitpos != -1)
if(i>0)
myLandUnits[unitpos] = myLandUnits[i -1];
else
myLandUnits[unitpos] = null;
}
unitpos = -1;
for(i = 0; i <200; i += 1)
{
if(myAirUnits[i] == obj)
unitpos = i;
if(myAirUnits[i] == null && unitpos != -1)
if(i>0)
myAirUnits[unitpos] = myAirUnits[i -1];
else
myAirUnits[unitpos] = null;
}
unitpos = -1;
}
}
else
{
if(type == 1)
{
for(i = 0; i <200; i += 1)
{
if(enemyBuildings[i] == obj)
unitpos = i;
if(enemyBuildings[i] == null && unitpos != -1)
if(i>0)
enemyBuildings[unitpos] = enemyBuildings[i -1];
else
enemyBuildings[unitpos] = null;
}
unitpos = -1;
}
if(type == 2)
{
for(i = 0; i <200; i += 1)
{
if(enemyLandUnits[i] == obj)
unitpos = i;
103
if(enemyLandUnits[i] == null && unitpos != -1)
if(i>0)
enemyLandUnits[unitpos] = enemyLandUnits[i -1];
else
enemyLandUnits[unitpos] = null;
}
unitpos = -1;
for(i = 0; i <200; i += 1)
{
if(enemyAirUnits[i] == obj)
unitpos = i;
if(enemyAirUnits[i] == null && unitpos != -1)
if(i>0)
enemyA irUnits[unitpos] = enemyAirUnits[i -1];
else
enemyAirUnits[unitpos] = null;
}
unitpos = -1;
}
}
}
function AddResources(obj : GameObject)
{
for(var i : int = 0;i <200;i += 1)
if(mapResources[i] == null)
{
mapResources[i] = obj;
mapResourcesIdle[i] = 0;
break;
}
}
function AddBase(obj : GameObject)
{
var props : properties;
props = obj.GetComponent("properties");
if(props.team != myT eam)
for(var i : int = 0;i <20;i += 1)
if(enemyBase[i] == null)
enemyBase [i] = obj;
}
function RemoveBase(obj : GameObject)
{
var id : int;
var props : properties;
props = obj.GetComponent("properties");
if(props.team == myT eam)
for(var i : int = 0;i <20;i += 1)
{
if(enemyBase[i] == null && i > 0)
104
enemyBase[id] = enemyBase[i -1];
if(enemyBase[i] == obj)
{
enemyBase[i] = null;
id = i;
}
}
}
function MakeEnemy()
{
for(var i : int = 0;i <20;i += 1)
if(enemyBase[i] != null)
{
targetedEnemy = enemyBase[i];
break;
}
}
function SetBase(obj : Gam eObject)
{
myBase = obj;
if(myT eam == 2)
buildManager.cellMakers[0] = obj;
}
function GetMyRace()
{
for(var j: int = 0;j<global.nrOfPlayers.length;j+=1)
if(global.nrOfPlayers[j].team == myT eam)
myRaceName = global.nrOfPlayers[j].race.T oString();
for( var k : int = 0; k <raceNames.length; k+=1)
if(myRaceName == raceNames[k].name)
{
myRace = k;
break;
}
}
“attackingAI.js”
#pragma strict
var activated : boolean = false;
@HideInInspector
var flyUnits : int ;
@HideInInspector
var landUnits : int;
@HideInInspector
var createLand : boolean = false;
@HideInInspector
var createAir : boolean = false;
@HideInInspector
105
var creatingLand : int = 0;
@HideInInspector
var creatingAir : int = 0;
@HideInInspector
var prepared : int = 0;
@HideInInspe ctor
var attackSpeed : float = 0.0f;
@HideInInspector
var preparePoint : Vector3 = Vector3.zero;
@HideInInspector
var onAttack : boolean = false;
@HideInInspector
var onLandUnits : int = 0;
@HideInInspector
var onFlyUnits : int = 0;
@HideInInspector
var GT1Units : int = 0;
@HideInInspector
var GT2Units : int = 0;
@HideInInspector
var GT3Units : int = 0;
@HideInInspector
var A T1Units : int = 0;
@HideInInspector
var A T2Units : int = 0;
@HideInInspector
var A T3Units : int = 0;
@HideInInspector
var currentTier : int = -1;
private var brain : coreAI;
private var global : globals;
private var idle : boolean = false;
private var swarm : swarmAI;
private var airUnitsReady : boolean = false;
private var landUnitsReady : boolean = false;
private var tm : float = 0.0f;
private var timePassed : float = 0.0f;
private var enemyBase : GameObject = null;
private var builder : builderAI;
private var attackForce : GameObject[];
private var defendForce : GameObject[];
private var attackNrOfUnits : int = 0;
106
private var currentWave : int;
private var neededAirUnits : int;
private var neededGroundUnits : int;
function Awake ()
{
brain = GameObject.Find("globals").GetComponent("coreAI");
global = GameObject.Find("globals").GetComponent("globals");
builder = GameOb ject.Find("globals").GetComponent("builderAI");
idle = true;
attackForce = new GameObject[100];
defendForce = new GameObject[100];
currentWave = 1;
GetRandomWave(1);
ResetAttacker();
}
function Update ()
{
if(activated && Application.loadedLevel != 0 && Timer(2))
{
if(enemyBase == null)
{
enemyBase = brain.enemyBase[0];
if(enemyBase != null)
preparePoint = global.VectorGetPoint(brain.myBase.transform.position,enemyBase.transform.position,20);
}
if(onFlyUnits >= neededAirUnits)
airUnitsReady = true;
else
CreateAir();
if(onLandUnits >= neededGroundUnits)
landUnitsReady = true;
else
CreateLand();
if(onLandUnits > landUnits && creatingLand == 0)
onLandUnits =landUnits;
if(onFlyUnits > flyUnits & & creatingAir == 0)
onFlyUnits =flyUnits;
if(!onAttack)
{
if(creatingAir <= 0 && creatingLand <= 0)
if(flyUnits >= neededAirUnits && landUnits >= neededGroundUnits && prepared >= neededAirUnits
+ neededGroundUnits)
{
prepared = 0;
onAttack = true;
attackNrOfUnits = flyUnits + landUnits;
GT1Units = 0;
GT2Units = 0;
GT3Units = 0;
A T1Units = 0;
A T2Units = 0;
A T3Units = 0;
if(currentWave < brain.attackAgent.attackWave.length -1)
107
{
currentWave += 1;
GetRandomWave(currentWave);
}
DefendT oAttack();
StartAttack();
}
}
else
if(attackNrOfUnits == 0)
onAttack = false;
}
}
function T estT eck(unit : String, tp : String)
{
var i : int = 0;
var j : int = 0;
var k : int = 0;
var bldTier : int = -1;
for (i = 0; i <global.techT ree.races.length ; i +=1)
{
if (global.techT ree.races[i].name == brain.myRaceName)
{
if(tp == "AirUnit")
{
if(brain.attackAgent.attackWave[currentWave -1].airTier1 != -1)
if(brain.attackAgent.attackWave[currentWave -1].airTier1 > A T1Units)
bldTier = 1;
if(brain.attackAgent.attackWave[currentWave -1].airTier2 != -1)
if(brain.attackAgent.attackWave[currentWave -1].airTier2 > A T2Units)
bldTier = 2;
if(brain.at tackAgent.attackWave[currentWave -1].airTier3 != -1)
if(brain.attackAgent.attackWave[currentWave -1].airTier3 > A T3Units)
bldTier = 3;
for (k = 0; k < global.techT ree.races[i].AirUnits.length ; k += 1)
{
if(unit == global.techT ree.races[i] .AirUnits[k].name)
{
if(bldTier != -1)
if(global.techT ree.races[i].AirUnits[k].tier != bldTier)
return false;
for(j = 0; j < global.techT ree.races[i].AirUnits[k].needs.buildings.length ; j += 1)
if(T estBuilding(global.techT ree.races[i].AirUnits[k].needs.buildings[j].name)
== false)
return false;
currentTier = bldTier;
break;
}
}
}
k = 0;
j = 0;
bldTier = -1;
if(tp == "GroundUnit")
{
108
if(brain.attackAgent.attackWave[currentWave -1].landTier1 != -1)
if(brain.attackAgent.attackWave[currentWave -1].landTier1 > GT1Units)
bldTier = 1;
if(brain.attackAgent.attackWave[currentWave -1].landTier2 != -1)
if(brain.attackAgent.attackWav e[currentWave -1].landTier2 > GT2Units)
bldTier = 2;
if(brain.attackAgent.attackWave[currentWave -1].landTier3 != -1)
if(brain.attackAgent.attackWave[currentWave -1].landTier3 > GT3Units)
bldTier = 3;
for (k = 0; k < global.techT ree.races[ i].GroundUnits.length ; k += 1)
{
if(unit == global.techT ree.races[i].GroundUnits[k].name)
{
if(bldTier != -1)
if(global.techT ree.races[i].GroundUnits[k].tier != bldTier)
return false;
for(j = 0; j < global.techT ree.races[ i].GroundUnits[k].needs.buildings.length ; j += 1)
if(T estBuilding(global.techT ree.races[i].GroundUnits[k].needs.buildings[j].name) == false)
return false;
currentTier = bldTier;
break;
}
}
}
break;
}
}
return true;
}
function T estBuilding(bld : String)
{
for (var i : int = 0; i <builder .whatIHave.length ; i +=1)
if(builder.whatIHave[i].name == bld)
if(builder.whatIHave[i].howMany > 0)
return true;
else
return false;
}
function GetUnits()
{
var isAttacking : boolean;
var prp : swarmAI;
for (var i : int = 0; i < 200; i += 1)
{
if(brain.myLandUnits[i] != null && brain.myLandUnits[i].GetComponent("swarmAI"))
{
prp = brain.myLandUnits[i].GetComponent("swarmAI");
isAttacking = prp.attacking;
if(!isAttacking)
landUnits = i+1;
}
if(brain.myAirUnits[i] != null && brain.myAirUnits[i].GetComponent("swarmAI"))
109
{
prp = brain.myAirUnits[i].GetComponent("swarmAI");
isAttacking = prp.attacking;
if(!isAttacking)
flyUnits = i+1;
}
}
}
function CreateLand()
{
var props : building_properties;
var unitName : String;
var found : boolean = false;
currentTier = -1;
unitName = WantT oBuild("land");
if(brain.myRace == 0)
for(var i : int = 0; i <= 99;i += 1)
{
if(found)
break;
if (brain.myBuildings[i] != null)
{
props = brain.myBuildings[i].GetComponent("building_properties");
for(var k : int = 0; k < props.units.length;k += 1)
if(props.units[k] != null)
if(props.units[k].unitName == unitName && props.units[ k].unitCost <=
global.teamGold[brain.myT eam])
{
if(props.props.state == "deployed" || props.ignoreDeploy == true)
if(props.T estQue())
{
props.units[k].buttonPressed = true;
props.imBuilding = true;
createLand = true;
onLandUnits += 1;
creatingLand += 1;
found = true;
break;
}
}
}
else
break;
}
else
if(brain.myRace == 1)
{
builder.CreateBuilding(unitName,"land");
}
}
function CreateAir()
{
var props : building_properties;
110
var unitName : String;
currentTier = -1;
unitName = WantT oBuild("air");
if(brain.myRace == 0 )
for(var i : int = 0; i <= 99;i += 1)
{
if (brain.myBuildings[i] != null)
{
props = brain.myBuildings[i].GetComponent("building_properties");
for(var k : int = 0; k < props.units.length;k += 1)
if(props.units[k] != null)
if(props.units[k].unitName == unitName && props.units[k].unitCost <=
global.teamGold[brain.myT eam])
{
if(props.props.state == "deployed" || props.ignoreDeploy == true)
if(props.T estQue())
{
props.units[k].buttonPressed = true;
props.imBuilding = true;
createAir = true;
if(currentTier == 1)
A T1Units +=1;
if(currentTier == 2)
A T2Units +=1;
if(currentTier == 3)
A T3Units +=1;
if(currentTier == 1)
GT1Units +=1;
if(currentTier == 2)
GT2Units +=1;
if(currentTier == 3)
GT3Units +=1;
onFlyUnits += 1;
creatingAir += 1;
break;
}
}
}
else
break;
}
else
if(brain.myRace == 1 )
{
builder.CreateBuilding(unitName,"air");
}
}
function WantT oBuild(what : String)
{
var nr : float ;
var passed : boolean = false;
var tryes : int = 0;
if(what == "land")
{
while(!passed)
111
{
nr = Mathf .Floor(Random.Range(0.1,brain.raceNames[brain.myRace].landUnits.Length – 0.1f));
passed = T estT eck(brain.raceNames[brain.myRace].landUnits[nr],"GroundUnit");
tryes +=1;
if(tryes >= 100)
return "";
}
return brain.raceNames[brai n.myRace].landUnits[nr];
}
if(what == "air")
{
while(!passed)
{
nr = Mathf .Floor(Random.Range(0.1,brain.raceNames[brain.myRace].airUnits.Length -0.1f));
passed = T estT eck(brain.raceNames[brain.myRace].airUnits[nr],"AirUnit");
tryes +=1;
if(tryes >= 100)
return "";
}
return brain.raceNames[brain.myRace].airUnits[nr];
}
}
function StartAttack()
{
for (var i : int = 0; i < 100; i += 1)
{
if(attackForce[i] != null)
{
swarm = attackForce[i].GetComponent("swarmAI");
swarm.attack = true;
yield WaitForSeconds (.2);
}
}
}
function AttackStarted()
{
airUnitsReady = false;
landUnitsReady = false;
flyUnits = 0 ;
landUnits = 0;
onLandUnits = 0;
onFlyUnits = 0;
}
function Timer(orderTimer : float)
{
tm += Time.deltaTime;
timePassed = tm;
if(tm >= orderTimer)
{
tm = 0;
return true;
}
else
return false;
112
}
function AttackerAdd(unit : GameObject)
{
for(var i : int = 0;i<100; i+=1)
if(attackForce[i] == null)
{
attackForce[i] = unit;
break;
}
}
function DefenderAdd(unit : GameObject)
{
for(var i : int = 0;i<100; i+=1)
if(defendForce[i] == null)
{
defendForce[i] = unit;
break;
}
}
function ResetA ttacker()
{
for(var i : int = 0;i<100; i+=1)
attackForce[i] = null;
}
function ResetDefender()
{
for(var i : int = 0;i<100; i+=1)
defendForce[i] = null;
}
function DefendT oAttack()
{
ResetAttacker();
var swrm : swarmAI;
for(var i : int = 0;i<100; i+=1)
{
if(defendForce[i] != null)
{
swrm = defendForce[i].GetCo mponent("swarmAI");
swrm.group = "attk";
swrm = null;
attackForce[i] = defendForce[i];
}
}
ResetDefender();
}
function RemoveUnit(unit : GameObject)
{
for(var i : int = 0;i<100; i+=1)
{
if(attackForce[i] == unit)
{
attackForce[i] = attackForce[attackNrOfUnits -1];
113
attackForce[attackNrOfUnits -1] = null;
attackNrOfUnits -= 1;
break;
}
if(attackForce[i] == null)
break;
}
}
function SendHelp(grp : String, en : GameObject)
{
var prp : properties;
var i : int;
if(grp == "attk")
{
for(i = 0;i < 100; i+=1)
{
if(attackForce[i] != null)
{
prp = attackForce[i].GetComponent("properties");
if(!prp.attacked)
{
prp.helping = true;
prp.myT arget = en;
prp.Retaliate(en);
}
}
else
break;
}
}
if(grp == "deff")
{
for(i = 0;i < 100; i+=1)
{
if(defendForce[i] != null)
{
prp = defendForce[i].GetComponent("properties");
if(!prp.attacked)
{
prp.helping = true;
prp.myT arget = en;
prp.Retaliate(en);
}
}
else
break;
}
}
}
function T estNeedHelp(grp : String)
{
114
var prp : properties;
if(grp == "attk")
{
for(var i : int = 0;i<100; i+=1)
{
if(attackForce[i] != null)
{
prp = attackForce[i].GetComponent("p roperties");
if(prp.state != "walk" || prp.state != "idle")
return true;
}
else
return false;
}
return false;
}
}
function GetRandomWave(priority : int)
{
var wavesT oRandom : int[];
var found : int = -1;
var waveT oBuild : int = 0;
wavesT oRandom = new int[40];
for(var i : int = 0;i < brain.attackAgent.attackWave.length;i+=1)
if(brain.attackAgent.attackWave[i].wavePriority == priority)
{
found +=1;
wavesT oRandom[found] = i;
}
if(found >= 0)
waveT oBuild = Mathf .Ro und(Random.Range(0.0F , found));
neededAirUnits = brain.attackAgent.attackWave[wavesT oRandom[waveT oBuild]].nrOfAirUnits;
neededGroundUnits = brain.attackAgent.attackWave[wavesT oRandom[waveT oBuild]].nrOfLandUnits;
}
“builderAI.js”
#pragma strict
var activated : boolean = false;
@HideInInspector
var whatIHave : Buildings[];
@HideInInspector
115
var cellMakers : GameObject[];
@HideInInspector
var cells : GameObject[];
@HideInInspector
var cellBuilt : int = 0;
@HideInInspector
var buildFxProps : fx_ properties;
@HideInInspector
var finished : boolean = true;
private var global : globals;
private var brain : coreAI;
private var bussy : boolean = false;
private var building : String = "";
private var tm : float = 0.0f;
private var timePassed : float = 0.0f;
private var gotT eck : boolean = false;
private var buildFx : GameObject;
private var lastBuild : String = "";
private var atkAI : attackingAI;
class Buildings
{
var name : String = "";
var howMany : int = 0;
function Buildings()
116
{
name = "";
howMany = 0;
}
}
function Awake ()
{
brain = GameObject.Find("globals").GetComponent("coreAI");
global = GameObject.Find("globals").GetComponent("globals");
atkAI = GameObject.Find("globals").GetComponent("attackingAI");
GetT eck();
cellMakers = new GameObject[5];
cells = new GameObject[30];
for(var j : int = 0;j < 30;j+=1)
cells[j] = null;
}
function GetT eck()
{
for (var i : int = 0; i <global.techT ree.races.length ; i +=1)
{
if (global.techT ree.races[i].name == brain.myRaceName)
{
whatIHave = new Buildings[10];
for (var k : int = 0; k < global.techT ree.races[i].Buildings.length ; k += 1)
{
whatIHave[k] = Buildings();
whatIHave[k].name = global.techT ree.races[i].Buildings[k].name;
whatIHave[k].howMany = 0;
gotT eck = true;
117
}
break;
}
}
}
function Update()
{
if(activated && Timer(4) && !bussy)
{
if(brain.myRace ==1 && brain.buildAgent.maintainedCells > cellBuilt)
BuildCell();
if(building == "")
building = NeedT oBuild();
if(building != "")
CreateBuilding(building,"none");
}
}
function NeedT oBuild()
{
for (var i : int = 0; i <brain.buildAgent.toBuild[brain.myRace].buildingList.length; i +=1)
for (var j : int = 0; j <whatIHave.length; j +=1)
if(whatIHave[j])
if(whatIHave[j].name == brain.buildAgent.toBuild[brain.myRace].buildingList[i].name)
if(whatIHave[j].howMany <
brain.buildAgent.toBuild[brain.myRace].buildingList[i].howMany)
return whatIHave[j].name;
return "";
}
118
function Timer(orderTimer : float)
{
tm += Time.deltaTime;
timePassed = tm;
if(tm >= orderTimer)
{
tm = 0;
return true;
}
else
return false;
}
function BuildingAdded( bd : String)
{
if(!gotT eck)
GetT eck();
for (var i : int = 0; i <whatIHave.Length ; i +=1)
if(whatIHave[i])
if(whatIHave[i].name == bd)
{
whatIHave[i].howMany += 1;
bussy = false;
break;
}
}
function BuildingRemoved( bd : String)
{
for (var i : int = 0; i <whatIHave.length ; i +=1)
if(whatIHave[i])
119
if(whatIHave[i].nam e == bd)
whatIHave[i].howMany -= 1;
}
function CreateBuilding(unitName : String,unitT p : String)
{
var props : building_properties;
var cb : can_build;
var bldloc : Vector3;
var srm : swarmAI;
var i : int = 0;
var k : int = 0;
var j : int = 0;
switch (brain.myRace)
{
/////////////////////// FOR RACE 1 /////////////////////////////////////
case 0 :
for(i = 0; i <= 99;i += 1)
{
if (brain.myBuildings[i] != null)
{
props = brain.myBuildings[i].GetComponent("building_properties");
for(k = 0; k < props.units.length;k += 1)
if(props.units[k] != null)
if(props.units[k].unitName == unitName && (props.units[k].unitCost +
brain.buildAgent.minimumResources) <= global.teamGold[brain.myT eam])
{
if(props.props.state == "deployed" || props.ignoreDeploy == true)
{
120
props.units[k].buttonPressed = true;
props.imBuilding = true;
bussy = true;
building = "";
break;
}
}
}
else
break;
}
break;
//////////////////////////////////////// ///////////////////////////////////
////////////////////////// FOR RACE 2 /////////////////////////////////////
case 1:
var m : int = 0;
if(finished && lastBuild == "")
for(i = 0; i < cells.length;i += 1)
if(cells[i] !=null)
{
cb = cells[i].GetComponent("can_build");
srm = cells[i].GetComponent("swarmAI");
for(k = 0; k < cb.units.length;k += 1)
if(cb.units[k] != null)
if(cb.units[k].unitName == unitName && cb.units[k].unitCost <= cellBuilt)
{
for(i = 0; i < cells.length;i += 1)
if(cells[i] != null)
{
cb = cells[i].GetComponent("can_build");
srm = cells[i].GetComponent("swarmAI");
121
if (cb && !cb.isBuilding)
{
if(cb.units[k].unitName == unitName && cb.units[k].unitCost <= cellBuilt)
{
if(cb.units[k].u nitType == cb.units[k].unitT p.Building)
{
while(srm.location == Vector3.zero)
srm.SearchForPosition(3,brain.myBase,2);
bldloc = srm.location;
}
else
bldloc = cells[i].transform.position;
cb.goCreate = bldloc;
cb.isBuilding = true;
j = cb.units[k].unitCost;
MakeGhost(cb,k,bldloc,cb.units[k].unitShadow.gameObject);
while(m<cells.length)
{
if(cells[m] != null)
{
cb = cells[m].GetComponent("can_build");
srm = cells[ m].GetComponent("swarmAI");
if(cells[m] != null && !cb.isBuilding)
{
cb.goCreate = bldloc;
cb.isBuilding = true;
j-=1;
cells[m] = null;
cellBuilt -= 1;
}
122
if(j == 0)
break;
m+=1;
}
else
m+=1;
}
if(unitT p == "land")
{
atkAI.onLandUnits += 1;
atkAI.creatingLand += 1;
if(atkAI.currentTier == 1)
atkAI.A T1Units +=1;
if(atkAI.currentTier == 2)
atkAI.A T2Units +=1;
if(atkAI.currentTier == 3)
atkAI.A T3Units +=1;
if(atkAI.currentTier == 1)
atkAI.GT1Units +=1;
if(atkAI.currentTier == 2)
atkAI.GT2Units +=1;
if(atkAI.currentTier == 3)
atkAI.GT 3Units +=1;
}
else if(unitT p == "air")
{
atkAI.onFlyUnits += 1;
atkAI.creatingAir += 1;
if(atkAI.currentTier == 1)
atkAI.A T1Units +=1;
123
if(atkAI.currentTier == 2)
atkAI.A T2Units +=1;
if(atkAI.cu rrentTier == 3)
atkAI.A T3Units +=1;
if(atkAI.currentTier == 1)
atkAI.GT1Units +=1;
if(atkAI.currentTier == 2)
atkAI.GT2Units +=1;
if(atkAI.currentTier == 3)
atkAI.GT3Units +=1;
}
lastBuild = cb.units[k].unitName;
finished = false;
}
cells[i] = null;
cellBuilt -= 1;
}
}
break;
}
break;
}
if(finished && lastBuild !="")
lastBuild = "";
///////////////////////////////////////////////////////////////////////////
break;
}
}
function BuildCell()
{
124
var props : building_properties;
var k : int;
props = cellMakers[0].GetComponent("building_properties");
for(k = 0; k < props.units.length;k += 1)
if(props.units[k] != null)
if(props.units[k].unitName == global.cellName && ( props.units[k].unitCost + brain.buildAgent.minimumResources) <=
global.teamGold[brain.myT eam])
{
if(props.props.state == "deployed" || props.ignoreDeploy == true && props.T estQue())
{
props.units[k].buttonPressed = true;
props.imBuilding = true;
building = "";
break;
}
}
}
function GetUnitT ype(obj : GameObject, nm : String)
{
if (nm == global.cellName)
for(var i : int =0;i<cells.length ;i+=1)
if(cells[i] == null)
{
cells[i] = obj;
cellBuilt += 1;
break;
}
}
func tion MakeGhost(cb: can_build, unt :int, poss : Vector3, ghost : GameObject)
125
{
buildFx = Instantiate(cb.units[unt].buildFx, poss, Quaternion.identity);
buildFx.transform.forward = Vector3(1,0, -1);
buildFxProps = buildFx.GetComponent("fx_properties");
buildF xProps.unitsNeeded = cb.units[unt].unitCost;
buildFxProps.pref = cb.units[unt].unitPrefab;
buildFxProps.team = brain.myT eam;
buildFxProps.cellName = global.cellName;
buildFxProps.objectName = cb.units[unt].unitName;
buildFxProps.duration = cb.units[unt].unitBuildTime;
buildFxProps.ghost = ghost;
buildFxProps.isAI = true;
buildFxProps.myPreff = cb.units[unt].buildFx;
buildFxProps.build = true;
global.markPos = Vector3.zero;
global.markT err = false;
}
“resourceAI.js”
#pragma strict
var acti vated : boolean = false;
@HideInInspector
var extractorNR : int = -1;
@HideInInspector
var minimumResources : int = -1;
@HideInInspector
var idlescv : int = 0;
private var genExOnGoing : boolean = false;
private var builtext : int = -1;
private var brain : coreAI;
private var tm : float = 0.0f;
private var timePassed : float = 0.0f;
private var global : globals;
private var bldAI : builderAI;
126
function Awake()
{
brain = GameObject.Find("globals").GetComponent("coreAI");
global = GameObject.Find("gl obals").GetComponent("globals");
bldAI = GameObject.Find("globals").GetComponent("builderAI");
}
function FixedUpdate()
{
if(Timer(2) && activated)
{
if(extractorNR != -1 && builtext < extractorNR && !genExOnGoing )
GenerateExtractor();
if(idlescv > 0)
GetT oWork();
}
}
function GetT asks(ext : int , minress : int)
{
extractorNR = ext;
minimumResources = minress;
}
function AddSCV(obj : GameObject, team : int)
{
for(var i : int = 0; i <= 199;i += 1)
if(team == 0)
{
if(brain.myScvs[i] == null)
{
brain.myScvs[i] = obj;
genExOnGoing = false;
builtext = i+1;
break;
}
}
else
if(brain.enemyScvs[i] == null)
brain.enemyScvs[i] = obj;
}
function RemoveSCV(obj : GameObject, team : int)
{
var s cvnr : int = -1;
for(var i : int = 0; i <= 199;i += 1)
if(team == 0)
{
if(brain.myScvs[i] == obj)
{
scvnr = i;
builtext -= 1;
}
if(brain.myScvs[i] == null && scvnr != -1)
if(i>0)
brain.myScvs[scvnr] = brain.myScvs[i -1];
127
else
brain.myScvs[i] = null;
scvnr = -1;
}
else
{
if(brain.enemyScvs[i] == obj)
scvnr = i;
if(brain.enemyScvs[i] == null && scvnr != -1)
if(i>0)
brain.enemyScvs[scvnr] = brain.enemyScvs[i -1];
else
brain.enemyScvs[i ] = null;
scvnr = -1;
}
}
function GenerateExtractor()
{
var props : building_properties;
if(brain.myRace == 0 || brain.myRace == 2)
for(var i : int = 0; i <= 99;i += 1)
{
if (brain.myBuildings[i] != null)
{
props = brain.myBuildings[i].GetComponent("building_properties");
for(var k : int = 0; k < props.units.length;k += 1)
if(props.units[k] != null)
if(props.units[k].unitName == brain.raceNames[brain.myRace].extractor )
{
props.units[k].b uttonPressed = true;
props.imBuilding = true;
props.aiCommand = true;
genExOnGoing = true;
break;
}
}
else
break;
}
else
{
bldAI.CreateBuilding(global.techT ree.races[1].extractor .name,"none");
}
}
function Get T oWork(obj : GameObject)
{
var minDist : float;
var ress : GameObject;
var prp : resource_properties;
var path : pathfinder;
path = obj.GetComponent("pathfinder");
minDist = -1;
for(var i : int = 0; i <= 99;i += 1)
if(brain.mapResources[i] != null)
128
{
prp = brain.mapResources[i].GetComponent("resource_properties");
if(prp.useable == true)
if(minDist >= Vector3.Distance(brain.mapResources[i].transform.position,obj.transform.position) || minDist ==
-1)
{
minDist = Vector3.Distanc e(brain.mapResources[i].transform.position,obj.transform.position);
ress = brain.mapResources[i];
}
path.SetDestination(ress.transform.position);
prp = ress.GetComponent("resource_properties");
prp.useable = false;
}
}
function GetT oWork()
{
var props : properties;
var prp : resource_properties;
var minDist : float;
var ress : GameObject;
var path : pathfinder;
minDist = -1;
for(var k : int = 0; k <= 199;k += 1)
{
if(brain.myScvs[k] != null)
{
props = brain.myScvs[k].GetComponent("properties");
if(props.state == "idle" && props.spawn == false && props.resourceT arget == null)
{
path = brain.myScvs[k].GetComponent("pathfinder");
for(var i : int = 0; i <= 99;i += 1)
if(brain.mapResource s[i] != null && brain.mapResourcesIdle[i] == 0)
{
prp = brain.mapResources[i].GetComponent("resource_properties");
if(prp.useable == true)
if(minDist >=
Vector3.Distance(brain.mapResources[i].transform.position,brain.myBase.transform .position) || minDist == -1)
{
minDist =
Vector3.Distance(brain.mapResources[i].transform.position,brain.myBase.transform.position);
ress = brain.mapResources[i];
}
}
props.resourceT arget = ress;
path.SetDestination(r ess.transform.position);
prp = ress.GetComponent("resource_properties");
prp.useable = false;
idlescv -=1;
}
if(props.state == "idle" && props.spawn == false && props.resourceT arget != null)
{
path = brain.myScvs[k].GetComponent("pathfinder");
path.SetDestination(props.resourceT arget.transform.position);
idlescv -=1;
}
}
129
}
}
function Timer(orderTimer : float)
{
tm += Time.deltaTime;
timePassed = tm;
if(tm >= orderTimer)
{
tm = 0;
return true;
}
else
return false;
}
“scoutAI.js”
#pragma strict
@HideInInspector
var resourceDiscovered : GameObject[];
@HideInInspector
var scoutNr : int = 0;
@HideInInspector
var scoutsOnRess : int = 0;
@HideInInspector
var knownRes : int = 0;
var activated : boolean = false;
var minimumResources : int = 150;
var aditionalRess : int = 3;
private var scoutNumber : int = 1;
private var brain : coreAI;
private var global : globals;
private var myTime : int;
private var resBrai n : resourceAI ;
private var otherT ask : int = 0;
private var genScoutOnGoing : boolean = false;
private var tmpTime : float = 0.0f;
private var tmpTime1 : float = 0.0f;
private var tmpTime2 : float = 0.0f;
private var baseScouted : boolean = false;
private var canCreate : boolean = false;
private var path : pathfinder;
function Awake ()
{
130
brain = GameObject.Find("globals").GetComponent("coreAI");
global = GameObject.Find("globals").GetComponent("globals");
resBrain = GameObject.Find("globals").G etComponent("resourceAI");
myTime = Time.frameCount;
scoutNumber = brain.scoutAgent.scoutNr;
resourceDiscovered = new GameObject[100];
if(!brain.scoutAgent.priorityEnemy)
baseScouted = true;
if(brain.scoutAgent.priorityEnemy)
otherT ask = 1;
for(v ar i: int = 0; i< 100;i+=1)
resourceDiscovered[i] = null;
GetKnownRess();
}
function Update ()
{
if(Mathf .Round((Time.frameCount – myTime)%4) ==0)
{
myTime = Time.frameCount;
if(!canCreate)
T estTimer(brain.scoutAgent.firstScoutTimer);
if(scoutNr < scoutNumber && global.teamGold[brain.myT eam] >= minimumResources && !genScoutOnGoing &&
canCreate)
GenerateScout();
if(scoutsOnRess < brain.scoutAgent.maxScoutsOnRes)
if(resBrain.extractorNR+aditionalRess > knownRes && scoutNr > 0 && D elay(5))
FindResources();
if(Timer(brain.scoutAgent.baseScoutInterval+brain.scoutAgent.firstScoutTimer) && scoutNr >0)
ScoutEnemy();
if(!baseScouted && scoutNr >0)
{
baseScouted = true;
ScoutEnemy();
}
}
}
function GetKnownRess()
{
yield WaitForSeconds (3);
var minDist : int = -1;
for(var i : int = 0; i <= brain.scoutAgent.knownStartingRess; i += 1)
for(var j : int = 0; j <= 99;j += 1)
if(brain.mapResources[j] != null)
if(!T estViewed(brain.mapResources[j]))
if(mi nDist >=
Vector3.Distance(brain.mapResources[j].transform.position,brain.myBase.transform.position) || minDist == -1)
{
minDist =
Vector3.Distance(brain.mapResources[j].transform.position,brain.myBase.transform.position);
resourceDiscovere d[i] = brain.mapResources[j];
}
}
131
function FindResources()
{
var path : pathfinder;
var swarm : swarmAI;
var minDist : int = -1;
var ress : GameObject = null;
for(var i : int = 0; i < 200;i += 1)
if(brain.myScouts[i] != null)
{
swarm = brain.myScouts[i].gameObject.GetComponent("swarmAI");
if(swarm.task == "none" || swarm.task == null)
{
path = brain.myScouts[i].GetComponent("pathfinder");
for(var j : int = 0; j <= 99;j += 1)
if(brain.mapResources[j] != null)
if(!T estViewed(brain.mapResources[j]))
if(minDist >=
Vector3.Distance(brain.mapResources[j].transform.position,brain.myBase.transform.position) || minDist == -1)
{
minDist =
Vector3.Distance(brain.mapResources[j].transform.position,br ain.myBase.transform.position);
ress = brain.mapResources[j];
}
if(ress != null)
{
if(otherT ask == 1)
otherT ask = 0;
scoutsOnRess +=1;
swarm.scoutT arget = ress.transform;
swarm.targetType = 1;
swarm.task= "scouting";
path.SetDestination(ress.transform.position);
break;
}
}
}
}
function RemoveRes(res : T ransform)
{
knownRes -= 1;
for(var i: int = 0; i< 50;i+=1)
if(resourceDiscovered[i] == res)
{
resourceDiscovered[i] = null;
break;
}
}
function GenerateScout()
{
var props : building_properties;
for(var i : int = 0; i <= 99;i += 1)
{
132
if (brain.myBuildings[i] != null)
{
props = brain.myBuildings[i].GetComponent("building_properties");
for(var k : int = 0; k < props.units.length;k += 1)
if(props.units[k] != null)
if(props.units[k].unitName == brain.raceNames[brain.myRace].scout && (props.units[k].unitCost +
minimumResources) <= global.teamGold[brain.myT eam])
{
props.units[k].butto nPressed = true;
props.imBuilding = true;
genScoutOnGoing = true;
break;
}
}
else
break;
}
}
function AddScout(obj : GameObject, team : int)
{
for(var i : int = 0; i <= 199;i += 1)
if(team == 0)
{
if(brain.myScouts[i] = = null)
{
brain.myScouts[i] = obj;
genScoutOnGoing = false;
scoutNr = i+1;
break;
}
}
else
if(brain.enemyScouts[i] == null)
brain.enemyScouts[i] = obj;
}
function RemoveScout(obj : GameObject, team : int)
{
var scoutnr : int = -1;
for(var i : int = 0; i <= 199;i += 1)
if(team == 0)
{
if(brain.myScouts[i] == obj)
{
scoutnr = i;
scoutnr -= 1;
}
if(brain.myScouts[i] == null && scoutnr != -1)
if(i>0)
brain.myScouts[scoutnr] = brain.myScouts[i -1];
else
brain.myScouts[i] = null;
scoutnr = -1;
scoutNr -= 1;
133
}
else
{
if(brain.enemyScouts[i] == obj)
scoutnr = i;
if(brain.enemyScouts[i] == null && scoutnr != -1)
if(i>0)
brain.enemyScouts[scoutnr] = brain.enemyScouts[i -1];
else
brain.enemyScouts[i] = null;
scoutnr = -1;
}
}
function ScoutEnemy()
{
var path : pathfinder;
var swarm : swarmAI;
var props : properties;
for(var i : int = 0; i < 200;i += 1)
if(brain.myScouts[i] != null)
{
swarm = brain.myScouts[i].gameObject.GetComponent("swarmAI");
props = brain.myScouts[i].gameObject.GetComponent("properties");
if(props.spawn == false)
if(swarm.task == "none" || swarm.task == null)
{
path = brain.myScouts[i].gameObject.GetComponent("pathfinder");
brain.MakeEnemy();
swarm.task = "scoutBase";
if(otherT ask == 1)
otherT ask = 0;
swarm.scoutT arget = brain.targetedEnemy.transform;
swarm.targetType = 1;
path.SetDestinatio n(brain.targetedEnemy.transform.position);
break;
}
}
}
function Timer(tm : int)
{
if(tmpTime == 0)
tmpTime = Time.time;
if(Time.time -tmpTime >= tm)
{
tmpTime = 0;
return true;
}
else
return false;
}
function T estTimer(tm : int)
{
134
if(tmpTime1 == 0)
tmpTime1 = Time.time;
if(Time.time -tmpTime1 >= tm)
{
tmpTime = 0;
canCreate = true;
return true;
}
else
return false;
}
function Delay(tm : int)
{
if(tmpTime2 == 0)
tmpTime2 = Time.time;
if(Time.time -tmpTime2 >= tm)
{
tmpTime2 = 0;
return true;
}
else
return false;
}
function T estViewed(obj : GameObject)
{
var prp : resource_properties;
prp = obj.GetComponent("resource_properties");
if(prp.useable == false)
return true;
for(var i : int = 0; i < 100;i += 1)
if(resourceDiscovered[i] == obj)
return true;
return false;
}
“swarmAI.js”
#pragma strict
private var global : globals;
private var props : properties;
private var building : building_properties;
private var unit : unit_properties;
private var pa th : pathfinder;
private var tryes : int = 0;
private var noPosition : boolean = true;
135
private var brain : coreAI;
private var scoutAgent : scoutAI;
private var attackAI : attackingAI;
private var uAction : unit_actions;
private var canAttack : boolean = false;
private var myTime : int;
private var nav : NavMeshAgent;
@HideInInspector
var walkT arget : Vector3 = Vector3.zero;
@HideInInspector
var location : Vector3;
@HideInInspector
var prepared : boolean = false;
@HideInInspector
var attack : boolean = false;
@HideInInspector
var attacking : boolean = false;
@HideInInspector
var group : String = "none"; ////deff ; attk ; supp; ext; bld;
@HideInInspector
var task : String; //// none ; scoutBase ; scouting ;
136
var scoutT arget : T ransform;
@HideInInspector
var targetType : int = -1; /// 0 : base ; 1 : resources;
function Awake()
{
myTime = Time.frameCount;
global = GameObject.Find("globals").GetComponent("globals");
props = this.gameObject.GetComponent("properties");
path = this.gameObj ect.GetComponent("pathfinder");
brain = GameObject.Find("globals").GetComponent("coreAI");
scoutAgent = GameObject.Find("globals").GetComponent("scoutAI");
attackAI = GameObject.Find("globals").GetComponent("attackingAI");
nav = this.gameObject.GetC omponent(NavMeshAgent);
if(props.objectType == 1)
building = this.gameObject.GetComponent("building_properties");
if(props.objectType == 2)
unit = this.gameObject.GetComponent("unit_properties");
uAction = this.gameObject.GetComponent("unit_actio ns");
if(uAction != null)
canAttack = uAction.canAttack;
if(brain.enabled == false)
this.enabled = false;
if(building)
group = "bld";
else
group = "none";
if(props.myName == global.techT ree.races[1].extractor .name)
group = "ext";
137
}
function Update ()
{
if(props.spawn == false)
{
if(building)
ImBuilding();
if(unit)
ImUnit();
}
}
function ImBuilding()
{
if(building.noDeploy == false && building.ignoreDeploy == false && props.state == "idle")
T ryT oLand();
if(props.attacke d)
attackAI.SendHelp("deff",props.attacker);
}
function ImUnit()
{
if(!props.imScout)
{
if(group == "ext")
{
if(props.attacked)
attackAI.SendHelp("deff",props.attacker);
}
else
138
{
if(Mathf .Round((Time.frameCount – myTime)%30) == 0)
{
if(group == "attk")
{
if(props.attacked)
attackAI.SendHelp("attk",props.attacker);
if(props.state == "idle" && props.helping)
{
props.helping = attackAI.T estNeedHelp("attk");
if(!props.helping && props.myT arget != null)
props.myT arget = null;
}
}
if(!prepared && group == "none" && props.state == "idle")
{
GoPrepare();
}
if(!prepared && group == "none" && props.state == "walk" && nav.speed <=0.1)
{
GoPrepare();
}
}
if(attack && !attacking && prepared && !props.attacked && !props.helping)
GoAttack();
if(props.state == "idle" || props.state == "walk")
{
if(attack && !props.attacked && props.myT arget == null)
GoAttack();
else
if(canAttack && !prepared)
139
{
if(walkT arget != attackAI.preparePoint || nav.velocity == Vector3.zero)
GoPrepare();
else
if(!attackAI.onA ttack)
if(Vector2.Distance(Vector2(this.transform.position.x,this.transform.position.z),Ve ctor2(attackAI.preparePoint.x,attackAI.preparePoin
t.z))< 10)
{
path.SetDestination(this.transform.position);
prepared = true;
group = "deff";
attackAI.DefenderAdd(this.gameObject);
attackAI.prepared += 1;
if(attackAI.attackSpeed > path.mySpeed)
attackAI.attackSpeed = path.mySpeed;
}
}
if(canAttack && prepared)
if(attackAI.attackSpeed > path.mySpeed || attackAI.attackSpeed == 0.0)
attackAI.attackSpeed = path.mySpeed;
}
}
}
else
{
if(task == "scoutBase" || task == "scouting")
Scout();
if(props.attacked && props.state != "attacked")
props.state = "attacked";
140
if(props.state == "attacked")
ReturnT oBase();
}
}
function T ryT oLand()
{
if(location == Vector3.zero)
SearchForPosition(path.objectRadius,this.gameObject,building.rampHeightDiff);
else
Land();
}
function SearchForPosition(radius : int, startObj : GameObject, diff : float)
{
var hit : RaycastHit;
var hits : RaycastHit[];
var mask = ~(1 < < 12);
var pt1 : int;
var pt2 : int;
var pt3 : int;
var pt4 : int;
var pt5 : int;
var pos : Vector3;
location = Vector3.zero;
pos = GetAPosition(startObj);
hits = Physics.SphereCastAll(pos,radius,Vector3.down,100,mask);
for(var i : int = 0;i< hits.length;i+=1)
{
if(hits[i].transform.gameObject.layer != 8 && hits[i].transform.gameObject.layer != 0)
141
return false;
if(hits[i].transform.gameObject.layer == 8)
pt1 = hits[i].point.y;
}
if(hits.Length == 0)
return false;
if (Physics .Raycast(pos+Vector3(radius/2.0,0,0),Vector3.down,hit,100,mask))
{
if(hit.transform.gameObject.layer != 8)
return false;
pt2 = hit.point.y;
}
else
return false;
if (Physics.Raycast(pos -Vector3(radius/2.0,0,0),Vector3.down,hit,100,mask))
{
if(hit.transform.gameObject.layer != 8)
return false;
pt3 = hit.point.y;
}
else
return false;
if (Physics.Raycast(pos +Vector3(0,0,radius/2.0),Vector3.down,hit,100,mask))
{
if(hit.transform.gameObject.layer != 8)
return false;
pt4 = hit.point.y;
}
142
else
return false;
if (Physics.Raycast(pos -Vector3(0,0,radius/2.0),Vector3.down,hit,100,mask))
{
if(hit.transform.gameObject.layer != 8)
return false;
pt5 = hit.point.y;
}
else
return false;
if(Mathf .Abs(pt1 – pt2) > diff )
return false;
if(Mathf .Abs(pt1 – pt3) > diff)
return false;
if(Mathf .Abs(pt1 – pt4) > diff)
return false;
if(Mathf .Abs(pt1 – pt5) > diff)
return false;
if(Mathf .Abs(pt2 – pt3) > diff)
return false;
if(Mathf .Abs(pt2 – pt4) > diff)
return false;
if(Mathf .Abs(pt2 – pt5) > diff)
return false;
143
if(Mathf .Abs(pt3 – pt4) > diff)
return false;
if(Mathf .Abs(pt3 – pt5) > diff)
return false;
if(Mathf .Abs(pt4 – pt5) > diff)
return false;
location = global.CastRay(pos,Vector3 .down,100,8);
if(location == Vector3.zero)
location = pos;
return true;
}
function GetAPosition(obj : GameObject)
{
var pos : Vector3;
var deg : int;
var radius : int;
radius = 15*Mathf .Floor(1+(tryes/10.0));
deg = tryes*60;
pos.x = obj.transform.position.x + radius*Mathf .Cos(deg * Mathf .Deg2Rad);
pos.z = obj.transform.position.z + radius*Mathf .Sin(deg * Mathf .Deg2Rad);
pos.y = obj.transform.position.y;
tryes += 1;
return pos;
}
function Land()
144
{
if(Vector2.Distance(Vector2(this .transform.position.x,this.transform.position.z),Vector2(location.x,location.z)) <= 5)
{
building.orderDeploy = true;
building.order = true;
location = Vector3.zero;
}
else
path.SetDestination(location);
}
function GoAttack()
{
if(brain.targe tedEnemy == null)
brain.MakeEnemy();
else
StartAttack(brain.targetedEnemy);
}
function StartAttack(enemy : GameObject)
{
props.attackMove = true;
if(!attacking)
brain.attackManager .AttackStarted();
path.SetDestinationSPD(enemy.transform.position,attackAI.attackSpeed);
attacking = true;
}
function Scout()
{
if(scoutT arget != null)
145
if(brain.scoutAgent.scoutRange >=
Vector2.Distance(global.Planar(this.gameObject.transform.position),global.Planar(s coutT arget.position)))
{
if(task == "scoutBase")
{
path.SetDestination(brain.myBase.transform.position);
scoutT arget = brain.myBase.transform;
task = "scouting";
ReturnFind();
targetType = -1;
return ;
}
if(task == "scouting" && targetType != -1)
{
task = "none";
scoutAgent.scoutsOnRess -= 1;
ReturnFind();
return;
}
if(task == "scouting" && targetType == -1)
{
task = "none";
return;
}
}
}
function ReturnFind()
{
var i : int = 0;
146
switch (targetType)
{
case -1:
break;
case 0 :
Debug.Log("All Buildings found");
break;
case 1 :
for (i = 0;i<100;i+=1 )
if(scoutAgent.resourceDiscovered[i] == null)
{
scoutAgent.resourceDiscovered[i] = scoutT arget.gameObject;
scoutAgent.knownRes +=1;
break;
}
break;
}
}
function GoPrepare()
{
path.SetDestination(attackAI.preparePoint);
walkT arget = attackAI.preparePoint;
}
function ReturnT oBase()
{
props.state = "walk";
task = "none";
scoutT arget = null;
147
path.SetDestination(brain.myBase.transform.position);
}
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Tehnici de inteligenta artificiala folosind motorul grafic Unity [620969] (ID: 620969)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
