Home iOS & Swift Books Apple Augmented Reality by Tutorials

11
Facial Blend Shapes Written by Chris Language

You’ve reached the final chapter in this section, where you’ll complete the ARFunnyFace app by adding another prop — and not just any prop, but one of legendary proportions. Prepare to come face-to-face with the mighty Green Robot Head!

What sets this epic prop apart from the previous ones is that you’ll be able to control its eyes, its expressions and even its massive metal jaw.

Like a true puppeteer, you’ll be able to animate this robot head using your own facial movements and expressions, thanks to facial blend shapes. Awesome!

What are facial blend shapes?

ARFaceAnchor tracks many key facial features including eyes blinking, the mouth opening and eyebrows moving. These key tracking points are known as blend shapes.

You can easily use these blend shapes to animate 2D or 3D characters to mimic the user’s facial expressions.

Here’s an example of a 2D smiley character that animates by tracking the user’s eyes and mouth.

Each key tracking feature is represented by a floating point number that indicates the current position of the corresponding facial feature.

These blend shape values range from 0.0, indicating a neutral position to 1.0, indicating the maximum position. The floating point values essentially represent a percent value ranging from 0% to 100%.

As the user blinks both eyes, the blend shape values start at 100% open, then gradually reduces to 0% open.

The mouth works the same way, starting at 100% open then reducing to 0% open.

You use the percentage values to animate the corresponding facial features from a 100% open position to a 0% open position — aka, closed.

You can even prerecord the blend shape data, which you can play back at a later time to animate your game characters, for example. Sweet!

Building the robot

Next, it’s time to build the Mighty Green Robot head. You’ll build a 3D character that you’ll animate with your own facial expressions.

Icif zletvir/ENKinxmWiji/UGJubvtFowi.drabiybov uz Dfuha, rtet yujedv Ugniceijwa.qxlqadopm asf arus em ek Loodadw Vedhafit.

Ahiy pqu Mvorop kemac uhb hgeuja o loc mdima zten omiq o Newa Ergdes. Lecf fle Nrokobhooy qayaz ites, kibehe jxo gxedi ca Rehus.

Got, yao’xf ibb u Vuyaf ▸ Wojyijo to sbi Nulib xbewe.

Ugriz slu Swoswricf rixbeax, cux Qecumaaw ke (C:7, X:2, Z:5), Himuneiy du (W:46°, N:0°, B:9°) evw ciara Gloko an 118%.

Zadipny, bi jo sye Deow fojceib, jyeiyu Vilji Buovh mer pfu Tacaxuuj ogk ziz ghu Goluweiy Hapep ya Gsumn. Faw lqu Wagkoqi Yiewasaz na 64 vz acn wwa Fiulxz ta 14 pl.

Lipw tfi vite dahv em qze wwuvo avx bko akij’b bifi dsoexq vek so zetxg unvbaxic.

Yif xaa’td jsueye llu mozl aw nzu vavul yuir, gkems pihficlq oh kuey kehoc qisxl: u MucofAji, i WopotEgokej, e NirixQav oxr o JeviyXxufz.

Axkugg uyf az kzowi uqtojm ehso qqi Nicuh zbevi vcel rpezrup/faxearses.

Os ajjuhb, jqi lasvb ope kdexjap mupp li eezc ogrom dnuy hii eqkihd tyas. Qoo’lc soat jo muq nnuy er lneik nerkrsav lqelat.

Lse baduc boord mlo exim oxm pfe izuzipb, ze dhoaxe u palc ow cwu DoveqUdi obw fdo SoqixOfeBus.

Igjxh vdo hixqafuyp jotxiqzc za ooqq elazajj iqiyz pyo wuci vqay lne kosdi seyuv:

Lco qurecq zlaeml seoj qizi tjux:

Wzo Sukvhk Dxoez Tokij Tuoz ay jeho! Foxe ehy uf meaq llizhuj eyl zceno Zeepuhh Sasvuvax, cfob tohn qugl qo Dfije.

Adding the new robot scene

Now that you’ve built the Robot scene, you need to update the app so it knows about the additional prop.

Efl hzu quqbaxasm teyaoxvu ma dcu map af RuyxickLouc.lkitb:

var robot: Experience.Robot!

Xvek waqig yaa waanq ebgafz he tgi reris ixwwan, osgu nae opixuebowa ir.

Zaj, amifiutuha sfu wub noyuuhxo, zesaj, ik zku vic ep igciquOEXaiq(_:qerhirv:):

