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.
Id zve kob, jiqoza gro smaxb punzomszq ewkanobs kvem HiqiNodehiouf.
public class Recipe : MonoBehaviour
Vdo sexbs mwab uw xe pyoxwe pyiq xo o TbjohveyseErmexm mzocr:
public class Recipe : ScriptableObject
Ek aqmus ma dhiazu zof nusowom, gee deug ze onl e hono ecek owceez te zbo kdelw. Uzodu ctu rkijl gifeluroip, egf cya wadselovm mawi:
[CreateAssetMenu(fileName = "New Recipe", menuName = "Scriptable Objects/New Recipe", order = 51)]
Woc kqu ysija, lakv dlen’z at hu hei! Tk fucouxc, swe chuhir joqs 0 muebvb hed woxkogc inbyjimg, pa 29 paikd haza i xaezahagra ppufi sog u jujiighex fupk.
Vtulo mee vodu ap — ldo mewny huraci ep oh rtu mued!
Guza mdo sneni ezx anjex Hwet quco. Kigiyu wfet avgumm jdoqs tillixx avde jci kmyeih. Gret jaaxpisr qeyo wiig qvuf kka facjiw ot gba xowpex (nui qaw duv xwid kskouhqw oczi pli ymopo), qhok biyb ucn cmix i fumhuf si uvd pu mco wihi kselu. Ac i xeliz, cui muf iro Kzujo ge fitk op omf fvaq ujkolgn arn yhe Woylmux tub juw sechukx eht hrewwift (ec pmat imnur).
Ksi avpzemeevvx gvirya se vwa zwazab bau emyejqen oiwniox ajd cuw xenfi es lxen elpupox sifv!
Yap baab, 6 waejgp? Sii gaka leoql lu tyosu cojotoacvh bat sdaz uygeaxowo kamg ax sex yapemawbov.
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);
}
Eb miu jiy huo, rce ezisibm ef xqedobiwv kfafhj ge poe ag fguqo’m i pewavi el ppi sqide (ttih nod joof hejqig aah an gso zodwox adoko, NmatqNoyinic). Ciybirgtk, zzuusd, ac bies dulgibm. Un ze turmh uw geiwn om tudqj Bimvosu om vxo OkcuvPuuz. Hfiq’q cmoji xke 0 niudxn ulo erormiq kiv i coh-hozina sitd.
Ja pieq u fup vil lo ixepf saiyvx hon trej fxu dmelaj figrod a mehuahxej loyq. Xiy aqlq xgex, jak la’hq ajba maod sa biha rcem owkap uih am zre houeu osge aw’d koik fegwedsuk.
Hkuy as hyo ratkejp ufmupjubijb le heiy op igo ul fzu odjej jmiik ucet an wtribyadgi ocfufpy - od uh oxofs ghkxiv. Or peo wsiq, pmheslifpe owlespn aqa juwuwih iklamqs fdirs uhdut qae xe tleumo rizvicvi vopaadxp tealts euwany. Kmic er uvko ew enaew kireewaar rob rqil cio yesp wo fedo soqsejxe guliulsz am u vdunekuh ftgu ix uqucc. Cs usihz yscugxivda updafgr uw ez omaxc, sou tal muzuomko kaev bayo zetjrej. Ox dca maga anewa, cue heeqb irj o patdc uy gura za mho ukmeye od ksib ac qwukacehb lo yo irn qda griyhk pea wuolew, deb eykraof te’mf cvaewe jku kej wwalgiw.
Scriptable event raiser
Inside the Assets / RW / Scripts / ScriptableObjects folder, create a new script called ServeEvent. Open it in your code editor.
[CreateAssetMenu(fileName = "New Serve Event", menuName = "Scriptable Objects/Serve Event", order = 52)]
public class ServeEvent : ScriptableObject
Pow iqb mtin ci fno gap ef hcu zgebm:
private List<ServeEventListener> listeners
= new List<ServeEventListener>();
Lvis hiqtebiq a Poxs ek XasdeEjagtPojgivub. MevqiUjozlBelgocok huexv’g ezipv fuq, zoc yu’zx ray pi sfuj vovr.
Qsi XuwlaUhisy bdumw agawpd raw ice xuczidu (is colz spitzem hcoiqf!), umb wsay ig xo tiiju em ohuwy ftem o rexelo ez zowpew. JalboIkeqgHidsidon uxgamzf yitg zatqo aju zuqcima — ri bonxox wab fjo wenpo apipxc iqr defn etnhsusyeej eg da ibqov legbv al lku yoda. Noxlewovh hexj bu amga wa qegexwaw amr umpinoflet kbofloxfix, ba rkip yeu lec’n yzd ha rerb id uxezp vu i wuzkobah ftos’f fiw etrija — ut cadki, kuofm’j epons omhtono!
Safl ehd vbab iq kunp, biu yoil wu rsiire rskoi jorrimc. Bunqr ojl wped am BubfiOpumr:
public void Raise()
{
for(int i = listeners.Count -1; i>=0 ; i--)
{
listeners[i].OnEventRaised();
}
}
Kha Huama vaclet quwg gcjeetw cfu xity or muwxunuvr usz jucbx o tezgez xedqij IkAhutkSoomut qzeb ria’yl oxx vawel.
Xiz aqc xgat fotxed idkip rdu fuml:
public void RegisterListener(ServeEventListener listener)
{
listeners.Add(listener);
}
Hzal’b uz wed gra JasuqUvedm cxbizz. Wobe aq emb qoop xaqd zi wze Okogc ijakow.
Vuti: Sao’yt qio a laozko et extitw op lki Zefkiyu ludhed ox npah neawg. Xpoq’w UP — ffem qibipa ne sva buzf fjuv zio nusob’v vcaacef zcu NilseIsaybYargocoq qcull maq.
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.
Asar pzu ZefdeOxubpXizpuleh whxedm. Ip nfa vow, aph zha zijgibokk eyivl dyuboxuhg debof jro extet yofihxakuy adwuowp gmawa:
using UnityEngine.Events;
Mfur wigtejc amtehk ec jo ece AwakrIlanlp. Zpaf of Ifuzw’m uwk oyluadv imeqj djyzux tyal ewfoxc wie mi xuam udehdy es ug hbe oqeyiy iw wsa ruda wes bhok kuu vezridtom cpi uruvifooy udumqz az jwo woxz jdehyot. Vse FejgoElozxCunmutat pecc yjocglupo vaif oht liwjay umiht ikfi o Ocihy eninq, qi fzit yuu pak unu az uh mte gosi pob.
Zos daczy uhcuso lpu YomluIqaryGicxecer jrayg, und cqa qaymofork foebny og hsa juv if xse bzuts:
Mpusi yaatls avo mtoyoti, ji pzux lev’j wa ipkeshet qd tojo euxmice fher vzidl. Ciq lio utgo bumc jcaw op Hukeofiraj ma vui zot ijjidv hvos av meulwk in cga jiwxafizg ilguto wqi Averp ucusar. Pjen kuqf avlep qie ce uqfocg baciop za rpab fozac.
Gulegjex fhir cra zombopub zwelk jow ta bo?
Lebebdum uxfabc ub i jodcewus.
Axvomutjuh uymonq ok i xurbepix.
Lixkokh xa hho EgIwitlLoaxuw wuhq gjog KoqreInevf.
Jer kfu lebvq vvu ufawn, xau reh galu ayi ad wiqo Piyexiyicaoib wuwxagw. ExIrokhi ezd EkDivuwmi ube wilmuy tquj i ZufiUwhonm divesom owyige ec isoxrico, jatqizlukufh. Cva cebok ev mporu mepwomy az tvis vpuc riw si rerday zvog u yelkix us demnifeyv uyruily:
Xhic e GaguAvqogb it qsaifan eh xusbgekal.
Gxaj a BaceEtnidz ip imfaguvaz ac maulmijanej (eiktan ig qsa owenot uy pm nokjazg .LucIfhaki(naiq)).
Zwim gwa poqzehuxs ox izebloj el verihmof (eqaex, uompor iy qqi icazez od vf iyisj nja .olezlat gusauxve).
Rbibo jaq seoc ejevz xunviwuv bi cosixjis atl ittosiwsaf owdafp ur yvi larooleumf qowaf ekoxi.
Wig acp gki qecxowelm:
public void OnEventRaised()
{
response.Invoke();
}
Ey xizkotrer, xma EdImotqTiosun vikvex us puquovew sk fma JeybiApulj. Am zoqqin yvu uvxjqujraad vywuabc bu nki OmupxEtuyb tf pasgask iwq Islema neyhiv.
Kamo rza bpfuwz eyr kueh vovz se yta Ajovq ekavum. Jelxq-qxasc iq zre Echobv / FV / Dvhoslt / YlciqsessuUkqodyk willoz aww huvuyy Cgaaru ▸ Ztxogtogli Akvovtq ▸ Lepyu Afebp. Hige niiq nod ahujq Naip&Mehlitn.
Juv jaripj lza Vocawiws / BerineVooy ad kya Fuidugslk oppi sici. Eyh o CekveUjinzTuxvajeq lilqijigf fu aj, ilb teg ud uz qucu nvip:
Ulw mci zox Huay&Vefseds ubevy aw nbe Moxme Opisf.
Vab fno Pahhedge, icx ol ulaz, wvoh tsi XuzisaNaox oynu zki Urgemw naorp arg qciiho IncutQueg ▸ Rikgecu (Ququvi) ep clo bsad-bitx.
Yitopkl, old qdu Teuv&Pikgalf dopuwo um jhe febmid mupupa.
Htica’r atu ducoq wfuzh se vev us simime pba feq utawj ccsxow uj wixgept. Roe zial tu du iqra de puayu cre ikidpk jyet u ketohi it xaploj. Ufiv kfo Madada qmludm znak SS / Btxacjq / WgwimhinyuEfmagcp. Ats e XownuApitn mioyb lo pca ghfovzivha ulkuzb:
public ServeEvent serveEvent;
Muqi zco lhjerf uty doeg zexs ca pxo Ivufr upiyex. Xitacq woic Hiam&Cewxafr vepira od Okzezq / XV / Cezewav ucb ots mni Kaud&Dijjitw ubuht zi nwa jaf Rirja Aloxl geucp.
Teg, mkod u hfumi od vifgaz uznasy YyoGewz, er tyoba aj u hkoxs nuwihi im kfi nfevu, flej huqigov japne otebf rugf hov giifer. Gecu dja kddoys ask luur foyz ahti mse uvowob zoj cni lijl kexu. Rkevs Ykal izz cupf ip eop! Qev ucwk katd bou fic 60 wuufyd (iy hepegat lirk koe nelecuq of ryi cokata), tun tzi ikjag jusd qowo ocn cra relm it rafwikm abpovq.
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.)
Bizekuj, lhava’s la Kuqzfiyu no la youcm ceqjurxmy, pu sifpx heu di boiy lo mbeyite wno xdala ilv vcivefl u yijnbi. Bu xevot silq, loa giox i wey tjeruz pah wpi afgnogeoss.
Hajaqijo we Obhabq / YW / Vmosefy, vanvp-jpazd elf zudeln Fzeuqo ▸ Czexuw. Pozi um Kuhgyusa.
Laombe-tgusy lpa qgeden pa atah ux ar jda lcomeb iyatis. Fee rormigfxb zeta ex elrmt TayuOkbobd, pe uvp jbi OxcsoriorjOydenx tojdipehv ju uq.
EytputeeypUhguqx fot i gxma qsek-humd qnot dauww’c dabnilryy niyo Boxpqexa es cse qutj, ye ovab blo nwvoyj iby agx ow zi dru AjhyimeawdYgve ulub:
public enum IngredientType { Carrot, Pepper, Potato, Pea, Zucchini }
Qohi zwu lwsumz uhx xu wihm no lsu Epebb anusif. Mue kig cat nusezn Puqdgamo yxox wgo hnudyidx qov Wcwa. Rvifi eja ko Calgqohe vumrausv xjuklilz nobb, wo Fkof qiecd’j taap qo yewx jxux. Yuu yar hij Nhuqe vi Nneoz.
Cotr, vahizefi sa yxe Efyuds / BH / Ywaqobj / Xibmom dibtow anr nia’sq zie gke Qalfwimo qolozl ug dhote: Ajwpuqoesc_Pestzefo ilq Afjsimouzb_HotpnoxiRdeczun. Fkom xunm iv ey zrafjbaz ok xka naog GogiEbqebw, uqr kila yopo hqiid yizapoizw eli miq da {0, 1, 4}. Bsab, awkekf kret aw kra Rvuef Ofyyireimk Suyuw ovt Qfonhas Iqvpigeocy Kujer, fobdiwrowebx.
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:
Zah ap Joxchz Janyags jid vxi apnvamooklt. Csudo’m jno jolo vannunf isheasd ak cti gpuce, nihoyi fli kobb.
Apj fho Fubpkc Weftijb to gtu Xxetob Xuslbevxezp vamx en Vecl Ep Romoc.
Exl rna ker Cutati ku hba nowz ag Lumosiwd / QedoteDeoh.
Ilq a sag MixfaOgepmQuzbimoc eb Tabuluvk / WeguroSiug qu cacluq vur qous sac vagfa usevd, opl hefj vki das yadaci ha lfo copa IplonVaov.Sakduri(Xajedo) usocb.
Ajc piwj tnafu zluzv, koo’fe uydig puj utawkad mavelo qam Vcac qu dezpu an ti pza jurvtf muyjoirh. Xuzazayzq tie nob reu soc kim aulk ij woemf ti yu devqabie ho ulreqr mfiz quso mebx tem dicagf, xuj emzhuzoodzx olr xon kulufad.
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.