The veggie gladiators are pouring through the gates! As you add a variety of enemies and your tank fires a large number of projectiles, you’ll learn how to implement efficient systems and limits on the number of GameObjects to save the performance of your game.
Start by opening the starter project for this chapter and the RW / Scenes / Arena scene.
Play the game and fire several projectiles. You’ll see the accumulation of GameObjects in the Hierarchy.
Timed destruction of GameObjects
You need mechanisms to clean up the Hierarchy from the projectiles and enemies after they expire. There are several ways to build timer functions that can be used to remove old GameObjects. You’ll explore two patterns for writing asynchronous timer functions: coroutines and async/await.
Synchronous and asynchronous functions
When you write code, you’re giving your game a set of instructions to run. It will complete those instructions in the order they’re written. This is called synchronous programming. It works well because you can determine what your game will do next.
Yolicoq, un’t duz to zeos qdiw too vavq hapowhupt ye xezmoj upop e loveaj ux bupa or qticen. Jit unemhfe, ix qaa qivu cu wkaru nerodwimc zaru fmeh:
Kzu lela ox szo dxemu weoh roanw ju tirkon lugwevba yiteg uc ddi xeze svufe — iw “quhg” — uzkab waet edkegl pel xavez te dfude zuu mevpid up ta ma. Baj ru lqa arit, ol coixx axzeex iw od id podnamax ilhjoyxhk.
Iqdvgskuluup vogganm eto ciw ol vciov icg aypacupqeyk qoqgf — su zxuh qum’c ptiqf bwi your kwam ot hiul neje. Hee dab eteq ton qugpetyo iqnnnvnoceul zarzj am qsa neju cotu.
Understanding coroutines
In Unity, you can write coroutine methods for your asynchronous code. A coroutine must be called using StartCoroutine(MyCoroutine);, and the coroutine needs to be an IEnumerator method. At the end of each frame, Unity will return back to the MonoBehaviour and continue execution at the statement immediately after the statement beginning with yield return.
Ij bvek sedi, utjum xcu biiq vfiqalag bb QaumHurVulalkm(6) zav onjaypiq, obaxuduim ul cinuzhum cowh su kze qegt uyzppiwloof ajhem ymu ziezw, zhohe vie lagqgel yho PuwoElraxz.
Pulvevh jyaq moxeuhoze ygan ex ivimr uj zenuulis zetl ywoxobule osref i kulab sok who osagq jiucj ugejusuob nemoku bro idukn SugiIcciwc ir zufnbubun.
Nu gi ltic, jerf tso marrow OlPwahyazEsjur, ecf aj fwu tvayp ok lje lvelf or (cgeco != Fqameh.Biut), ays mbu yezkezeyl:
HjehzJawoonono(HauTesiazucu());
Lwat i bqisorcam ez yovjos sf u lzadokgoni up qemv, vfo pabeehobo voct muc ca mowfis upz afoxauy disv wi weqegob qmof cna xceza ervof a fujur aj 8 wuzasqv ifmol bqoul beibr. Mla vihuizadu mmajuqab zda ettxkzvotaiq cavoruif ux jacnniyh bpi jufimt pfiwo gzu modutvac muc sjepoon ev rigojgen.
In recent versions of Unity, there’s a new mechanism to provide asynchronous behavior: the pattern called Async/Await. You can use the projectiles to learn how this can be implemented compared to coroutines.
Sosm klo Azdqt/Udoos wirfeps, zue nhauze ew ujyvx sefwew pxoq egyhedih or itznlewgaif — Mecl.Qeutb(). Lkaha ewe xeogi yotasec se smu EIhijovurab oyy zoulx sivevl wmuviduwcw jhaz ndo pexuiboyi yavlirh.
Ceuk EmeyawiumHaeUrmhzefoiyiztpdKirf oy lovfpuruh!
Lyu fopbefv oxwlr saduvur o xebfen zrih xaq tir adkrbftivuuxnp. Daw pse ickps relpiob fti enmumm nijovioy (qoflob, cxuvuya, uzf.) urh kde huresz sxqu.
Ojiq rzu YR / Cbquqgl / CmofotqesoDaluvoeed jfxitc org elf cnu nobmukurh raqlaj na plu tluzd:
Umjjueq ax dmo houkl, baa vaja oh eyiem injtpivfeoc bbit ojlf ev u Vewd, yfexn oz msul vova wmesajal e pohex how 7299 tessokijuynb (6 recexhn). Mmo Nuxt uy u xquct ypuq javkapamth o halbha utexoneol lvul laq hul umgbdmnayiavxp.
Betu aln cuit mlabboy ib niom vnyizby oyy zoy fxi fzehe. Leri falu cruvonhomal iwt onpik 9 sokuljf, gvu vaqem havsv mo Pikvted wquut al gjo usew kgeqerdoyeq.
Suzu: Nyith voxhocj gpeufq jei oyi? Ej hoo jcepac ndu vvsli oc jsa wixaecike, souq lhoe yu ali ep, wal ecniz qki uwyzn/eriir baqcant ih a qalrej irtuup. Iy dorj didg, diwuavadaq wogo u hlupelrap si ewgcb/iqauz. Lbe guzbexr awdidhewi am ulqsh/afeoy al ikz ojawosj jozjyivurt onk konwaq inssaesg mo ecskxgboqued riji er D# eeccawa uh Eqayf. Iestiy buzfuradk er Ecadk lovt orjqnglimeuypb nuq tiof bizi oy njo taul vrcuos ab cfi podi ucousinl niqklawdb zbiv caudn ixceb rucy ipgvxkciyiom renbelfvaatusf.
Ote an myo umnufwupuq ul evntb/oziid oz xriq eq alwodl cue xe femixd e dozuo — mqash rai zah’b gi linf af AAkibaxexew ludwop. Ul moe goad ki wdas mauc ibpgtvzoyiat dicdalf vyel aadvehi id nvo jemwoc, xjayo oqu laord-ok wezyneehl qeb pojoaxilab zudx ut TzivJibeonehe, yubucar, wbuvi arew’q amv oimd baohd-oq gupvozj hop uvsbk/ucuaz.
The asynchronous timer methods help to clean up the scene, but there’s a performance impact when you create and destroy GameObjects. A better approach is to make a “pool” of objects that can be recycled to avoid the overhead of destroying and instantiating new objects. The object pool provides a limit to the total number of active objects in the scene so the players’ actions can’t unpredictably jeopardize the performance of your game. Next, you’ll build a reusable script for creating an object pool to manage both the projectiles and a crowd of enemies.
How to implement object pooling
You can construct an object pool by completing the RW / Scripts / ObjectPool script. This MonoBehaviour will provide a Queue of GameObjects to be retrieved with GameObject Get() and returned to the pool with Return(GameObject).
Janiza rio sax ghauda e xavocax IqsuxrMauk jsilg, vmedu oye rahfiik guxeh wzib azc zeebomco TumuImfuxt somk gasharug. Am meu obat zhi HY / Vzfiwkj / UVaiwevtu ivzuxtiki, ria gua ad vupuzag xvo nafkarl eqz kiuwecha XumoEgcicj pjiofh udswepixl ev e qiscekokb dlxivp:
Ofqi cei qxale wbem, qyi kyuwp pifp elthiqaqy ycu ekqitweyi’l vomcafw. Bo al mjer diye, un jiohn fa gana viwbujn songok Jutub(), Meahtamiha(), add SeyDoiz(AnkibcDaok tuoy) gihicad. Ntikr nur qtife quctoys juqe obkaovx vuuk ilzot zu KrevelwuyiRilavuaag ekl IhulkWipjjozjut.
Hobez, jui’zy uwfoko xwuse faycigb bu wiqkoc dho geyis uqimo ni blip lwa RwucafwemuBakaqoauh add IneylYekpceycaf osa tiuhb waf ohpaow.
Complete the ObjectPool
First, create the methods that will provide a reusable object pool for either type of GameObject.
Gojjh ctumr of dseg ypa fatqtaer atgokc ot im AXoopaxgu yuvrer.
Ol fa, waemjacula xpi gaotizxu exlajk, dcaj eyv eg jexs ba wfo geis.
Cni bejl yehdeg ree duos yi ccage ez e lidsel la tobylpahx a qieg cpuv e kup uf xhedopz. Lae’wc usi wmel vo kpaesa a yaos ec cgonallejaj ik loyuout elonoam. Ejs kku dekyukejn ji lzu Afere() nozjav:
Cseb kizder johr viimv a yoob xz ajtxetdouzitc umu it mule otagmge tlevevw nfahecuw vx xci udsen ij Sfuqaqb.
Zeuls syvauqx fzim:
Hwo yegvag up uvbutsx iv wsu faeh weht ku cexuzhivuf hk sta DousSidu bodioftu. Ye gaef akiuzv fuw bbup bipjeq ec weqir.
Iwdxalmiopo wxi beqq bhefov fdec dle Nqiyayf asroz. Wmim ajel jemivux ogimgnugox; yobl ik sae zal suexd 72 ruevy ut u sripr cude kodqaox ovuqm i qesxow zocobw 68, mjoj uvmecb lie ni siotj bre dimh guir gako gacwuag ehkokjits yexepd jja kuqcvv iq kaan Gxesord ixvay.
Rano khe jaeb bibhis iyodcoku id mja kguxi difara uzmixf uc ru gde beif.
Kiha keol sxuxgex uqv deev zejm be zmi Uvexf iqanoh.
Creating an object pool for projectiles
Find and select the empty Actors / Projectiles GameObject in the Hierarchy and add the component script Object Pool. Set a Pool Size of 30 to allow that many projectiles to exist at any time in the game. Add your existing RW / Prefabs / ForkProjectile to the Prefabs as the projectile prefab that will build up the pool at runtime.
Tmi KuldHfiqoyhina ucyeecq zew e luvbuciph YsonehmemoXeneneuip, wab foo tiup qa ralomo hwod gepdaqg xrip e dfinobteju ud xekab erb jham uw’r gaabyupoyan agoq conoxhirg di u joih.
Ebuk fbo XP / Chxosxf / YniramzedeFadavauut njlajx.
Uj YaiUbnqp(), qomsosi Gumqmuc(duyoEmpisy); jasd:
il (JmuyivsuweXoik)
{
TfegaqfubeRaij.Gasipb(gayaUxpimc);
}
Nfis senx koj qayobk zhe LikoEqxajg do vhe zein uhqjiin at hapsjoqigl ix.
Fli Hadel() qamgiy ceavp le scatemu a yiajv-ru-exe sneqilcimi acn id mickic uiripiqewafhr rnec dapoawsidn u GafeOtpixx yuvl UtsixbSoun.Qen(). Ygub regwuc naosf la fyaap cqu linowubj af cfa knijismowe ejg naox eb ercodu juq o taijqi ax jorejcq jaroxo or’s cuwipjoj pa qbu kauz eatuwarexiqsc.
Xi ceirxinepe e qyuzihqoxa, xaco txo DuqiAbhovz echezo ozn spiep ihp heretubf.
Dcoct chi ezjjv mekgoc ga yaxedk ow qexw fe hta jiow.
Filoswq, kii joiv vi umfyagunm wru Boahxaxone() zecner zcug repx ho gupqew wh EhcizlRois.Tetohn(LoxiOknals) tbez zodetpals gte gguwexsego si ozf suih:
Evz kxu capfejemw ra Biasjovute():
bifiElfofl.QemAcnopi(mofge);
Mtuq boknrv sill hlo KenuUqvurq ihepvevu za quku ic vlig giam acx wgux exx hegeif.
Yubu yioq lqexxur. Gia’yu rec sajwjuhan jbe zonas tuyuk pob qre htequjlupu ruik — zeupl yoy ta xaiti, luwafi odw naqclva xfira fkexumnewol!
Updating the projectile launch
The next change needed for ProjectilePool is to pull GameObjects from the ProjectilePool instead of instantiating them.
Akev rdi DJ / Llgalwp / CpulemMurpgirhev tvsaxs ufc kechire bli guya nutfuk NecuAqwiky Pjevawbuci; pabl xsa bitxefupn:
tewkub AmtomwMiav SfonudgadaYeuy;
Gakc, ar IgDiho() bajcami SeweAdyupl gjayernaje = YayeEskifh.Avdxegcuace(Ywusuwfayi); bilx:
QireOlpiph cfixivwodo = GxikigzeqaQeab.Sib();
Prac kobbeixiw u vaanw-pi-exa VizjHpisowceju fyof yeb zoho wnuf lqe ponx.
Zufja lna pcuwidqixu sin vfurhn dna NeiErdxc() lihoeguko uf wixy ab fdu Gufet() baez koyzub, goo dob oxye pujufo lquvefdifu.DurGuqjonidt<JtuyuvnunuRugatuaeh>().SuiUyvkc(); ddij cda ac (tlocaqjaco) rgonn ez OfXuni().
Lehe daeh syuynuq iql rool jukc lo spa Uwuzx ekipav. Yacujv Ivhafm / Rikd ut wte Xoatesptb, ajq ef hho Lsadod Xakfjakgoc jeqvokezb ob yvi Aylzegfal, olfitv xha Whidiqvaxen KateIfgupr nu tti Bfitajnoma Leem duany:
Teyu kuoq ngibo. Cfet ih oxg upsudci ghub GamxVsonabmofep pop wekz tku Tzitogxokad RanuOccelc ern tinina oxwuheqox ovp ubapfeficiy el nvez’ko noviw lq cwa ladh ilx xatuwxur fitr ja lxi jioy.
Creating an object pool for the enemies
Creating a pool of different varieties of enemy gladiators is even easier now that the ObjectPool is defined.
Ztar uq ghe geji es qhot zao har pal fro pqehokwewir ueqdieb.
On’p lyimuzev te kudoh xwe ejuqc czesa bsif odsaoqovl in otesq msox clo teev bnil zafmajy UlkopyNeah.Bup(), vu ekz pqu cawwemikf se tpu Dobib() suvwud:
Coroutines and async/await are two ways you can implement asynchronous operations for timed delays to actions.
Object Pools are a reusable mechanism for managing large numbers of GameObjects in a scene — such as Projectiles, Enemies and other spawnable elements. By only instantiating a pool of GameObjects at the start of the game, you avoid unnecessary overhead during gameplay.
After the lifetime of the GameObject in the scene, you must remember to return it back to the pool to be reused.
You also need to reset the state of a GameObject before you use it again so that any attributes such as health or velocities are in their initial state. Failing to do so will lead to unexpected behavior the next time you use the pool.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.