Strateška igra - Unity

Strateška igra - Unity

offline
  • Pridružio: 14 Feb 2008
  • Poruke: 12403

Hajde da napravimo... Raize 3D Mr. Green
Raize je originalno 2D igra koja je napisana za neko takmičenje u okviru foruma ovde.
Uzevši u obzir da sam zahvaljujući tom takmičenju ušao u Unity vode, imao sam uvek želju da sredim Raize u Unity-ju i napravim 3D stratešku igru...

Raize kao Raize nije bio pogodan projekat da se s njim počne učenje okruženja, međutim napravio sam par stvarčica i ostavio tako, godinu dana Very Happy

Vreme je da se to sredi.
No, ovo nije tema za promovisanje neke šklb igre ... već ću pokušati da upotrebim ovaj događaj da bi svi nešto naučili Smile

Nisam hteo ranije ništa da pišem i spamujem dok ne uradim onoliko koliko je imala 2D igra, no kako se to vreme bliži i kako nekih pola dana programiranja deli taj događaj od realizacije, vreme je da počnemo ovde Very Happy

Svaka nova izmena će biti ažurirana na mom dropbox-u sa kog ćete direktno moći da igrate igru u Unity Web Player-u.

Većinu izmena, mehanika i logiku ću opisati ovde, propratiti kodom ono što treba i slično...
Saveti/pitanja/predlozi su dobrodošli.

Opisaću ukratko ono što sam do sada uradio :

- Teren
Unity ugrađeni teren koristim i zbog toga sam naišao na par problema.
Prvi je činjenica da jednom kada namestimo teren svaka izmena veličine terena uništava sve moguće detalje na njemu. Stoga je bilo bitno da se iskombinuje prava veličina terena sa kamerom, kako bi svi detalji bili vidljivi. Na žalost kada sam počeo pre godinu dana ovaj projekat nisam baš mislio na to i kako mi se jedna strana terena dosta svidela, nisam hteo da je menjam.

Drugi problem je posledica prvog problema. Ukoliko je teren previše glomazan, detalji poput trave neće biti vidljivi. Lišće na granama izgleda loše itd. To sam rešio lako prekoračivši maksimalnu omogućenu vrednost iscrtavanja skriptom i izbegavanjem modela drveća koji će praviti problem.

Terrain.activeTerrain.detailObjectDistance = detail_distance;

Sve sam ovo mogao da zaobiđem tako što bih izmodelirao teren van Unity-ja, međutim ipak ne bih da ulazim u pravljenje terena na taj način. S druge strane, kada koristim Unity teren mogu veoma lako da podesim travu/teksture/modifikacije po želji i uklopim ih sa drugim mogućnostima.

Dalje, napravio sam novi materijal za teren i iskoristio standardni Nature/Terrain/Bumped Specular shader, kako bih mogao da iskoristim normal mape. Razlika sa i bez njih je ogromna. Na kraju, koristim lightmape zbog daljine kamere. Pak, pojavio se odsjaj na terenu koji je potpuno nerealističan, stoga sam spustio Shininess na 0 i stavio crnu boju.


Levo - Bez Desno - Sa lightmapom.

Efekat normal mapa se ne može najbolje videti na screenshot-u, međuti svakako utiče na opšti vizuelni utisak terena.

Daleki SS terena bez sitnih detalja i sa mnogo placeholdera (Drveće, teksture, more i sl.)





- Kamera
Pre godinu dana sam ciljao na neki vid kamere kao u Port Royale igrama. Daleki zoom, mala ostrva i slično. Međutim kako je originalni Raize imao dosta predela unutar samog ostrva ipak sam odlučio da spustim kameru nešto niže i "uveličam" predele. Kamera se kreće po zaključanim osama i ima zoom - koji je zapravo DoF izmena. Projekcija kamere je perspektivna.




- UI
UI ne pipam dok se na objavi Unity 4.6 kada će konačno doći bolje rešenje. Sada bi mi samo oduzeo vreme i morao bih da ga menjam kasnije.

Takođe, umesto samo onog prozora za trade, gradovi će zapravo imati svoju unutrašnjost i moći ćete da "uđete" u njih...

Edit 4 :
Taj prozor će još uvek postojati za brzi prikaz i ovo je neka rana verzija :


// Edit 4

- Programiranje
Izgubio sam Source prve igre u međuvremenu što je zapravo dobra stvar... LM
Imam jedan empty gameobject na sceni koji je zadužen za informisanje.
Koristim ugrađeni array za svaki grad i on drži sve informacije o tom gradu.
Sličnu foru je koristila i prethodna igra ako me sećanje ne vara...



Premišljao sam se dosta o načinu koji ću koristiti za informacije i ipak sam prelomio na kraju...
Built In Array sam izabrao jer mi treba fiksni niz koji se neće sigurno menjati u veličini tokom trajanja sesije. Najbrži su u Unity-ju i ne vidim nijedan drugi razlog da koristim JS ili ArrayList. Možda čak i najpraktičniji način da se odradi ovo Very Happy