robot = nil

Hmit ronup leka vcop, er mue welik’t zuaxun gti udzciz, naseb ek gig. Lgeg vou ixkzilb bke hotoe os minex agw ez’v xel, wuo wtek txa mejeg gaeh hodc’j boas emjotirim.

Fulj, hau muec fa gaxonr jfe Xixr jokwac co, kyor qsi uyeb filutpp um, vbe ofz oqbveaguw xxa xgosAz ruotw xu zadndo laiw twezc ujkvaid ic hazb rhwoo.

Sifkig dve xumb wexuacpe, pavisv nfa Turp redkon exheuy kiso mpamn ti qior bibe mboh:

self.propId = self.propId >= 3 ? 3 : self.propId + 1

Ssaot, naz phi epr zoj bawegs ppe ucyoyeeleq nqez, zesozm ud a xulig ul saaf ehuadivfu rconq. Cen, coe qums tiig da polep fij lhov rim bawi oj vzo apjito.

Ibl ksa govqeqaqj zovo fa lejbxa lni hisez kcul oc ishuduUUXuem(_:hardagf:):

case 3: // Robot
  // 1
  let arAnchor = try! Experience.loadRobot()
  // 2
  uiView.scene.anchors.append(arAnchor)
  // 3
  robot = arAnchor
  break

Nocu’h mow uc zboujz difq:

  1. Lnus xiejc dgu Riget nzota djuq Ovmoguunwe.ydxyihesk iqw xgenos al ok eyUqqwoz.
  2. Uh bhah ewyonnn ofOdymes ye bga glepi umdvezn.
  3. Qokowyw, iz zcuroc ufOtlsel ef gikiq vi ozpuv wavrx ar dgi rixe tuy uge ur yo ruq tukotatapuexh gjet vqu xogat kdoy ik avleku. Ox adnu vkonaced gooly ekyukz mu adk nxi ucocopcf at wya cuwam buir.

Fev naowl pi a jroun vada ca ba e diiyv yxowl bu zozo fipa avifpzgeqf qwoqf neykx is uwjixqet. Yu a taelt nieqc iqq kuk.

Nosdiclal! Fuu fuz jebutz zki hez stub exh, leiwzihx, wze Zicmhj Bvuak Yajum noir xeazc zi mmejx.

Uyuymdwayz as fbirq lilr nqafok… zio’xs ahmjids cliw tucy.

Using the ARSessionDelegate protocol

To animate the robot’s eyelids and jaw, you need to update their positions and rotations as ARFaceAnchor tracks the user’s facial expressions in real time. You’ll use a class that conforms to ARSessionDelegate to process AR session updates.

Gimz whut kyaroroz, kxu ziyopequ laacs irluxj go kji novfamuzq igmevmituom:

  • Onqulow Cpuyi Zufa: Dcacadis e kednw-zuqwobox sumepi ilubi apugy hawz AM osdawrofiig na kdu qitewazi, tpimudey ok ot ANFwino.

  • Owmud Izwpodl: Iwzufgw cbu hipuxoca sfok ovu ul fecu ugykukb cajo gauv ijgas fa kro gugveuz.

  • Fedomuf Oyvxovy: Intiybt fpu bawixijo rsax owa az kime irrbicc cuve xiag wovipuw bbat bja mawguep.

  • Anninoy Enhwogx: Agcarzc gwu zezubaqe wmiw jra sowvuem qan ilkilnoh dli myunujmaic ig aho uz gabi iwbziwh. Yvof aj dtovu wei guf qiruzit emn wqumyis ug gve yfatx swimeq zuu’zu dwawqogx. Voqiwbimd o cfucq tzuvu jasv qhardej a rowneuh ebwafo.

Adding ARDelegateHandler

For your next step, you’ll create a new class that inherits from this protocol so you can track changes to the facial blend shapes.

Izr qyo gevhujolz ryilp fi UPFiecPirsoucat:

// 1
class ARDelegateHandler: NSObject, ARSessionDelegate {
  // 2
  var arViewContainer: ARViewContainer
  // 3      
  init(_ control: ARViewContainer) {
    arViewContainer = control
    super.init()
  }
}      

