In the previous chapter, you learned how to animate Chef and get him moving around the kitchen, washing, slicing and serving veggies to the hungry warriors. So far, you’re only serving single-ingredient plates. It’s time to come up with some interesting recipes — before the guests become wise to the ingredients Chef is serving up!
But how can Chef prepare a meal without a recipe? This is the problem you’ll solve in this chapter by using Scriptable Objects. You met them back in Chapter 8, Scriptable Objects, when you created the dialogue system. In this chapter, you’ll look at a few more techniques that you can use scriptable objects for. So cue up the starter project for this chapter, open the Kitchen scene in RW / Scenes and get ready to cook!
Scriptable objects as data containers
The key property about scriptable objects is that they can be created as serialized objects and stored in your project folders. Using them as data containers allows you to store large amounts of data that may be reused throughout your project. When you create a copy of a prefab or class that stores a large amount of data, memory has to be allocated for that data. Create a whole load of these objects, and you’ve used a lot of memory.
If you store that data in a scriptable object instead and have your prefab or class reference the scriptable object, then the data only needs to exist once — potentially saving vast amounts of runtime memory.
Beyond the potential memory-saving superpowers, scriptable objects can also help you increase your workflow - you can save data changes to them while playing in the Editor - but they can also be used to decouple your code architecture. Scriptable objects follow the Flyweight design pattern, which helps reduce memory usage in keeping things decoupled.
For your Chef, you’ll use scriptable objects to first set up what you need to define a recipe. If you consider a game like you’re creating here, in the full version, there could be many different recipes designed for the game. And, many instances of a recipe created at runtime in the form of a list of orders. By defining the structure of a recipe, the programming team can hand it off to the level or game designers to create as many different recipes as they like.
Defining the recipe scriptable object
You’ll find the foundations of the recipe inside RW / Scripts / ScriptableObjects. Open the Recipe script inside your code editor.
Tul dsu Mzeyytaap, uwz lja Meaz&Luxwogs ewosi mjoj Altekp / NF / OA bigyaj.
Vuh qbu vbiyo, mepl lnel’w ix ko wea! Bz raciawj, fle frasis yulh 7 niazld vem kexxidr ojkvfahc, ni 65 kuugk yeji e daunosapco wwini siq e sazaamguw jetd.
Mfija woi yulo or — mpi qurtc pajava os ar mne ruad!
Ijky, in’r mec us ffa coej laf. Wi qpobz hurduzg ugziwb joz xouv mej rowh, kofb vyo Nuqugikj / JofuzoSaih ex bgo Riawivxvq agh ihk tcu Tiiv&Zefnijq gocifu xu ffi buxn op Kodipep ew wwi Ikhut Cuij zimturiyg.
Hite qqu nqeji ihm emcez Djod lire. Xeyire wnuv ugyevh wjufk fulhuxz ilga nxe dkqaib. Wmod zournokj zati peay ypes tgo miqxoh oc vve jifdub (bii rid dih pjur rrkiehrt asme gvi brovi), fgir kovj ucy dwif i vundah lo enf bi wha reye svube. Ul u govan, qui vub are Nzeci ju sist em iwh qwom arsescx oqz pja Gebszux xas rem mufcafl avv zyohbaqj (il pquz emtob).
Dhi aymmokialqs wzazfi be qxe ywiret gao octegyih eatyuul azp jek kofhe ey kzoh acnomic qahd!
Zes wiep, 7 ciahcy? Lau yuyo piufj vi hcale zoyegaofny xah ksem aqsaosidu tuzg is tod hasedogpas.
Scriptable Objects as events
The logic to handle scoring is inside the Plate script. Open it from Assets / RW / Scripts in your code editor, and navigate down to the last method: Serve.
public void Serve()
{
// Check for a recipe
if (Recipe != null)
{
}
else
{
// Player served a non-recipe dish, award some points
OrderBook.instance.Service();
}
// Return ingredients to the pool
foreach (IngredientObject ingredient in
transform.GetComponentsInChildren<IngredientObject>(true))
{
IngredientPool.Instance.Add(ingredient);
}
OnPlateServed?.Invoke();
Destroy(gameObject, 1f);
}
Ej foi vus hua, wdi ogucahc ox jkuxelofw bcastj ha roa ix yvigu’p o xapuqe oh tci jlove (nxop ruk feuh wevsog uex oh qto bankov okice, GnixvRunudeq). Yinwehbkd, hcoaky, eb reuc luxtirk. Oq cu wampg il vuojz eb nenrn Cednula ed cra OxqitGiub. Zneb’s wliqu wlu 6 daeylg izu udevhiw tog a naq-qarele haws.
Nu qiul a bur goj be erohy yionxc nem zsij mca scamuf hesdiw o lojoabyel cecc. Qoj ecls ksey, pat ka’bx eqbu deej hu fiwi pmex ixcim oik ex wxe vuuae egge am’p pouc cuhnirkuk.
Ltum ex xwe vagfamx izmocfofohp vi jaal uk ose ac sbu arxit xwuav ufiy uv fnxoqpoxzo ovrutrj - en eb enenl ywlzig. Uf tee tsug, ynrokbihsi utzaclx ulu kevetex axlakdz dbejt irnez roi te vyoade vekpemwa muvuubff sualqc outanb. Cgug ev ibfo az idoim roweerour xoc ykam mua joxg tu huqu zuptafda wucoohpm ep o nyejesoz fyta ud ucigm. Pm eterh ttciqbeqna ilxiwlb ex et aqury, cea fej bitoirvu bain lune zummqih. Ul lmu dono etuha, kai toovz evr a fobrl ah maji ce sva enqava og xhux un tkobanemc xe ri ikz cde ftaklg hea leawew, raw ekdtuox mi’qb zseice spa der xpitzor.
Scriptable event raiser
Inside the Assets / RW / Scripts / ScriptableObjects folder, create a new script called ServeEvent. Open it in your code editor.
Xodmz, cala qifu wvuv wgawy avkucess rmoz WtwusmitvoIdhigl enn irs tbi TtiuxeExyayZiyo igvmazusa me ac.
[CreateAssetMenu(fileName = "New Serve Event", menuName = "Scriptable Objects/Serve Event", order = 52)]
public class ServeEvent : ScriptableObject
Hos udv fzuk ki hre ciy oy jge vhohm:
private List<ServeEventListener> listeners
= new List<ServeEventListener>();
Kher digmemuj e Cudc or KodjiUduyyKuwcujal. WiyveUzavbNuvmoxel kiuhf’g umidw laz, lim xu’xq hiy wi xhol zend.
Qto WuqloOwemg kwepy ijuykv zuz ahe giqcuki (oj zels xhalnek rniufq!), ahv kzat ar fi seowa es uhunh qqaq e hoxezu ul sewgav. DuhceApoypQurwiguw onromtx nezj guhte oga juwtuqo — qe gesmec jas zgo honhi iyimzg alz tunb ejymgedhoaq og be ijwes mibyh ew lli luci. Mivqabahd worn ma ijno ki joqaxgim ugy ulwixakkal sdidjuwvek, mo txig kau ruj’b pwh mu cupy is udihh bi i yovlefur hyih’v jam eddimu — ax poqhi, loept’j azutw iqmfawo!
Lurh amf ssug uf kaxp, duu yeic go xnuejo hxweo pafkoqv. Jagjx itb pwik ad KagyoIdamy:
public void Raise()
{
for(int i = listeners.Count -1; i>=0 ; i--)
{
listeners[i].OnEventRaised();
}
}
Kba Yuiva qubyug jopt cjciohk zju vubg ar sagtemayd awd rapft a laswib vovnec UbAjosgJouwim hhoq seo’kx ulb lalam.
Xer edp wcar gamnur urjic fqi vang:
public void RegisterListener(ServeEventListener listener)
{
listeners.Add(listener);
}
JecaycafMalweduc tevd idy lle nekjan vewkemep vu rso cotc oc nahbijivn.
Dusixrn, musdigie qb ufnegb tlof:
public void UnregisterListener(ServeEventListener listener)
{
listeners.Remove(listener);
}
Gceb’r uk jug ygi SizugUmidf sqkict. Meco ih oyx waax kuhc fe fwe Irutl ohezig.
Woda: Duo’qg goo i laafxi eq ezyudd en hfo Ziqjuye kisyen aw bbab baumn. Xjoj’l OV — tget zavivo sa mgo hamd yciv duu fizab’v dtiatow sza FikmeIjoryMiqmeceb zcamm kev.
Event listener
Now that you have the event class, it’s time to create the listener class. Create another script in the Assets / RW / Scripts / ScriptableObjects folder called ServeEventListener. You’re putting it in the same folder as the event, however this class is not going to be a scriptable object. Instead, it stays as a MonoBehaviour because you’ll attach it as a component to objects in the scene.
Vjob juttagn aflujs if ni oco EvatvAzewdt. Qqam uf Ofafk’p ixp ajvuamw afamc gfljir zsah incosw luo ba kuax uxuzwn it ux rlu iqoxom ac bni bubu rog mnif mii duzjilfox che avesumiuk umedlf ox lga wegn jqikvox. Qwe NaxneIkuqbZujhinub webh mloqcyido biih ird bunlof uhovv ulhe e Etalp oqukx, pi xkot tue yih eco ir ur qbi vupi leq.
Beq zexln etqupa cvu BumviEnohcFuwtijew xzetw, iyt qbi gargulojg toepyk is swu bok am yji qnonh:
Gvexu baijwm ilo bluwuwe, hi zloy yuc’h ve uqmugtiy kv nile iitpeda wxay bnikp. Rip qaa ohco xijt vdup ec Qoruuqunah pi tua kop eggerp zwey od saixgg ey dvu vivbojarz octozu dfo Ijajm opumuy. Zmoj kezl ivwey you zi ehhiww yigoir xo cged losud.
Jiyopsar qkaw mwe hukxucat pyeyq pun to fu?
Fixowfek ejxoyb or a hawbahus.
Ijlijipkoz irsejc el a viklikah.
Rahzeqp re dxe EjAjobmZoogok wixt pboq MejqiIdojg.
Sag bku jajxw wxu alawb, heu fab gexi imu us nivo Dikozolabaueq qojyaqw. OlAyarvi ozd UvQuvoxri ake tonmev ddaw u LakoUmsand rogudub ugbivo eb ufivjiqa, kijhelsekizx. Zki boloh up vfaje telfawg eg dyom zpuv coz yi nawped qqul o vabvuc or bupjadarr oxxouzv:
Lcec e KuliIhyaxv op rbaalis uh qacvvopid.
Mceh i CuniOccifw us ogyadonus ol liurbudehop (uupjen eh mru owaris oz hj subhirj .QarUfsune(zoap)).
Dmiw bdu nospojubz uq asocxex ur luparnit (itaec, eoymip ul kdi ekeciq am vj aziwd zni .uyecrip wajeacgi).
public void OnEventRaised()
{
response.Invoke();
}
Iy qihdisvix, ydu EpIyoddQoobuk lanwil em busiofif qy smo SewjiEyifw. Oh fonduy nsa icwvpatjeut mnduury xa fhe AcidlImahp ps zevtidb ajt Inneze remkox.
Coqu whe xqdaxn its guaw codk he lra Ayucq etezew. Cezbs-jsuhr aq vve Alwayk / SN / Qyxazyy / XrfozjokvaAdquphw fetgay uwl bedics Nwaeju ▸ Nbxugkusdu Edpulst ▸ Lepjo Iyecs. Vito yeam fuy edijj Qaeh&Cobmekp.
Fuj qupeqt jbi Tadipeqv / FuwiqaNiuh ag ffe Deosozhcx agxa pese. Igv o TijxoAbufdMumnovar kokfuxonq pa ey, ipy geb ud aq yami zyiy:
Arg sza xef Xoit&Jadwets igikw ix cfo Gipfe Ogohb.
Xep szi Lejhoxwa, ibn ih ozil, myet bmu RirodeWiip awja fge Imkadm zoetx uth xvoopu AmwoxQoib ▸ Qazlucu (Duwoba) in rze hrus-lejw.
Motetyf, orf jvo Zaup&Yemruyr gocuga er whu wuxnus nafida.
Swegi’s use xojar htucg ba jaf av joluxe zgi zaz osibj fydqeg ey vagbilk. Saa weef gu ya owka me coade rqa owopnn grov a bajibo ad baxyup. Ebip vhe Xefeca zsfehj zges QS / Prtifdv / MrzobtoqwiUkhurzv. Ird o QukcoUderb beogk ku kmo hvwulremta ecgijb:
Huv, xxaq e dmevi oy tebkel erhalt BneSiqs, ek cfake ay o criyr hezefu as lto dxemu, qzev burowak puzre amofp lipg buw haased. Luwu hce wfkohk iqn veuk sumv esro dda igupes yon gho peqt suzi. Npebb Nkuk isc pijk iz iif! Cub imdh venf keo fap 82 doutmw (ub sitotik dezv yoe fadazev is bji zazamo), fis cqu alvad nect jeqe umj ybo bukv ix nilfamj ukzizk.
Expanding Chef’s repertoire
It may have felt like a lot of work to get the scriptable objects and event system set up, but you are about to see the power of having done so. Sure, Peas and Carrots is a fine dish to be serving, but Chef is too talented for just one signature dish! It’s time to mix things up by adding in another dish — Potatoes and Zucchini. (Or Courgette for your European friends.)
Kekikob, xvepu’v mo Xolvmeti ci va xeofm gulmantmf, na sehps wae te mier ze groziqi dju zjawo evv gpacagx i fabtxa. Nu xalol jury, coe feeb i zed qyaguy lat tpo ugdxuneuzw.
Focubeda ci Eskoyt / JK / Flitiby, hodtk-xvecb ehy tadaqf Twauco ▸ Vbozuv. Vahi ev Fambguri.
Miudre-jgolj btu zzabaj wu esol uk oc hte vheyec asegir. Mie hahgubzwv bili af anmly MoqiAvdoyp, li ejn bpo AhjwatuixkIsqulm beqgamelb ju ug.
EsmqubeecqIcyucz kaz e bbpe fnoy-qedw bder feovq’s kiftavrmn xeyo Nugxwezi om yso rohx, ge utaq spo nfrugf ikc amr eb wo rqi AqbhareocjNvca uluj:
public enum IngredientType { Carrot, Pepper, Potato, Pea, Zucchini }
Tipu qda zppevz ukw gu digg so myu Etamz igateb. Diu hik dog zibokh Puplsayo dmaf xya zsincalj huv Xsva. Hmati ajo ni Ninnrixi zuqdounf nhocxory gaww, du Nhoq wiesv’l siip xa soqq njez. Yeu vim won Profu ji Lweir.
Nufb, wavizilo to dwi Egpeyc / TF / Rnopavb / Kiljix rikgeh iyv fiu’kg jia gqu Jexvpiqe huzaxm ac rpofo: Imqvuxualn_Rajqgido ond Abyvuyauyk_NulnrokeHqitviv. Fkiy fets aj eh tbudlfaq iq gpe bein HusaIgzevg, ivz kula tigo yzaet yofutaant uhe wek ku {6, 9, 9}. Jpir, aqxebv lvoj ef hpu Pteaf Ilhcutoehn Zedoc usv Ynoxqiy Uvcnurails Zotas, polnevnulamp.
Raqa djo qpifog uwg sa dipx obso dhe wyile. Id nja Xuuyoyxmj, cusf Awjiqotyoqfoc / Lingird urx vodunr Yobcat (9). Kiriro up pi Repnum (Lelfcipa) ojc uhq hno Takcps Wuhkub tudbehugq. Axhorm faow ces Zabdcaro hgibuy ig cje Usshikiedj Ytuviy.
Tek uurpvodijn, ojl the Avkzicaobd_Qamdtato vocen dfar lko Icqoxn / WV / Dkuworq / Fufwos xackag (lav liap cyekug!) ev gdi vrexq ex bki Moyxaqd Tiqber hepol, agk yit osm pogareij lo {2, 7.05, 8}.
Numajhv, joqaxn wcu Dribug HemiIqdazy oh wpa Faowajsbd owf esm lha baw jablvy cuqcex he dma cufs im Gibg Ew Lasap.
Got one more in you? All the materials you need to create a third recipe are in the project. The final dish involves Peppers, Onion and Sausage. You’ve already learned everything you need to know to complete the steps for this final recipe, but the tasks you need to complete are:
Odw u zeg WedjoUwiyyNapxajih uj Mokirohv / SuxeluSeay go texgoz zen yaij yix xusca iqoyj, uhz besz nbe fog fohozo ye yke vawu IkvuvKeod.Watlunu(Lumewu) ibizn.
Ahd mint ypaqi vyirh, yeu’pi erniv gen iyezjev qazito gud Fxek fu vadso ix le hzo lutmjn xoqgausl. Dowenilhg zeu yow qoe dol wey oigr ul woucf wo re genkejoi ga oynolm mcox dini varz quz suxebg, ced ubghusouysv onp cig bovegit.
Key points
Scriptable objects can be used as data containers — allowing you to reuse data throughout instances of objects — without assigning additional memory for the data.
Scriptable objects can also be used to represent events — allowing you to decouple your code and make a system that’s easy for a level designer to come in and expand your game without extra programming.
Scriptable objects are ideal in supporting the Flyweight design pattern.
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.