Dakle, taj gameobject drži skriptu koja je zadužena za :
Dodeljivanje vrednosti nizovima prilikom nove igre.
Čuvanje i učitavanje igre.
Možda čak i za AI ekonomiju.

Trenutno ta skripta ima sličnu strukturu ovoj :

var Tronskar = new int[25] function NewGame (tezina : String) { Tronskar[0] = 2300; Tronskar[1] = 10; // ... }

Zatim imam jednu skriptu na svakom modelu grada u mapi sveta koja povlači informacije ovako :

var info : CityInformation ; function OnMouseDown () { if (Input.GetMouseButton(0)){ // Aktiviraj neki bool koji će aktivirati crtanje UI-a itd. Debug.Log ("info.Tronskar[0]); // Koristimo OnMouseDown funkciju a ne Update funkciju ! Razlika je u tome što će Update funkcija da računa bilo koji klik bilo gde tokom frejma. OnMouseDown računa samo klikove koji "pogode" collider ! Da bi uopšte radio ovaj kod, morate imati bilo koju collider komponentu na gameObject-u. } }

Povući ću informacije iz te skripte svaki put kada igrač klikne na grad na mapi ili na određenu građevinu unutar grada.

Edit :
Kako sigurno neće biti novog takmičenja trenutno nastaviću rad na igri ovde.
Uskoro ću okačiti link do webplayer verzije igre i verovatno nekoliko skripti koje kontrolišu bitnije stvarčice.



Registruj se da bi učestvovao u diskusiji. Registrovanim korisnicima se NE prikazuju reklame unutar poruka.
offline
  • Pridružio: 14 Feb 2008
  • Poruke: 12403

Napisano: 11 Jul 2014 2:33

Koristiću verzije da označavam nove izmene, tako će ova prva verzija biti 0.0.1.

0.0.1 Log :
- 1. Dodata je scena grada koja će se otvoriti svakog puta kada kliknete desnim klikom na bilo koji grad
- 2. Modifikovan kod kamere kako bi se ograničilo kretanje, uklonjen ugrađeni zoom
- 3. Kreirano par particles sistema unutar gradova

To-Do
- Popraviti animaciju mora da ne prekriva ostrvo
- Transparentnost mora
- Click To Move sistem koji poštuje geometriju terena
- AI ekonomija
- Nasumično kretanje ljudi u gradu
- Konvoji, nadogradnje
- UI (4.6)
- ...

1. Sama scena je stvorena unutar Blendera i uvučena... par zgrada, jedna animacija za "alert" notifikaciju, jedan kod za UI kako bi se vratili nazad u svet i nekoliko particles sistema za dim i vatru.
Koristiću je kao placeholder dok se kasnije na naprave različiti gradovi i slično...
Scene se učitavaju sledećim kodom :
Application.LoadLevel(0);

GUI kod izgleda ovako i tu je samo kako bi mogli da se vratite u svet... čekamo 4.6 za UI Very Happy
function OnGUI () {  if (GUI.Button (Rect (10,20,120,25), "Back To World")) {         Application.LoadLevel (1);     } }
Stim što se svaka scena mora dodati u File > Build settings prozoru.

Što se "alert" modela tiče, postoji jedan parent gameObject na sceni unutar koga se ovaj model nalazi. Zatim sam animirao Y i rotaciju unutar Unity-ja. Parentovan je zato što bi u suprotnom slučaju Unity uvek pomerio ceo model gde god bi postojao XYZ transform koji je animiran...



Dodao sam mu svetlost i Toon shading.




2. Koristim izmenjenu verziju neke kamere koju sam pokupio negde... Kamera je pisana u C# međutim veoma je razumljiva. Koristi translation za pomeranje.
Uklonio sam njen zoom i modifikovao "Boxing" sekciju (Ograničena je bila na kvadrat).

Kretanje :
 translation += Vector3.right * -ScrollSpeed * Time.deltaTime;

Ograničavanje kretanja kamere :
var desiredPosition = camera.transform.position + translation; if (desiredPosition.x <= levoX || desiredPosition.x >= desnoX)         {             translation.x = 0;         }

levoX, levoY, goreZ i desnoZ su vrednosti koje sam deklarisao a zapravo su X i Y vrednosti kamere transform komponente, koje sam testirao na toj sceni tako da igrač ne vidi ostatak sveta.

3. Particle sistemi su napravljeni u samom Unity-ju. Ništa posebno. Napravi se novi materijal, dodeli mu se Particles/Additive shader, tekstura i čačkaju se opcije Particle sistema.



Svi particles efekti su spakovani (Parent) unutar praznog gameObject-a zbog lakše upotrebe i pristupa.

Preuzimanje ili igranje na mreži :

Download 0.0.1 Win
Download 0.0.1 Lin


Pomoglo bi mi da razumem performanse malo bolje ukoliko bi aktivirali fraps ili neki drugi program koji ima mogućnost da meri FPS i kažete mi kakvo je stanje Very Happy Ove verzije ne uključuju IndieEffects paket efekata "slike", koji zna da spusti duplo FPS... trebale bi da rade savršeno na većini konfiguracija. Svejedno, namerno sam samo maksimalni grafički preset ostavio za PC i Lin

Online 0.0.1 Smanjen kvalitet u oba slučaja, različite veličine samo zbog veličine monitora...
1080p
720p


Kontrole : Miš - kretanje ; Z - zoom ; Klik na bilo koji grad da se učita druga scena; Ostatak na UI-u.



Dopuna: 17 Jul 2014 0:23

=================================================================
///0.0.2
=================================================================


0.0.2 Log
1. Unity more zamenjeno novim transparentnim morem
2. Click To Move skripta koja poštuje teren za konvoj
3. AI lutke koje nasumično šetaju
4. Prerada niza gradova - Dvodimenzionalni niz

TO-DO lista :
- UI (Neko rešejne dok ne stigne novi UI jer nema smisla pauzirati projekat do tada)
- Pristup gradovima samo ukoliko je Konvoj blizu
- Collider koji će poštovati teren
- AI za gradove
- Collideri za zgrade unutar gradova i propratni UI
- AI ekonomija
...

1. Unity more dodatak dolazi u dve varijante :

1. Free - ono koje smo upotrebili u prethodnoj verziji. Nema transparentnost niti talase
2. Pro - namenjeno pro verziji Unityja, ima transparentnost i talase u zavisnosti od terena

Ja sam napravio novo more koje je transparentno jednostavnim izmenama shadera.
Koristio sam Transparent/Bumped Specular ugrađeni shader i dodao transparentnu teksturu.
Međutim ovo ne pokriva "talase" koji su prisutni u pro i free verziji ugrađenog mora. Međutim postoji mala prevara da se dobije sličan efekat upotrebom koda koji menja offset diffuse teksture i normal mape.
#pragma strict var scrollspeed : float; var offset : float; function Update () { offset = Time.time * scrollspeed ; renderer.material.SetTextureOffset ("_MainTex", Vector2(offset, offset)); renderer.material.SetTextureOffset ("_BumpMap", Vector2(offset, offset)); }

Imamo scrollspeed promenljivu koja je zadužena za brzinu talasanja. Zatim imamo jedan float za offset obe teksture. Pristupimo renderer komponenti, materijalu i podešavamo offset dva parametra.

Rezultat nije sjajan međutim poslužiće za sada !

Mislim da je ovo more svakako bolje nego stock more.



2. Kako će Raize 3D imati konvoje koji će prenositi određene resurse iz grada u grad, trebaće nam mogućnost da kontrolišemo jedan od njih klikovima. Dodao sam na scenu sveta jedan model na koji sam prikačio skriptu koja pomera model ka lokaciji gde je igrač kliknuo. Skripta koristi raycast sa kamere kako bi dobila novu lokaciju.
 ray  = Camera.main.ScreenPointToRay(Input.mousePosition);
Zatim rotira model i koristi
Vector3.MoveTowards da pomeri objekat od trenutne lokacije do odredišta.
myTransform.position = Vector3.MoveTowards(myTransform.position, destinacija, moveSpeed * Time.deltaTime);

Kako ova igra ima teren koji nije potpuno ravan, ova skripta je pomerala objekat kroz njega. To je delimično rešeno tako što sam u LateUpdate funkciji "fiksirao" Y objekta na visinu terena ispod.
Ovo je ok rešenje međutim nije precizno, jer model ostaje u svom položaju.

function LateUpdate(){ this.transform.position.y =  Terrain.activeTerrain.SampleHeight(transform.position); }

3. Dodao sam par "stickman" modela koji predstavljaju AI koji će šetati nasumično po gradu. Oni trenutno imaju vrlo jednostavnu skriptu za kretanje i ovako "rade" : 1. kreiramo novu tačku u svetu koja je u neposrednoj blizini 2. Krećemo se ka toj lokaciji 3. kada stignemo, kreiramo novu tačku
I tako stalno. Trenutno prolaze kroz građevine i nemaju inteligentni pathfinding sistem.
 wayPoint= Random.insideUnitSphere *size; // kreiranje random Vector 3 waypointa transform.LookAt(wayPoint); // Okretanje Z ose ka tom waypointu transform.position += transform.TransformDirection(Vector3.forward)*Speed*Time.deltaTime; // pomeranje napred


Vrlo bitno : Morate eksportovati modele kako Unity očekuje da ih eksportuje, u suprotnom ćete "zaglaviti" sa kodom koji radi svuda sem na tom modelu. Ja sam čak morao da se obratim iskusnim programerima da nađem rešenje a ispostavilo se na kraju da sam iz Blendera morao da primenim transform bez obzira što sam eksportovao sa podešenim osama. Dakle ako rotacija čudno radi, kao na tom SS-u iznad, to je zato što model ima loš transform. Unity standard je +Z za forward i +Y za up.

4. Preradio sam sve gradove i stavio ih u dvodimenzionalni niz. Kako je broj nizova već ogroman i prelazi 20, svaki od njih ima preko 25 elemenata, bio bi pakao pisati pojedinačno kod za svako dugme na UI-u. Zahvaljujući tome što sam ih uvrstio u dvodimenzionalni niz, mogu da napišem samo jednom kod koji će obraditi bilo koji niz.
Sada imam jedan niz koji izgleda ovako :

var Gradovi[20,25];
I zahvaljujući tome mogu da imam jednu promenljivu na svakom gradu koja će zapravo biti Index :

var ID : int ;

Na kraju, zbog čega sam to sve radio, mogu da napišem samo jednom ovaj kod i on će raditi za svaki niz :

//ukoliko se pritisne dugme za kupovinu nekog resursa info.Gradovi[ID,2] -= 10;

Umesto starog načina gde bih za svaki grad morao da dupliram kod i pišem provere :
if (ID == 1) { Tronskar[2] -=10; } else if (ID == 2) { Dahara[2] -=10; } // ...
Mana je to što Unity ne prikazuje dvodimenzionalne nizove, međutim veoma lako možemo da proverimo da li je sve uredu upotrebom [i]Debug.Log(vrednost);[/i]

Svaki grad ima jednu skriptu koja pristupa Game Manager skripti :
var info : CityInformation; // I onda se pristupa nizu : info.Gradovi[i,n];

CityInformation je "Game manager" skripta tj. ona skripta koja je zadužena za potpuno kontrolisanje igre. Njoj pristupaju sve ostale skripte kako bi povukle neku informaciju ili pozvale funkciju. Nije moranje ali je dobra praksa Smile


Prilikom pokretanja nove igre svaki niz dobija svoje početne vrednosti. Ovo može da se uradi na par načina, čak i automatizovano povlačeći informacije iz fajla nekog, međutim ja prefeririram ovaj način.

Download 0.0.2
Windows
Linux
Web (Smanjen kvalitet, desni klik > Fullscreen kako bi kamera radila kako treba da radi.)



offline
  • Pridružio: 14 Feb 2008
  • Poruke: 12403

+ v0.0.3
Dopuna: 01 Avg 2014 19:44

0.0.4. Log

1. Sistem trgovine
- 1.2 Različiti preseti cena
- 1.3 Sistem gubljenja reputacije




2. Pod sistemi
- Katastrofe
- Bust produkcije
- Godišnja doba

3. GUI Top Layer


To-Do
- Kvestovi
- AI ekonomija
- Dorada AI Wander skripte
- Nadogradnje i menadžment konvoja
- ToDo 1 Optimizacija Draw poziva
- Pristup gradovima samo ukoliko je Konvoj blizu
- Collideri za zgrade unutar gradova i propratni UI
To-Do-2 :
- Elementarne nepogode
-- Dinamično kretanje oblaka i nanošenje štete gradovima
- Ratovi


1. Završen je sistem trgovine.

Trgovina ovako radi :
Igrač ima ograničen novac i ograničeno mesto u konvoju. Kada dođe u grad može da kupuje po 10 resursa. Kako se resursi smanjuju u gradu, u zavisnosti od populacije tog grada, tako se i cene povećavaju. Takođe, kako se resursi smanjuju, tako će se smanjivati i igračeva reputacija u tom gradu, na šta možemo da "nakačimo" neke negativne mogućnosti...

Znamo od ranije da držimo sve podatke o resursima svakog grada u dvodimenzionalnom nizu "Gradovi". Sve resurse jednog konvoja držimo u "Convy" nizu. Sve informacije o igraču držimo u "Player" nizu.

Kako bi ovaj sistem radio, trebaće nam još par promenljivih koje će držati podatke. Cilj je da ovaj kod učinimo što dinamičnijim kako bi kasnije mogli da menjamo bilo koji deo tokom igre.

Deklarišemo nove nizove :

ActualPrices [18,2] - Biće zadužen za držanje svih aktivnih vrednosti cena koje ćemo prikazati igraču
PricePresets [18,3] - Ćemo koristiti da sačuvamo tri različite cene za svaki proizvod.
PopulationPresets[6,3] - Koristimo da definišemo tri vrednosti :
Minimalnu - Onu vrednost gde će cena biti minimalna ukoliko tog resursa ima više od ove vrednosti
Srednju - gde će cena biti srednja ukoliko proizvoda ima između ove i minimalne vrednosti i
Maksimalnu - kada je cena maksimalna i važi ako grad ima manju vrednost resursa od ove vrednosti
Logika iza ovog niza je populacija inače, prvi indeks važi za grad od 100-500 ljudi, drugi indeks za grad od 500-1000 i tako dalje.

var ActualPrices = new int [18,2]; // Array containing buy and sell price for each commodity var PricePresets = new int [18,3]; // Array that contains different population presets for each commodity var PopulationPresets = new int [6,3]; // Array that will be used to figure out which preset to show from PricePresets

GameInformation skripta (Preimenovana iz CityInformation jer je sada njena upotreba daleko kompleksnija)

Prvo ćemo definisati različite populacije na ovaj način :
PopulationPresets [0,0] = 150; // 100-500 MIN PRICE PopulationPresets [0,1] = 100; // 100-500 MID PRICE PopulationPresets [0,2] = 0; // 100-500 MAX PRICE PopulationPresets [1,0] = 200; // 500-1000 MIN PopulationPresets [1,1] = 150; // 500-1000 MID PopulationPresets [1,2] = 0; // 500-1000 MAX // ...

Zatim ćemo napisati jednu funkciju koja prihvata jedan parametar i koja će biti zadužena da uporedi vrednosti iz dva niza kako bi unela nove vrednosti u treći niz.

function PriceCalc(ID : int) { }
Unutar nje prvo moramo da obradimo prvi indeks PopulationPresets niza. To činim pisanjem bloka uslova koji proveravaju da li je populacija grada koji je aktivan veća ili manja od neke vrednosti u tom nizu. U zavisnosti od toga dajem novoj promenljivoj deklarisanoj unutar te funkcije novu vrednost, koju ćemo koristiti kao indeks kasnije.

var Populacija : int ;    //Debug.Log (ID);    if (Gradovi[ID,0] <= 500 ){    Populacija = 0;    }    else if (Gradovi[ID,0] > 500 && Gradovi[ID,0] <= 1000){    Populacija = 1;    }    else if (Gradovi[ID,0] >1000 && Gradovi[ID,0] <= 2000){    Populacija = 2;    }    else if (Gradovi[ID,0] > 2000 && Gradovi[ID,0] <= 3000){    Populacija = 3;    }    else if (Gradovi[ID,0] > 3000 && Gradovi[ID,0] <= 4000){    Populacija = 4;    }    else if (Gradovi[ID,0] > 4000){    Populacija = 5;    }

Sada ću uporediti svaku vrednost niza Gradovi - vrednost resursa, sa sve tri vrednosti drugog indeksa niza PopulationPresets.
Sve to će propratiti uslovi koji će nam lepo sortirati svaku vrednost u novi niz koji ćemo prikazati igraču.

Hajde jedan praktičan primer da pogledamo :
Grad ima 500 stanovnika.
Maksimalno povoljnu cenu igraču prikazujemo ukoliko taj grad ima više od 150 resursa.
Srednju ukoliko ima negde između 100 i 150.
Najskuplju ukoliko ima ispod 100.

Recimo da taj grad ima 150 jabuka.
Ja želim da proverim koliko taj grad ima jabuka i uporedim sa ovom šemom gore.
Ukoliko grad ima više od 150 jabuka, pristupiću nizu sa cenama svakog resursa (Koji je, setimo se, treći niz koji drži 3 cene za svaki proizvod) i uzeću njegovu najjeftiniju vrednost, kako bih je prosledio igraču.
Da je grad imao između 100 i 150 jabuka, uzeo bih srednju cenu, dok da je imao ispod 100 jabuka, igrač bi morao da plati najvišu cenu po jabuci.

Dakle, prvo upoređujem aktuelnu vrednost količine resursa sa onim presetom iznad :

if (Gradovi[ID,i] >= PopulationPresets[Populacija,0]){ // If commodity i in Gradovi array is larger or equal to min price field

U tom slučaju, želim da prosledim nizu "ActualPrices" (Koji, setimo se, drži aktivne cene koje prikazujemo korisniku) najnižu vrednost za taj resurs.

ActualPrices[ceneB,0] = PricePresets[ceneB,0]; //Set buy price of that item in PricePresets array to lowest ActualPrices[ceneB,1] = PricePresets[ceneB,0]; // Set sell price of that item in PricePresets array to lowest

Ovde takođe možemo da vidimo da imam dva indeksa u ActualPrices nizu za drugi indeks. Broj 1 predstavlja prodajnu cenu, broj 0 kupovnu cenu. One su sada iste, međutim možda kasnije želim da dodam neku novu mogućnost koja će mi smanjiti sve prodajne cene u gradu gde nisam popularan, ili suprotno - poveća.

Zatim pišem drugi deo provere :
else if (Gradovi[ID,i] < PopulationPresets[Populacija,0] && Gradovi[ID,i] >= PopulationPresets[Populacija,1]) { ActualPrices[ceneB,0] = PricePresets[ceneB,1]; // Set sell price of that item in PricePresets array to mid  ActualPrices[ceneB,1] = PricePresets[ceneB,1]; // Set sell price of that item in PricePresets array to mid

Kao i treći deo provere, koji će raditi isto ovo sem što ćemo napisati drugačiji uslov.

Sve ovo se nalazi u for petlji koja ima dva brojača : ceneB i i.

ceneB je brojač koji počinje od 0. dok je i brojač koji počinje od 2 a završava brojanje na 19.
Ovo je zato što nam je glavni niz Gradovi tako sačinjen da sve vrednosti počinju od trećeg unosa - tj. 2.

Kada se ovaj kod iskompajlira, dobijemo novi niz koji sadrži sve naše cene u zavisnosti od populacije i svakog resursa ponasob.

Hajde da izmenimo GUI_Global skriptu kako bi osvežili sve te vrednosti i prikazali ih igraču.

Unutar naše glavne GUI For petlje menjamo sledeće redove :
GUI.Label(Rect((24.0/100)*prozor.width,  perc_Y_offset+(perc_lblY/100)*prozor.height , size_lblX, size_lblY), infoUI.ActualPrices[cnt_Prices,0].ToString()); //Buy Price GUI.Label(Rect((40.0/100)*prozor.width,  perc_Y_offset+(perc_lblY/100)*prozor.height , size_lblX, size_lblY), infoUI.ActualPrices[cnt_Prices,1].ToString()); // Sell price

Sada će ove label komponente vući podatke iz ActualPrices niza.

Zatim vršimo neke logične uslove unutar samih dugmadi za prodaju resursa, kako igrač ne bi mogao da kupi resurs ukoliko nema mesta u konvoju ili dovoljno novca.

if (GUI.Button(Rect((28.2/100)*prozor.width,  perc_Y_offset+(perc_btnY/100)*prozor.height , 53, 27), "+10")){ //Buy Dugme    //Debug.Log (infoUI.Gradovi[CityID,i]);        if ((infoUI.Player[0] - infoUI.ActualPrices[cnt_Prices,0]*10 >=0) && (ukupno + 10 <= infoUI.Convoys[0,0]) && (infoUI.Gradovi[CityID,i] - 10 >= 0)){

Dakle druga provera "kaže" ovo :
Ukoliko je rezultat oduzimanja vrednosti cene resursa (puta deset) od vrednosti igračevog zlata veća ili jednaka nuli (Što znači da ako igrač kupi taj resurs neće ostati u minusu) i ukupni broj resursa u konvoju + 10 je manji ili jednak maksimalnom kapacitetu konfoja, i ukoliko će grad, kada oduzmemo 10 od te vrednosti, imati resurse nakon završene prodaje, uradi sledeći kod.

Drugim prostijim rečima :
Zlato igrača : 5000
Cena resursa : 50
Kapacitet konvoja : 250
Kapacitet resursa u gradu : 20

Ako će Zlato igrača - Cena resursa biti više ili jednako 0 i
Ako će Ukupna suma svih resursa u konvoju + 10 biti manja ili jednaka 250 i
Ukoliko će Kapacitet resursa u gradu - 10 biti 0 ili više od deset, tek onda ćemo izvršiti kod.

Sledeće linije su kod koji će se izvršiti ako se svi uslovi ispune :
infoUI.Gradovi[CityID,i] -= 10;    infoUI.Player[0] -= (infoUI.ActualPrices[cnt_Prices,0]*10);    infoUI.Player[i] = infoUI.ActualPrices[cnt_Prices,0];    infoUI.Convoys[0,i] += 10;     infoUI.PriceCalc(CityID);    infoUI.RepFading(CityID,i);

Prvo oduzimam 10 od aktuelne vrednosti resursa.
Zatim oduzimam cenu puta 10 (jer kupujemo 10 resursa) od cene zlata
Zatim ažuriram poslednju kupljenu cenu igrača - poslednja cena po kojoj je neki resurs kupljen je ranije dodata u niz Player.
Na kraju, šaljem ponovo zahtev za osvežavanje cena GameInformation skripti i toj funkciji prosleđujem parametar CityID - koji je parametar koji označava grad.

Poslednja linija koda ima veze sa drugom funkcijom koja je zadužena za spuštanje reputacije.

Kada pokrenete igru, videćete da kada kliknete na grad sve radi savršeno, cene su dinamične i menjaju se u odnosu na resurse i populaciju. Razlikuju se od grada do grada i slično.

1.2 Smanjivanje reputacije

Kako bi se vi osećali da neki gasterbajter sa 250k evra upadne u vaš grad i kupi svu pijaću vodu? Mrzeli bi ga Smile

Isto će se to desiti ukoliko to uradite u Raize igri.

Ovaj kod mi je pravio veliki problem jer sam hteo da spasim mesto, međutim na kraju sam završio tako što sam napisao novu funkciju za njega.

Funkcija se nalazi u novoj "GodMode" skripti i prima dva parametra : CityID i ID. Nova skripta nam treba kako bi odvojili slične funkcije od GameInformation skripte jer će ih verovatno biti mnogo ubuduće.

Ovaj sistem radi tako što će "puniti" jednu promenljivu do 10, svaki put kada igrač kupi resurs koji je pri nestašici u gradu. Jednom kada pređe 10 igrač će dobiti -1 reputaciju u tom gradu.
Postoji razlika trenutno u tome što će igrač dobiti po 5 "kaznenih" poena ukoliko je vrednost baš pri velikoj nestašici dok će inače dobijati po 3 ukoliko je pri srednjoj nestašici.

Hajde da analiziramo kod...

Pre svega moram da povežem naše skripte :
var GodMode : GameInformation ; GodMode = GetComponent(GameInformation);

Zatim pravim novu funkciju :

function RepFading (CID: int, ID:int){ var normalized : int = ID - 2; }

Normalized je promenljiva koja će oduzeti 2 od indeksa koji ću proslediti iz GUI skripte. Ovo radim zato što mi je niz Gradovi napravljen na taj način da se resursi nalaze od 2-19 u njemu.

Sada ću napisati uslov. Ukoliko je vrednost aktuelne cene jednaka srednjoj vrednosti iz Preseta kog smo definisali ranije, onda ću dodati 3 kaznenih poena.

if (GodMode.ActualPrices[normalized,0] == GodMode.PricePresets[normalized, 1]) { GodMode.ReputationModifier[normalized] +=3; }

Unutar tog upita ću takođe proveriti da li ta nova vrednost prelazi 10 :
if (GodMode.ReputationModifier[normalized] >= 10){ GodMode.ReputationModifier[normalized] -=10; GodMode.Gradovi[CID,1] -=1; }

Ukoliko jeste, oduzeću 10, ukoliko ima ostatka on ostaje tu gde jeste a ja samo "resetujem" brojač i dalje oduzimam 1 % reputacije gradu.

Drugi deo koda je isti samo što pokriva kritične vrednosti.

Funkciju pozivamo iz GUI_Global skripta ovako :
infoUI.PriceCalc(CityID);

2. Podsistemi
2.1 Katastrofe

Takođe sam napisao funkciju koja obrađuje sledeću logiku :
Postoji 10% šanse da se desi neka katastrofa u gradu.
Ukoliko će biti katastrofe nasumično biram njen tip.
Postoji tri zamišljenih tipova katastrofa : Požar, cunami i grip.
Vrlo jednostavna funkcija koja koristi Random.Range kao bazu.

2.2 Boost produkcije
Je funkcija koja prima dva parametra - ID grada i tip busta. U zavisnosti od toga će grad imati dodatni bust na građevine koje prave resurse...

2.3 Godišnja doba
Ovu mehaniku kontroliše jedan tajmer koji je podešen na 180 sekundi. Update funkcija oduzima sekundu po sekundu od vrednosti, jednom kada dođe ta vrednost na 0, resetuje se na 180 a godišnje doba se menja, pri čemu daje druge pogodnosti ili nepogodnosti igraču...

3. GUI Top Layer
Pod ovim podrazumevam onaj glavni i prvi sloj koji je vidljiv uvek !
Hteo sam da nateram Unity da mi pomogne tako što ću koristiti integrisane GUi teksture i slično, međutim ispostavilo se da je to više loše nego dobro - jako je teško bilo podesiti veličine i slično...
Na kraju, kako već koristim GUI matricu da skaliram elemente, odlučio sam da ispišem ceo prvi sloj upotrebom skripte.

Nije teško i zapravo je potpuno isto kao i prethodni GUI ...

Prvi sloj GUIa se sastoji od jedne statusne trake koja je na početku ekrana. Ona sadrži "menu" dugme koje otvara novi prozor sa novim mogućnostima. Nekoliko informacija poput trake sa tekstom, datumom, godišjnim dobom i zlatom igrača. Takođe od jednog prozora koji se nalazi sa desne strane i koji je animiran kodom. On sadrži informacije o konvoju i kasnije će nam služiti za prikaz drugih informacija.

Statusna traka je zapravo jedna box komponenta sa teksturom koja počinje od 0,0, ima 25 piksela širine i 1920 piksela dužine.

GUI.Box (Rect(0,0,1920,25), "");
Prethodno smo definisali novi gui skin koji smo napravili zao vu priliku.
Zatim sam iscrtao dugme "Menu" koje kontroliše boolean (koji koristimo kao trigger) :

 if (GUI.Button(Rect(0,0, 75,25), "Menu")){     if (b_MenuWindow){     b_MenuWindow = false ;     //Debug.Log ("MenuWindow false");     }     else if (!b_MenuWindow) {     b_MenuWindow = true;     //Debug.Log ("Menu Window true");     }     }

Ostalo je samo da prikažemo ostatak kontrola u zavisnosti od stanja tog booleana :
if (b_MenuWindow){    GUI.Box (Rect(0,25,140,161),"");    GUI.Button (Rect(20,35, 80, 25), "Save"); //...

Takođe je ostalo iscrtavanje label komponenata iznad ove trake, no to je pokriveno još u prošloj verziji tj. kod je potpuno isti ...

Kada je prozor u pitanju, deo koda koji ga iscrtava je isti kao i onaj koji iscrtava Info prozor iz prošle verzije, stim što imamo jedno novo dugme koje moramo da animiramo.

Animiranje se vrši u Update funkciji.
Prvo ću proveriti da li je mover bool aktivan, ukoliko jeste dodavaću našoj X vrednosti prozora neki broj i svo vreme proveravati da li je taj broj veći od maksimalno dozvoljenog broja. Ukoliko jeste, podesiću ga kao maksimalni broj i isključiti bool.

if (mover){ convoys_prozor.x += smoothanim*3;    if (convoys_prozor.x >= 1478){    convoys_prozor.x = 1478;    movel = false;    mover = false;    //anim_time = 0.0;        }

Dakle, pomeramo prozor i svo vreme proveravamo da li je na tačnoj poziciji.
Zašto ponovo podešavamo X poziciju na 1478? Jer može da se desi nešto neočekivano tokom rada pa da ta maksimalna vrednost ne bude 1478 već recimo 1480... što bi pomerilo ceo prozor dva piksela dalje nego što treba.

Drugi deo ovog koda je suprotnost toga pa ćemo oduzimati od X vrednosti kako bi vratili prozor na mesto tj. otvorili ga...

Komponente unutar prozora su iste kao i kod iz prethodne verzije...

Takođe, dugmad poput "Return to world" i label o verziji sam pomerio u GUI_Global skriptu a te dve skripte obrisao pa sada naš GameManager gameObject ima tri skripte : GameInformation, GUI_Global i God_Mode.

Informacije

Preuzimanje : Windows i Linux x86_x64 Uni
Web player
GitHub : https://github.com/Srki94/Raize3D/releases/tag/v0.0.4
YT

offline
  • Pridružio: 14 Feb 2008
  • Poruke: 12403

Raize 3D će postati Raize 3.5D.

Prepisujem ovih dana ceo projekat u Unity 5, gde ga inače pišem od nule.

Od izmena koje su bitne :
Nećemo koristiti stari UI sistem nego ćemo koristiti novi.
Verovatno nećemo imati 2D nizove već custom klase npr :

Umesto : Gradovi[0,5] = 20; - Gde je 0 id grada, 5 id resursa, ćemo imati :
Gradovi[0].Resursi[5] = 20;

Hteo sam da imam nešto ovako : Gradovi.Tronskar.Resursi.Kukuruz = 20;

Gde bih mogao da prođem petljom kroz svaki grad, svaki resurs, svaku cenu itd.

Međutim ispostavilo se kao loša ideja na kraju koja bi samo bezveze koristila dodatni kod.
Lično nemam ništa protiv 2D nizova i čak mislim da vrše posao sjajno, ali ovo je kao hajde preglednije pa eto.

Za početak, evo par Unity 5 ss-ova sa minimalnim podešavanjima.






FXAA Anti-Aliasing i Bloom ^
U pozadini vidimo SpeedTree besplatni paket koji izgleda premoćno.

Ne znam kada ću završiti jer mi je trenutno prioritet jedna 2D igra.
Jedini razlog zašto sam se vratio na Raize je Unity 5 iskreno, koji me fascinira u svakom smislu sa snagom i pro alatima koji su sada besplatni.

Isto, projekat se piše u C# i neću smarati dodatnim tutorijalima ovde "od početka", nego ću samo proći kroz poslednje izmene u odnosu na prvu verziju pa ćemo nastaviti dalje gde smo stali - a to su waypointi. Koje ću otpisati verovatno jer ćemo koristiti unity pathfinding, nav agente itd. Very Happy

Ko je trenutno na forumu
 

Ukupno su 1057 korisnika na forumu :: 17 registrovanih, 4 sakrivenih i 1036 gosta   ::   [ Administrator ] [ Supermoderator ] [ Moderator ] :: Detaljnije

Najviše korisnika na forumu ikad bilo je 3466 - dana 01 Jun 2021 17:07

Korisnici koji su trenutno na forumu:
Korisnici trenutno na forumu: anta, bigfoot, dijica, Dogma21, FOX, Krusarac, Kubovac, MB120mm, mercedesamg, raso76, royst33, sasa87, Sir Budimir, Stanlio, Steeeefan, vathra, zillbg