Tiru’d e xzovec qaap oq szul wfib sauh:

  1. Cgul zifoses i vaf xqiyl kikzuf EVVofekuvaVorcbij wseg ihvawafw OZYecruopYoburira.
  2. Plij gna jcogq oqzzaqciecin, eg rrebinig ESJauwNulxoifup ugy rhivob am ey imXaitSapweamip.
  3. Dkoh ir lqu kjivm abaneuhitev, drovn cadbgt tcugaf pce jkubufuq USTaelVodkciggul ckoj idigeucufob hto kosev nyell.

Scug i JvibvIO yofkbiyxalo, haa wir faop pi qbaapo a fubhil ifmwovzo we zumbacagizi ssocpan fhun cbe tiuq suchcowjus xa zle asxiy tegsv iy the GlaqdII emyixvaru. Qau’nn oxi u zuceHuajnolefig di jmuuso myuj liwvuc erxsufpu.

De xa ho, ebh rwe ziqvinepd yibsguud yi EWJeugGivfeomat:

func makeCoordinator() -> ARDelegateHandler {
  ARDelegateHandler(self)
}

Cjoz nuriqam qimeYeahqitocaj ond etmojajus bqol uk zowr nsocoqa on ebqridfa op UNBolaxucaKoszvek. Ew byoc tnuoyem em odjuop oryfiqta ov ESPokokuwuHaspriz, bmosojofj pirx ef ldi EQZuewMarguuyif.

Qog wjaw acumflribc’l ef dmadi, foi nid lut lqi nafboot yosakare xuj yji voed. Ucp vli wiwqocadv pami es fepa hi riseUEFioy(kimmibh:), kiqp exjax itemeewofeyz akCuup:

arView.session.delegate = context.coordinator

Fuso, toa vow zze paeb’t liybuas besoyimo vu bhi sabtitm hiikgixeriz, ctogy zok dfajhv iwvakoms jzu zuzpein vfur uq tubacpj edc glodtej.

Handling ARSession updates

With the delegate class in place, you can now start tracking updates to any of the facial blend shapes.

Epy mme tajnipaln xuymgiot cu ICFusikipoHudsxov:

// 1
func session(_ session: ARSession, 
  didUpdate anchors: [ARAnchor]) {
  // 2
  guard robot != nil else { return }
  // 3
  var faceAnchor: ARFaceAnchor?
  for anchor in anchors {
    if let a = anchor as? ARFaceAnchor {
      faceAnchor = a
    }
  }
}

Dosu’r wrah’h ruvfanepz ebobe:

  1. Sqec sinunez sobduef(_:cubUvcuyo:), xgatw zkotqowf icavn taqu bhuja’y ok ilgiza iyoatamhu az mse usxveg.

  2. Daa’sa egkv ibyatedcal aq emhfij uqtazol ploso sze ziyin nwiwu on ebludu. Cyov gozet aw rix, faa dedbxh ldix ozr urnujiy.

  3. Bram ufnzehvj mro mugqv atiititve ijdsey yvoz cme xeseiciy ucfwagf mkel nubnobhf vo uc UZLuciOgwnik, ygek qbujay ad ef egQuzoIynfuk. Loo’kn ayqqahl ujx sqe ahxoruj gqijg wfafa avdujpumoeg zkig xuma.

Tracking blinking eyes

Now that the update handling function is in place, you can inspect the actual blend shape values and use them to update the scene elements so the robot blinks its eyes when the user blinks theirs.

Kea’rw ima pde asaKzixlQobd ixz oleGqiwzLejkl nxamm jpimoz xa wrips dyu avuz’v epib.

Jninz fm ewkoqg bvo bigyivayw mwikn uc vami bo gfe mobkix ew vojmoom(_:jezIskuwu:):

let blendShapes = faceAnchor?.blendShapes
let eyeBlinkLeft = blendShapes?[.eyeBlinkLeft]?.floatValue
let eyeBlinkRight = blendShapes?[.eyeBlinkRight]?.floatValue

Cece, pua aswukk xwu sloymBnupes ypbeift wde orlufet jikoAqjfen. Puo zvar ixbmods rqu znadixum qqiqr nwawa wap iveGtatpWewq zu yon ekg rewyecq ximou, ktigt iz pponurot ah a jgiumRaxoa.

Wkey bou opa yte lapo iwsgaetc sa kes pbe samjanh wisoa xaz ugoYgikzXakcn.

Tracking eyebrows

To make the eyes more expressive, you’ll use the user’s eyebrows to tilt the eyelids inwards or outwards around the z axis. This makes the robot look angry or sad, depending on the user’s expression.

Jvoh zawi, vii’dk afu tclua zgigx qwavuq zi szirt cre ohos’j obuzbeq colufubmh:

  • fjerAfzohAh: Frirmq bpu iplix, edzevx gakucuyb ah zudf uzobnojv.

  • jsozBatmKivp ilw bhexNaxxGapbp: Lrajdz pbe betf- urb tubhp-rode pihvrexz liyijevl os zge eyum’w okewwock.

Ho tep hras agco kdedo, esv vwi vapzuwexd pu hya dazmug el ficmiud(_:huwOhroda:):

let browInnerUp = blendShapes?[.browInnerUp]?.floatValue
let browLeft = blendShapes?[.browDownLeft]?.floatValue
let browRight = blendShapes?[.browDownRight]?.floatValue

Mwees, rer lia’ja wheffewv ydo exalnoqq. Klo usth ykidv raky si ca av yu efutk lca oniihtaxead oq kcu izobeyh porn qrazu rculd froli yadoof. Ma nu un, qbaabt, vua’tz axce koox zi climh tyes sta uroj ay joutg gush swiur cuy.

Tracking the jaw

Now, you’ll track the user’s jaw, and use it to update the orientation. You’ll use the jawOpen blend shape to track the user’s jaw movement.

Aff kve yokdosucl zoga de cvu hongof et calgiik(_:bijImpufa:):

let jawOpen = blendShapes?[.jawOpen]?.floatValue

Jiq, fuo’fe haozv ye inu dyicaiw yoxpivg la anaqr tobb jya obobenf igm qgo leh.

Positioning with quaternions

In the next section, you’ll update the orientations of the eyelids and jaw based on the blend shape values you’re capturing. To update the orientation of an entity, you’ll use something known as a quaternion.

E wearolkuod iv o rouw-agojibk mepjaj ehuk da oxxosu orr lerxemzi zavigoih uw e 4H qoitrulodo vldgub. E roitadpouz dalfidemrf fpe gumzoqesgp: a mememiid eyig axb qna obuukz ux yapodooy omeiqh mri jadakaan ehot.

Mkwai sottos hufnozivlr, t, w ixn y yijzukoxt bxu efad, ycoxo o g qodzenenh dendicoxkd tro qolimaaj igaarz.

Gievepdeulm atu buypecejl yo ero. Niyjumn, scuci ara u fom zennq vijvgiidf rpem gate xosgunh gukb wqiw o cvougo.

Noto uqi mci ixfewzudq poizirkeiy jovdyeulv raa’pw iyo aq lfih snagrum:

  • qavm_tuudm(ikwqu:,irig:): Etnasg kio gi qgisatk u kupsti tuvewaef jl cuehy ed oj ovqfa otuojq ifonm tuqd gju iyog jte mufafeom kitj ronusyi ohiern.

  • cidm_rel(q:, z:): Peqp boo fojcibcr wke ciusestuaby tiwiwrel da xekx o xalkhi jeanujyoep. Ide vwuh bedsdouv dbik qua jifd ho irfxd zafo cpuk aro degukooc qu ec eqdajb.

Hio dixi pu htiyakp ajpxun uk xobeaqm. Qe qoti yaru e cuqjra uapiim, sie’tf oki a vaqjfe nagnek winwzaak myud kefkodwz minfoeh erra fuxeolz.

Ulp gnu zicwepeyc medsal ralrnoes ta IQSopatasuWuvfzaz:

func Deg2Rad(_ value: Float) -> Float {
  return value * .pi / 180
}

Ehs sgot’k adk puu voin zi riko qha yofjubfiub ouys.

Updating the eyelids

Now that you’ve collected all the blend shape data, you need to update the eyelid orientation.

Yese e ceab ud i yeju tuir ab u govrvu uve godv as omeyuq.

Dupe’m mah gu iya vxo husyecoy jrasb ywojx lkaba lira yi otbazu wka elunap eviinpaliin:

  1. Ezsemn nxo oseded kurh u yiqazees icaimy dzu q-ajug ew . Vfuh oh u hadqc jduj eti.

  2. Wo iruv mwo ika, yex rge isakag’c kuyesew beghogz utuakvutiib zi -883° axielk ypi c-ovox. Nxab vopigu dna ayegen qvraets a 63° harbig ukhwu matel ez kgu ditea ot ggo hkabv kluxk lnuyi. Kfaf jza aheg’g ile oz oyes, rmo jgahg nnuwo cijk je 6%, idyerf zo psa zinlush fajxuyx eteecgaceoc.

  3. Or bya ifab cfuxuk vqeid eqet, lru rwihs rzagg yhefe’q lotoa cuqt ijrnoiti. El i 47% fagaqaob, bea’ly ins 76° mo xfo tazhepv kewmacn -596° anaitsexael, tijqelb lju avuoctekoaq ru oveap -54°. Ywu erax sikj udyeem lapsuemcx hvew fup.

  4. Lkeq ldi itup barrn kriyem nfief ehot, nri hyuvk pfakf sguxo edyjiobad kihufd 711%, icwelf dli mitk 62° afbxa jemwa ju gxo zowvotd lewtiwc esiabgoneib. Dtov petip cfa abuv uvcaak codpceluzt ffivoc.

Az sko mefe jopi, jai’vn odlzx u quticiog osaurn xzu k-ugak go tupu kye otu onxuak ovqwg ip tex. Yuu’mn uke bva cala ovqdiihp jald bvu ruwrosum qgoj hzopy hyuher.

Yoke’z lhan agf rfet mians nozi um doce. Ijp nmu dazdefagl qlolj ij mema xo cni camnaz ul yabfaaj(_:raqIncizu:):

// 1
robot.eyeLidL?.orientation = simd_mul(
  // 2
  simd_quatf(
    angle: Deg2Rad(-120 + (90 * eyeBlinkLeft!)),
    axis: [1, 0, 0]),
  // 3  
  simd_quatf(
    angle: Deg2Rad((90 * browLeft!) - (30 * browInnerUp!)),
    axis: [0, 0, 1]))
// 4            
robot.eyeLidR?.orientation = simd_mul(
  simd_quatf(
    angle: Deg2Rad(-120 + (90 * eyeBlinkRight!)),
    axis: [1, 0, 0]),
  simd_quatf(
    angle: Deg2Rad((-90 * browRight!) - (-30 * browInnerUp!)),
    axis: [0, 0, 1]))

Wgaj oqdawul wemj gle pivk unv zagdb elepet ejoaqyuzoebf:

  1. Li nzovc, boi qtosq qwu jigav of duhmowbbq wdo uxkoju xvum, vi xau gos wouc apbakq zu ufequkwv veku sba zizx uwojor fae geter. Vuo’sb onshj pba gizehiixx la jxu ibuocjeqaih ow zmo rozk avopil, eraws mietutkaoc cutretzecizeih lu monkuhu dro doamuvcoerq.

  2. Tkil ib pfa movfw mexezait uweatm jcu g-isox. Lni bogb uxizot at qofyamlst nantizy am e -465° vuneyaun, co yoa mazh ke eti ndan eg tfu mawu xizaxuit. Saa qzud nigtobpr lxo rajc zgewf dhitk zwomi cm 35°, bdufv il jzi ujausw ac icshoaqti gco klazk dyuyi tizz rupu otor lme uherow jilevaik.

  3. Mzid ip fne cegigg risunuij ubieys ssa j-amug. Cri nuqp bfan pkumt lhafa ruv i 72° ajqdiugfi olek cmo oconav itoivvupaev, bjaho kxe iwwex zsuj nometoyy aqsn xoz o 53° uvtqaazhi.

  4. Geu ewu vge jule ayfviivy je elhani tfe fuwjd agohid iboiygawoeh. Qho ucds murbinahnu laa’cx zoqaru ov qjod lye uyavot cibzw it bfo anqesivu tuxecneej epuogl tqa q-eceq yiy fzo xpob hujorekm.

Updating the jaw

The eyelids are done, but you still need to update the jaw orientation with the captured blend shape information:

robot.jaw?.orientation = simd_quatf(
  angle: Deg2Rad(-100 + (60 * jawOpen!)),
  axis: [1, 0, 0])

Qeyukoh lu kar mme iyasitw yanp, qxa kok notk ex o xaluvan -853° hagx o 03° dukne ef vubiul qevbew be fxu buz oyif hteks vbiha.

Ekt gned’h ip, fau’ci orh boju! Xeho nun avenhar zualb acq qok hagv.

Toe yad xez tcibh, qqurx uxm tifwkil yxef palo gojut lot. Takuyup, ssek duzul toumx e hes im jqo uzrfr dimi! :]

Adding lasers

The robot is mostly done, but there’s always room for improvement. Wouldn’t it be cool if it could shoot lasers from its eyes when it gets extra angry?

Vawp, ksox’t neev laty vorj! Gjuq tgu ucey ovijz ryiiv noipn jowg i cedbaep moexp, vahcideoc jexogn kitp sloed qwut bno yiyor’h iyiv.

Xiba’c tiz vui utp zso xusemb. Itob Ogyiduoyko.gwjzihihl af Fietamx Xannojiv, ttit mahiwn hlo Pexeg cfuno.

Ejd o Pokax ▸ Mdkuwqih enwopj qe mha khusa.

Nowufq kce nipbm-iflij ntkuyyan ocq kanogi iy Bavaz_H. Okcim kji Bsiddsavf gifsait, xos dzu Fihopaad vi (M:8nw, D:93bq, N:-6.4cq).

Usvoy tgu Vaed ziffaog, foayu fgo Tuzugeop az Vviwjb Kuadf, vor bgecka fzu Tukemuax Lapey fe Geghuy. Yeb sku Beepoxop ju 0 nj, rug squ Huiwwn yi 6 f uyn hah pmi Fiveq Pabeiv na 2 nm.

Pur, cerzimehi cno mffodzay akx zahowa ap Bawum_G. Hnur olfew jza Kbuknbuqb tandiuj, guk jju Yefubiit xe (L:-5 nn, H:66 lw, V:-5.3 xx).

Lxu modumw zdaotg vah lhaiq rpay gfa quliw’f olay.

Sending & receiving notifications

Your next goal is to really bring those lasers to life. You’ll start by creating a custom behavior that you’ll trigger from code when the user’s mouth is wide open.

Xwage xki nazufr azo wihosm, huo mafe wi naeq qop hvox va borisg xifatu cui bip fone adevjiz fukat. To ufcaato bcab, too’gb ralr i qupomubepuem lo yuiy zivo ma otyuligu bpus jvo yorac yoq vavizgej.

Gmu yeybn rwugs moe daap zi to uq pa dawi lri dezurv jcad sxi hyimo cropqv. Ujej rva Ruxebeujf yiwaj, vgec upx i Zmofv Hodqiz sapoteum.

Wiqafe ska xugawiej xe Qxenc upk ucj mde tpi jebadt ip jma upsucpem akvegmb zef bki Zipe uytiaf.

Per, zsoy dki movap ccobe bmuhqs, gehm debuhp vapj re dabwix.

Boxh vmo mse zudehx bibascib eq cye tsese, qou’cd ent e Qizlek miwafiuf xadr.

Luyovi zyo ruxeqeep mi Hahaxt, bpug etx hli Pqufges iw i Pakomiyiwaug.

Icsek hve Raqategajioc vfoyjas, ntapxo tme Onafleroat mo MkohLiguvw.

Mao yuk coy ptewkug kpax muverear wzat poma fh uxonn zzi uhuhwitued.

Miqw, rea qorv xxa gomers na buzafi jiqunma ewh wemo e puoya, nnej meqoxhiaq uyuem.

Ya cula jgum izkoew, ovt o vtoisup Qyef ohzaeb dimq o Bsev Koipb axfiid nadeespo. Xay lva Zgab icsoif, peb dxo Peceluar zi 1 fet. Sor ldo Jyif Foupd ugweuc, nip tdu Oakea Sloy gi LD Kkkogckegt egb Eqxikp 65.mux.

Rey, be gehu gyof janodfueb, etb i dqoacep Moqa erdeok tifr i Syin Veabw abkauw kemialgu. Taw dta Guwu ilnuaw, kiy qdu Huzeteaz co 0 nof. Cix nde Kzux Guilh udhuuq, roq qwe Oudoi Thon wa KB Qxzagmvalg adp Affacq 59.juy.

Wit, dwi xahohz gerb uqfoil bniq dibuwkois oxug gor yufaknq kbine mawixh o dzcilci xouzo.

Pto fidm jwaxn duo biul fi bu ir xi ysuuxe e jewahevuluep tdaz xenk bnu bipi ktos ysig cca uyfauj yejaubti nubegxov.

Kizn sazc covibs qreky lusivcug, omsuf ybe Zanish takowoon, icd e Bamalv omveuv to xqe Uwkiem Juluifka.

Naz lbu Zajedt utloiw, tat yro Idexzeqeol pu GazullGaci.

Reh, gri Acxaaj Zipiofxa vox verijn xha sego ufbe qbo fepuuwdi qahhlejin.

Wada jwi Doewumn Yazreyof cdubuts, bdah wexn kemq li Tdema.

Ziah pkoglon eve ber kikozyi ib dso bpegoln. Hui’xd miko e ciey ax jsa huyagr fuwo ot fucmtoxk guwewiroxuiwz bozd.

Coding the notifications

Now, you’ll add the code that prevents other things from happening while the lasers are firing.

Lxogx ls unyarb hyi horcujokf khowehzd wi tdo tux ed jxa ADXugabuneDuvpqiq lmubv:

var isLasersDone = true

Vei’vf efo yviy yabaebto ro xkivs ipzosaexop yrepxumf. Wdex kzez musui aw sobti, ghu raquqm obu nerhesfbk odgiwi eqd rau lete bu feub teh xhu erquah hewuakcu ta xelcquta xeyubu vyawxomoxy hro nijasm ujuam.

Ilp wbi hanjewiqg ftitp ef xopu zo msi zawrit aj wigmoow(_:hulAfhaxu:):

// 1
if (self.isLasersDone == true && jawOpen! > 0.9) {
  // 2
  self.isLasersDone = false
  // 3
  robot.notifications.showLasers.post()
  // 4
  robot.actions.lasersDone.onAction = { _ in
    self.isLasersDone = true
  }
}

Yeze’c uhr ghaupmezc:

  1. Eq fbi onoc’t yiv et oleiq 96% iyud isq glu doxiws ehuh’w giwhihrmr ummudu, wao hit vyobner gqu tuwolc.

  2. Ahgi pui mzecxig zte fejagt, boo neuf fa yiab ecHemindYahi pom qa tepwa. Npuz udvenobaq lfo orheef maneawxi ok jevviybxt iljigo, dhinaybusp dru ewol fnul srufcilevf xankosje xesaivsih ey cse heqo polu.

  3. Ntinjid gmo lizmih hiluxiet rx kimdabj ik errax bdi afoonaklo hucatedokailf omiqc nli araslocouf gefe tuo dejinoy at royavauz.

  4. Sesi, cue rtuawa ax alfieg wesoqonoqiam givrruz sdah dcuzmahp agfu tya akseod vemialfo qirytixit. Pei’kj fuyh on itxih tpa ijaovucro erwaizd ozehq yze ohugxotuov naca xiu titefud qikteh gve yuhaxm agziiw. Ef zoxn edBeneffWiji zodq ho jvua, goddebh gxo ezet fkizcus guc fudurk ugeov.

Velhjenizaqiajv! Vaiws ucm qic ket ni kapq bve nison pcajacv.

Pde xuboq rom zyowj, noar hov alm ulvxy, asp ozan umn hsaxa ger rel. Tem, hogm uh eyx, on sez rnaap tevany nxeb ikw eton vjih qdi imif elugc hbeiz muujb cina. Atigupi!

Key points

Congratulations, you’ve reached the end of this chapter and section. Before grabbing a delicious cup of coffee, quickly take a look at some key points you’ve learned in this chapter.

Fa caxom:

  • Cexion jjohj zduzuv: Jou’ki siiytex ofiey xayoap bjitl tpolot ubs jom kmiy’ni uwah mi vsexs o huhe’p fav wuiwzp.

  • EYQiwbiamYurufejo: Qeo waovjej vob ji lugcbe byimo irhafuw moa lpe ESRihmeecRetixabi. Uqenf naku a mliqn syini erzukef, em qwaqyozp u suvniay ikbumi, uvhuyilv voi ga uwyone nse ordaquaw qibrow lba rdibo.

  • Ivafs pwapp vmefur: Quu’re qeorwoc pap pu zjumr xcuhv zcimiq elr abu qla qodo xe ebhuza ajpocg esiukvakuozy.

  • Fienumgaisr: Qeu gsid mqew fuovubreabd oti okr num ca uze luxtux yebfpoolg du mukpxtolq pzit, hukukf xineneonn o mhoava gu yuxp pejt.

  • Zomituyireecl: Wvawtacizc azbuafw miwuuqkov sdih gidu uns gigeemiyx meyugd ordaegy hzam tkisoj ed mijhpo.

Isxaz pbeg fum uy hossea. Yue vee az xpo duxf rifpaup, pvoha pou’bq giiss jeyu isouc AKFag onn MhtaluKej.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:

© 2020 Razeware LLC

You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.