iOS 9 Game Development Essentials -...

Preview:

Citation preview

iOS9GameDevelopmentEssentials

TableofContents

iOS9GameDevelopmentEssentials

Credits

AbouttheAuthor

AbouttheReviewers

www.PacktPub.com

Supportfiles,eBooks,discountoffers,andmore

Whysubscribe?

FreeaccessforPacktaccountholders

Preface

Whatthisbookcovers

Whatyouneedforthisbook

Whothisbookisfor

Conventions

Readerfeedback

Customersupport

Downloadingtheexamplecode

Downloadingthecolorimagesofthisbook

Errata

Piracy

Questions

1.TheSwiftProgrammingLanguage

HelloWorld!

Nomoresemicolons

Variables,constants,andprimitivedatatypes

Variables

Constants

Moreaboutconstants…

Arrays,matrices,sets,anddictionaries

Arrays

2Darrays/matrices

Sets

Dictionaries

Mutable/immutablecollections

Editing/accessingcollectiondata

Iteratingthroughcollectiontypes

Objective-CandSwiftcomparison

Objective-C

Swift

Charactersandstrings

StringInterpolation

Mutatingstrings

Stringindices

CommentinginSwift

Boolean

Ints,UInts,floats,anddoubles

Integersandunsignedintegers

Floatsanddoubles

ObjectsinSwift

Typesafetyandtypeinference

Optionals

Unwrappingoptionals

Optionalbindingandchaining

ControlflowinSwift

Ifstatements

Forloops

Do-whileloops

Switchstatements

Functionsandclasses

Functions

Tuples

Classes

Summary

2.StructuringandPlanningaGameUsingiOS9StoryboardsandSegues

Model-View-Controller

AniOSapp’slifecycle

Themain()function

TheUIApplicationclass/object

TheAppDelegateclass

Viewcontrollers

Viewcontrollertypes

Storyboardsandsegues

Segues

Storyboardsversuscoding

Summary

3.SpriteKitand2DGameDesign

AbriefhistoryofiOSgamedevelopmentengines

Thegameloop

Tilegame–SwiftSweeper

WhatisSwiftSweeper?

CreatingourSpriteKitgame

AnoverviewoftheSpriteKitstructureandobjects

Scenetransitionsandthechoiceofcode,storyboards,and/orSKSfiles

AnSKTransitionexample

ASKScene/storyboardexample

SKScenetransitionswithSKSfiles

Assets,sprites,andicons

Spriteatlasesandanimatingsprites

Creatingourgamelogic

GameBoard

PuttingitalltogetherinGameScene.swift

DemoBots

Summary

4.SceneKitand3DGameDesign

SceneKitbasicsandworkingwithnodes

SpriteKit/SceneKitinteractivity

Theissuewithinheritance-basedstructuringandgamedesign

OurfirstSceneKitscene–theXcodetemplate

SceneKitprojectflowandstructure

SceneKitDebuggingOptions

HandlinguserinputinSceneKit

SceneKitfeaturesintroducediniOS9/Xcode7

Audionodesand3Dsound

Ambienceandmusic

SpriteKitscenetransitionsinSceneKit

Foxdemo

Particlesystems

Placingparticlesintoourpioscene

SpriteKit

SceneKit

IntroducingSceneKitandSpriteKitphysics

Visuallycomposedgamescenescgs

Summary

5.GameplayKit

Entitiesandcomponents

UsingGKEntityandGKComponentobjectsinourgames

Statemachines

Agents,goals,andbehaviors

Pathfinding

MinMaxAI

Randomsources

Rulesystems

Summary

6.ExhibittheMetalinYourGame

TheAppleMetalAPIandthegraphicspipeline

CPU/GPUframeworklevels

Graphicspipelineoverview

Whatareshaders?

Typesofshaders

WhyisMetalfasterthanOpenGLES?

ThebasicMetalobject/codestructure

Summary

7.PublishingOuriOSGame

Theeverchangingprocessofappsubmission

Beforesubmittingyourapp

PreparingourappsforiTunesConnect

Submittingyourappinthetesting/betaphase

CreatinganiTunesConnectapprecord

Updatingthebuildstring

Archiveandvalidateyourapp

UploadyourapptoiTunesConnect

BetatestyourgamewiththeTestFlightservice

Externaltesterinvites

Analyzingcrashreportsandfeedbackfromtesters

Submittingyourgameforreview

Updatingyourgame

Summary

8.TheFutureofiOSGameDevelopment

Agreaterfocusonfunctionalprogramming

TheAppleWatch

Component-basedstructuring

TheriseofVR

Summary

Index

iOS9GameDevelopmentEssentials

iOS9GameDevelopmentEssentialsCopyright©2015PacktPublishing

Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthepublisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.

Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyoftheinformationpresented.However,theinformationcontainedinthisbookissoldwithoutwarranty,eitherexpressorimplied.Neithertheauthor,norPacktPublishing,anditsdealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecauseddirectlyorindirectlybythisbook.

PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthecompaniesandproductsmentionedinthisbookbytheappropriateuseofcapitals.However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.

Firstpublished:October2015

Productionreference:1261015

PublishedbyPacktPublishingLtd.

LiveryPlace

35LiveryStreet

BirminghamB32PB,UK.

ISBN978-1-78439-143-0

www.packtpub.com

CoverimagebyChuckGaffney

CreditsAuthor

ChuckGaffney

Reviewers

MohitAthwani

RahulBorawar

ChadyKassouf

JoniMikkola

CommissioningEditor

JulianUrsell

AcquisitionEditors

VinayArgekar

SonaliVernekar

ContentDevelopmentEditor

ParitaKhedekar

TechnicalEditor

EdwinMoses

CopyEditor

DiptiMankame

ProjectCoordinator

JudieJose

Proofreader

SafisEditing

Indexer

HemanginiBari

Graphics

AbhinashSahu

ProductionCoordinator

NiteshThakur

CoverWork

NiteshThakur

AbouttheAuthorChuckGaffneyisaprogrammer,voiceactor,andgamedeveloper.Heownsacompany,Chuck’sAnimeShrine,andhasworkedforsomestudiosinNewYork.SomeofChuck’srecentprojectsincludeVRandUnityprojectsformajorstudiosandbusinessfirms,inadditiontoiOSandSwiftprogramming.

Iwouldliketothankmyfamilyforgivingmemyfirstvideogamesystemin1985attheyoungageoftwo.Thewonderandmysteryofcontrollingwhat’sonthescreenhasstuckwithmeeversince.Mostimportantly,Iwouldliketothankmyfiancée,Danielle,forkeepingmeonmytoeswiththisbookandunderstandingthetimeittooktocraftit.Thankyouforbeingtherethroughtheupsanddownsthatcomefrompursuingsteadyandworthwhileworkinthefieldofsoftwaredevelopment;particularlyduringthissummer,whenthingsfinallychangedafteryearsofdoingnothingbutseeminglystaringatcloseddoorsandcallingouttodeafears.

AbouttheReviewersMohitAthwaniisaself-taughtiOSdeveloperandhasbeendevelopingappssincetheearlydaysofiOS3.Hehasworkedwithseveralclientsallaroundtheworld,andhascarriedoutintenseresearchinthefieldoffacialdetectionandrecognitiononiOS.Hisapp,iRajanee,becamethenumberoneappontheIndianappstore,andhasfetchedhimtremendoussuccess.

MohitstartedhiscompanyGeeks(http://www.geeksincorporated.net)withafriendin2010,andhassincealsoinvolvedhimselfinconductingtrainingsessionsoniOSforstudentsandcorporates.Hiswebsite,http://indianios.guru/,hostsalotofintroductoryvideosandtutorialsondevelopingforiOSwithSwift.

IwouldliketothankmyparentsforgiftingmemyfirstMacBookandiPhonethatallowedmetobecomeaniOSdeveloper.Iwouldliketothankmyfriendsandeverybodywhohaveencouragedmetocomeupwithnewideasandconcepts,andPacktpublishingforgivingmetheopportunitytoreviewthisbook.

RahulBorawarisacomputersciencegraduatefromJodhpurInstituteofEngineeringandTechnologyinRajasthan,India.Heisapassionatesoftwarecraftsman,andlovesdesigningsoftwareformobiles.Fromthestart,hehasbeenamobileapplicationdevelopercreatingapplicationsforiOSandAndroidplatforms.Hehasbeenworkingonmobiledevelopmentsince2011andhaspublishedmanyappsontheappstore,suchasCatchtheAliens(a2Dlevel-basedgame)andDrawYourStories(akids’appforcreatingfableswithdrawingstuffs).Heiscurrentlyworkingasasoftwaredevelopmentengineerinthemobileteamforarealestateproduct-basedcompany(CommonFloor).HehasreviewedonemorebookforPacktPublications,namediOSGameProgrammingCookbook,whichcanbeviewedathttps://www.packtpub.com/game-development/ios-game-programming-cookbook.

YoucanfollowhimonTwitter(https://twitter.com/RahulBorawar)andonGitHub(https://github.com/Rahul2389).Youcanalsocheckhiswebsite,http://rahulborawar.branded.me.

Firstofall,IwouldliketothankPacktPublishingforgivingmetheopportunitytoreviewthistechnology-richcookbookandenlightenmyiOSapplicationdevelopmentskills.Secondly,thankstomyfamilyforsupportingmeinmycareerasatechnicalguy.

ChadyKassoufisanindependentiOSandwebdevelopmentexpert.Hestartedprogramming23yearsagoandhasn’tstoppedsince.

Sevenyearsago,hedecidedtoleavehisjobasateamleaderinoneoftheleadingdigitalagenciesandstarthisownbusiness.

Hisinterests,besidescomputers,includearts,music,andfitness.Hecanbefoundonlineathttp://chady.net/.

JoniMikkolaiscurrentlyworkingonhisnextmobilegameinnorthernFinland.Hekeepshisgamedevelopingstaminaupbytrainingregularlyatthegymandeatinghealthily.

Amongdevelopinggames,heoftenreadsbooks,playsthepiano,orbakesbuns,tokeephisideasflowingandhismindfocused.Heconstantlykeepschallengingthestatusquo,which,inturn,helpsinlearningnewwaystocreatethings.

Hehasdevelopedgamesprofessionallyforover4yearsmostlyformobileplatforms.Hetargetscasualgamesandfocusesoncreatingsimplisticdesigns.Withonegamereleased,heiscurrentlyworkingonhisnextgame,whichwillbereleasedinlate2015forAndroidandiOSplatforms.

www.PacktPub.com

Supportfiles,eBooks,discountoffers,andmoreForsupportfilesanddownloadsrelatedtoyourbook,pleasevisitwww.PacktPub.com.

DidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFandePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandasaprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwithusat<service@packtpub.com>formoredetails.

Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signupforarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooksandeBooks.

https://www2.packtpub.com/books/subscription/packtlib

DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigitalbooklibrary.Here,youcansearch,access,andreadPackt’sentirelibraryofbooks.

Whysubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser

FreeaccessforPacktaccountholdersIfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccessPacktLibtodayandview9entirelyfreebooks.Simplyuseyourlogincredentialsforimmediateaccess.

PrefaceSincetheintroductionofiOS8in2014,gamedevelopmentfortheiOSplatformhasgonethroughsomemajorchanges.ThefirstofthosechangeswastheintroductionoftheSwiftprogramminglanguage,afunctionalprogramminglanguagemadebyAppletobesimpletocodeandmoderninitscapabilities,allwhilebeingfastenoughtohandlemodernappandgamedevelopment.iOS8alsointroducedthe3Dgamedevelopmentframework,SceneKit.SceneKitalloweddeveloperstoquicklydesign3Dgamesandworkwith3DassetsinasimilarfashiontoiOS7’sSpriteKit.Ayearlater,inthesummerof2015,iOS9wasintroduced,alongwithanewsetoftoolsforbothseasonedandbrandnewiOSgamedevelopers.Thenewframework,GameplayKit,letsdevelopershandlethegamerules,AI,gameentities,andgamestatesseparatelyfromtheinheritancelogic.InadditiontoGameplayKit,AppleshowedofftheFoxgameexamplethatdisplayshowXcodecannowdomuchofthesamevisualeditingfunctionalitiesseeninmultiplatformgameengines,suchasUnityandUnrealEngine.

WewillfirstbecomefamiliarwiththeSwiftprogramminglanguageandhowitcanbeusedinthescopeofgamedevelopment.ThegoalistounderstandiOSgamedevelopmentfromthegroundup,learningthetoughercode-centricmethodologyofmakingagame.InadditiontotakingalookatApple’sownexampleprojectsforthevariousiOSgameframeworks,wewillseesomecodeexamplesfromtwogames,thefirstgamebeingapublishedSwift-developed2DscrollinggamenamedPikiPopandtheotherbeingatile-basedMinesweeperclonenamedSwiftSweeper.Asweprogressthroughthebook,wewillstillkeepcodeasthecoreofourmethodforgamedevelopment,butwilllookintothevisualtoolsintroducediniOS9that,inadditiontoGameplayKitandthecomponent-basedstructuring,canallowustocreateagamethatisonlylimitedbyourimagination.Wethendiveintotopicofthelow-levelAPIs,suchasOpenGLESandMetal,fordeveloperswhowishtogetdowndirectlytotheGPU.

Intheend,wehopethatyouunderstandhowiOScontinuestobeapowergamedevelopmentplatform,whetheryouareadeveloperwhocomesfromthetraditionalcode-centricschoolofcomputerscience,oryouareapartofthegrowingvisual-based/drag-and-dropdesignparadigm.Ourgoalisthatwhenyouarefinishedwiththisbook,youwillhaveanumberofvastlydifferentanddetailedgameideas,whichyouthencanimmediatelybeginbuildingwithSwiftandtheiOS9platforms.

WhatthisbookcoversChapter1,TheSwiftProgrammingLanguage,providesanintroductionandguidancetotheSwiftprogramminglanguage.

Chapter2,StructuringandPlanningaGameUsingStoryboardsandSegues,helpsreadersknowthebasicflowofaniOSappbymakinguseofstoryboardsandseguesinordertoeitherplanorpreplaniOSgames.

Chapter3,SpriteKitand2DGameDesign,introducesandexplainstheuseoftheiOS2Dgamedevelopmentframework,SpriteKit.

Chapter4,SceneKitand3DGameDesign,helpsreaderslookintotheiOS3Ddevelopmentframework,SceneKit,andvisualtoolsintroducediniOSthatcanbeusedforbothSceneKitandSpriteKit.

Chapter5,Gameplaykit,introducestheGameplayKitframework,auniversalgamelogicandAIframeworkintroducediniOS9.

Chapter6,ExhibittheMetalinyourGame,discussesaboutadvancedtopics,suchastheGPUgraphicspipelineandanintroductiontoApple’slow-levelAPI,Metal,forgettingthebestperformanceoutofyourgame.

Chapter7,PublishingOuriOSGame,explainsthestepsneededtobetatestandpublishiOSgamesbymakinguseofthetestingandqualityassuranceservice,TestFlight.

Chapter8,TheFutureofiOSGameDevelopment,discusseshowprogramming,iOS,andgamedevelopmentasawholemightchangeorimproveinthenearfuture,andhowitrelatestothemostrecentiOSplatformsandframeworks.

WhatyouneedforthisbookHere’swhatyouneedforthisbook:

Xcode7orlaterMacOSXYosemiteorlater

WhothisbookisforThisbookisintendedforgamedeveloperswhowishtodevelop2Dand3DgamesforiPhoneandiPad.IfyouareadeveloperfromanotherplatformoragameenginesuchasAndroidorUnity,acurrentiOSdeveloperwishingtolearnmoreaboutSwiftandthelatestfeaturesofiOS9,orevenifyouarenewtogamedevelopment,thenthisbookisforyou.Somepriorprogrammingknowledgeisrecommended,butnotrequired.

ConventionsInthisbook,youwillfindanumberoftextstylesthatdistinguishbetweendifferentkindsofinformation.Herearesomeexamplesofthesestylesandanexplanationoftheirmeaning.

Codewordsintext,filenames,fileextensions,pathnames,anduserinput,areshownasfollows:“Aswecansee,theAppDelegate.swiftandtheViewController.swiftfileswereautomaticallycreatedforusandrightbelowthat,we’dfindtheMain.Storyboardfile.”

Ablockofcodeissetasfollows:

letscore=player.score

varscoreCountNum=0

do{

HUD.scoreText=String(scoreCountNum)

scoreCountNum=scoreCountNum*2

}whilescoreCountNum<score

Whenwewishtodrawyourattentiontoaparticularpartofacodeblock,therelevantlinesoritemsaresetinbold:

//Collisionbitmasks

typedefNS_OPTIONS(NSUInteger,AAPLBitmask){

AAPLBitmaskCollision=1UL<<2,

AAPLBitmaskCollectable=1UL<<3,

AAPLBitmaskEnemy=1UL<<4,

AAPLBitmaskSuperCollectable=1UL<<5,

AAPLBitmaskWater=1UL<<6

};

Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,forexample,inmenusordialogboxes,appearinthetextlikethis:”Alternately,imaginethattheplayerlostalloftheirlivesandgotaGameOvermessage.”

NoteWarningsorimportantnotesappearinaboxlikethis.

TipTipsandtricksappearlikethis.

ReaderfeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook—whatyoulikedordisliked.Readerfeedbackisimportantforusasithelpsusdeveloptitlesthatyouwillreallygetthemostoutof.

Tosendusgeneralfeedback,simplye-mail<feedback@packtpub.com>,andmentionthebook’stitleinthesubjectofyourmessage.

Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideatwww.packtpub.com/authors.

CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.

DownloadingtheexamplecodeYoucandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.

DownloadingthecolorimagesofthisbookWealsoprovideyouwithaPDFfilethathascolorimagesofthescreenshots/diagramsusedinthisbook.Thecolorimageswillhelpyoubetterunderstandthechangesintheoutput.Youcandownloadthisfilefromhttp://www.packtpub.com/sites/default/files/downloads/iOS9_GameDevelopmentEssentials_ColorImages.pdf

ErrataAlthoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdohappen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthecode—wewouldbegratefulifyoucouldreportthistous.Bydoingso,youcansaveotherreadersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufindanyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthedetailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedandtheerratawillbeuploadedtoourwebsiteoraddedtoanylistofexistingerrataundertheErratasectionofthattitle.

Toviewthepreviouslysubmittederrata,gotohttps://www.packtpub.com/books/content/supportandenterthenameofthebookinthesearchfield.TherequiredinformationwillappearundertheErratasection.

PiracyPiracyofcopyrightedmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.IfyoucomeacrossanyillegalcopiesofourworksinanyformontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.

Pleasecontactusat<copyright@packtpub.com>withalinktothesuspectedpiratedmaterial.

Weappreciateyourhelpinprotectingourauthorsandourabilitytobringyouvaluablecontent.

QuestionsIfyouhaveaproblemwithanyaspectofthisbook,youcancontactusat<questions@packtpub.com>,andwewilldoourbesttoaddresstheproblem.

Chapter1.TheSwiftProgrammingLanguageAtthecoreofgamedevelopmentisyourgame’scode.Itisthebrainofyourprojectandoutsideoftheart,sound,andvariousassetdevelopments.Itiswhereyouwillspendmostofyourtimecreatingandtestingyourgame.UpuntilApple’sWorldwideDevelopersConferenceWWDC14inJuneof2014,thecodeofchoiceforiOSgameandappdevelopmentwasObjective-C.AtWWDC14,anewandfasterprogramminglanguage,Swift,wasannouncedandisnowtherecommendedlanguageforallcurrentandfutureiOSgamesandgeneralappcreation.

Asofthetimeofwriting,youcanstilluseObjective-Ctodesignyourgames,butprogrammers,both,newandseasoned,willseewhywritinginSwiftisnotonlyeasierforexpressingyourgame’slogic,butevenmorepreformat.Keepingyourgamerunningatthatcritical60fpsisdependentonfastcodeandlogic.EngineersatAppledevelopedtheSwiftprogramminglanguagefromthegroundupwithperformanceandreadabilityinmind,sothislanguagecanexecutecertaincodeiterationsfasterthanObjective-Cwhilealsokeepingcodeambiguitytoaminimum.Swiftalsousesmanyofthemethodologiesandsyntaxesfoundinmoremodernlanguages,suchasScala,JavaScript,Ruby,andPython.

So,let’sdiveintotheSwiftlanguage.

NoteItisrecommendedthatsomebasicknowledgeofobject-orientedprogramming(OOP)beknownpreviously,butwewilltrytokeepthebuild-upandexplanationofcodesimpleandeasytofollowaswemoveontothemoreadvancedtopicsrelatedtogamedevelopment.

HelloWorld!It’ssomewhattraditionalwhenlearningprogramminglanguagestobeginwithaHelloWorldexample.AHelloWorldprogramissimplyusingyourcodetodisplayorlogthetextHelloWorld.It’salwaysbeenthegeneralstartingpointbecausesometimesjustgettingyourcodeenvironmentsetupandhavingyourcodeexecutingcorrectlyishalfthebattle.Atleast,thiswasmorethecaseinolderprogramminglanguages.

Swiftmakesthiseasierthanever,andwithoutgoingintothestructureofaSwiftfile(whichweshalldolateronandisalsomucheasierthanObjective-Candpastlanguages),here’showyoucreateaHelloWorldprogram:

print("Hello,World!")

That’sit!ThatisallyouneedtohavethetextHelloWorldappearinXcode’sdebugareaoutput.

NomoresemicolonsThoseofuswhohavebeenprogrammingforsometimemightnotethattheusuallyall-importantsemicolon(;)ismissing.Thisisn’tamistake;inSwift,wedon’thavetouseasemicolontomarktheendofanexpression.Wecanifwe’dlike,andsomeofusmightstilldoitasaforceofhabit,butSwifthasomittedthatcommonconcern.

NoteTheuseofthesemicolontomarktheendofanexpressionstemsfromtheearliestdaysofprogrammingwhencodewaswritteninsimplewordprocessorsandneededaspecialcharactertorepresentwhenthecode’sexpressionendsandthenextbegins.

Variables,constants,andprimitivedatatypesWhileprogramminganyapplication,eitherifnewtoprogrammingortryingtolearnadifferentlanguage,firstweshouldgetanunderstandingofhowalanguagehandlesvariables,constants,andvariousdatatypes,suchasBooleans,integers,floats,strings,andarrays.Youcanthinkofthedatainyourprogramasboxesorcontainersofinformation.Thosecontainerscanbeofdifferentflavorsortypes.Throughoutthelifeofyourgame,thedatacanchange(variables,objects,andsoon)ortheycanstaythesame.

Forexample,thenumberoflivesaplayerhaswouldbestoredasavariable,asthatisexpectedtochangeduringthecourseofthegame.Thatvariablewouldthenbeoftheprimitivedatatypeinteger,whichisbasicallywholenumbers.Datathatstores,say,thenameofacertainweaponorpower-upinyourgame,wouldbestoredinwhat’sknownasaconstant,asthenameofthatitemisnevergoingtochange.Inagamewheretheplayercanhaveinterchangeableweaponsorpower-ups,thebestwaytorepresentthecurrentlyequippeditemwouldbetouseavariable.Avariableisapieceofdatathatisboundtochange.Thatweaponorpower-upwillalsomostlikelyhaveabitmoreinformationtoitthanjustanameornumber;theprimitivetypeswementionedprior.Thecurrentlyequippeditemwouldbemadeupofproperties,suchasitsname,power,effects,indexnumber,andthespriteor3Dmodelthatvisuallyrepresentsit.Thus,thecurrentlyequippeditemwouldn’tjustbeavariableofaprimitivedatatype,butbewhatisknownasatypeofobject.Objectsinprogrammingcanholdanumberofpropertiesandfunctionalitiesthatcanbethoughtofasablackboxofbothfunctionandinformation.Thecurrentlyequippediteminourcasewouldbeasortofplaceholderthatcanholdanitemofthattypeandinterchangeitwhenneeded,fulfillingitspurposeasareplaceableitem.

NoteSwiftiswhat’sknownasatype-safelanguage,soweshouldkeeptrackoftheexacttypeofdataandevenit’sfutureusage(thatis,ifthedataisorwillbeNULL),asit’sveryimportantwhenworkingwithSwiftcomparedwithotherlanguages.ApplemadeSwiftbehavethiswaytohelpkeepruntimeerrorsandbugsinyourapplicationstoaminimum,sowecanfindthemmuchearlierinthedevelopmentprocess.

VariablesLet’slookathowvariablesaredeclaredinSwift.

varlives=3//variableofrepresentingtheplayer'slives

lives=1//changesthatvariabletoavalueof1

ThoseofuswhohavebeendevelopinginJavaScriptwillfeelrightathomehere.LikeJavaScript,weusethekeywordvartorepresentavariable,andwenamedthevariablelives.

Thecompilerimplicitlyknowsthatthetypeofthisvariableisawholenumber,theprimitivedatatypeInt.

Thetypecanbeexplicitlydeclaredassuch:

varlives:Int=3//variableoftypeInt

Wecanalsorepresentlivesasthefloatingpointdatatypesdoubleorfloat,asfollows:

//livesarerepresentedhereas3.0insteadof3

varlives:Double=3//oftypeDouble

varlives:Float=3//oftypeFloat

Usingacolonafterthevariable’snamedeclarationallowsustoexplicitlytypecastthevariable.

ConstantsDuringyourgame,therewillbepointsofdatathatdon’tchangethroughoutthelifeofthegameorthegame’scurrentlevel/scene.Thesecanbevariousdata,suchasgravity,atextlabelintheHeads-UpDisplay(HUD),thecenterpointofcharacter’s2Danimation,aneventdeclaration,orthetimebeforeyourgamechecksfornewtouches/swipes.

Declaringconstantsisalmostthesameasdeclaringvariables.

Usingacolonafterthevariable’snamedeclarationallowsustoexplicitlytypecastthevariable.

letgravityImplicit=-9.8//implicitdeclaration

letgravityExplicit:Float=-9.8//explicitdeclaration

Aswecansee,weusethekeywordlettodeclareconstants.

Here’sanotherexampleusingastringthatcouldrepresentamessagedisplayedonthescreenatthestartorendofastage:

letstageMessage="Start!"

stageMessage="YouLose!"//error

SincethestringstageMessageisaconstant,wecannotchangeitonceithasbeendeclared.Somethinglikethiswouldbebetterasavariableusingvarinsteadoflet.

Tip“Whydon’twedeclareeverythingasavariable?”

Thisisaquestionsometimesaskedbynewdevelopersandisunderstandablewhyit’sasked,especiallysincegameappstendtohavealargenumberofvariablesandmoreinterchangeablestatesthananaverageapplication.Whenthecompilerisbuildingitsinternallistofyourgame’sobjectsanddata,moregoesonbehindthesceneswithvariablesthanwithconstants.

Withoutgettingtoomuchintotopics,suchastheprogram’sstackandotherdetails,inshort,havingobjects,events,anddatadeclaredasconstantswiththeletkeywordismoreefficientthanvar.Inasmallapponthenewestdevicestoday,thoughnotrecommended,wecouldpossiblygetawaywiththiswithoutseeingagreatdealoflossinappperformance.Whenitcomestovideogames,however,performanceiscritical.Buyingbackasmuchperformanceaspossiblecanallowabetterplayerexperience.Applerecommendsthatwhenindoubt,alwaysuseletatthetimeofdeclarationandhavethecompilersaywhentochangetovar.

Moreaboutconstants…AsofSwiftversion1.2,constantscanhaveaconditionallycontrolledinitialvalue.

Priortothisupdate,wehadtoinitializeaconstantwithasinglestartingvalueorbeforcedtomakethepropertyavariable.InXcode6.3andnewer,wecanperformthefollowinglogic:

letx:SomeThing

ifcondition

{

x=foo()

}

else

{

x=bar()

}

use(x)

Anexampleofthisinagamecouldbeasfollows:

letstageBoss:Boss

if(stageDifficulty==gameDifficulty.hard)

{

stageBoss=Boss.toughBoss()

}

else

{

stageBoss=Boss.normalBoss()

}

loadBoss(stageBoss)

Withthisfunctionality,aconstant’sinitializationcanhavealayerofvariancewhilestillkeepingitunchangeable,orimmutablethroughitsuse.Here,theconstantstageBosscanbeoneoftwotypesbasedonthegame’sdifficulty:Boss.toughBoss()orBoss.normalBoss().Thebosswon’tchangeforthecourseofthisstage,soitmakessensetokeepitasaconstant.Moreonifandelsestatementsiscoveredlaterinthechapter.

Arrays,matrices,sets,anddictionariesVariablesandconstantscanrepresentacollectionofvariouspropertiesandobjects.Themostcommoncollectiontypesarearrays,matrices,sets,anddictionaries.Anarrayisanorderedlistofdistinctobjects;amatrixis,inshort,anarrayofarrays;asetisanunorderedlistofdistinctobjects;andadictionaryisanunorderedlistthatutilizesakey:valueassociationwiththedata.

ArraysHere’sanexampleofanarrayinSwift:

letstageNames:[String]=["DowntownTokyo","HeavenValley","Nether"]

TheobjectstageNamesisacollectionofstringsrepresentingthenamesofagame’sstages.Arraysareorderedbysubscriptsfrom0toarraylength-1.So,stageNames[0]wouldbeDowntownTokyo;stageNames[2]wouldbeNether;andstageNames[4]wouldgiveanerrorsincethat’sbeyondthelimitsofthearrayanddoesn’texist.Weuse[]bracketsaroundtheclasstypeofstageNames,[String],totellthecompilerthatwearedealingwithanarrayofstrings.Bracketsarealsousedaroundtheindividualmembersofthisarray.

2Darrays/matricesAcommoncollectiontypeusedinphysicscalculations,graphics,andgamedesign,particularlygrid-basedpuzzlegames,istwo-dimensionalarrays/matrices.2Darraysaresimplyarraysthathavearraysastheirmembers.Thesearrayscanbeexpressedinarectangularfashioninrowsandcolumns.

Forexample,the4x4(4rows,4columns)tileboardinthe15-puzzlegamecanberepresentedasfollows:

vartileBoard=[[1,2,3,4],

[5,6,7,8],

[9,10,11,12],

[13,14,15,""]]

Inthe15puzzlegame,yourgoalistoshiftthetilesusingtheoneemptyspot(representedwiththeblankstring""),toallendupinthe1-15orderaswesaw.Thegamewouldstartwiththenumbersarrangedinarandomandsolvableorder,andtheplayerwouldthenhavetoswapthenumbersandtheblankspace.

TipTobetterperformvariousactionsonand/orstoreinformationabouteachtileinthe15game(andothergames),it’dbebettertocreateatileobjectasopposedtousingrawvaluesseenhere.Forthesakeofunderstandingwhatamatrixor2Darrayis,simplymakeanoteofhowthearrayissurroundedbydoublyencapsulatedbrackets[[]].Wewilllateruseoneofourexamplegames,SwiftSweeper,tobetterunderstandhowpuzzlegamesuse2Darraysofobjectstocreateafullgame.

Herearewaystodeclareblank2Darrayswithstricttypes:

vartwoDTileArray:[[Tiles]]=[]//blank2Darrayoftype,Tiles

varanotherArray=Array<Array<Tile>>()//samearray,usingGenerics

ThevariabletwoDTileArrayusesthedoublebrackets[[Tiles]]todeclareitasablank2Darray/matrixforthemade-uptype,tiles.ThevariableanotherArrayisaratheroddlydeclaredarraythatusesanglebracketcharacters<>forenclosures.Itutilizeswhat’sknownasGenerics.Genericsisaratheradvancedtopicthatwewilltouchmoreonlater.Theyallowveryflexiblefunctionalityamongawidearrayofdatatypesandclasses.Forthemoment,wecanthinkofthemasacatch-allwayofworkingwithobjects.

Tofillinthedataforeitherversionofthisarray,wewouldthenusefor-loops.Moreonloopsanditerationswillbeexplainedlaterinthechapter.

SetsThisishowwewouldmakeasetofvariousgameitemsinSwift:

varkeyItems=Set([Dungeon_Prize,Holy_Armor,Boss_Key,"A"])

ThissetkeyItemshasvariousobjectsandacharacterA.Unlikeanarray,asetisnotorderedandcontainsuniqueitems.So,unlikestageNames,attemptingtogetkeyItems[1]wouldreturnanerroranditems[1]mightnotnecessarilybetheHoly_Armorobject,astheplacementofobjectsisinternallyrandominaset.Theadvantagesetshaveoverarraysisthatsetsaregreatatcheckingforduplicatedobjectsandspecificcontentsearchinginthecollectionoverall.Setsmakeuseofhashingtopinpointtheiteminthecollections,socheckingforitemsinaset’scontentcanbemuchfasterthaninanarray.Ingamedevelopment,agame’skeyitems,whichtheplayermayonlygetonceandshouldneverhaveduplicatesof,couldworkgreatasaset.UsingthefunctionkeyItems.contains(Boss_Key)returnstheBooleanvalueoftrueinthiscase.

NoteSetswereaddedinSwift1.2andXcode6.3.TheirclassisrepresentedbythegenerictypeSet<T>,whereTistheclasstypeofthecollection.Inotherwords,theset,Set([45,66,1233,234]).wouldbeofthetypeSet<Int>,andourexampleherewouldbeaSet<NSObject>instanceduetoithavingacollectionofvariousdatatypes.

WewilldiscussmoreonGenericsandclasshierarchylaterinthischapter.

DictionariesAdictionarycanberepresentedthiswayinSwift:

varplayerInventory:[Int:String]=[1:"BusterSword",43:

"Potion",22:"StrengthBooster"]

Dictionariesuseakey:valueassociation,soplayerInventory[22]returnsthevalueStrengthBoosterbasedonthekey22.Boththekeyandvaluecouldbeinitializedtoalmostanyclasstype*.Inadditiontotheinventoryexamplegiven,wecanhavethefollowingcode:

varstageReward:[Int:GameItem]=[:]//blankinitialization

//useoftheDictionaryattheendofacurrentstage

stageReward=[currentStage.score:currentStage.rewardItem]

Note*Thevaluesofadictionary,thoughratherflexibleinSwift,dohavelimitations.Thekeymustconformtowhat’sknownasthehashableprotocol.Basicdatatypes,suchasIntandString,alreadyhavethisfunctionality.So,ifyouaretomakeyourownclasses/datastructuresthataretobeusedindictionaries,saymappingaplayeractionswithplayerinput,thisprotocolmustbeutilizedfirst.Wewilldiscussmoreaboutprotocolslaterinthischapter.

Dictionariesarelikesetsinthattheyareunorderedbutwiththeadditionallayerofhavingakeyandavalueassociatedwiththeircontentinsteadofjustthehashkey.Likesets,dictionariesaregreatforquickinsertionandretrievalofspecificdata.IniOSappsandinwebapplications,dictionariesareusedtoparseandselectitemsfromJavaScriptObjectNotation(JSON)data.

Intherealmofgamedevelopment,dictionariesusingJSONorviaApple’sinternaldataclass,NSUserDefaults,canbeusedtosaveandloadgamedata,setupgameconfigurations,oraccessspecificmembersofagame’sAPI.

Forexample,here’sonewaytosaveaplayer’shighscoreinaniOSgameusingSwift:

letnewBestScore:Void=

NSUserDefaults.standardUserDefaults().setInteger(bestScore,forKey:

"bestScore")

ThiscodecomesdirectlyfromapublishedSwift-developedgamenamedPikiPop,whichwewillusefromtimetotimetoshowcodeusedinactualgameapplications.

Again,notethatdictionariesareunordered,butSwifthaswaystoiterateorsearchthroughanentiredictionary.Wewillgomoreindepthinthenextsectionandlateronwhenwemoveontoloopsandcontrolflow.

Mutable/immutablecollectionsOneratherimportantdiscussionthatwe’veleftoutishowtosubtract,edit,oraddtoarrays,sets,anddictionaries.However,beforewedothis,youshouldunderstandtheconceptofmutableandimmutabledata/collections.

Amutablecollectionissimpledatathatcanbechanged,addedto,orsubtractedfrom,whereasanimmutablecollectioncannotbechanged,addedto,orsubtractedfrom.

ToworkwithmutableandimmutablecollectionsefficientlyinObjective-C,wehadtoexplicitlystatethemutabilityofthecollectionbeforehand.Forexample,anarrayofthetypeNSArrayinObjective-Cisalwaysimmutable.TherearemethodswecancallonNSArraythatwouldeditthecollection,butbehindthescenes,thiswouldbecreatingbrandnewNSArrayobjects,thuswouldberatherinefficienttodothisofteninthelifeofourgame.Objective-Chassolvedthisissuewiththeclasstype,NSMutableArray.

ThankstotheflexibilityofSwift’stypeinference,wealreadyknowhowtomakeacollectionmutableorimmutable!TheconceptofconstantsandvariableshasuscoveredwhenitcomestodatamutabilityinSwift.Usingthekeywordletwhencreatingacollectionwillmakethatcollectionimmutable,whileusingvarwillinitializeitasamutablecollection.

//mutableArray

varunlockedLevels:[Int]=[1,2,5,8]

//immutableDictionary

letplayersForThisRound:[PlayerNumber:PlayerUserName]=

[453:"userName3344xx5",233:"princeTrunks",6567:"noScopeMan98",211:

"egoDino"]

Thearrayofintegers,unlockedLevels,canbeeditedsimplybecauseit’savariable.TheimmutabledictionaryplayersForThisRoundcan’tbechangedsinceit’salreadybeendeclaredasaconstant.Thereisnoadditionallayerofambiguityconcerningadditionalclasstypes.

Editing/accessingcollectiondataAslongasacollectiontypeisavariable,usingthevarkeyword,wecandovariouseditstothedata.Let’sgobacktoourunlockedLevelsarray.Manygameshavethefunctionalityofunlockinglevelsastheplayerprogresses.Let’ssaythattheplayerhasreachedthehighscoreneededtounlockthepreviouslylockedlevel3(as3isn’tamemberofthearray).Wecanadd3tothearrayusingtheappendfunction:

unlockedLevels.append(3)

AnotherneatattributeofSwiftisthatwecanadddatatoanarrayusingthe+=assignmentoperator:

unlockedLevels+=[3]

Doingitthiswayhoweverwillsimplyadd3totheendofthearray.So,ourpreviousarray[1,2,5,8]isnow[1,2,5,8,3].Thisprobablyisn’tadesirableorder,sotoinsertthenumber3inthethirdspot,unlockedLevels[2],wecanusethefollowingmethod:

unlockedLevels.insert(3,atIndex:2)

Now,ourarrayofunlockedlevelsisorderedto[1,2,3,5,8].

Thisisassumingthoughthatweknowamemberofthearraypriorto3issortedalready.TherearevarioussortingfunctionalitiesprovidedbySwiftthatcouldhelpkeepinganarraysorted.Wewillleavethedetailsofsortingtoourdiscussionsofloopsandcontrolflowlaterinthischapter.

Removingitemsfromanarrayisjustsimple.Let’sagainuseourunlockedLevelsarray.Imaginethatourgamehasanoverworldfortheplayertotraveltoandfromandtheplayerhasjustunlockedasecretthattriggeredaneventthatblockedoffaccesstolevel1.Level1wouldnowhavetoberemovedfromtheunlockedlevels.Wecandoitlikethis:

unlockedLevels.removeAtIndex(0)//arrayisnow[2,3,5,8]

Alternately,imaginethattheplayerhaslostalloftheirlivesandgotaGameOvermessage.Apenaltyforthiscouldbetolockthefurthestlevel.Thoughprobablyaratherinfuriatingmethodandusknowingthatlevel8isthefurthestlevelinourarray,wecanremoveitusingthe.removeLast()functionofarraytypes.

unlockedLevels.removeLast()//arrayisnow[2,3,5]

NoteThisisassumingthatweknowtheexactorderofthecollection.Setsordictionariesmightbebetteratcontrollingcertainaspectsofyourgame.

Herearesomewaystoeditasetoradictionaryasaquickguide.

Set

inventory.insert("PowerRing")//.insert()addsitemstoaset

inventory.remove("MagicPotion")//.remove()removesaspecificitem

inventory.count//counts#ofitemsintheSet

inventory.union(EnemyLoot)//combinestwoSets

inventory.removeAll()//removeseverythingfromtheSet

inventory.isEmpty//returnstrue

Dictionary

varinventory=[Float:String]()//createsamutabledictionary

/*

onewaytosetanequippedweaponinagame;where1.0couldrepresentthe

first"itemslot"thatwouldbeplaceholderfortheplayer's"current

weapon"

*/

inventory.updateValue("Broadsword",forKey:1.0)

//removesanitemfromaDictionarybasedonthekeyvalue

inventory.removeValueForKey("StatusBooster")

inventory.count//countsitemsintheDictionary

inventory.removeAll(keepCapacity:false)//deletestheDictionary

inventory.isEmpty//returnsfalse

//createsanarrayoftheDictionary'svalues

letinventoryNames=[String](inventory.values)

//createsanarrayoftheDictionary'skeys

letinventoryKeys=[String](inventory.keys)

IteratingthroughcollectiontypesWecan’tdiscusscollectiontypeswithoutmentioninghowtoiteratethroughthemenmasse.

Here’ssomewaywe’diteratethoughanarray,aset,oradictionaryinSwift:

//(a)outputseveryitemthroughtheentirecollection

//worksforArrays,SetsandDictionariesbutoutputwillvary

foritemininventory{

print(item)

}

//(b)outputssorteditemlistusingSwift'ssorted()function

//worksforSets

foriteminsorted(inventory){

print("\(item)")

}

//(c)outputseveryitemaswellasitscurrentindex

//worksforArrays,SetsandDictionaries

for(index,value)inenumerate(inventory){

print("Item\(index+1):\(value)")

}

//(d)

//IteratethroughandthroughthekeysofaDictionary

foritemCodeininventory.keys{

print("Itemcode:\(itemCode)")

}

//(e)

//IteratethroughandthroughthevaluesofaDictionary

foritemNameininventory.values{

print("Itemname:\(itemName)")

}

Asstatedpreviously,thisisdonewithwhat’sknownasafor-loop;withtheseexamples,weshowhowSwiftutilizesthefor-invariationusingtheinkeyword.Thecodewillrepeatuntilitreachestheendofthecollectioninalloftheseexamples.Inexample(c),wealsoseetheuseoftheSwiftfunction,enumerate().Thisfunctionreturnsacompoundvalue,(index,value),foreachitem.Thiscompoundvalueisknownasatuple,andSwift’suseoftuplesmakesforawidevarietyoffunctionalitiesforfunctions,loops,aswellascodeblocks.

Wewilldelvemoreintotuples,loops,andblockslateron.

Objective-CandSwiftcomparisonHere’saquickreviewofourSwiftcodewithacomparisontotheObjective-Cequivalent.

Objective-CHere’sasamplecodeinObjective-C:

constintMAX_ENEMIES=10;//constant

floatplayerPower=1.3;//variable

//ArrayofNSStrings

NSArray*stageNames=@[@"DowntownTokyo",@"HeavenValley",@"Nether"];

//SetofvariousNSObjects

NSSet*items=[NSSetsetWithObjects:Weapons,Armor,

HealingItems,"A",nil];

//DictionarywithanInt:Stringkey:value

NSDictionary*inventory=[NSDictionarydictionaryWithObjectsAndKeys:

[NSNumbernumberWithInt:1],@"BusterSword",

[NSNumbernumberWithInt:43],@"Potion",

[NSNumbernumberWithInt:22],@"Strength",

nil];

SwiftHere’stheequivalentcodeinSwift:

letMAX_ENEMIES=10//constant

varplayerPower=1.3//variable

//ArrayofStrings

letstageNames:[String]=["DowntownTokyo","HeavenValley","Nether"]

//SetofvariousNSObjects

varitems=Set([Weapons,Armor,HealingItems,"A"])

//DictionarywithanInt:Stringkey:value

varplayerInventory:[Int:String]=[1:"BusterSword",43:

"Potion",22:"StrengthBooster"]

Intheprecedingcode,weusedsomeexamplesofvariables,constants,arrays,sets,anddictionaries.First,weseetheirObjective-CsyntaxandthentheequivalentdeclarationsusingSwift’ssyntax.Fromthisexample,wecanseehowcompactSwiftiscomparedwithObjective-C.

CharactersandstringsForsometimeinthischapter,we’vebeenmentioningstrings.Stringsarealsoacollectionofdatatypes,butaspeciallydealtcollectionofcharacters,oftheclasstype,string.SwiftisUnicode-compliant,sowecanhavestringslikethefollowing:

letgameOverText="GameOver!"

Wecanhavestringswithemojicharacterslikethefollowing:

letcardSuits="♠♥♣♦"

Whatwedidintheprecedingcodewascreatewhat’sknownasastringliteral.Astringliteraliswhenweexplicitlydefineastringaroundtwoquotes””.

Wecancreateemptystringvariablesforlateruseinourgamessuchas:

varemptyString=""//emptystringliteral

varanotherEmptyString=String()//usingtypeinitializer

Botharevalidwaystocreateanemptystring””.

StringInterpolationWecanalsocreateastringfromamixtureofotherdatatypes,knownasStringInterpolation.StringInterpolationisrathercommoningamedevelopment,debugging,andstringuseingeneral.

Themostnotableofexamplesaredisplayingtheplayer’sscoreandlives.Thisishowoneofourexamplegames,PikiPop,usesStringInterpolationtodisplaythecurrentplayerstats:

//displaystheplayer'scurrentlives

varlivesLabel="x\(currentScene.player!.lives)"

//displaystheplayer'scurrentscore

varscoreText="Score:\(score)"

Takenoteofthe\(variable_name)formatting.We’veactuallyseenthisbeforeinourpastcodesnippets.Inthevariousprint()outputs,weusedthistodisplaythevariable,collection,andsoonwewantedtogetinformationon.InSwift,thewaytooutputthevalueofadatatypeinastringisbyusingthisformatting.

ForthoseofuswhocamefromObjective-C,it’sthesameasthefollowing:

NSString*livesLabel=@"Lives:";

intlives=3;

NSString*livesText=[NSStringstringWithFormat:@"%@(%ddaysago)",

livesLabel,lives];

NotehowSwiftmakesStringInterpolationmuchcleanerandeasiertoreadthanitsObjective-Cpredecessor.

MutatingstringsTherearevariouswaystochangestrings,suchasaddingcharacterstoastringaswedidtocollectionobjects.Herearesomebasicexamples:

vargameText="Theplayerentersthestage"

gameText+="andquicklylostduetonotlevelingup"

/*gameTextnowsays

"Theplayerentersthestageandlostduetonotlevelingup"*/

Sincestringsareessentiallyarraysofcharacters,likearrays,wecanusethe+=assignmentoperatortoaddtothepreviousstring.

Also,akintoarrays,wecanusetheappend()functiontoaddacharactertotheendofastring.

letexclamationMark:Character="!"

gameText.append(exclamationMark)

//gameTextnowsays"Theplayerentersthestageandlostduetonot

levelingup!"

Here’showweiteratethroughthecharactersinastring,inSwift:

forcharacterin"Start!"{

print(character)

}

//outputs:

//S

//t

//a

//r

//t

//!

Notehowagainweusethefor-inloopandevenhavetheflexibilityofusingastringliteralifwe’dsoliketobewhat’siteratedthroughbytheloop.

StringindicesAnothersimilaritybetweenarraysandstringsisthefactthatastring’sindividualcharacterscanbelocatedviaindices.Unlikearrays,however,sinceacharactercanbeavaryingsizeofdata,brokenin21-bitnumbersknownasUnicodescalars,theycannotbelocatedinSwiftwithInttypeindexvalues.

Instead,wecanusethe.startIndexand.endIndexpropertiesofastringandmoveoneplaceaheadoroneplacebehindtheindexwiththe.successor()and.predecessor()functions,respectively,toretrievetheneededcharacterorcharactersofastring.

HerearesomeexamplesthatusethesepropertiesandfunctionsusingourpreviousgameTextstring:

gameText[gameText.startIndex]//=T

gameText[gameText.endIndex]//=!

gameText[gameText.startIndex.successor()]//=h

gameText[gameText.endIndex.predecessor()]//=p

NoteTherearemanywaystomanipulate,mix,remove,andretrievevariousaspectsofstringsandcharacters.Formoreinformation,besuretocheckouttheofficialSwiftdocumentationoncharactersandstringsathttps://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html

CommentinginSwiftInourcodesnippetsthusfar,onemightnotenotationswithdoubleforwardslashes//orwithforwardslashesandasterisks/**/.ThesearehowwecancommentormakenotationsinourSwiftcode.Anyonewho’scodedinC++,Java,Objective-C,JavaScript,orotherlanguageswillseethatSwiftworkspracticallythesame.

Single-linecommentsarestartedwiththedoubleforwardslashes,//,whilemultilinecommentsoracommentblockbeginswith/*andendswith*/.

Takethefollowingexample:

//Thisisasinglelinecomment

/*

Thisisacommentblock

thatwon'tenduntilitreachestheclosingasterisk/forwardslash

characters

*/

Commentingisusedtohelpnavigateyourcode,understandwhatitmightdo,andcommentoutlinesofcodewemightnotwanttoexecute,butatthesametimewanttokeepforlater(thatis,print()logcallsoralternativestartingpropertyvalues).

NoteFromXcode6Beta4onward,wecanalsoutilizethefollowingcomments:

//MARK:,//TODO:,and//FIXME.//MARKisequivalenttoObjective-C’s#pragmamark,whichallowstheprogrammertolabelasectionofyourcodethatisaccessibleinXcode’stopbreadcrumbdropdownlist.//TODO:and//FIXMEgiveustheabilitytosectionoffpartsofcodethatwewishtomaybeaddfeaturestointhefutureordebug.Evengameswithwell-organizedclassstructuringcanbedauntingtosiftthrough.Theadditionoftheseadditionalmark-uptoolsmakesplanningandsearchingthroughourgames’codethatmucheasiertodo.

BooleanAnintegralpartofallprogramming,game,orotherwiseistheuseofBooleanvalues.Booleanvaluestypicallyreturneithertrueorfalsevalues,yesorno,or0or1.InSwift,thisisthejoboftheBoolclassofobjects.Theuseofthefunction.isEmpty()inourpastcollectiondatatypeexamplesreturnsaBooleanvalueoftrueorfalsebasedonwhetherthatcollectionisemptyornot.

Ingamedevelopment,onewaywecoulduseBooleanvaluesistohaveaglobalvariable(avariableaccessibleinscopethroughoutourgame/app)thatchecksifthegameisover.

varisGameOver=false

Thisvariable,takenfromthePikiPopgame,startsthegameoffwithavariableoftypeboolnamedisGameOverwithastartingvalueoffalse.Iftheeventsofthegamecausethisvaluetochangetotrue,thenthistriggerstheeventsassociatedwiththegameoverstate.

NoteUnlikeBooleanvaluesinObjective-C,SwiftusesonlytrueorfalsevaluestorepresentBooleanvariables.SwiftstricttypesafetydoesnotallowtheuseofYESandNOor0and1,aswehaveseeninObjective-Candotherprogramminglanguages.

However,readingandcontrollingthistypeofinformationaboutourgame,knownasthegame’sstate,isbestcontrolledwithmorethanjustasingleBooleanvalue.Thisisbecauseyourgameandthecharactersinyourgamecouldhavevariousstates,suchasgameover,paused,spawn,idle,running,falling,andmore.Aspecialobjectknownasastatemachinebestmanagesthistypeofinformation.StatemachinesshallbecoveredinmoredetailwhenwediscusstheGameplayKitframework.

Ints,UInts,floats,anddoublesInadditiontoBooleanvalues,anotherbasicdatatypewehaveuptothispointbrieflymentionedisthevariousnumericobjects,suchasintegers(Ints),unsignedintegers(UInts),floatingpointnumbers/decimals(floats),anddoubleprecisionfloatingpointnumbers/decimals(doubles).

IntegersandunsignedintegersIntegersrepresentnegativeandpositivewholenumbers,whileunsignedintegersrepresentpositivewholenumbers.LikewithCandotherprogramminglanguages,Swiftletsuscreatevarioustypesofintegersandunsignedintegersfrom8,16,32,and64bits.Forexample,anInt32typeisa32-bitinteger,whileaUInt8typeisan8-bitunsignedinteger.ThesizeofthebitsforIntsandUIntsrepresentshowmuchspaceisbeingallocatedtostorethevalues.UsingourUInt8example,anumbermadefromthistypeofunsignedIntcanonlystorethevalues0-255(or11111111inabase-2system).Thisisalsoknownas1byte(8bits).Ifweneedtostorenumberslargerthan255ornegativenumbers,thenmaybeanInt16typewouldsufficeasthatcanstorenumbersbetween–32767and32767.Usually,wedon’thavetoworrytoomuchaboutthesizeallocatedbyourintegervariablesandconstants.So,usingjusttheclassnameofIntwillworkfineinmostcases.

NoteThesizeofIntwilldifferdependingonthetypeofsystemweareworkingon.Ifwearecompilingourcodeona32-bitsystem,anintegerwillbeequaltoInt32,whilethesameintegerwouldbeanInt64ona64-bitsystem.

SwiftcanletusseewhatourminimumandmaximumvaluesareforanIntvariablewiththe.minor.maxclassvariables(thatis,Int16.max=32767andUInt.min=0).

FloatsanddoublesFloatsare32bitfloatingpointnumbers/fractions,suchaspi(3.14),orthegoldenratio,phi(1.61803).

Ingamedesigning,weworkwithfloatingpointvaluesandrangesratheroften,beittodeterminetheCGPointinxandyofa2Dsprite,usinglinearinterpolationforsmoothingagame’scameramovementin3Dspace,orapplyingvariousphysicsforcesonanobjector2D/3Dvector.Theprecisionneededforeachsituationwilldetermineifafloatisneededorifthe64-bitfloatingpointvalue,thedoubleisneeded.Doublescanbeaspreciseas15decimalplaces,whileafloatissixdecimalplacesprecise.

TipIt’sactuallybestpracticetousedoublesinsituationsthatwouldworkforeitherfloatsordoubles.

ObjectsinSwiftThecoreaspectofobject-orientedprogramming(OOP)isofcoursetheconceptofobjects.C++beganthisparadigminprogramming,whileJava,C#,Apple’sObjective-C,andotherlanguageswereallessentiallybuiltfromthisfoundation.

SwiftisanOOPlanguagewiththesamedynamicobjectmodelasObjective-C,butpresentedinacleaner,type-safe,andcompactway.

Youcanthinkofanobjectexactlyasitsounds,anabstractthingorcontainer.Anobjectcanbesomethingassimpleasastring,orsomethingascomplexastheplayerobjectinthelatestvideogame.Technicallyspeaking,anobjectinaprogramisareferencetoasetofvariousdatainanallocatedchunkofmemory,butit’ssufficienttojustunderstandthatanobjectcanbeavariableorareferencetoaninstanceofaclass,Struct,orblockofcode.

Anobjectcanhavevariousdatafields/aspectsassociatedwithit,suchasproperties,functions,parentobjects,childobjects,andprotocols.InlanguagessuchasCforexample,anintegervariableisusuallyrepresentedasjustrawdata,buttheintegertypeinSwiftisactuallyanobject.Thus,wecanaccessextrainformationandperformfunctionsonIntobjectsinourcode.WepreviouslysawthiswiththeInt.maxvariable,whichreturnsthehighestnumberthatcanberepresentedbytheIntclass.Again,dependingonthemachineyouareworkingon,thiscouldbethesamevalueasInt32.maxorInt64.max.

varhighestIntNumber:Int=Int.max

Accesstofunctionsandpropertiesofanobjectusesdotnotation,aswesawwiththepreviousexample.Int.maxandInt.minareactuallyspecialpropertiesknownasclassvariables,whichrepresentallinstancesofanInttypeobject.

Let’slookathowSwiftdealswithobtainingpropertiesandfunctionsofaninstanceofanobjectusingamade-upPlayertypeobject.

letcurrentPlayer=Player(name:"Fumi")//(a)

letplayerName=currentPlayer.getName()//(b)

varplayerHealth=currentPlayer.health//(c)

currentPlayer.attackEnemy()//(d)

We’llgetbacktothesecondhalfofline(a),butjustunderstandthatitcreatesaninstanceofanobjectofthetypePlayernamedcurrentPlayer.Line(c)createsavariablenamedplayerHealththat’ssetbythehealthpropertyofcurrentPlayer;herewiththedotnotation.Lines(b)and(d)usethedotnotationtocallthefunctionsgetName()andattackEnemy().ThegetName()functioninthiscaseisafunctionthatreturnsastringthat’sassignedtotheconstant,playerName.Line(c)createsavariablenamedplayerHealththatiscreatedbyreferencingthehealthpropertyofcurrentPlayer,alsousingdotnotation.Line(d)isadirectcalltothePlayerclass’attackEnemy()function,whichyoucanimaginefornowjustperformswhatwouldmakecurrentPlayerdoherattack.Thisfunctiondoesn’treturnavalueandthusiswhat’sknownasavoidtypefunction.

Asforline(a),onemightnotethatitdoesn’tusethedotnotation.ThisishowSwiftdoes

what’sknownasaclassinitializer;designatedbytheparenthesis()aftertheclassnameandwiththeparametercalledname:thatsendsastring,Fumi,totheobject’sclassinitializer.

Wewillbedivingdeeperintotheuseofobjectsmomentarilyaswemoveontofunctionsandclasses.

TypesafetyandtypeinferenceObjectsand,aswe’llsee,functionsontheseobjectsinSwiftaretype-safe.Whatthismeansisthatifweperformafunctiononastringobjectwhenthecodewasexpectinganinteger,thenthecompilerwillwarnusearlyonintheprocess.Intheveinofgamedesign,ifweweretohavetheplayerperformanactiononlyanenemysupposedtodo,thenSwiftwillknowthroughitsinherentlytype-safenature.

Swift’stypeinferenceissomethingwe’vementionedbefore.Unlikeotherlanguageswhereyouhavetodeclaretheobject’stypeeverytimeit’sinitialized,Swiftwillinferwhattypeyoumean.Forexample,wehavethefollowing:

varplayerHealth=100

//SwiftautomaticallyinfersthatplayerHealthisanIntobject

OptionalsAswestatedbefore,Swiftisatype-safelanguage.ApplealsocreatedSwiftwiththeintentionofkeepingasmanypotentialerrorsandbugsinthecompilationstateofdevelopmentasopposedtoruntime.ThoughXcodehassomegreatdebuggingtools,fromtheuseofbreaks,logging,andtheLLDBdebugger,runtimeerrors,particularlyingamescanbetoughtospot,thusbringingthedevelopmentprocesstoahalt.Tokeepeverythingtype-safeandasbug-freeaspossibleduringcompilation,Swiftdealswiththeconceptofoptionals.

Optionals,inshort,areobjectsthatpotentiallycanbeorstartasnil.Nil,ofcourse,isanobjectthathasnoreference.

InObjective-C,wecoulddeclarethefollowingstringvariableforagame:

NSString*playerStatus=@"Poisoned";

playerStatus=nil;

InSwift,wewouldwritethisinthesameway,butwe’dfindoutveryquicklythatXcodewouldgiveusacompilererrorindoingso:

varplayerStatus="Poisoned"

playerStatus=nil//error!

EvenmoreconfusingforanyonenewtoSwift,we’dalsogetanerrorifwedidsomethingassimpleasthis:

varplayerStatus:String//error

Creatingempty/undeclaredobjectsinourgamesmakessenseandissomethingwe’doftenwanttodoatthestartofourclasses.Wewantthatflexibilitytoassignavaluelateronbasedontheeventsofourgame.Swiftseemstobemakingsuchabasicconceptimpossibletodo!Noworries;Xcodewillinformyouinmostcasestosuffixaquestionmark,?,attheendofthesenilobjects.Thisishowyoudeclareanobjectasanoptional.

So,ifwewanttoplanourgame’spropertiesandobjectsinSwift,wecandothefollowing:

varplayerStatus:String?//optionalString

varstageBoss:Boss?//optionalBossobject

UnwrappingoptionalsLet’simaginethatwewanttodisplaywhatcausedaplayertoloseinthegame.

varcausedGameOver:String?=whatKilledPlayer(enemy.recentAttack)

lettext="PlayerLostBecause:"

letgameOverMessage=text+causedGameOver//error

BecausethestringcausedGameOverisoptional,Xcodewillgiveusacompileerrorbecausewedidn’tunwraptheoptional.Tounwrapthevalueinanoptional,wesuffixanexclamationpoint!attheendoftheoptional.

Here’sourGameOvermessagecode,nowfixedusingtheunwrappedoptional:

varcausedGameOver:String?=whatKilledPlayer(enemy.recentAttack)

lettext="PlayerLostBecause:"

letgameOverMessage=text+causedGameOver!//codenowcompiles!

Wecanalsoforceunwrapoptionalsearlyatdeclarationtoallowanypotentialerrorstobetakencareofatruntimeinsteadofwhencompiling.Thishappensoftenwith@IBOutletsand@IBActions(objectsandfunctionslinkedtovariousstoryboardsandothertoolsthatarebasedonmenu/viewtools).

@IBOutletvartitleLabel:UILabel!//labelfromaStoryboard

varsomeUnwrappedOptional:GameObject!//ourownunwrappedoptional

NoteIfpossible,thoughit’srecommendedtousethebasicwrappedoptional?asmuchaspossibletoallowthecompilertofindanypotentialerrors.Usingwhat’sknownasoptionalbindingandchaining,wecandosomegreatearlylogicchecksonoptionalsthatinpriorlanguageswouldhaveinvolvedvariousifstatements/controlflowstatementstosimplycheckfornilobjects.

Keepingcodeclean,safe,andeasytoreadiswhatSwiftaimstodoandwhySwiftgoesoutofitswaysometimestoforcemanyoftheseruleswithoptionals.

OptionalbindingandchainingOptionalbindingischeckingwhetheranoptionalhasavalueornot.Thisisdoneusingtheveryhandyif-letorif-varstatements.Let’slookbackatourearliercode:

varcausedGameOver:String?=whatKilledPlayer(enemy.recentAttack)

lettext="PlayerLostBecause:"

ifletgotCauseOfDeath=causedGameOver{

letgameOverMessage=text+gotCauseOfDeath

}

Thecodeblock,ifletgotCauseOfDeath=causedGameOver{…},doestwothings.First,usingthekeywords,iflet,itautomaticallycreatesaconstantnamedgotCauseOfDeathandthenbindsittotheoptionalcausedGameOver.ThissimultaneouslycheckswhethercausedGameOverisnilorhasavalue.Ifit’snotnil,thentheifstatement’scodeblockwillrun;inthiscase,creatingtheconstantgameOverMessagethatcombinesthetextconstantwithgotCauseOfDeath.

Wecanuseif-vartosimplifythisevenfurther:

lettext="PlayerLostBecause:"

ifvarcausedGameOver=whatKilledPlayer(enemy.recentAttack){

letmessage=text+causedGameOver

}

Theif-varstatementcreatesatemporaryvariableusingourpreviouslyusedoptionalcausedGameOveranddoesaBooleanlogiccheckbasedontheresultofwhatKilledPlayer(enemy.recentAttack).Thestatementistrueifthere’sanon-nilvaluereturned.Notehowwedon’thavetouseeitherwrapped(?)orforcedunwrapping(!)oftheoptionalinsuchacase.

Optionalchainingiswhenwequerydownintothepropertiesofanobjectusingthedotoperatorwhilealsodoinganil/valuecheckaswedidwithoptionalbinding.Forexample,let’ssaythatwehaveagamewherecertainEnemytypescancauseaplayertoloseinstantlyviaanEnemyinstancenamedcurrentEnemy.Inthisexample,currentEnemy.typewouldbeastringthatreturnsthenameofthekindofenemythathittheplayer.Optionalchainingusesthecustomdotmodifier?.whileaccessingapotentiallynilcheckonaproperty.Here’sthecodetogetabetterideaofhowthisworks:

ifletenemyType=currentEnemy?.type{

ifenemyType=="OneHitKill"

{

player.loseLife()//runtheplayer'slostl

}

}

Chancesarethatwe’dprobablynotmakeanenemywithoutadesignatedtype,butforthesakeofunderstandingoptionalchaining,observehowthischecksforthepossiblenilobjectthat’dbereturnedbycurrentEnemy.typeusingcurrentEnemy?.type.Likehowthedotoperatorfunctionswhereyoucandrilldownthepropertiesandpropertiesofproperties,thesamecanbedonewiththerecurring?.perpropertythatisdrilleddown.In

thiscode,wedoaBooleancomparisonwith==toseeifenemyTypeisthestringOneHitKill.

Don’tworryifthesyntaxoftheifstatementsyntaxisabitofamystery;next,wediscusshowSwiftusesifstatements,loops,andotherwayswecancontrolvariousobjectdataandtheirfunctions.

ControlflowinSwiftControlflowinanyprogramissimplytheorderofinstructionsandlogicinyourcode.Swift,likeanyotherprogramminglanguage,usesvariousstatementsandblocksofcodetoloop,change,and/oriteratethroughyourobjectsanddata.Thisincludesblocksofcodesuchasifstatements,for-loops,do-whileloopsandSwitchstatements.Thesearecontainedwithinfunctions,whichmakeuplargerstructureslikeclasses.

IfstatementsBeforewemoveontohowSwifthandlesoneofthemaintopicsofOOP,functionsandclasses,let’squicklyrunthroughif-elsestatements.AnifstatementcheckswhetheraBooleanstatementistrueorfalse.Wehavetheexampleasfollows:

ifplayer.health<=0{

gameOver()

}

Thischeckswhetherornottheplayer’shealthislessthanorequalto0,designatedbythe<=operator.NotethatSwiftisOKwiththerenotbeingparenthesis,butwecanusethisifwewishorifthestatementgetsmorecomplicated,asinthisexample:

if(player.health<=0)&&(player.lives<=0){//&&="and"

gameOver()

}

Here,wechecknotjustwhethertheplayerhaslostalloftheirhealth,butalsoifalloftheirlivesaregonewiththeand(&&)operator.InSwift,likeinotherlanguages,weseparateouttheindividualBooleancheckswithparentheses,andlikeotherlanguages,wedoalogic-orcheckwithtwobarkeys(||).

HerearesomemorewaystowriteifstatementsinSwiftwiththeaddedkeywords,else-ifandelse,aswellashowSwiftcancheckif-notacertainstatement:

//(a)

if!didPlayerWin{stageLost()}

//(b)

ifdidPlayerWin

{

stageWon()

}

else

{

stageLost()

}

//(c)

if(enemy==Enemy.angelType){enemy.aura=angelEffects}

elseif(enemy==Enemy.demonType){enemy.aura=demonEffects}

else{enemy.aura=normalEffects}

//(d)

ifletonlinePlayerID=onlineConnection()?.packetID?.playerID

{

print("ConnectedPlayerID:/(onlinePlayerID)"

}

//(e)

ifletattack=player.attackType,power=player.powerwherepower!=0{

hitEnemy(attack,power)

}

//(f)

letplayerPower=basePower+(isPoweredUp?250:50)

Let’slookatwhatweputinthecode:

(a):Thischecksthenot/reverseofastatementwiththeexclamationpoint,!,via!statement.(b):Thischeckswhethertheplayerhaswonornot.Otherwise,thestageLost()functioniscalled,usingthekeywordelse.(c):Thischecksifanenemyisanangelandsetsitsauraeffectaccordingly.Ifthisisnot,thenitwillcheckifit’sademonusingelse-if,andifthat’snotthecase,thenwecatchallotherinstanceswiththeelsestatement.Wecouldhaveanumberofelse-ifstatementsoneafteranother,butifwestarttostacktoomany,thenusingfor-loopsandSwitchstatementswouldbeabetterapproach.(d):Usingoptionalchaining,wecreateanonlineIDconstantbasedonif;weareabletogetanon-nilplayerIDpropertyusingif-let.(e):Thisusesif-let,whereoptionalbindingbecameafeatureinSwift1.2.Insteadofhavingnestedif-letsandotherlogicchecks,akintohowSQLqueriesaredoneinbackendwebdevelopment,wecancreateverycompact,powerfulearlylogicchecking.Inthecaseofexample(e),wehaveanenemyreceiveanattackbasedonwhattypeofattackitisandthepoweroftheplayer.(f):Thisisanexampleofcombiningthecreationofaconstantwiththekeywordletanddoingashorthandversionofanifstatement.WeshorthenanifstatementinSwiftwiththequestionmark?andcolon:.Hereistheformatforshorthandinganifstatement:bool?trueResult:falseResult.IfisPoweredUpistrue,thenplayerPowerwillequalbasepower+250;iffalse,thenit’sbasepower+50.

ForloopsWetouchedonfor-inloopsbeforedealingwithcollections.Hereagainisafor-inloopinSwiftthatwilliteratethroughacollectionobject:

foritemNameininventory.values{

print("Itemname:\(itemName)")

}

Forsomeofusprogrammerswhoareusedtotheolderwayofusingfor-loops,don’tworry,Swiftletsuswritefor-loopsintheC-style,whichmanyofusareprobablyusedto:

forvarindex=0;index<3;++index{

print("indexis\(index)")

}

Here’sanotherwayofusingafor-loopwithoutusinganindexvariable,notedwiththeunderscorecharacter_butofcourseusingaRange<Int>objecttypetodeterminehowmanytimesthefor-loopiterates:

letlimit=10

varsomeNumber=1

for_in1…limit{

someNumber*=2

}

Notethe…betweenthe1andlimit.Thismeansthatthisfor-inloopwilliteratefrom1-10.Ifwewantedittoiteratefrom0tolimit-1(similartoiteratingbetweentheboundsofanarray’sindex),wecouldhaveinsteadtyped0..<limitwherelimitisequaltothearray’s.countproperty.

Do-whileloopsAnotherverycommoniterationloopinprogrammingisthedo-whileloop.Manytimeswecanjustutilizethewhileportionofthislogic,solet’slookintohowandwhywemightuseawhileloop:

letscore=player.score

varscoreCountNum=0

whilescoreCountNum<score{

HUD.scoreText=String(scoreCountNum)

scoreCountNum=scoreCountNum*2

}

Ingamedevelopment,oneuseofthewhileloop(thoughexecuteddifferentlyinagameapp,thisaccommodatesiteratingonceperframe)isfordisplayingthecountingupofaplayer’sscorefrom0tothescoretheplayerreached—acommonestheticofmanygamesattheendofastage.Thiswhileloopwilliterateuntilitreachestheplayer’sscore,displayingonHUDobjectshowingtheintermediatevaluesupuntilthatscore.

Ado-whileloopispracticallythesameasthewhile-loopwiththeextracaveatofiteratingthroughthecodeblockatleastonce.Theend-stagescorecountexamplecanalsoillustratewhywewouldneedsuchaloop.Forexample,let’simaginethattheplayerdidreallybadandgotnoscorewhenthestageended.Inthewhileloopgiven,ascoreofzerowon’tletusentertheblockofcodeinthewhileloopsinceitdoesn’tfulfillthelogiccheckofscoreCountNum<score.Inthewhileloop,wealsohavecodethatdisplaysthescoretext.Thoughmaybeembarrassingtotheplayer,wewouldwanttocountuptothescoreandmoreimportantly,stilldisplayascore.Here’sthesamecodedonewithado-whileloop:

letscore=player.score

varscoreCountNum=0

do{

HUD.scoreText=String(scoreCountNum)

scoreCountNum=scoreCountNum*2

}whilescoreCountNum<score

Nowscoretextwilldisplayeveniftheplayerscorednothing.

SwitchstatementsSwitchstatementsareusefulwhenwewishtocheckmanydifferentconditionsofanobjectinafullyencompassingandneatwaywithouthavingawallofelse-ifstatements.Here’sacodesnippetfromthegamePikiPopthatusesaSwitchstatementfromthegame,PikiPop,thatsetsthepercentageaGameCenterachievement(inthiscase,a6xcombo)basedonthenumberoftimesthecombowasachievedbytheplayer.Don’tworrytoomuchabouttheGameCentercode(usedwiththeGCHelpersingletonobject);that’ssomethingwewillgooverinfuturechapterswhenwemakegamesinSpriteKitandSceneKit.

switch(comboX6_counter){

case2:

GCHelper.sharedInstance.reportAchievementIdentifier("Piki_ComboX6",

percent:25)

break

case5:

GCHelper.sharedInstance.reportAchievementIdentifier("Piki_ComboX6",

percent:50)

break

case10:

GCHelper.sharedInstance.reportAchievementIdentifier("Piki_ComboX6",

percent:100)

default:

break

}

Theswitchstatementheretakesthevariableusedtocounthowmanytimestheplayerhita6Xcombo,comboX6_counter,andperformsdifferenttasksbasedonthevalueofcomboX6_counter.Forexample,whentheplayerhasdonea6XCombotwice,thePiki_ComboX6achievementgets25%fulfilled.Theplayergetstheachievement(whenat100%)whenthecounterhits10.Thepurposeofthekeywordbreakistotellthelooptoexitatthatpoint;otherwise,thenextcaseblockwilliterate.Sometimes,thismightbedesiredbyyourgame’slogic,butkeepinmindthatSwift,likemanyotherlanguages,willcontinuethroughtheswitchstatementwithoutbreak.Thekeyworddefaultisthecatch-allblockandiscalledwhenthevalueoftheitemcheckedbytheswitchstatementisanythingbutthevariouscases.Itcanbethoughtofasanequivalenttotheelse{}block,whileallofthecasesaresimilartoelseif(){}.ThedifferencethoughisthatSwiftrequiresallcasesoftheswitchbehandled.So,thoughwecansufficewithanifwithoutanelse,wehavetohaveadefaultcaseforaswitchstatement.Again,thisisdonetokeepSwiftcodesafeandcleanearlierinthecodingprocess.

FunctionsandclassesUpuntilthispoint,wehavekeptfromdiscussingprobablythemostimportantaspectsofSwiftoranyOOPlanguagesforthatmatter—howthelanguagehandlesfunctionsonobjectsandhowitorganizestheseobjects,objectproperties,andfunctionsandperformsvariousobject-orienteddesignconcepts,suchaspolymorphismandinheritancewithclasses,Structs,enums,protocols,andotherdatastructures.ThereismuchmoretodiscussabouthowSwiftutilizestheseconcepts,morethanwecanfitinthischapterbutthroughoutthecourseofthisbook,especiallyaswegetintohowtouseApple’sgame-centricSpriteKitandSceneKitframeworks,wewillfleshoutmoreonthesetopics.

FunctionsInObjective-C,functionsarewrittenthefollowingway:

-(int)getPlayerHealth(){

returnplayer.health;

}

Thisisasimplefunctionthatreturnstheplayer’shealthasaninteger—theIntequivalentinObjective-C.

Thestructureofthefunction/methodisasfollowsinObjective-C:

-(return_type)method_name:(argumentType1)argumentName1

joiningArgument2:(argumentType2)argumentName2…

joiningArgumentN:(argumentTypeN)argumentNameN

{

functionbody

}

Here’sthesamefunctioninSwift:

funcgetPlayerHealth()->Int{

returnplayer.health

}

//Howwe'dusethefunction

varcurrentHealth:Int=0

currentHealth=getPlayerHealth()

ThisishowafunctionisstructuredinSwift:

funcfunction_name(argumentName1:argumentType1,argumentName2:

argumentType2,argumentNameN:argumentTypeN)->return_type

{

functionbody

}

Notehowweusethekeywordfunctocreateafunctionandhowtheargument/parameternamesarefirstwiththetypessecond,separatedbythecolon(:)andwithinparenthesis.

Here’swhatatypicalvoidfunctionlookslikeinSwift.Avoid-typefunctionisafunctionthatdoesn’treturnavalue.

//withaPlayertypeasaparameter

funcdisplayPlayerName(player:Player){

print(player.name)

}

//withoutanyparameters;usingaclassproperty

funcdisplayPlayerName(){

print(currentPlayer.name)

}

Inavoidfunction,there’snoneedtowrite->returnType,buteveniftherearenoparameters,wedohavetoputinthe()parenthesisattheendofthefunctionname.

TuplesAratherpowerfulaspectofSwiftisthatfunctionreturntypes(andconstants/variables)canincludeacombinationofvaluesintoasinglevalue.Thesecombinationsarecalledtuples.Here’sanexampleofanunnamedtuple:

lethttp503Error=(503,"ServiceUnavailable")

Here’satupleusedasareturntypeinafunctiondirectfromApple’sSwiftdocumentation.Observehowitusesmuchofwhatwe’velearnedthusfar:

funcminMax(array:[Int])->(min:Int,max:Int){

varcurrentMin=array[0]

varcurrentMax=array[0]

forvalueinarray[1..<array.count]{

ifvalue<currentMin{

currentMin=value

}elseifvalue>currentMax{

currentMax=value

}

}

return(currentMin,currentMax)

}

ExcerptFrom:AppleInc."IOSDeveloperLibrary".

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swif

t_Programming_Language/Functions.html#//apple_ref/doc/uid/TP40014097-CH10-

ID164

ClassesInOOP,classesmakeupthebasicframeofanobject,itsfunctionalityandinteractionswithotherclasses,objects,andvariousdatastructures,suchasprotocols,Structs,extensions,generics,andenumerations.Inthefollowingchapters,aswebegintostructureourgames,wewilldivedeeperintoalloftheseconcepts,butfornow,let’sunderstandthebasicsofclassesandhowtheydifferinSwiftfromObjective-Candotherlanguages.

Here’sthebasicstructureofaclassinSwift:

//(a)

Global-projectwideproperties/variables

//(b)

classclassName:parentClassName,protocolName…protocolnName

{

//(c)

classscopeproperties

//(d)

initializers(init(),convenience,required,etc)

//(e)

funcfunction_name1(argumentName1:argumentType1,argumentName2:

argumentType2,argumentNameN:argumentTypeN)->return_type

{

function-scopevariablesandbody

}

.

.

.

funcfunction_nameN(argumentName1:argumentType1,argumentName2:

argumentType2,argumentNameN:argumentTypeN)->return_type

{

function-scopevariablesandbody

}

//(f)

deinit()

}//endoftheclass

//(g)

global-projectwideproperties/variables(alternativeposition)

TheSwiftclassstructureworkssomewhatsimilartowhatweseeinC#andJava,asopposedtoObjective-C’stwofiles’(.h/header,.m/.mm/implementation)setup:

(a):Wecanhaveproperties(likevariables,constants,Structs,andenums)outsideoftheclassdeclaration,whichwouldmakethemglobalinscope,akaaccessiblethroughouttheentireproject/game/app.(b):Thisistheactualclassrepresentedbywhatwenamedour.swiftfile.Again,thisisdifferentfromObjective-C’sclassname.h-classname.m/.mmdualfilesetupforasingleclass.Aclasscanbeachildclassofanotherclass.Wedon’thavetodeclareaparent/baseclassinSwift.Classeswemakecanbetheirownbaseclasses.WecanmakeclassesasObjective-CclassesbysubclassingthemfromNSObject.

ThebenefitofthatisgettingObjective-Cruntimemetadataandcapabilities,butwetakeahitinperformancefromtheextrabaggage.EitherinthesameplaceastheparentClassorafterthecolon:ofparentClass,wecandeclarewhichprotocolsthisclasswilladhereto.We’lldiscussmoreonprotocolslaterinthebook,butjustthinkofthemasmakingsureyourclassutilizesthesamefunctionsastheprotocoldictates.(c):Thesearewherewe’dplacevariables,constants,Structs,enums,andobjectsthatarerelevantforuseinthescopeoftheclass.(d):Initializersarespecialfunctionsweusetosetupthepropertiesinsection(c)whenotherclassesanddatastructuresuseinstancesoftheclassviaclassName(initializerparameters).Wewilldiscussmoreoninitializersmoreinthenextchapteraswestructureourgames.Theydon’thavetobeatthetopoftheclass,butit’sagoodpracticetodoso.(e):Thesearewhereyourclassfunctionswillbedeclaredanddeveloped.Wecanhavefunctionsthatareknownasclassfunctions.Thesearedesignatedwiththekeywordsclassfunc.Inshort,classfunctionsarepartoftheclassasawholeasopposedtoaninstanceoftheclass.It’sbestpracticetoplacetheseabovethenext,morecommontypeoffunction,thepublicfunctions,thatcanbeaccessedbyotherclassesandpropertiesviathedotoperator(thatis,className.function(parameters)).Usingtheprivatefunckeywords,asinC#andJava,wecancreateprivatefunctionsthatareonlyaccessibletotheclass’sownfunctionsandproperties.(f):Thedeinit()functionisaspecialoptionalfunctionthatdealswithhowwecleanupthedataallocatedbyourclasswithmemorymanagementandeliminatingwhat’sknownasmemoryleaks.Apple’sARC(AutomatedReferenceCounting)handlesmostofthis,buttherearekeywords,suchasweakandunowned,thatwewillattimeshavetoputbeforevariouspropertiestomakesurethattheydon’thangaroundafteruse.

Thisisaratherinvolvedtopic,butworthlookingintotoavoidmemoryleaksinyourgame.ARCdoestakecareofmostofthis,buttheremightbeobjectsinyourgamethatcouldpotentiallyhangaround.It’shighlyrecommendedtoreadApple’sowndocumentationonthistopic,asmemorymanagementiniOSisalwaysintheevolvingstage.YoucanviewthefulldocumentationonARCandmemorymanagementinSwiftathttps://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html

(g):Ifwewish,wecanhaveglobalpropertiesalsoatthebottomofour.swiftfiles,aftertheendoftheclassdeclaration.Apple’sowngameexample,Adventure(https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.htmlplacesglobalpropertiesinthisspot.

SummaryThere’smuchmoreabouttheSwiftprogramminglanguagethanwecouldfithere.Throughoutthecourseofthisbook,wewillthrowinafewextratidbitsandnuancesaboutSwiftasitbecomesrelevanttoourupcominggamingprogrammingneeds.

IfyouwishtobecomemoreversedintheSwiftprogramminglanguage,Appleactuallyprovidesawonderfultoolinwhat’sknownasaPlayground.

PlaygroundswereintroducedwiththeSwiftprogramminglanguageatWWDC14inJuneof2014andallowustotestvariouscodeoutputsandsyntaxeswithouthavingtocreateaproject,buildit,andrunitandrepeatagain,wheninmanycaseswesimplyneededtotweakafewvariablesandfunctionloopiterations.

ThereareanumberofresourcestocheckoutontheofficialSwiftdeveloperpage(https://developer.apple.com/swift/resources/).

TwohighlyrecommendedPlaygroundstocheckoutareasfollows:

TheGuidedTourPlayground(https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.playground.zipThisPlaygroundcoversmanyofthetopicswementionedinthischapterandmore,fromHelloWorldallthewaytoGenerics.TheBalloonsPlayground(https://developer.apple.com/swift/blog/downloads/Balloons.zip):TheBalloonsPlaygroundwasthekeynotePlaygroundsdemonstrationfromWWDC14andshowsoffmanyofthefeaturesPlaygroundshavetooffer,particularlytomakeandtestgames.

Sometimes,thebestwaytolearnaprogramminglanguageistotestlivecode,andthat’sexactlywhatPlaygroundsallowustodo.

Inadditiontotestingsnippetsofcodeinourgames,iOS9alsoallowsustoplanandstructureourgames,whichisthetopicofthenextchapter.

Chapter2.StructuringandPlanningaGameUsingiOS9StoryboardsandSeguesVideogamedevelopmenthashadaninterestinghistory.Itstartedasanoffshootofbothelectricalengineeringandcomputerscience.Gameswereagreatchallengeforengineerstomakethemostoutofthelimitedhardwareand,ofcourse,makesomethingfun.Today,videogamesandvideogamedevelopmentarestillbuiltonthosefoundationsoftechnology,math,andengineeringbut,fordecades,havealsobeenmajorplayersintheworldofentertainment,storytelling,andmedia.

Beitifyouareamajorstudio,asmallteam,orcreatinggamesallbyyourself,planningandstructuringyourgameprojectscangiveyouthefoundationneededtosavetimeinthedevelopmentprocess,dividetheworkouttoothersifonateam,andofcourse,bringyourgametolifeascloseaspossibletohowyouimaginedit.

StartingwithiOS5,Appletookapagefromtheentertainmentindustryinhowtostructureandplanaproject,bigorsmall;byusingtheconceptofstoryboards.Storyboardsareagraphicrepresentationofthevariousstepsandstructuresofaproject;beitananimation,amovie,orinourcase,iOSgames.Storyboardswillgraphicallyshowtheflowofaproductionorapp.Inanimation,forexample,storyboardsareusedtofleshoutmajorframesorstorypointsoftheproduction.Onceit’sagreedonastowhattheseriesofeventsinascenewillbe,animatorswillanimatearoundthosekeypoints.DependingonwhethertheproductionisprelayorADR,voiceactingcouldalsobeplacedintothestoryboardprocess,whichgivestheanimatorsevenmorespecificcontenttoworkwith.

Inthecaseoftheactualgameapplication,storyboardscanrepresentmajorpartsofyourgame,suchastheIntroscene,OpeningMenuscreen,PauseScreen,GameOverScreen,orthegenericlookofamaingamelevel.ApplenamedthesestructuresinXcodestoryboards,andthepathsbetweenthemareknownassegues.Throughoutthischapter,weshallbelookingintohowtomakeuseofthesefeatureswhilemakingagameapp.

TheprecedingisanexampleofasimpleiOSStoryboard.

Model-View-ControllerBeforewegetintostoryboardsiniOS9,it’sbestthatwefirstdiscussthebasicflowofaniOSappandtheconceptofModel-View-Controller(MVC).Model-View-Controllerisanarchitecturalparadigmusedinsoftwareengineering,programming,andevennowinwebdesign.WecanthinkofthemodelportionofMVCasthelogicorbrainsofanapplication’sbehavior.Thislogicisusuallyindependentoftheuserinterfaceanddetermineswhattodowiththeapp’sdata.

We’veactuallyalreadygoneoverthemodelportionofMVC!TheSwiftprogramminglanguagediscussedinthepreviouschapteristhatmodel;thisisthecasewithitsObjective-CpredecessorandanyotherprogramminglanguageusediniOSoranyothergamedevelopment.Yourgame’scodecontrolswhattodowiththeplayer,level,andenemy/goaldata.

TheviewportionofMVCisthevisualrepresentationofthemodel.Thisofcoursewouldincludethenumerousvisualaspectsofourgames,fromourplayer’sanimationframes,variousin-gamestatsontheHUD,particleeffects,andmore.

ThecontrollerportionofMVCcanbethoughtofasthegluethatholdsthemodelandviewtogether.Itisalsothepointatwhichtheuserofyourgameinteractswith.Beitactions,suchasabuttonpress,abasictouch,aswipe,orothergestures,recognizedbyyouriOSdevice,thecontrollertakesthatuserinput,manipulatesyourmodelandthenthemodelupdatesyourviewaccordingly.

ThisdiagramistakenfromApple’sownAdventureGameExample.

WhenweworkwithiOSapps,thefirstrecommendedentrypointforcodeandstoryboardinfoistheRootViewController.Aswe’llcometofindout,MVCisintrinsicallybuiltintoiOSappdevelopmentandtheXcodeIDE.Storyboardsareacollectionofdifferenttypesofviewcontrollerswithvaryingtasksthatarelinkedbysegues.

AniOSapp’slifecycleBeforewemoveontoworkingwithstoryboards,segues,andthefoundationofourgameapps,it’sbestwegoovertheoveralllifecycleofaniOSappasit’simportanttoknowtheentrypointsofourcodeandvariousobjects/structuresofourapps.

Insertapplifecycleimageryherebeforewemoveontoworkingwithstoryboards,segues,andthefoundationofourgameapps.It’sbestwegoovertheoveralllifecycleofaniOSappasit’simportanttoknowtheentrypointsofourcodeandvariousobjects/structuresofourapps.

Source:https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html

AnyonewhohasworkedwithC/C++,Java,orotherlanguageswillbefamiliarwiththemain()function.Themain()functionisusedtodesignateyourprogram’smainentrypoint.TheprecedingexampleishowAppledesignatesthetypicalmainfunctionforapps.EssentiallywhatthisisdoingiscallingthefirstclassinthetypicallifecycleofiOSapps,theAppDelegateclass.

Themain()functionHere’sthecodewiththemain()function:

#import<UIKit/UIKit.h>

#import"AppDelegate.h"

intmain(intargc,char*argv[])

{

@autoreleasepool{

returnUIApplicationMain(argc,argv,nil,

NSStringFromClass([AppDelegateclass]));

}

}

//Objective-CexampleoftheMain()function

Notehowthemain()functioniswritteninObjective-C.Swiftagainmakesdeclaringtheentryofyourapplicationeasier.

@UIApplicationMain

classfirstClassCalled

{

//classcode

}

WhilebuildinganiOSappwithSwift,themain.mfileseeninpriorObjective-Cprojectsisnolongerneeded.Instead,weuseanAttributecall,@UIApplicationMain,justbeforethedeclarationoftheclassthatisfirstcalled.

NoteSwiftattributes

Attributes,beginningwiththeatcharacter,@,areusedtoaddadditionalinformationtoadeclarationoratype.InSwift,theyhavethefollowingsyntax:

@attributename

@attributename(attributearguments)

Asinotherprogramminglanguages,attributes,dependingontheirfunctionality,canbeusedtodescribeobjects,functions,andevenentireclasses.

Forexample,the@objcattributeisusedtodeclarecodethatisreadableinObjective-C.

Aswe’llseewhileusingandlinkingvariousobjectsinthestoryboardswithourcode,theattributes@IBOutletand@IBActionareusedtodescribeobjectsandfunctionsrepresentingobjectswecreateinXcode’sInterfaceBuilder.

WewilldiscussmoreonAttributesinChapter7,PublishingOuriOS9.0Game.

TheUIApplicationclass/objectUIApplicationistheobjectresponsibleforcontrollinganapp’sevent-loopaswellashandlingotherupper-levelappprocesses.Gameappornot,thisispresentinalliOSappsandiswhatisfirstcalledatthemainentrypointandworkstogetherwiththeAppDelegateclass.ThoughitispossibletosubclassUIApplication,it’susuallynotrecommended.CustomizationstowhatyourgamedoesduringvariousappstatesarewhatweusetheAppDelegateclassandViewControllersfor,evenifstoryboardsarenotutilized(thatisifyouchoosetomostlyhardcodeyourgame).

TheAppDelegateclassWecanthinkoftheAppDelegateclassasyourapp’smainhub.It’sthetoplevelofgeneralcustomizationforyourgame.WhilemakinganappinSwift(gameornot),it’stheclassthatisgiventhe@UIApplicationMainattributebecauseit’sthegeneralfirstentryofyourgame’smodel/code.

Here’sthecodethatAppleprovideswithalmosteveryiOSapppresetinXcode:

importUIKit

@UIApplicationMain

classAppDelegate:UIResponder,UIApplicationDelegate{

varwindow:UIWindow?

funcapplication(application:UIApplication,

didFinishLaunchingWithOptionslaunchOptions:[NSObject:AnyObject]?)->

Bool{

//Overridepointforcustomizationafterapplicationlaunch.

returntrue

}

funcapplicationWillResignActive(application:UIApplication){

//Sentwhentheapplicationisabouttomovefromactiveto

inactivestate.Thiscanoccurforcertaintypesoftemporaryinterruptions

(suchasanincomingphonecallorSMSmessage)orwhentheuserquitsthe

applicationanditbeginsthetransitiontothebackgroundstate.

//Usethismethodtopauseongoingtasks,disabletimers,and

throttledownOpenGLESframerates.Gamesshouldusethismethodtopause

thegame.

}

funcapplicationDidEnterBackground(application:UIApplication){

//Usethismethodtoreleasesharedresources,saveuserdata,

invalidatetimers,andstoreenoughapplicationstateinformationto

restoreyourapplicationtoitscurrentstateincaseitisterminated

later.

//Ifyourapplicationsupportsbackgroundexecution,thismethod

iscalledinsteadofapplicationWillTerminate:whentheuserquits.

}

funcapplicationWillEnterForeground(application:UIApplication){

//Calledaspartofthetransitionfromthebackgroundtothe

inactivestate;hereyoucanundomanyofthechangesmadeonenteringthe

background.

}

funcapplicationDidBecomeActive(application:UIApplication){

//Restartanytasksthatwerepaused(ornotyetstarted)while

theapplicationwasinactive.Iftheapplicationwaspreviouslyinthe

background,optionallyrefreshtheuserinterface.

}

funcapplicationWillTerminate(application:UIApplication){

//Calledwhentheapplicationisabouttoterminate.Savedataif

appropriate.SeealsoapplicationDidEnterBackground:.

}

}

Thisisthedirectcodeandcomments(asofXcode6.4)thatAppleprovidesforuswhenusingtheiOS9gamepreset.Beforewediveintostructuringourgameswithstoryboardsandthetwomainframeworks(SpriteKitandSceneKit),it’sbesttounderstandwhathappensinthisclass.Eventsthathappentoyourgameapprelatingtothedevice,particularlythosethatareoutsideoftheplayer’scontrol,suchasincomingphonecalls,notifications,andthedeviceshuttingdownduetolowbatterypower,aswellasthosecontrolledbytheplayer(thatispausingthegame),arehandledbythisclass.Aswesee,Applealreadyprovidesgreatinstructionsforwhateachfunctionofthisclassdoes,sobesuretoreviewthem.Wewillcomebacktotheseaswecreateourgamesandhandlethosespecificsituations.NotethattheAppDelegateclasshasanoptionalvariable(meaningitcanbenil)namedwindowandisofthetype,UIWindow.AUIWindowobjectisachildofUIViewandcanallocatevariousdisplays/objectsthatcanbeputintotheviewoftheuser.Technically,wecanuseobjectsofUIWindowandUIViewincodedirectlytocreatethevisualsofourgame,butAppleprovidesmorerobustobjectsthathandleboththeuser’sinteractionwiththescreenandview.TheseobjectsarewhatmakeupiOSstoryboards;theablynamed,ViewControllers.

ViewcontrollersViewcontrollersareprobablyoneofthemostvitalstructuresofiOSdevelopmentandarewhatstoryboardsarevisuallyrepresentingwhendesigningtheminXcode’sInterfaceBuilder.Intermsoftheirtypicalentrypointorder,it’sMAIN—>AppDelegate—>RootViewController—>[callstoanyadditionalViewControllersinstance].

WhenwecreateanewappprojectinXcode,ApplewillmakeadefaultRootViewControllernamedViewControllerforus.Here’sit’scode:

importUIKit

classViewController:UIViewController{

overridefuncviewDidLoad(){

super.viewDidLoad()

//Doanyadditionalsetupafterloadingtheview,typicallyfroma

nib.

}

overridefuncdidReceiveMemoryWarning(){

super.didReceiveMemoryWarning()

//Disposeofanyresourcesthatcanberecreated.

}

}

ThisisthestartercodegiventousinXcodewiththedefaultViewController.swiftclass.Aswesee,it’sasubclassofUIViewControllerandthusinheritsallofitsparentclass’sfunctions.OneofthemshownhereisthefunctionviewDidLoad().InSwift,whenwewishtooverrideafunctionofaparentclass,weusethekeywordoverridebeforethefunctiondeclaration.Wealsoseethatsuper.viewDidLoad()iscalledaswell.Whatthisdoesiscalltheparent’sownversionofthisfunctionbeforeweaddourowncode/customizationsandisrecommendedwhenusinganyofthefunctionsofUIViewController.TheUIViewControllerfunctionshandlevariousviewstates;viewDidLoad()handleswhentheviewisfirstloadedandiscalledonceforthelifeoftheUIViewControllerobjectduringanapp’slifecycle.Ifwewanttocallsomecodeeverytimeaviewisseen,wecanusetheviewDidAppear()functionofUIViewControllerinstead.

Here’savisualrepresentationoftheseviewstates.

Herestoryboardsandsegues,aswe’llsee,essentiallygiveusavisualandcustomizablerepresentationoftheseverystatesandthetransitionsbetweenthemwithoutusingtoomuchcode.

TodiveevendeeperintotheUIViewControllermethods,checkoutApple’sdocumentationonthesubject:

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/

NoteForanyonefamiliarwiththegamedevelopmentengineUnity(whichhasscriptswrittenineitherC#,JavaScript,orthePythonderivative),onewaywecanimaginetheUIViewControllerfunctionsviewDidLoad()andviewDidAppear()isthattheyaresomewhatsimilartotheUnityfunctionsAwake()andOnEnabled(),respectively.Onefunctioniscalledwhenthesceneisfirstloadedandtheotherjustbeforethefirstframethattheobjectisvisible/enabled.TheUIViewControllerfunctionshoweverareonamoreupper-levelbasisfortheentiretyoftheappasopposedtoapergameObjectbasis.

FormoreinformationandgraphicsontheentireiOSapplifecycle,checkoutthefulldocumentationhere:

https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html

ViewcontrollertypesViewcontrollerscomeinanumberoftypesandwecancreateourownbysubclassingthem.Thetwomaintypesarecontainerviewcontroller,whichholdotherviewcontrollers,andcontentviewcontrollers,whichaswecanimagine,arewhatdisplaythecontent.ContentviewcontrollersincludetheRootViewController,whichisthefirstviewcontrolleraccessedaftertheapp’sentrypointandisalsothefirstviewcontrollerseeninthedefaultMain.StoryboardfileinapresetXcodeproject’sinspector.Therearealsootherspecialtypesofviewcontrollers,liketheUITableViewController,usedtodisplaydatalistedintablecellformatsandtheNavigationController,whichcontrolsthenavigationlogic/imageryoftheappwhenmovingbetweenotherviewcontrollers.

Foramorein-depthlookatthevariousviewcontrollersavailableinUIKit,checkouttheofficialdocumentationseenhere:

https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/index.html#//apple_ref/doc/uid/TP40007457-CH2-SW1

It’sactuallyatthispointthatwecanbegintocodeourgame,albeitentirelyprogrammingtheMVCmodel.InthebeginningofiOSgamedevelopment,thiswasessentiallyhowonewouldgoaboutdevelopingagamefortheoriginaliPhone.We’dprogrammaticallyworkwiththeUIWindowandViewControllerobjectsandourgame’sowncustomclassestocrafttheapp.AsthefamilyofiOSdevicesgrew,anobviousissuebegantoarise.Thoughwecan,andsometimesmighthaveto.programmaticallychangecodebasedonthedevice,dealingwithagrowingnumberofscreensizesanddevicetypesmadeitsothatourcodewouldalwayshavetoberefactoredandproducedeverincreasingambiguitywheneveranewAppleiOSdevicewasannounced.Also,let’snotforgetthatgamedevelopmentisasmuchofavisualdesigner/animator’sworkasitisaprogrammer’s.Editing,positioning,refining,andlaterupdatingvariousvisualaspectsofagamecanbeverytimeconsumingifdoneentirelyviacode.

Storyboardsweremadetohelpalleviatethisissuebyallowingustovisuallydesignourgameintheprojectitselfasopposetohavingourownpossiblyhandwrittenstoryboardsthatdescribejustamodel-based,code-centricdesign.WiththeintroductionofAutoLayoutinXcode5,wecan,withoutusinganycode,makeoneprojectandgeneralviewforallvarietiesofiOSdevices.WeshalltouchonAutoLayoutaswenowfinallymoveontoworkingwithStoryboardsandsegues,butforamorein-depthlookonAutoLayout,checkouttheofficialdocumentationonApple’sdeveloperportal:https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG

StoryboardsandseguesLet’snowfinallygettoworkingwiththesetoolsandlearnthebasicsofstructuringgameappsonabroaderstoryboardlevel.Asofthewritingofthisbook,thelatestversionofXcodeavailableisversion7.0.Thiswillbetheversionweshallworkwith,butXcodeisalwaysupdatingwithevenabetaversionavailabletoseparatelytestthenewestfeatures.

Visithttps://developer.apple.com/xcode/todownloadandreaduponallthatXcodehastoofferforiOSdevelopers.

Tostartstructuringyourappusingstoryboards,followtheseinstructions:

1. First,openXcodeinyourApplicationsfolder(orinyourDockifyouplaceditthereforeasyaccess).

2. Next,clickonCreateanewXcodeProject.

3. Youwillnowbeaskedtochooseatemplatepreset.4. Forthesakeofjustunderstandingstoryboardsandsegues,selecttheSingleView

Applicationtemplate.(Don’tworry,wewillbeusingthegametemplateinthenextchapter).

5. Nowwechooseourproject’soptions.NameyourprojectStoryBoardExample.6. IntheLanguagedropdown,makesurethatitissettoSwiftandensuretheDevices

dropdownissettoUniversal.7. ThereshouldbeotherfieldsfilledinbyXcode,suchasyourorganizationnameand

organizationidentifier.Thoseareinvolvedwiththeinformationthatwillbepublishedwithyourappwhenitcomestodeploymentaswellasthecontentofyourcode’scopyrightcomments.WecanfornowkeeptheseattheirdefaultsettingthatXcodehasfilledin.

8. ClickonNextandthenselectavalidlocationinyourfilestosavethisproject.

Nowwehaveourdefaultappcreatedbythetemplate.Weshouldseeontheleft-handside,intheFileNavigatorPane,variousfilesandfolderscreatedforus.Aswecansee,theAppDelegate.swiftandtheViewController.swiftfileswereautomaticallycreatedforusandrightbelowthat,we’dfindtheMain.Storyboardfile.Thisisourstoryboardandwhenyouclickonit,youshouldseethetwopanesopenatthecenterofyourXcodewindow.TheleftsideistheviewcontrollerScenedropdown,whichshowsthehierarchyofthescenecontrolledbytheprovidedtheviewcontroller.Therightpaneinthecenterallowsustovisuallyseetheviewcontrollerandeventuallyelementsthatwecanplaceinit.Themainvisualpartofthestoryboardcanbezoomedinandzoomedout.Asweaddmorescenestoit,thiswillallowustoseetheentiretyofourstoryboardortheportionsweareworkingon.

Youmighthavetozoomoutslightlytoseeit(usingyourmouseorusingthepinchinggestureonyourtrackpadwithaMacBook),buttotheleftoftheViewControllerscenethere’sagrayarrow.ThisistheentrypointandthefirstViewControllersceneattachedtothisarrowisyourRootViewController/Initialscene.

TipWhenaddingmorescenestoyourstoryboard,foreitherdebuggingpurposesordesignchoice,youcansimplychangethescenethatisfirstenteredbyclickinganddraggingthatarrowtotheleftofthatscene.

Let’sstartbycreatingaseparatesceneforourstoryboard:

1. AtthebottomoftheUtilitiespanel(thefarrightpaneloftheXcodeproject),therearefouriconsdesignatingthevarioussnippetsandobjectswecanplaceinourproject’scodeandthestoryboard.Clickonthethirdiconfromtheleftifit’snotalreadyselected.ThiswillopentheObjectLibrary.

2. WecanseethattheverytopoftheObjectLibraryhasaViewControllerobject.

3. Dragthisontothestoryboard’scanvas,preferablytotherightoftheinitialscene.

NoteIftheUtilitiespanelisn’topen,clickontheupperright-mosticonatthetopofyourproject’stoolbarwindow.

NoteThethreebuttonsinyourtoolbarcanbetoggledtoclosetheNavigationpane,Debugpane,andUtilitiespane,respectively.Closingthesewhenapplicablecanhelpexpandthegeneralview,knownasthecanvasofyourstoryboardscenes.

Nowwehavetwoscenesinourstoryboard,butnothingistheretotelluswhattheyare.Theyarejusttwoblankscenes!

Let’sputaLabelobjectinthesescenestorepresentwhattheyareandatruntimetelluswhichonewearein.

Tokeepthisinthemindsetofdevelopingagame,let’sputalabelinthefirstonecalledIntroScene,wherewe’dmaybehaveanintroanimationtoourgamewithaStart/Optionsmenu,andinthenextone,putthelabelGameScenetorepresentthatthisiswherethatactualgameplaywouldoccur.

Here’showtodothat:

1. GotothebottomoftheUtilitiespanelandusethesearchfieldtosearchlabel.Thiswillisolatethelabelobject,soyoudon’thavetoscrollthroughtheentirelist.

2. Dragthelabelobjecttothecanvasofthefirstscene.Ifitdoesn’tlooklikeit’stryingtosnaptothescene’scanvas,youmighthavetoselecttheViewportionofthatviewcontrollerscene’shierarchy,usingtheleftpaneoftheMain/Storyboard’smainview.Alternately,youcanalsodouble-clicktheviewintheInspectortogetthesceneinfocussothatyoucanplacethelabelontoit.

3. Aswedragit,trytocenterthelabelasbestaspossible.Thecanvaswillindicatethatweareattheverticaland/orhorizontalpartofthatscenewithdottedbluelines.Dropitinthecenter.

TheUtilitiespaneshouldhavesomefieldsvisiblewhenselectingthelabeltocontrolvariousaspectsofitstextlikefontsize,alignment,andstyle.

4. ThelabelwilljustsayLabelasthedefault,solet’srenameittoIntroSceneforthefirstscenebyeitherdouble-clickingthelabelitselfinthecanvas,orchangingthenameinthesecondfielddownfromTextintheUtilitiespanel.

5. Let’smakethislabelabitmoreprominent,sosingle-clickonthelabel,clickonthe[T]iconintheFontfield,andmakethestyleboldwithasizeof28.

Notehowthelabelisclippedfromthesizeincreaseandhardlyvisible.

6. Simplyclickonthelabelandexpandoutanyoneoftheeightscalingiconsatthecornersofthelabelobjectonthecanvas.

Repositionthelabeltoreturnittothecenterofthescene.

7. CreatethesamelabelforthesecondsceneweaddedbysimplytypingCommand+Dtoduplicatethelabel(astonothavetorepeatallofthesteps)andthendragittothecenteroftheotherscene.Zoomoutasneededandpossiblyclickbackontotheviewpartofthehierarchyifthefocuschangepreventstheabilitytodragthelabelacross.

Thoughratherrudimentaryandwithstillsomemoreworktodowith,thisisallittakestocreateseparatescenesvisually.Ifyouhaveanideaofhowyouwanttostructureyourgame,thisiswhereyoucanstartwiththeuseofstoryboards.Ofcourse,thereisstillmoretodoherebeforewemakethisstoryboardhaveanyfunction.

WecanseethatXcodeisgivingusthefollowingwarning:

Sceneisunreachableduetolackofentrypointsanddoesnothaveanidentifierforruntimeaccessvia-instantiateViewControllerWithIdentifier.

ThisisreferringtotheGameSceneobjectthatisessentiallyorphanedduetonoconnectiontotheIntroScenenortheapp’sentrypoint.

Thisiswhereseguescomeintoplay.Yet,beforeweworkwithseguesandcreateaflowtothesescenesandmore,ifweweretorunthisapp,we’dnoteanotherissue.Wecouldhaveswornthatwecenteredthetext,butifsimulatingorrunningthisin,say,aniPhone6s,thetextiscompletelyofftotheupper-rightside.ThisisbecausethedefaultcanvasisageneralizedalldevicetemplatetobeginwithviaAutoLayout.

AutoLayouthasgotteneasierwitheachnewbuildofXcode,butonecouldstillargueit’sstillabitofahassleattimestofinetune,particularlywhencreatingconstraints(setspaces/marginingbetweenvariousstoryboardobjects).Let’stakeaquicklookathowtoworkwithconstraints.

OnequickwaytoalleviatetheissuewehavehereistojustworkwiththeBaseValuespanelfoundatthebottomcenterofthestoryboardcanvasbyclickingonthew/Anyh/Anytext.Onceclicked,apop-uptableofcellswillappear.Rollingoverwithyourmouseortrackpadtothevariouscellswillbringupanumberofdifferentconfigurationsasopposetow/Anyh/Any.What’sgreataboutthisisthatyoucanchange/addanddeletevariousobjectssimplybasedonthedevicetypeusingtheseoptions.

NoteBeforestoryboardsandAutoLayout,thiswouldinvolvehugeamountsoftestingandrefactoringofcodeinaviewcontrollerorNibclassestogetthelayoutjustthewayyou’dlikevisually.Applewouldthencreatethenextdevicewithadifferentscreensizetopriordevices,itwouldbecomeanevengreaterhassleorthedeveloperwouldriskabrokengameonthenewestdevice.

TomakethelabelsbeinthecenterforalliPhonesinportraitmodeforexample:

1. Hoverandclickonthecenterleft-handsideoftheAutoLayoutpanelwhereit’llsayCompactWidth|AnyHeightatthetopofthatpop-uppanel/table.

2. Thisshouldnowchangethedisplaytextatthebottomofthecanvastow/Compact

h/AnyandshrinkthewidthofthesceneasthislayoutrepresentsalliPhonesinPortraitandofanyheight(soitcouldbeabitoffinheightonanolderiPhone4SasopposetotheiPhone5orlater).

3. Notehowthelabelsareoffcentertowardtheupperright.ThisiswhatwouldhavebeenseeninthesimulatororonanactualiPhoneintheportraitorientation.Dragthembacktothecenter,andtheyshouldnowlookastheyareseeninthisconfigurationofthestoryboard’scanvas.IfdesigningforiPad,thentheotherconfigurationswouldneedtobechangedforthat.

NotePinningwithconstraintscouldactuallystreamlinethisprocess.Forexample,let’ssaythatyouwanttoplaceaPausebuttonattheupperrightcornerofyourGameSceneandyouknowthatnomattertheorientation,itwillalwaysbeatacertaindistance(inpercentagesorpixels)awayfromtherightandtopofadevice’sscreen.Wecanclick

onthepinbutton atthebottomofthecanvastocreatetheseconstraintsinthew/Anyh/Anyconfigurationandskipmanuallyadjustingtheicononeveryoneofthebaseconfigurations.

Xcodealreadygivesusascene,theLaunchScreen.xibfile,which,ifyouhavealreadyranyourcode,wasactuallywhatwasseenfirstbeforethefirstviewcontrollerinthestoryboard.

TohavejustyourMain.StoryboardfilebeatstartupyoucanselectthemainprojectfileatthetopleftcornerintheNavigationpaneandintheLaunchScreendropdownoftheAppsIconsandLaunchImagessection,selectMain.Storyboard.

Then,youcandeletetheLaunchScreen.xibfileifnolongerneeded.Itcanbeagoodfiletoseeworkingconstraints,andifsobeit,itcanbeyourinitialsplashscreenforyourgame.Moreonconstraintscanbefoundhereintheofficialdocumentation:https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithConstraintsinInterfaceBuidler.html

SeguesGameshavescenes,andallsceneshavetransitionsbetweenthem.Seguesaresimplytransitionsbetweenscenesinastoryboard.Seguescomeinvarioustypes:

Show:Thispushesthenextviewcontrollerontopofthecurrentone;italsoallowsforcallingbackifusingaUINavigationControllerinstance.ShowDetail:WhenusingUISplitViewController,aContainerviewcontrolleristypicallyusediniPadappstobrowsenews/emailapps,wheretheleftsideofthepageisaUITableViewControllerobjectandtheothersideofthesamepagearethedetailsofthattable/list.ThiscallsthedetailsfortheDetailViewcontrollerportionofthepagewhentriggeredbyagesturefromtheselecteditemontheUITableViewControllerside.Presentmodally:Thispresentsthenextviewcontrolleroverthecurrentbutinsuchawaythatitcanbecanceled,suchasafull-pagepopup.Popover:ThisislikePresentmodallybutwithmoreoptionsinsizingtocreateasmallerpop-upwindowthatcanbeclosedanddisposedof.Custom:ThisisaversionofaseguethatyoucancompletelycustomizewithOOPcode.

Thetypicalstoryboardstructurewhenbuildingsay,ane-mailapp,willmorethanlikelyneedtomakeuseofanavigationcontrollerandUITableViewcontrollerstostructurethedataandflowoftheapp.Now,wecanverywelldothesamethingforgameapps.GameOver,Menu,Rankings,andPausescreenscouldmakeuseoftheseviewcontrollers.Forourexample,we’llkeepitsimpleandunrestrictedtoletyou,thedeveloper,haveabetterstartingpointtobranchfrom.

NoteOurexamplehereisrathersimple,butinadditiontoprovidingcodeforthisproject,anevenmoredetailedstoryboardwillbeavailableusingvariousviewcontrollersandobjects.

Let’stakecareofthatwarningandlinkupthesescenesaswellasbegintoshowtheoverallstructureofatypicalgameusingstoryboards.

1. First,intheIntroScene,placeabuttonlabeledSTARTrightundertheIntroScenelabel.Placingabuttononastoryboardisdoneexactlythesameaswithalabel.SearchforbuttonorscrolldowntheobjectsintheUtilitiespanelandthendraganddropthebuttonontothescene.

2. NowcreatetwomorebuttonsontheGameSceneview;onebuttonlabeledPauseatthetop-rightcornerofthesceneandanothernamedQuitoppositethePausebuttonontheupper-leftcorner.

3. CreateanewViewControllerobjectonthescene,preferablyaboveorbelowtheGameSceneonthecanvas.

4. OnthenewPauseScene,createalabelPAUSEDthesamewaytheGameSceneandIntroScenelabelsweremade.

5. Then,addtwobuttons,QuitandResume,andplacethemrightunderthePAUSED

label.

Nowtocreatetheseguesvisuallyusingthestoryboard:

1. Control-ClicktheSTARTbuttonobjectontheIntroSceneandthenwhilestillpressingControl-Click,dragtheobjecttowardtheGameSceneonthecanvas.Youshouldseeabluelinefollowyourcursorasyoudragacross.(ifyouneedmorespace,zoomoutabitandalsotemporarilyclosetheNavigationandUtilitiespanelsusingthetollbarbuttons).

2. Dropthispointanywhereontheviewthatisn’tanotherobject;youshouldseetheentireviewglowbluewhiledoingso.

3. ApopupaskingforthetypeofSeguewillcomeup.SelectShow.4. That’sit!You’vecreatedasegue,andyou’vealsotoldthestoryboardthatwhenthe

userclicksthatbutton,it’llopentheGameScene—ViewController.5. Beforeyoumoveontocreatingmoresegues,clickonthedoor-likesymbolonthe

canvasthatrepresentsthesegue.OnthetoprightintheUtilitiespanel’sAssetsinspector,youshouldseeanemptyIdentifierfield.Wecanleavethesegueemptyifwe’dlike,butnamingitcouldbeofuseifwewishtocallthesegueincodewiththefollowingline:

performSegueWithIdentifier("segueIDNameeWithIdentifi)

6. Nowrepeatsteps1through3tocreatethefollowingsegues:

1. LinkGameScene’sQuitbuttonbacktoIntroScene.2. LinkGameScene’sPausebuttontothePAUSEDScene.3. LinkPAUSEDScene’sResumebuttontotheGameScene.4. LinkPAUSEDScene’sQuitbuttontotheIntroScene.

Thewarningshouldnowbegoneasallofthescenesareconnectedwithsegues,andafterpossiblysomeAutoLayoutfixes,runningtheappnowhasagame-likescenestructurethattransitionthewaywe’dnormallyseeinothergames.Wecangofromhereandmakeotherscenes,suchasaGameOverscene,aStageWinscene,orothers.Evenifthismightnotbethewayyou’dlikeyourfinalgame’stransitionstoendup(particularlysincethedefaulttransitionoftheShowseguedoesaquickvertical),thiscanbeaveryquickwayofprototypingyourgamerightoffthebat.Customseguesandseguestriggeredwithcodearehowwecandivedeeperintofinetuningwhenthedefaultsettingmightnotmatchwithourvisionofourgames.

Here’smoredocumentationonmakingcustomsegueclassesifyoureallywanttodivedeeperintosegues:

https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIStoryboardSegue_Class/index.html#//apple_ref/doc/uid/TP40010911-CH1-SW11

SimilarlytohowweControl-Draggedthebutton’slinkagetothenextviewcontrollerscene,wecandothesametoourViewController.swiftfile.

Here’sasummeryonhowtodothatforthefirstviewcontroller:

1. Removetheprevioussegue.Onewaytodosoistoright-clickthebuttonandtoclickonxintheTriggeredSeguessection.

2. ClickontheIntroScene’sviewinthehierarchytogetitinfocus.3. Control-DragabluelinefromtheyellowicononthetopleftoftheIntroScene’s

viewcontrollertotheGameScene’sviewcontrollerandselecttheShowtypeofsegue.

4. ClickonthesegueiconinthecanvasandnowgivetheidentifierofthisseguethenamestartGame.

5. OpentheAssistantEditor(thetwointerlockingcirclesbuttononthetop-rightportionoftheXcodetoolbar);closesomepanestomakeanyneededroom.

6. Control-DragtheStartbuttonintotheViewControllerclass;preferablyatthebottomofthecodebutstillwithintheclass’sclosingbrackets.

7. Thiswillprompttheoutlet/actionpopup.SelecttheActionoptionintheConnectiondropdownandnameitstartButton.

8. ThiswillcreatetheIBActionfunction:@IBActionfuncstartButton(sender:AnyObject){}.

9. Typethefollowingcodebetweenthebraces:self.performSegueWithIdentifier("startGame",sender:nil)

10. Thistellstheviewcontrollertoperformtheseguewhenthisbuttonispromptedusingcode.

StoryboardsversuscodingThere’snosinglecorrectwaytodothedesignstructureofyourappaslongastheMVCmodelisfollowed.Actually,thereareprogrammersouttherewhoarecompletelyfinewithjustusingtheinitialviewcontrollerandneveruseasingleNiborstoryboardfile;thuspurelybuildingtheirgamecontrolledbythelogicoftheircodeandcallstothevariousViewobjectsprogrammatically.IniOSdevelopment,there’ssomewhatofadesignsplitbetweenthreemainbranches,hardcoding,Nibs,andstoryboards.Theoriginalmethodologywascoding;NibscameinlatertofirstallowdirectvisualeditinginXcodeandthenthatevolvedintoStoryboards,furtherbuiltuponwiththeadditionofAutoLayout.

Thereasonthere’sasplitbetweensomedevelopersandstudiosonthevisualstructuremethodologyofaniOSappisbecauseonedrawbacktoNibsandstoryboardsaretheirlackofportability.Ifyouwantedtoportyourgametoanotherplatform,suchasAndroid,atdescentpace,heavyuseofstoryboardswouldmakeitarathertoughtoporttheapptotheotherplatformsincethesedesignfeaturesarespecifictotheiOSplatform.Thisiswhenpurecodewouldbemorebeneficial.Storyboardsthoughgiveusdevelopersaneditable,visualrepresentationoftheapp/gamewewishtomakeandtheabilitytodolittletonochangesasthefamilyofdeviceschange.

Evenothergamedevelopmentengines,suchasUnity,UnrealEngine,andmore,workonamoresandboxing,visualrepresentationmethodologywithyourcodeactingasmoreofacomponenttothevisualasopposedtothefullstructureofeverythingthatappearsbeforeyourgamecharactersevengetrenderedtothescreen.

SummaryInthischapter,wewentoveranumberofappprojectstructuringandintroductiontopics.First,wewentovertheModel-View-Controllerparadigmfollowedbyallapps,gameornot,andtheoveralllifecycleofaniOSappthatfollowsthisstructuring.Next,wereviewedtheentrypoint(s)andpathwayofyourcodeinatypicalappaswellastheupper-levelobjectsusedalongtheway,suchastheApplicationsystemobject,theAppDelegateclass,andviewcontroller.Lastbutnotleast,wediscussedthemaintopicofthechapter—storyboards,segues,andinstructionsonhowtocreateasimplegameflowstructure.Fromhere,wecanseehowrelativelyeasyandquickitcanbetostructurevariousscenesforyourgameandtransitionbetweenthemwithsegues.Again,notethatalthoughstoryboardsarerecommended,theycansimplystartasageneralguidetowardthefinalproduct,whichgivesyou,thedeveloper,theabilitytovisualizeyourgameevenifintheendpreferringamorecode-heavydesignchoice.

Inthenexttwochapters,wearegoingtofinallygetintoreallycodinganddesigningactualplayablegames.Wewillstartoffwith2Dgames,andsinceiOS7,ApplehasgiveniOSdevelopersit’sownframeworktohandle2Dspritesandgamephysics.ThisframeworkisamplynamedSpritekit.

Chapter3.SpriteKitand2DGameDesignNowthatweunderstandthebasicsofcodinginSwift,thegenericflowandclassstructureofaniOSapp,aswellastheoptionalstructuringofappswithstoryboardsandsegues,wecanmoveontotransformingourappsintoplayablegames.

Forthischapter,wewillbeginwiththe2DgamedesignandgamedevelopmentframeworkcreatedexclusivelybyAppleforiOSgamedevelopersknownasSpriteKit.SpriteKitfirstbecameavailablewithiOS7tohelpsimplifythegamedevelopmentprocessforthefamilyofiOSdevices.Theframeworkrunsatypicalrenderinglooptodrawandupdate2Dobjects/spritestoyourgame’sscene.There’smuchgoingonbehindthescenestorunthisloopanddrawyourgamesprites.Thankfully,Applebuiltthefirstpartygamedevelopmentframeworkstodomuchoftheheavyliftingforus.Thisway,wecanfocusmoreonmakingthegameitselfwithoutworryingtoomuchabouthowthatgamewillconnectandrunwiththehardware,somethingdevelopersinthepasthadtocontendwith.

EveryupdateofiOSandXcodecontinuestoaddmoretoolsandframeworkstoimprovetheeaseofgamedesign,includingthecompanionframeworkintroducedfirstatWWDC15foriOS9knownasGameplayKit.GameplayKitcanallowustoseparate,copy,andmodularizethegamelogicandevencopyforuseinfuturegameprojects,beitSpriteKitorthe3Dframeworkofournextchapter,SceneKit.WewillgooverGameplayKitinlaterchaptersaswell.Attheendofthischapter,wewilllookatacompletegameexamplethatisforasimplegameinitsgameplaybutsomewhatcomplexinitslogic.

AbriefhistoryofiOSgamedevelopmentenginesSpriteKitandthe3Dgameframework,SceneKit,werenotthefirstmethodsusedfordevelopinggamesiniOS.We’llquicklyseewhyitbecameawelcomedadditiontothedevelopertoolset.Initially,we,thegamedevelopers,hadtopracticallytalkdirectlywiththeGPUusingtheOpenGLAPItoputboth2Dand3Dgraphics/verticesontothescreen.Ontheupperlevel,therealwayswasFoundationandCocoaTouchtointeractwithusergesturestomanipulateUIKitobjects,butdealingwithgamedevelopmentessentials,suchasSpriteSheets,mipmaps,normalmaps,partialemitters,boundingboxes,andculling,involvedsomeleveloflower-levelstructuring.ApplemadethosecallstovariousgraphicsbuffersandVBOsslightlyeasierwhentheycreatedtheirGLKitframeworkin2011.Thankfully,variousthird-partyframeworks,suchasCocos2D,Box2D,Sparrow,GameMaker,Unity,UnrealEngine,andothersmadethisprocesslessengineering-intensiveinanefforttokeepthedesignaspectofgamedesignthefocus.GameMaker,Unity,andUnrealEnginearemoresandboxing-/drag-and-drop-styledenginesakintothementalitybehindstoryboardsandsegues,whileenginessuchasCocos2DandSparrowaremorecode-heavy/boilerplateOOPstructuresthatshortcuttheinitialcodingbuildup.EnginessuchasUnityandUnrealEnginearegreatinthattheyofferamorehands-onsandboxing-typeenvironmentwithvariousfeaturesthatsimplifytheMVCmodel.Somedrawbackstosuchenginesarethattheyaresometimesclosedsource,usuallycostmoneytoutilizetotheirfullestandaren’tdevice-specific(Unityparticularlyfallsintothiscategory).Workingwiththesevisualenginescouldsometimesleadtooptimizationsbeingrequiredinplatform-specificIDEssuchasXcode,duetoasometimesone-size-fits-allmethodology.Apple’sSpriteKitandthe3DAPI,SceneKitwhichwe’llseelater,giveusafirst-partyplatform-specificmiddlegroundthatgrantsthedeveloperbothupper-levelAPIediting,butevenlower-levelgraphicAPI(OpenGL/Metal)customizations.

NoteThenegativestosandbox/drag-and-drop-styledengineshavedecreasedovertime.EnginesusedbyAAAstudios,suchasUnrealEngine,Unity,Havok,andothershavelessenedtheirupper-levelambiguitybetweentheAPIandtargeteddevices’lower-levelcode.AgoodexampleofthiswouldbeUnity’sIL2CPP,whichconvertstheupper-levelAPIcallsdirectlytofastdevice-specificC++code.ThisincludescodeandgraphicspipelineoptimizationsthatmakeuseofApple’sslimMetalAPI.Thishomogenizationofupperlevelapplicationswithtraditionalboilerplatecodenowallowsdevelopersfromallskilllevelstomakeamazinggames.ThatiswhyfromiOS8,iOS9,andonwards,theApplegamedevelopmentframeworksadoptedamorevisualdesignmethodology.Xcode7introducedgamestatemachines,components,andtheabilitytoedit/copyandreuseplayeractionsandanimationsthroughoutyourprojects.ThisallowsdeveloperstoworkspecificallyiniOS/Xcodewhileutilizingthevisualdesignbenefitsofthedevice-independentgameengines.

Forthischapter,wewilllearnhowtomakeatilepuzzlegamenamedSwiftSweeperusingtheSpriteKitframeworkandwithamoretraditionalboilerplatecodemethod.Thismeansthatwewillmakeourfirstdemogameinacode-heavy/model-centricfashion.NotonlywillthisgiveusalookintotheinnerworkingsofSpriteKit’scodebutitwillalsoletusutilizemorefromtheSwiftprogramminglanguagefromChapter1,TheSwiftProgrammingLanguage.

WewillconcludethischapterbybrieflymentioningApple’slatestSpriteKitdemogame,DemoBots,whichutilizesmoreofthevisualtools/frameworksfromXcode7andlater.Seeingthemorecode-intensivemethodfirstthoughwilllaterletusappreciatethetimesavedwiththesenewertools.

Applehasgoneoutoftheirwaytomimicthevisualdesignmethodologytogamedesignseeninotherenginessincegamedesignisasmuchaboutcode/logicasitisaboutartanddesign.

ThegameloopThegameloopisagamedeveloper’sroadmap.Thenamesdifferdependingontheframeworkandplatform,butthesamerulesapply.Thegameloopcomprisesofallthemethods,physicsupdates,anddrawcallsthatoccurduringasingleframeofyourgameandtheirorderofexecution.Thegoldenruletogamedevelopmentistotrytokeepthisloopalwaysspinninginfulliterationsatnoslowerthan16.6milliseconds,or60framespersecond.

Thereareaspectsofthegameloopthatdon’thavetobecontrolledbythegamedeveloperasmuchastheyusedtobeinthepast,thoughwedohavetheoptiontoworkdowntotheveryGPUcallsusingOpenGL,orevenbetter,Apple’sMetalAPI.Wewilldiscussmoreonthesetopicslateron.

HereiswhattheSpriteKitgamelooplookslike:

TheprecedingisanillustrationgiventousdirectlyfromtheAppleDevelopersite.Weseeanumberoffunctionsthatarecalledduringasingleframe.Thefirstfunctioniteratedthroughisupdate().Theupdate()functioniswhereweaddmostofourowngame-specificupdatesandvariouschecksongameobjects(suchaspositionsandcharacterstatuses).

Theloopstructuregivesustheoptiontodoupdatesafterweknowacertainsetoftasksintheframehavehappened,that’swheredidEvaluateActions(),didSimulatePhysics(),

didApplyConstraints(),anddidFinishUpdate()functionscomeinhandy.

NoteAnyonecomingfromUnitymightbefamiliarwithitsgeneralgameloopfunctions,suchasAwake(),Start(),FixedUpdate(),update(),andLateUpdate().TheSpriteKitgameloopallowssomesimilarcode/renderflow,butaswe’llsee,therearesomeslightdifferences.

Formoreonthegameloopanditsfunctions,seethefollowinglinkfromtheAppledocumentationathttps://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Actions/Actions.html

Utilizingtheothergameloopmethodscouldmakesurecertaincallsinyourgamedon’tgooutoforderandcanevenhelpwiththeimportanttaskofmakingthemostoutofeachframeinafast,efficientmanner.

Forinstance,inthepublicgamePikiPop,mentionedpreviously,here’showthegameusesthegameloopinitsmainGameScene.swiftcode:

//Update()Example

//FrommainGameScene.swift

overridefuncupdate(currentTime:CFTimeInterval){

//Updateplayer

if(player?.isPlayable==true){

player!.update(currentTime)

}

}

TheprecedingcodefirstcheckswhethertheplayerisplayablewiththeisPlayableBoolean.Thisstatuscanmeananumberofthings,likeiftheplayerisaliveornot,isspawning,andsoon.Thegameloop’supdate()function,whichisbeingoverriddenfromitsparentupdate()functionoftheSKSceneobject,takesaparameterofthetimeutilitytypeCFTimeInterval.CFTimeIntervalisaspecialCoreFoundationdoubletypethatmeasurestimeinsecondsandthusupdatestheplayerobject(ifnotnull)duringeachinterval.

AsabriefsummaryofPikiPop,it’saprocedural2Dside-scrollinggamesomewhatsimilartothegameFlappyBird.UnlikeFlappyBird,Pikiisabletotraversethegameinalldirectionsbasedonplayertapsandswipes.Pikicouldgettrappedbetweenthestageobjectsandtheedgeofthestage.

TheprecedingimageisPikigettinginjuredifpushedintotheleft-handsideofthescreen.

Edgesinthatgame’sstagesuseSpriteKit’sownspecialobjectsnamedSKConstraints.Moreontheselater,butinshort,theydictatetherangeandorientationSpriteKitspritescantake.SpritesinSpriteKit(bothdeveloper-definedobjects,suchasPikiPop’sPlayerobjectandthedefaultSKSpriteNode)areallderivedfromSKNodeobjectsthatworkwithSKConstraintsandotherphysics-basedframeworkfunctionality.

WecouldcheckwhetherPikiisbeingpushedagainstthecornerintheupdate()partofthegameloop,butsinceconstraintsarepartoftheframework’sphysicsarchitecture,it’sbesttodothischeckduringthedidSimulatePhysics()portionoftherenderloopofSKSceneasseenhere:

overridefuncdidSimulatePhysics(){

//runcheckonPlayer

letblock:(SKNode!,UnsafeMutablePointer<ObjCBool>)->

Void={node,stopin

/*checksifthenodeistheplayerandismoved/crushedtotheleft

byaphysicsobject.Thisisdonebycomparingthenode'spositiontoa

positionthatis,inthiscase,lessthan26%offtheleftsideofthe

screen;calculatedbymultiplyingthescreen'swidthby0.26*/

ifletplayerNode=nodeas?Player{

if(playerNode.position.x<self.frame.size.width*0.26&&

playerNode.isPlayable){

playerNode.playerHitEdge()

}

}

}

...morecode

Thefirstpartofthiscode,letblock:(SKNode!,UnsafeMutablePointer<ObjCBool>)->Void={node,stopin,isdoneinwhat’sknownasablockoraclosuresyntax,whichSwiftletsusdoratherdynamically.Don’tmindthedetailsofthiskindofcodeforthemoment;justnotethatwechecktheplayer’spositioninxversustheedgeofthewindow’sframeinthisportionofthegameloop.

NoteHere’smoreinformationonwritingblocks/closuresinSwift:

https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html

Tilegame–SwiftSweeperTimetostoptalkingaboutSpriteKitandgetrightintoit!Asstatedatthebeginningofthischapter,wewillfirstshowyouhowtomakeasimple-lookingtilegameinSpriteKitusingtheslightlymoredifficultboilerplate/code-drive-styleddesign.Don’tworry,thisisnotgoingtoinvolvedirectcallstotheGPUwithC++andhandlingextremelytinymemoryrequirementslikeveterangamedevelopersdidduringtheearlyconsoledays.However,wewillbeusinglotsofcode-heavycallswithSpriteKitobjects,functions,andclasses.Granted,gettingdownintothecodedirectlyiscontinuallybecominglessofthedeveloper’sresponsibilityasApplecontinuestomakemoredesign-centricfunctionalitiesinXcode.

Knowingthecodestructurecangiveyouanedgeoverdeveloperscominginonamoretop-downmethodologyandcodingwillalwaysbebehindcustomgamelogic.

WhatisSwiftSweeper?SwiftSweeperisacloneoftheclassictilepuzzlegame,MineSweeper,writtenentirelyinSwift.SwiftSweepermakesuseofSwift’sabilitytouseUnicodeemoticonssothatwedon’thavetousemanyimageassetsandshouldgiveusagreatstartingpointtomakingourowntile/puzzlergamewithdifficultylevels.

Wewillbuildupmuchofthegamefromscratch,butthefullsourcecodecanbefoundathttps://github.com/princetrunks/SwiftSweeper.

NoteAsatthetimewritingofthisbook,thiswasbuiltinXcode7Beta(7A120f)fortheinitialiOS9releaseandoptimizedforiPhone.

Thegoalofthegameistotapeverytileonthegameboardwithouthittingmineshiddenthroughouttheboard.Youdogetsomehelpthough.Everytilethatisn’taminewilltelltheplayerhowmanytilesarounditaremines.Iftheplayerknowsthatatilewithoutadoubtisamineviatheprocessofelimination,theycanplantaflagonthattiletomakesurethattheydon’ttapthatspace.Tapallofthetilesthataren’taminetowinthegame!SwiftSweeperevensavesthetimeittookyoutowinforeachdifficultylevelyouchosetogivethegameabitofreplayvalue.

CreatingourSpriteKitgameNowthatweknowthegoalofourgame,here’showwegoaboutbuildingitinSpriteKit:

1. First,openXcodeandcreateanewproject.2. NowselecttheGametemplateandclickonNext.

3. Next,fillintheproductname.WewillnamethisprojectSwiftSweeperExampleandmakesurethatthelanguageisSwiftwithSpriteKitselectedasthegametechnologyaswellasthedevicessettoiPhone.

4. Then,clickonNext,andwenowhaveabrandnewSpriteKitgameprojectwithanumberoffilesalreadywrittenupforustogetusstarted.

5. Nowclickontheproject’smainfileinthenavigationpaneanddeselectallbutthePortraitselectionintheDeviceOrientationfield.

6. Sincewearegoingtoworkmostlywithcode,wecanalsoeitherignoreordeletetheGameScene.sksfilefornow.ThesefilesareXcode’soptionforyoutovisuallydesignyourgamescene.WewillknowmoreonthesefileslaterwhenweworkwithourmorevisuallydesignedSpriteKitgameexample.

7. BuildandruntheapptoseeApple’sdefaultSpriteKitproject,whichhasHelloWorldwritteninChalkdusterfontandarotatingspaceshipappearswhereyouclickortaponthescreen.

AnoverviewoftheSpriteKitstructureandobjectsBeforeweaddourcode,let’susethistemplatetogetanideaonhowSpriteKit’sbasicobjects,functions,andflowwork.

Aswestatedinthepreviouschapter,AppDelegate.swiftisthemainentrypoint.ThecodethenmovestoGameViewController.swift,whichisachildoftheUIViewControllerclassthatimportstheSpriteKitframework.ThefollowingcodeiswrittenintheviewDidLoad()functionofGameViewController:

overridefuncviewDidLoad(){

super.viewDidLoad()

ifletscene=GameScene(fileNamed:"GameScene"){

//Configuretheview.

letskView=self.viewas!SKView

skView.showsFPS=true

skView.showsNodeCount=true

/*SpriteKitappliesadditionaloptimizationstoimprove

renderingperformance*/

skView.ignoresSiblingOrder=true

/*Setthescalemodetoscaletofitthewindow*/

scene.scaleMode=.AspectFill

skView.presentScene(scene)

}

}

TipDownloadingtheexamplecode

Youcandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.

Usingthekeywordoverride,thisversionofviewDidLoad()cannoweitheraddtoorwelloverridetheparentclass’sfunctionality.super.viewDidLoad()callstheparentclass’soriginalfunctionalityandthenitworksitsowncustomfunctionality.ThisishowSwifthandlestheOOPconceptofinheritance.

Next,weseehowagamesceneisfirstcreatedwithGameViewController.AmajoraspectofSpriteKitisthatitworksinscenesthataremembersoftheSKSceneclass,whicharethemselveschildrenoftheSKNodeclass.TheSKNodeclassesarethemainbuildingblocksofnearlyeveryobjectinSpriteKit.Beitsprites,lights,videos,effects,physicsfields,audiofiles(SKAudioNodes),cameras(SKCameraNodes),orlabels/UIobjects,theyareSKNodeclasses.Theseobjectsallholdimportantinformation,mostimportantlycoordinateinformationofobject’snodefamily.Forgames,thisallowsthedevelopertocreatecustomclasses,suchasEnemies,GameLights,Tiles,andsoon,thatallhavescreenandotherinformationonbothparentandchildnodes.Forexample,wecanhiteveryenemyonthescreenwithanattackbytheplayerbycallinganinheritedfunctioninaparentEnemyclass.Wedon’tneedtocheckforeachindividualtypeofenemybutinsteadenumeratethrough

theparentnodesinthevariousgameloopfunctionsofSKScene:

enumerateChildNodesWithName("player",usingBlock:block)

Doyouremembertheblock/closurecallinPikiPop?ToactuallyuseitinthedidSimulatePhysics()functionofSKScene,wecalltheenumerateChildNodesWithNamefunctionofSKNodetotargetonlythosenodesinthesceneandhavethatblockofcoderunforeachmemberinthescenewiththatname.

playerNode.name="player"

ThenameissimplyastringthatcanbesetusingtheSKNode.nameproperty.Haveeverycustomnodeinitiatewithagivenname(orchangeduringgameplay),andyouhaveawholegroupofobjectsyoucansingleoutinthescene.

YoucanfindmoreonSKNodeinApple’sofficialdocumentationathttps://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKNode_Ref/.

Scenetransitionsandthechoiceofcode,storyboards,and/orSKSfilesTheGameScene.swiftclassinourprojectinheritsfromSKScene,anditistherethatthegameloop/renderingfunctionswementionedearlieroccur.SpriteKitrunsonscenes,andscenescanbetransitionedandseguedtoandfromit.

Inthepreviouschapter,weshowedhowtostructureagameusingstoryboardsandsegues.SKScenemakesitwhereyoudon’tevenhavetousestoryboardsbutjuststraightcodetotransition.Wecanusestoryboards,andwecanalsovisuallydesigneachindividualsceneusing.sksfilesoracombinationofallthreemethods.Withcode,SKScenecantransitionwiththeSKTransitionobjectsandfunctions.Actually,aswe’llseewithSwiftSweeper,wecanjustusecodetomanuallyrefreshassetsinthescenetodotransitions.ThismethodisratheroldfashionedandnotaselegantasSKTransitionstoryboardsandSKSfiles,solet’stakeaquicklookathowtotransitionscenesincodewithSKTransition,storyboards,andbrieflyintoSKSfilesviacode.Later,andinthenextchapter,wewillfocusmuchmoreonthevisualSKSfilessinceeveryupdatetoiOSandXcodecontinuestoputthefocusonthesevisualtoolstoshortenthecodingtimeandworkflow.

AnSKTransitionexampleThefollowingcodechangesthegame’sscene:

overridefunctouchesBegan(touches:Set<UITouch>,withEventevent:

UIEvent?){

super.touchesBegan(touches,withEvent:event)

ifletlocation=touches.first?.locationInNode(self){

lettouchedNode=self.nodeAtPoint(location)

iftouchedNode.name=="SceneChangeButton"{

lettransition=

SKTransition.revealWithDirection(SKTransitionDirection.Up,duration:1.0)

letscene=AnotherGameScene(size:self.scene!.size)

scene.scaleMode=SKSceneScaleMode.AspectFill

self.scene!.view!.presentScene(scene,transition:transition)

}

}

}

TheSKTransitionclassesarereallyjusttypesofsegues.Asintheprecedingcode,thetransitionisadirectionalswitchtothenextscenewiththeSKTransitionDirection.Upenumeratortype.AswesawinGameViewController,thenewsceneiscreatedwiththesimilarfunctionsthatcontrolthescene’sviewsizeandaspectratioandthenpresentsthatscenetotheunwrappedviewwithself.scene!.view!.presentScene(scene,transition:transition).

Alsonotethatthistakesplaceinthesamefunctionasweseeinourcurrentproject’sGameScene.swiftclass,overridefunctouchesBegan(touches:Set<UITouch>,withEventevent:UIEvent?){}.ThisisthefunctionthathandlestouchgesturesfromtheplayerandcheckswhetherthenameofthenodetouchedmatchestheSceneChangeButtonstring.

MoreonSKTransitionandotherneattransitioneffectsyoucangiveyourgamescanbefoundhereintheofficialdocumentation:

https://developer.apple.com/library/prerelease/ios/documentation/SpriteKit/Reference/SKTransition_Ref/

NoteAsofSwift2.0/iOS9,thistouchdelegatefunctiontakesinaparameterthatisasetofUITouchesviatouches:Set<UITouch>andanoptionalUIEvent.ThisisachangefrompastSwiftiterationsandcouldchangeinfutureupdates.

ASKScene/storyboardexampleHere’sthecodeforaSKScene/storyboardexample:

@IBActionfuncbuttonPressed(button:UIButton)

{

//Removebuttonfromtheview

button.removeFromSuperview()

ifletscene=GameScene.unarchiveFromFile("GameScene")as?GameScene{

//Configuretheview.

letskView=self.viewasSKView

skView.showsFPS=false

skView.showsNodeCount=false

//usedforoptimizationofSKView

skView.ignoresSiblingOrder=true

scene.scaleMode=.AspectFill

skView.presentScene(scene)

}

}

Aswesawinthepreviouschapter,usingthevisualhelpofstoryboardfilescangiveusgreatvisualroadmapstoourapps,bothgameandnon-game.Theprecedingcodeusesalinktoan@IBActionlinkageonastoryboardfiletosetanewscene.

Storyboardsingamescanbegreatfortheprototypingphasewhenweknowjustthegeneralstructureofourgame,andcanbeperfectforthegame’smenunavigationsorevenforallindividualgamescenes*.

Thebuttonitselfisremovedbeforethetransitionviathebutton.removeFromSuperview()calltopreventamemoryleakcausedbythenewscenebeingdrawnoverwhatcouldhavebeenanunseenmenubutton—unseentotheplayerbutnottothegame’smemorystack.

Tip*It’susuallythebestpracticetoonlyusestoryboardsforoverallnavigationmenusandnotforeachindividuallevel/scene.TheSKSceneandSKNodefunctionalitycanletusreusesimilarscenestructuresandsavemuchofthecodingforsimilarlystructuredlevels.Gameswithmanylevelscouldturnourstoryboardsintoawebofconfusingstructuresandthusundotheirinitialpurpose.Sceneswiththeactualgameplaycouldjustbeintheirownsingleviewcontrollerinthestoryboard,andwe’dhavethepause,share,andothermenusbecontrolledbystoryboardsegues.

SKScenetransitionswithSKSfilesA.sksfileisaspecialSpriteKitscenefilethatcanallowthecreationofasceneaswellastheplacementoftheplayer,particles,enemies,andlevelassetsinavisual,draganddropway.Transitioningtoavisuallydesigned.sksfileinSwiftisthesameasourinitialSKTransitionexample.

overridefunctouchesBegan(touches:Set<NSObject>,withEventevent:

UIEvent){

/*Calledwhenatouchbegins*/

letintroNode=childNodeWithName("introNode")

if(introNode!=nil){

letfadeAway=SKAction.fadeOutWithDuration(1.0)

introNode?.runAction(fadeAway,completion:{

letdoors=SKTransition.doorwayWithDuration(1.0)

letgameScene=GameScene(fileNamed:"GameScene")

self.view?.presentScene(gameScene,transition:doors)

})

}

}

ThecreationofthegameSceneconstantwiththeSKSceneinitializerfileNamedandthenpresentingthatscenetotheviewworksthesamewitheitherthe.swiftfileor.sksfile.Thisgivesustheflexibilitytobothcodeand/orvisuallydesignourgamescenes.InthecaseofSwiftSweeper,wewilldothemorecode-centricmethodology,butfeelfreetobuildonthisgameonyourownifyouwishwitheithermorecode,Storyboards,and/orwithvisuallydesignedSpriteKitScene(.sks)files.

Assets,sprites,andiconsAsofXcode7,gameassetsareplacedintheAssets.xcassetsfolder.PreviousversionsofXcodemighthavehadanImages.xcassetsfolderforthegame’siconsandsprites,butthishaschangedandmightcontinuetochangewitheachnewiOSrelease.

AnimagefromApple’sWWDC15conference

StartingwithiOS9andXcode7,theassetsfolderwasgivenevenmoreflexibilitywiththeabilitytohandlethevariousappiconsizes,thelaunchimage,setsofimages,andspriteatlases.ThisalsoallowsustodevelopwithvariousmemorysavingcapabilitiesintroducediniOS9likeappslicing/appthinningandon-demandresources.Theappslicing/thinningfeaturemakessurethatonlytheassetsrelevanttothedevicearedownloaded,whichsavesspaceontheplayer’siPhoneoriPad.On-demandresourcesletustagassetsthatareavailableinthedevice’smemoryonlyduringcertainpartsofourgames.Thisway,wecancreateevenlargergamesforourplayerstoexperiencewithouttaxingthesometimes-limitedspaceintheApplefamilyofdevices.

Youcanfindmoreonappslicing/thinningathttps://developer.apple.com/library/prerelease/ios/documentation/IDEs/Conceptual/AppDistributionGuide/AppThinning/AppThinning.html

Whensettingupyourgameforon-demandservices,somethingthatcouldbegreattoknowintheinitialplanningofyourgames,canbefoundintheofficialdocumentationathttps://developer.apple.com/library/prerelease/ios/documentation/FileManagement/Conceptual/On_Demand_Resources_Guide/

SpriteatlasesandanimatingspritesSwiftSweeperactuallydoesn’tuseanimatingsprites;aswe’llsee,itsimplyusesUnicodeemoticoncharacterstoanimatethescreen.Yet,wecan’tdiscussSpriteKitand2Dgame

developmentwithoutmentioningsprites,animatingandoptimizingthemwithtextureatlases/spritesheets,couldwe?Aspriteatlasisacollectionofimagesbundledintoasingleimage,alsoknownasaspritesheetortextureatlas.Whiledeveloping2Dgames,itishighlyrecommendedtousetextureatlasesasopposedtovariousimagesetsbecausetotherenderer,textureatlaseswillequatetofarfewerdrawcallsandthuscanmakesurethatyourgamerunsatthatneeded60fps.TheCollectables.atlasfolderinAssets.xcassetscouldholdallofyourgame’scollectablesandwiththeSKTextureAtlasclass,efficientlydrawthosecollectablestothescreen.Whenstoringtheimagestosaytheplayer’sidle,walking,andjumpinganimations,weusetextureatlasestostorethem.

Creatingatextureatlasisverysimpleandispresentedasfollows:

1. SimplyclickonyourAssests.xcassetsfolderandright-clickonanemptypartofthefolder’shierarchy.

2. ClickonNewSpriteAtlasandjustlikethis,wehaveafolderwherewecanstorevariousspritesforourgame.

3. Makesuretonamethefolderbasedonhowyouwishtocategorizethegroupsofsprites.You’dneedthisnamewhenreferencingthemincode.

Tocreateareferencetothisatlasincodeandanimatethesprites,weuseSKTextureAtlasasfollows:

letPlayerAtlas=SKTextureAtlas(named:"Player.atlas")

lettextures=map(1…4){numberin

PlayerAtlas.textureNamed("player_sprite_normal_\(number)")

}

letanim=SKAction.animateWithTextures(textures,timePerFrame:

self.animationRefreshRate_)

letidleAnimation=SKAction.repeatActionForever(anim)

self.runAction(idleAnimation)

First,thiscodecreatesanSKTextureAtlasreferencetotheplayer’sspriteatlasusingtheinitializerSKTextureAtlas(named:"Player.atlas").Then,wecreateanarrayoftexturesusingoneofSwift’sordersblockmap(NSRange){…}.Thisisaclosureblockthatiteratesthroughthetexturesinthespriteatlasbasedontherangespecifiedinthemapcall.Thenumberobjectisasimpleindexobjectwecanusetorepresenttheindexofthemapping.

Thisisdonebecauseourplayerhasthesespritenamesforthenormal/idleanimation:

"player_sprite_normal_1","player_sprite_normal_2",

"player_sprite_normal_3","player_sprite_normal_4"

Sinceweknowthatthespriteanimationsarenamedwithanindexednamingstructure,it’sbettertouseSwift’sfunctionalprogrammingtools,suchasmap(),heretosimplifythecode.2DSpriteswithmanyframe-by-frameanimations(gamessuchasMetalSlug)couldbeiteratedthroughinsuchafashion.

SKTextureAtlasalsohasaclassfunctionnamedpreloadTextureAtlaseswecanusetopreloadanarrayoftextureatlases:

SKTextureAtlas.preloadTextureAtlases([PIKIATLAS,BGATLAS,COLLECTABLESATLAS,H

UDATLAS,OBSTACLESATLAS])

{

//performothertaskswhileloadingTextureAtlases

}

Thisisgreattomakesurethatastage’sspritesareloadedbeforeenteringthestage.

CreatingourgamelogicForthesakeofsimplicity,MineSweeperwon’thavemanydifferentassetsoranyspritetextures.ItinsteadusesSwift’sUnicodeemoticoncharactercapabilitiesandUIViewcallstodesignthegame’sgraphicsinaratherold-fashioned,veryMineSweeper-likeway.

Notonlydowedothistogiveusasomewhatsimplisticstartingpoint,buttoshowhowSwiftcodeandSpriteKitclassescanletuscreatetheentiregame’slogicandflowwithouttheinitialneedofspriteassets.Thisway,ifdevelopingasateamorbyyourself,thegamecanbemadebeforedoingthesometimesgruelingprocessofmakingwonderfulvisualassets.Thinkingwithcodeandstructurefirstcanensurethatyouhaveaworkingprototypethatyoucanpolishlaterwithsprites,music,andatmosphere.

We’vesofarleftSwiftSweeperwaitingasjustashelloftheSpriteKitgametemplate.It’sabouttimewegettothegame’smodel:

1. First,let’saddourimageassets.Formoreinformation,visithttps://mega.co.nz/#!XhEgCRgJ!4QqKMl1l1P4opWU7OH2wEN_noVQ86z5mxEyLuyUrcQo

ThisisalinktotheAssets.xcassetsfolderofSwiftSweeper.Wecanaddtheseindividually,butthesimplestwayistojustreplaceyourproject’sAssets.xcassetsfolderdirectlyinyourcomputerwhereyourproject’sfolderislocated.YoucanhaveXcodeopenwhileyoudothis,it’llautomaticallyupdatefromtheoriginaltemplatefiles.

2. Next,let’saddthesoundfilesfromthefollowingURL:

https://mega.co.nz/#!T5dUnJZb!NUT837QQnKeQbTpI8Jd8ISJMx7TnXvucZSY7Frw5gcY

3. Addthesoundsbydoingthefollowing:

1. Right-clickontheSwiftSweeperExamplefolderthatholdstheSwiftfilesandthengotoNew|Groupfromthemenu.

2. NamethisfolderSoundsanddragittothebottomofthefileswithinthesameSwiftSweeperExamplefolder.

3. Right-clicktheSoundsfolderandselectAddFilesTo"SwiftSweeperExample".

4. AddthesoundsfromtheSwiftSweeperSoundsfolder,andtheyshouldnowbeinyourproject.

Alloftheassetsshouldbenowintheproject,sonowwecanbuildourgame.Let’sfirststartwiththeactualtiles.

NowcreateanewSwiftfile,nameitTile,andpastethefollowingcodeintothefile:

classTile{

//Properties

//(1)

letrow:Int

letcolumn:Int

//(2)

varisTileDown=false

varisFlagged=false

varisAMine=false

//(3)

//Minescounter

varnearbyMines:Int=0

//(4)

init(row:Int,col:Int){

self.row=row

self.column=col

}

}

Herearesomestepwiselogicweadheretowhilecreatingtiles:

1. Whilebuildinganycodelogic,weusuallyplacethepropertiesaboutthisobjectatthe

top.WeknowthateachtileinagameofMineSweeperwillbepartofarowandacolumn.Thenumberoftherowandthecolumnthistilewillhaveduringgameplaywon’tchangeduringthecourseofasingleround,sowemakethemconstantswiththekeywordletandsetthemwiththetypeIntasweknowthatyoucan’thavefractionsofaroworacolumn,atleastintermsofthetileobjects.

2. Atilecanhaveafewdifferentstates.Itcouldbealreadytapped,itcouldhaveaflagplacedonit,andifit’saamine.Sincethesearetrue/falseproperties,wesetthemwithasBooleanvariablesisTileDown,isFlagged,andisAMine.Wesetthemtofalseinitially.

3. TilesinMineSweepercounthowmanytilesaroundthemaremines,sowecreatetheintegercounternearbyMinestoholdthatinformation.

4. Whenaninstanceofatileobjectiscreated,wewantthegametosetitsrowandcolumnnumberplacementontheGameBoard,sowecreatethedefaultinitializer,init,tohavetwoparameterinputsforboththerowandcolumn.

That’sallweneedfortheTileobjects,solet’smoveontosettingthebuttonfunctionalityoftheseTileobjectswiththeMineTileButtonclass.

CreateanewSwiftfileandnameitMineTileButtonandpastethefollowingcodeintoit:

//(1)

importUIKit

classMineTileButton:UIButton{

//(2)

vartile:Tile

lettileSize:CGFloat

//(3)

init(tileButton:Tile,size:CGFloat){

self.tile=tileButton

self.tileSize=size

letx=CGFloat(self.tile.column)*tileSize

lety=CGFloat(self.tile.row)*tileSize

lettileBoundingFrame=CGRectMake(x,y,tileSize,tileSize)

super.init(frame:tileBoundingFrame)

}

//(4)

requiredinit(coderaDecoder:NSCoder){

fatalError("init(coder:)hasnotbeenimplemented")

}

//(5)

//buttontext;

//replacebuttonwithanSKSpriteforbetterGUIinterface?

funcgetTileLabelText()->String{

if!self.tile.isAMine{

ifself.tile.nearbyMines==0{

return"0"

}else{

return"\(self.tile.nearbyMines)"

}

}

//(6)

return"💥"

}

}

Here’stheexplanationofthecode:

1. SincewearecreatingaUIButtonobject,weimporttheUIKitframeworkforthisobject.

2. Thesearethepropertiesofthisbuttonobject.WeneedaTileobjectnamedtiletoreference,aCGFloatsizenamedtileSizetorepresenttherectanglethisbuttonwilloccupy.

3. TheinitializerforthisclasstakesinaTileobjectnamedtileButtonandaCGFloatnamedsize.Weassigntheclass’sowntiletotileButtonandtileSizetosizeandthenwemakeasquarenamedtileBoundingFramewiththeCGRectMake()method.ThisisdonejustafterwesetanxandyvalueofCGFloattothesquarebasedonthetileSize.TheUIButtonparentinit(frame:)initializerusesthetileBoundingFrameastheparameterviasuper.init(frame:tileBoundingFrame).

4. SinceXcode5,theinitfunctionisneededmainlytokeepthecompilerhappywhiledealingwithUIobjects.

5. ThefunctiongetTileLabelText()returnsastringbasedonthestatusofthetileobject.Ifthetileisnotamine,weknowthatwehavetoeitherplacesomethingfortherebeingnotiles;traditionally,thisisjustablankspaceoranempty""string,butfornow,wearejustplacing0there,leavingthelogicopenforcustomization.Honestly,wecouldsimplyreturnthenestedif-elsestatement’sreturn\(self.tile.nearbyMines),andit’dreturnthesameresult.Aswesee,it’sreturningtheparticularTileobject’snearbyMinesproperty.

6. Ifthetileisamine,thenwereturnthecollisionUnicodeemojicharacter.ThegetTileLabelText()functioniscalledwhentheplayertapsanunflaggedtile.

7. Swift’sabilitytouseUnicodecharactersymbolscanbeagreatvisualaidintheplanningprocessofyourgames.ThecollisionUnicodeemojiusedinline(6)isU+1F4A5(128165).Ifyouseeonlyasquareboxandnottheredexplosion-likecharacter,itcanbeseeninthefullprojectdownloadmentionedearlierinthechapteroratthefollowinglink.

NoteFindmoreinformationonthisemojiathttp://www.charbase.com/1f4a5-unicode-collision-symbol.

GameBoardNowthatwehaveourtileobjectandbuttonlogicthatwillrepresenteachtileobjectnamedMineTileButton,weneedtocreateanobjectrepresentingthecollectionoftheseobjects,thatis,GameBoard.

ThefullGameBoard.swiftcodeisabittoolargetoshowhereinitsentirety,sowewillsummarizeitsmainfeaturesandsegments.

Wecanviewtheentirecodeeitherinthefullprojectlinkmentionedearlierinthechapter,ordirectlybelowinordertocopytoyourcurrentgameprojectfile:

https://mega.co.nz/#!X8FB2aAK

ForourGameBoard,wearelookingtocreateatiledboardof10x10sizethatalsohasthreelevelsofdifficulty:easy,medium,andhard.Tocreatethedifficulty,wesimplyuseanenumeratornameddifficultytostorethegame’sdifficultylevels.

ThemostimportantpropertiesofGameBoardincludeboardSize_(whichissetto10inthiscase),avariablethatwillrepresentthenumberofminesthatwillbeplacednamedmineRandomizer,thenumberofminesactiveontheboardnamedmineCount,andtheTileobjectsthatwillpopulatetheboardnamedtiles.

Makeanoteofthesyntaxusedforthetilesproperty:

vartiles:[[Tile]]=[]

Inthisway,wecancreateanordered2Darray(ormatrix)inSwift*.TheGameBoardobjectwillbasicallystoreanarrayofanarrayofTiletypeobjects.

Note*Swiftdoeshavemorewaystoexpressmatrices,forexample,wecanuseStructstodefineourownuniquematrices.Asatthetimeofthispublication,Swiftdoesnothaveitsowntruefunctionalityforfixedlengtharrays,asweseeinvariousClanguages.However,usingthenestedbraces[[]]isfineforwhatwearetryingtoaccomplish.

TheinitializerforGameBoard,init(selectedDifficulty:difficulty){},takesintheplayer-selecteddifficultyasit’ssingleparameterthenbuildstheboardbasedontheboardSizepropertyandthenusesthefollowingnestedfor-inlooptopopulatetheentireboardwithTileobjects:

forrowin0..<boardSize_{

vartilesRow:[Tile]=[]

forcolin0..<boardSize_{

lettile=Tile(row:row,col:col)

tilesRow.append(tile)

}

tiles.append(tilesRow)

}

Sincethetilesobjectisa2Darray,wefirstneedtoperformthisnestedloopthatfirstcreatesa1DarrayofTileobjects(namedtilesRow)foreachrowandthenaddatilefor

eachcolumninthatrowwiththe.appendfunction.Themaintiles2DarrayisthenappendedthattilesRowarray.

TipIfyouwishtomakeaGameBoardinstancethatisarectangleorofanothershape,you’dhavetotakeintoaccountthedifferingcolumnandrowamounts.Thiswouldmakethenestedfor-loophavemorecomplexitybyneedingaseparatecolumnSizeandrowSizeproperty.Manypuzzlegameswillmaketheirboardslookcomplextotheplayerbutmightstillkeeptheirinternalstructuressimpletoeithersquaresorrectanglesbyinsteadfillinginthattilewithanonplayablesectionorbackground/transparenttile.

It’sawayforadevelopertocutcornerswhileatthesametimeallowingcomplexfunctionalityanddesign.It’swhywebuiltthisgamewithseparateclassesrepresentingtheTiles,thetilebuttonfunctionalities,andthegameboardlayout.

Usinginheritance,wecancontinuetocustomizewhateachtiledoesandthusallowamyriadoffeaturesbasedonasimplefoundation.

It’swhyvideogameshavealwaysbeentheposterchildrentomakethemostoutofobject-orienteddesign.

Don’tworryifatfirstit’stoughtogetafullunderstandingofthis,asnestedloopstendtobebraintwisters.Justobservehowtheinteriorfor-loopwon’texituntilit’sdonefillingincolumnsbasedontheboardSize_property.Thiskindofloopismadeeasierwiththefactthattherowsandcolumnsareallequalat10.

TheinitializerthencallstheresetBoard()function,whichresetsthemineCountto0,anddoestwomorenestedfor-loops:

forrowin0..<boardSize_{

forcolumnin0..<boardSize_{

self.createRandomMineTiles(tiles[row][column])

tiles[row][column].isTileDown=false

}

}

Thisboard-iteratingfor-looprandomlysetswhichtilesareminesusingthecreateRandomMineTiles()functionaswellasresetsthetilestobeinguntouchedwiththetiles[row][column].isTileDown=falsecall.ThecreateRandomMineTiles()functionworksoffthecurrentdifficultylevel,particularlythemineRandomizerpropertythatisdeterminedintheimplementDifficulty()function.ThehigherthemineRandomizervalue,thelessofachancetheiteratedtilewillbemadeintoamine.

Thenextnestedfor-loopinresetBoard()isthefollowing:

forrowin0..<boardSize_{

forcolumnin0..<boardSize_{

self.calculateNearbyMines(tiles[row][column])

}

}

Thisiteratesthrougheverytileontheboardandsetsthenumbertheplayerwillseeif

tapped.Thatnumberofcoursebeingthenumberofminessurroundinganon-minetile,thatis,thenearbyMinespropertyoftheTileclass.

ThisrathercomplexchainofcalculationsbeginswiththecalculateNearbyMines()functionandrunsthroughthearray/tileindexcalculatingfunctions,getNearbyTiles()andgetAdjacentTileLocation().Weprovidedvariousdetailedcommentsineachofthesefunctionstogetabetterunderstandingonhowtheywork.It’sadvisedthatyoureadtheintricatedetailsonhowit’sdonebuttonotmuddyanalreadycomplexgamelogicexplanation,takenotesonthefollowinglineingetNearbyTiles():

letnearbyTileOffsets=

[(-1,-1),//bottomleftcornerfromselectedtile

(0,-1),//directlybelow

(1,-1),//bottomrightcorner

(-1,0),//directlyleft

(1,0),//directlyright

(-1,1),//topleftcorner

(0,1),//directlyabove

(1,1)]//toprightcorner

Ifanylineinthesethreecomplexfunctionsistobeunderstood,it’sthisone.ThenearbyTileOffsetobjectisanexplicitlywrittenarrayoftuples,whichcontainseveryoffsetthatcouldexistaroundasingle2Dtile.Actually,it’sbesttothinkofeachmemberofthisarrayasan(x,y)2DVector.

Thus,ascommentedintheprecedingcode,theoffsetof(-1,-1)wouldbetothebottomleftofthetilesincex=-1(left1)andy=-1(down1).Similarly,(1,0)istotheright,(1,1)isthetop-rightcorner.

Wealsohavetotakeintoaccountthatsometilesareontheedgeand/orcolumnoftheboard,thussomeofthetileoffsetswon’treturnthereferencetoanothertile;they’llinsteadreturnnil.

for(rowOffset,columnOffset)innearbyTileOffsets{

//optionalsincetilesinthecorners/edgescouldhavelessthan8

surroundingtilesandthuscouldhaveanilvalue

letajacentTile:Tile?=

getAjacentTileLocation(selectedTile.row+rowOffset,col:

selectedTile.column+columnOffset)

//ifvalidAjacentTileisn'tnil,addtheTileobjecttothe

nearbyTilearray

ifletvalidAjacentTile=ajacentTile{

nearbyTiles.append(validAjacentTile)

}

}

Thisfor-loopingetNearbyTiles()notonlycheckstheoffsetsofeverytile,butalso,usingthecalltogetAjacentTileLocation(),accountsforedgeorcornertiles.

Again,thesethreefunctionsarerathercomplex,eveninalessline-by-line/semi-genericexplanationoftheirfunctionality.So,don’tworryifyoudon’tunderstandtheflow/orderatfirst.

Finally,forresetBoard(),wecan’twinthegamewithoutknowingiftheplayergoteverynon-minetile,sowegetthatinformationwiththeline:

numOfTappedTilesToWin_=totalTiles_-mineCount

Whentheplayer’snumberofcompletedmoves(countedintheGameSceneclass)equalsnumOfTappedTilesToWin,theplayerwins!

Thisisalldonebeforetheplayermakesthefirstmove!Thisisdoneinordertohavethevaluesalreadypredetermined.Yes,wecouldmakesomeofthesecalculationsduringtheplayer’stouch,butdealingwithboilerplategamelogicisusuallyfastenoughtopreparethegameatloadtimesothatwecanusethegameplaytofocusoneffects,sequences,andothervisualnotificationsduringthegameloop.

ThisfunctionalityiscontrolledbytheGameScene.swiftfile,whichwewillsummarizenext.

PuttingitalltogetherinGameScene.swiftWenowhavethecoreofSwiftSweeper’slogicsetup,butnowit’stimetopresentitinourSKSceneprovidedbythegametemplate,GameScene.Thissceneusesthegame/renderingloopfunctionsthatwementionedatthebeginningofthechapter.

TheSwiftSweeperversionofGameScene.swiftisratherlargeatabout800linesofcode,solikeGameBoard,wewon’tbegoingoveritlinebylinebutinsteadwe’llbesummarizingsomeoftheimportantaspectsofthescene.Asstatedpreviously,everyupdatetoXcodeandiOSbringsmorevisualwaysofsettingupthesescenes,sogettingtoknoweverylineofcodeinthisexampleisn’tnecessary,butstillrecommendedifyoureallywishtodivedeepintohowtousecodetopresentSpriteKitgamescenes.

Thefullcodecanbefoundinthefullprojectlinkmentionedearlierinthechapteror(ifyou’vebeenbuildingitfromscratchthroughoutthechapter)atthelinkmentionedhere:

https://mega.co.nz/#!PgljBL7b

Weusedvarious//MARK:commentstosectionoffpartsofthiscode,soyoucannavigateeasier.Aftercopyingthecodeintoyourproject,youcouldbuildandruntheapp.Aslongaseverythingwasplacedintotheprojectcorrectly,youshouldhaveaworkingversionofSwiftSweeperrunningonyourphoneorinthephonesimulators.PlaythroughitabittogetanideawhatisbeingdoneinGameScenetopresentthegame.Sometimes,seeingagameinactionletsusseethecodebehinditbetter.Ifanyerrorspopup,somethingwentwrongandifallelsefails,youcandownloadthecompletedprojectfromhttps://github.com/princetrunks/SwiftSweeper.

ThefirstvisualentrypointinGameScene,didMoveToView(),isactuallyrathersmallasfollows:

overridefuncdidMoveToView(view:SKView){

self.backgroundColor=UIColor.whiteColor()

stageView_=view

loadInstructions()

}

Wesimplysetthebackgroundcolortowhiteandloadtheinstructions.Again,wedidn’tsaythatthiswasmeanttobeabeautiful-lookinggame.

TheloadInstructions()functionmanuallyplacestheinstructionsspriteonthescreenandsetsthecurrentGameState_enumto.Instructions.Agamestateorstatemachineiscommongamedevelopmentmethodologythatinstructscharacters,theplayer,andthegameitselfwhatstateitisin.Thiscouldbeusedtomakesurethatcertainpartsofthegameplaydon’thappeninpartstheyaren’tsupposeto.iOS9/Xcode7introducedtheframework;we’lldiveintomorelaterchaptersnamedGamePlayKit,which,amongothergamelogicfunctions,workswithstatemachinesthatcanbemodularandindependentfromaspecificscene.ComponentsfromtheclassSKComponentsandmoremodernusageofSKAction,alsointroducediniOS9,workinthesameway,independentfromOOPinheritance.Thinkofmoredynamic/usableversionsofprotocols.

ThenextoverallstepintheGameSceneisthechooseDifficultyMenu()thatcamewiththeremoveInstructions()function,whichwascalledaftertheplayertapsthescreen.Thistapischeckedinthefunctionwementionedinafewexamplesprior,touchesBegan(),usingthegamestateasalogiccheck:

overridefunctouchesBegan(touches:Set<UITouch>,withEventevent:

UIEvent?){

/*Calledwhenatouchbegins*/

fortouchintouches{

//flagbuttonPressed

ifCGRectContainsPoint(flagButton_.frame,

touch.locationInNode(self)){

flagButtonPressed()

}

//instructionsremovedwhentapped

ifCGRectContainsPoint(instructionsSprite_.frame,

touch.locationInNode(self))&&currentGameState_==.Instructions{

removeInstructions()

}

}

}

NotehowthetouchesBeganfunctionisactuallyrathersimple.Itonlychecksifwetappedtheflagbuttonorifwetappedontheinstructions.Whataboutthetiles?Well,rememberthatwemadethesetilesallmembersofUIButtonwiththeMineTileButtonclass.Here’sthefunctionthatcontrolsthis:

functileButtonTapped(sender:MineTileButton){

//exitfunctionifnotplayingthegame

if(currentGameState_!=.MineTap&&currentGameState_!=

.FlagPlanting){

return

}

//revealstheunderlyingtile,onlyifthegameisinthemain

state,akaMineTap

if(!sender.tile.isTileDown&&currentGameState_==.MineTap){

sender.tile.isTileDown=true

sender.setTitle("\(sender.getTileLabelText())",forState:

.Normal)

//sender.backgroundColor=UIColor.lightGrayColor()

//mineHIT!

ifsender.tile.isAMine{

//sender.backgroundColor=UIColor.orangeColor()

self.mineHit()

}

//countsthemoves;alsousedincalculatingawin

moves_++

}

elseif(!sender.tile.isTileDown&&currentGameState_==

.FlagPlanting){

self.flagPlant(sender)

}

}

MembersoftheUIButtonclasssendoutareferenceofwhathasbeentappedtothescene.

Inthisgame,isanobjectofthetype,MineTileButton.Usingthegamestatetocheckifit’slogicaltothescene,weeitherendtheroundifamineishitwiththemineHit()functionorweincrementthemovesperformed(usedtocalculatethewinbycomparingittonumOfTappedTilesToWin_calculatedatthestartoftheround).Ifthegamestateis.FlagPlanting,thenweinsteaddealwiththelogicbehindplantingaflagonthetiles.Tileswithflagsdon’treactto.MineTapgamestatetapsandthus,ifyouputaflagonthewrongtile,youwon’tgetthewinuntilyouuncoverallofthenon-minetiles.

Throughtherestofthecode,we’llfindatimer,alertsfortheplayerbasedontheoutcome,andeventheabilitytosavetimesperdifficultylevelsusingtheclassfunctionsoftheNSUserDefaultsclass.

Again,it’snotexactlyallthatvisuallyelegant,butintricateincodeandmostimportantlyafullyfunctioninggame.WeadviseyoutocheckoutmoreofthecodeinGameScene.swift,butonemajorissuetoourdesignonemighthavecausedinthebeginningisthatthisonlyworkswithiPhones.

Usingvisualtoolssuchasautolayout,seenbrieflyinthepreviouschapter,willalloweasierdesignchangesfortheentirefamilyofiOSdevices.SincemanyofthevisualassetsinSwiftSweeper’sGameSceneweremanuallyplacedintheview(particularlytheinstructions),we’dhavetoaccountforeverydevicetypeincode.Thisispossible,butasthefamilyofdevicesgrows,manualcodeusedforscreenvisualscouldbebrokenrathereasilyinfutureiOSupdatesanddeviceannouncements.That’swhyinournextchapteraboutSceneKitandlater,wewillmostlydivergefromthiscode-centricstructureandembracethehands-ontoolsandnewerframeworkssuchasGamePlaykitfromXcode7andlater.

DemoBotsAsattheinitialpublicationofthisbook,WWDC15recentlycompletedandgaveusagreatnewSpriteKitdemoprojectforiOS9andXcode7namedDemoBots.

DemoBotsisaSpriteKitprojectprovidedbyApplethatusescomponents,statemachines,on-demandservices,GameplayKit,ReplayKit,andmore!

ThefullprojectdocumentationtoDemoBotscanbefoundathttps://developer.apple.com/library/prerelease/ios/samplecode/DemoBots/Introduction/Intro.html

ToseeitinactionfromWWDC15,seethevideoandPDFfilefromtheDeeperintoGameplayKitwithDemoBotskeynote:

https://developer.apple.com/videos/wwdc/2015/?id=609

TheSpriteKitkeynotecanbefoundhere:

https://developer.apple.com/videos/wwdc/2015/?id=604

DemoBots’sgameplayevenhaseasilyeditableenemyAI/navigationschemesusestheSKCameraNodeintroducediniOS9thatfollowstheplayeranddoesn’tmovethescenearoundintheviewasinpastversionsofSpriteKit.Aswementionedatthebeginningofthechapter,mimickingthetoolsweseeinmultiplatformgameengines.

SummaryWewentthroughanumberoftopicshereinthischapter.WefirstspokeonwhySpriteKitwasawelcomedadditiontoiOSafteryearsofdevelopersonlyhavingthird-partygamingframeworks,suchasCocos2DandSparrow.WediscussedhowSpriteKitfitsinthegamedevelopmentecosystemasratherpowerful,multiplatformgameengines,suchasUnityandUnrealEngine,continuetobecomemoreprominent.Next,wewentintotheSpriteKitgameloopandrenderingcyclethatisusedbySKScene.Then,webegantobuildourdemotilegame,SwiftSweeper,anddovemoreintothebasicstructureofSpriteKit’smostprominentobjectclasses.TheiOS9assetsfolderwasreviewedinadditiontotextureatlasesandhowtoanimatespritesusingtheseassettools.Then,wewentintotherathercomplexlogicandcodethatgoesintomimickingatilegamesuchasMineSweeper.

Next,wemoveontoiOS’s3Dgamedevelopmentframework,SceneKit,wherewewilldivergemoretowardsthevisualtoolsApplenowbringstoussinceiOS8/iOS9.We’lltakelessofacode-centricmethodologynowthatweknowthebasicscene/codestructurethatbothSceneKitandSpriteKitshare.SpriteKitscenescanoverlaySceneKitscenes,sowewillseesomeofwhatwehintedatwithApple’sownDemoBotsdemoshortly.

Chapter4.SceneKitand3DGameDesignForthischapter,wewillbegoingovertheiOSframeworkusedfor3DgamedevelopmentknownasSceneKit.SceneKitfirstbecameavailableiniOS7butoriginallywasjustusedforMacOSdevelopment.Previously,developershadtocode3DgamesusingOpenGLorthird-partyframeworksandengines,suchasCocos3D,UnrealEngine,Havok,andUnity.AsthegraphicalpowerintheiOSfamilyofdevicesimproved,sodidtheneedforanimmersive,hands-onfirst-party3Dgamedesignengine.SceneKitshortlybecameavailableforiOSgivingdevelopersanXcodebuilt-insolutiontomake3Dgames.

Inthepreviouschapter,weapproachediOSgamedevelopmentinamorecode-basedmethodology.We’llstillbeworkinginsomecode,butsincetheintroductionofXcode5andXcode6,ApplehasprovidedsomegreatdemosthatshowhowtheIDEcanbejustasvisuallydynamicofagameengineasmultiplatformgameenginesare.ThebenefitofusingXcodeandtheSpriteKit/SceneKitframeworksoverthoseenginesisthatyouhaveadedicateddesignenvironmentforaspecificplatform.Inourcase,thatplatformisiOSandtheApplefamilyofdevices.AsiOSfrequentlyupdatesandcontinuestogivenewfeatures,Xcodeandtheseframeworkswillupdatewithit.Updatestothemultiplatformenginesusuallyoccuratalaterdatewithsometimestheadditionalneedtoinstallpluginstoensurethatyourapprunssmoothlyinfutureupdates.

Inadditiontotheverydynamicandtool-richDemoBotsSpriteKitdemo,theJune2015WorldWideDeveloper’sConferencealsointroducedawonderfulSceneKitdemonamedFox.TheFoxdemoalsomakesuseoffeaturesintroducediniOS9thatwecanuseforeitherSpriteKitorSceneKit,suchasreusableactions,components,andstatemachines.

Inthischapter,wewillgooverthebasicsofSceneKitandwewillmakeasimpleSceneKitscene(knownasSCNScene)usingbothcodeandthevisualdesigntoolsXcodeprovides.Wewillthenaddphysics,lights,andparticlestoourSceneKitobjectsandscene.WewillthenwrapupwithalookintotheWWDC15FoxDemoandsomeofthefeatures/APIsituses,whichbecameavailableiniOS8andiOS9.

NoteInthepreviouschapter,weleftoutmuchoftheseassetcreationfeaturesinourdiscussiononSpriteKit.WithSpriteKitscenefiles,(.sks),wecanalsocreategameassets,suchaslights,physicsfields,boundingboxes/physicsconstraints,normalmaps,textures,entirelevels,andcharactersinthesamefashionthatSceneKitscenefiles(.scn)work.WewillattimesshowtheSpriteKitmethodtosimilarfeatures.

SinceSpriteKitandSceneKitsceneassetsworksimilarlyandcanbetogetherinthesamescene(thankstotheirinheritnode/treefunctionality),wethoughtthatitwasbesttosavethevisualandassettooldiscussionforthischapter.Thepreviouschapter’stalkonthegame/renderloopandmuchofthescenecodefunctionalitywillworkinSceneKitmuchlikeitdidpreviouslyinSpriteKit.

Soinotherwords,wearealreadysetuptodiverightintoSceneKit.

SceneKitbasicsandworkingwithnodesLikeSpriteKit,SceneKitisbasedontheconceptofnodes.SpriteKitobjectsarechildrenoftheSKNodeclass,whileSceneKitobjectsarechildrenoftheSCNNodeclass.

TheprecedingimageistheSceneGraphhierarchyfromApple’sSceneKitintroduction.Aswesee,SceneKithasvariousnodesthatbranchofffromtheSCNSceneclass.TheseincludethegenericSCNNodeforlights,geometry,andthecamera.

Nodesareatreedatastructurethatcanhaveothernodesaddedtothemandhaveinformationofothernodesinthestructure.Asseenintheprecedinggraph,it’sshownwiththechildNode[]arrayandparentproperties.Spatialinformation,suchasposition,scale,andorientation,canbereceivedfromtheseproperties.Thisiswhatmakesnodesuniquetootherparent-childstructuringinobject-orienteddesign(OOD).

InSpriteKit,we’dtypicallyaddanodetooursceneortoanothernodewithinoursceneviatheaddChild()function.InSceneKit,thesamefunctionalityisdonewithaddChildNode().Forexample,themainrootnodeinaSceneKitsceneistheSCNScenenodethatisplacedintheSCNViewnode,thatis,theframework’suniqueversionoftheUIViewclass.Toaddabasicsphereobjecttoourscene,we’ddothefollowing:

letsphereGeometry=SCNSphere(radius:1.0)

letsphereNode=SCNNode(geometry:sphereGeometry)

self.rootNode.addChildNode(sphereNode)

AsstatedwithSpriteKit,workingwithnodesinSpriteKitcanallowustogroupvarious

membersofourgamescenetogetherintotheirownparentnodesandmakeactionsontheminonecallalsoiteratingthroughforloopsorotheriterationcalls.

SpriteKit/SceneKitinteractivityOnegreatfeatureofSceneKitisthatwecanhaveaSpriteKitsceneoverlayour3Dgame.

self.overlaySKScene=skScene

UsingtheSCNViewpropertyoverlaySKcene,wecantakeanalreadyestablishedSKScenenode(whichcanbeacharacter,ananimationsequence,anHUD,andmore)andhavetheminour3Dscene.

Wanttohaveacutespriteanimationoverlayyour3Dcharacter’sstagewinormaybewanttomakea2.5Dgamewith2Dspritesandphysicsoverlayinga3Dbackground?Thenthisishowyoucandoit.

ThemostcommonfunctionalityofmixingSpriteKitwithSceneKitisthatSpriteKitistheHUDfortheSceneKitscene.Thelives,collectables,andcharactericonseenintheearlierFoxdemoshowsaSpriteKitnodeoverlayingaSceneKitscene.

Nodesingeneralcanhelpaddafunctionalstructuretoyourgameandgamescenes.Ahighrelianceonnodesandinheritanceingamedesigndoesn’tcomewithoutitsflawsthough.

Theissuewithinheritance-basedstructuringandgamedesignBeforegoingforward,weshouldmentionaboutacertainpitfallthatcouldplagueagamethatreliestoomuchontheconceptofnodesandeventhegeneralconceptofinheritance-basedstructuringinOOD.Whenpossible,it’sbestnottorelytoomuchoninheritanceforyourgamelogicandworkmorewithwhat’sknownascomposite-basedstructuring.We’llgodeeperintothisinournextchapterwhenwetalkaboutthehelpergamedevelopmentframeworkfirstintroducediniOS9,GamePlayKit,buthere’saglancesothatweknowthatworkingwithinheritanceandevennodesmightnotalwaysbethebestsolutioninourgames.

Atfirstglance,onemightthinkthatinheritance-basedstructuringisperfectlymadeforgamedevelopment.ManyofusfamiliarwithOODknowthatwecanhavegenericparentclassesornodesofourgameobjects,suchasanall-encompassingGameObjectclass,andthenuseinheritanceandpolymorphismtoworkwithuniquechildclassesfromthisbaseclass.Forsmall,simplisticgamesthatwillholdtrue,butgamestendtohaveobjectsthatcouldsharesomeofthesamefunctionality,butmakenosensetohaveinaparent-childstructure.

Takethistypicalstructuringinatower-basedstrategygame:

Inatypicaltowergame,we’dhaveourbase,tower,andenemyobjectsthatcanallinheritfromagenericGameObjectclasswedefine.Towerscanfireatenemiesbutsocanenemiesbackatthetowersandotherplayer-basedobjects.Partofgoodprogramminganddesignistohavereusablecodeandmethods.Normally,we’ddothiswithinheritance.Theprecedinggraphshowstwo-wayinheritancethatcansolvethis.WewouldthenwantaShootingEnemyclassthatinheritsthemovementandshootingfunctionality.Wecan’tdothis,asthatwouldinvolveinheritingfromtwoseparateandratherunrelatedclassesofobjects.InOOD,there’sonlyonechild-parentrelationship.ThenextsolutionshownontherightwouldbetohavethegenericGameObjectclasshavethisfunctionality.TheissuethatarisesisthatouroncesimpleGameObjectparentclassbecomesallbutsimpleandweinevitablywanttoaddadditionalfeaturesandfunctionalitiestoobjectsinourgame.Inthepast,thiswouldinvolverefactoringtonsofcodetoaccommodatewhatessentiallyaresimpledesignadd-ons.Protocolsusedtobesomewhatofasolutiontothisasthey’dforceustomakeaclassinacertainway,buteventheycouldgetconfusinganddon’tinvolvetheimplementationofthesefeatures.

Thesolutionwouldbetoworkwithentitiesandcomponents.

Thisprecedingdiagramgivesanexampleofcomposite-basedstructuring.Withthismethodology,wecanhavecomponentsthatsharesimilarfunctionality,beingusedbymultipleandusuallyunrelatedgameobjects.Thisway,thegenericGameObjectclassinthisexampledoesn’thavetohaveeverypossiblefunctionofitschildclassandwecankeepEnemyclassesasbeingmembersofEnemy.Thesharedfunctionalitycanbewrittenonceandthenusedthroughoutthegameandevenintheothergameswewishtomake.iOS9’sSpriteKitdemo,DemoBots,andtheSceneKitdemomentionedearlier,Fox,bothusecomposite-basedstructuringforactionsandanimations.

It’simportantwhenthinkingwithnodesinbothSpriteKitandSceneKitthattheyareusedinthecontextoftheViewoftheMVCmodel,orinbothframeworks,thecontextoftheirscenes.

AsforscenesinSceneKit,let’smoveontomakingaverybasicone.

OurfirstSceneKitscene–theXcodetemplate3Dartandanimationisaveryin-depthtopic.Wecouldgoonadnauseamaboutmaterials,shaders,lighting,sculpting,PVRtextures,andallofthetopicsofwhatmakesgreat3Dobjectsforgames,movies,architecture,oranyother3Dobject-basedapplication.

Someofthedetailsofthesetopicsarebeyondthescopeofthisbook,sofornow,let’skeepthingssimple.

Let’sworkwiththedefaultSceneKitsceneandobjectsthatXcodegivesusasastart,asshownintheprecedingimage:

NoteAsofthetimeofwritingthisbook,weusedtheSceneKittemplateforXcode7–Beta.Basedontheversionyouuse,theremightbesomedifferences.

1. First,openXcode,createanewproject,andselecttheGametemplate.

2. Next,nameyourproject,makesurethattheGameTechnologyfieldsaysSceneKit,andclickonNext.

3. TheprojectfilesandstructureareaboutthesameaswesawwithSpriteKitbutwithacoupleofdifferences,particularlytheart.scnassetsfolder.Theonlydifferenceisthatthereisnowanart.scnassetsfolderinadditiontoAssests.xcassets.Thisiswhereour3Dobjectsareheld.Clickonthatfoldertoseetheship.daeassetthatAppleprovides.

WiththeSceneKiteditor,wecanviewandeditthefollowing3Dfiletypes:

DAEOBJAlembicSTLPLY

TheexamplegiventousisaspaceshipofthetypeDAEandwiththeship.daefileastheship’stexturefile(texture.png).Beforewelookintothecodeandhowthesceneworks,buildandruntheprogramoneitheryourowndeviceortheXcodedevicesimulator.

Fromthesamplescene,weseeourspaceshiprotatinginfrontofablackbackgroundandwecanchangeitsorientationwhenweswipetheship.Tappingontheshipcausesittoglowredforamoment.

Let’snowseewhat’sgoingonwiththecodeandthenwe’llgetintothetoolstheeditorgivesustoeditourobjectsandsceneswithoutanycode.

SceneKitprojectflowandstructureLikeSpriteKit,aSceneKitsceneusesthesamegame-renderingloopaswesawfromthepreviouschapterandthesametypeofentrypointstructuringwementionedinChapter2,StructuringandPlanningaGameUsingiOS9StoryboardsandSegues.WehavetheAppDelegate.swiftfilethatisourentrypointwiththeabilitytocontrolspecialappfunctionalitybasedonupperleveldeviceevents,suchastheappclosing,goingintothebackground,andcomingbackfrombeinginthebackground.WealsohavethelaunchscreenandMain.storyboardfilesasseenbeforeinSpriteKit.

ThedifferencewiththeMain.storyboardfileisthatithasaSceneKitsceneicon,shownwiththecube,asseenintheprecedingscreenshot.

TheViewControllerclasstheAppDelegatemovestoistheGameViewController.swiftclass.Thisiswhereallofourcodeforthedemotakesplace:

overridefuncviewDidLoad(){

super.viewDidLoad()

//createanewscene

letscene=SCNScene(named:"art.scnassets/ship.dae")!

...

WeseethatwebeginwiththeoverwrittenviewDidLoad()function.SceneKitletsuscreateanentirescenewithevenaninstanceofour3Dobject/assets,asseenfromtheunwrappedletscene=SCNScene(named:"art.scnassets/ship.dae")!call.Thissimplycreatesthesceneobject.Togettheobjectseenonthescreen,westillneedtoattachthistotheSCNViewnode,aswewillseelaterinthefunction.

Let’slookatsomemoreofthecodehere:

//(1)createandaddacameratothescene

letcameraNode=SCNNode()

cameraNode.camera=SCNCamera()

scene.rootNode.addChildNode(cameraNode)

//placethecamera

cameraNode.position=SCNVector3(x:0,y:0,z:15)

//(2)createandaddalighttothescene

letlightNode=SCNNode()

lightNode.light=SCNLight()

lightNode.light!.type=SCNLightTypeOmni

lightNode.position=SCNVector3(x:0,y:10,z:10)

scene.rootNode.addChildNode(lightNode)

//createandaddanambientlighttothescene

letambientLightNode=SCNNode()

ambientLightNode.light=SCNLight()

ambientLightNode.light!.type=SCNLightTypeAmbient

ambientLightNode.light!.color=UIColor.darkGrayColor()

scene.rootNode.addChildNode(ambientLightNode)

//(3)retrievetheshipnode

letship=scene.rootNode.childNodeWithName("ship",recursively:true)!

//(4)animatethe3dobject

ship.runAction(SCNAction.repeatActionForever(SCNAction.rotateByX(0,y:2,

z:0,duration:1)))

//(5)retrievetheSCNView

letscnView=self.viewas!SCNView

//setthescenetotheview

scnView.scene=scene

//(6)allowstheusertomanipulatethecamera

scnView.allowsCameraControl=true

//showstatisticssuchasfpsandtiminginformation

scnView.showsStatistics=true

//configuretheview

scnView.backgroundColor=UIColor.blackColor()

//(7)addatapgesturerecognizer

lettapGesture=UITapGestureRecognizer(target:self,action:

"handleTap:")

scnView.addGestureRecognizer(tapGesture)

TheviewDidLoad()functionmentionedearlierisprovidedtousinthetemplate.It’sactuallyrathersimpletofollowandotherthanthehandleTap()function,doespractically

allthat’sneededtocreatethisscene.Anyonewho’screated3DgraphicsinOpenGLeitherforiOSorotherplatformswouldappreciatehowSceneKitgivesusanumberofsimpleupperlevelcontrolsforthesceneandobjects.Herearemoredetailsoftheprovidedcode:

Online(1),anSCNNodenamedcameraNodeiscreated,andweassignthecameraattributeofSCNNodetotheSCNCameraNodetype.Then,thecameraisplacedinathree-dimensionalspaceusingtheSCNVector3()functiononthecamera’spositionproperty.Inthiscase,thecameraisplacedat(x:0,y:0,z:15).Inotherwords,thexandycoordinatesaresetattheoriginwhilethecameraismovedslightlybackwardsinthezaxis.

YoucanfindtheSceneKitcoordinatediagramathttps://developer.apple.com/library/ios/documentation/SceneKit/Reference/SceneKit_Framework/

ThecoordinatesysteminSceneKitiswhat’sknownasaRight-HandedCoordinateSystem.Onetricktounderstandthe3Dcoordinatesisifwetakeourrighthand,makeagun-likegestureoutwithourthumbupintheairandpointerfingerstraightaheadofuswhileourmiddlefingertothesideatarightanglefromthepointerfinger,we’dhaveourx,y,andzcoordinates.Yourmiddlefingerwouldbeonthexaxis(left/right),yourthumbwouldbeontheyaxis(up/down),andyourpointerfingerwouldbeonthezaxis(backward/forward).

Inthe(2)blockofcode,weareaddinglightstoourscreen.SceneKit,aswellasSpriteKit,letsuscreateanumberofdifferentlightingeffects,fromambientocclusion,the

useofnormalmaps,andmore.Here,aninstanceofSCNNodeiscreatedwiththenamelightNode,andtheSCNNodepropertylightisassignedtheSCNLightclasstype.Thefirstlightcreatedandaddedtothesceneiswhat’sknownasanSCNLightTypeOmnitypelight,asseenfromtheimplicitlyunwrappedcalllightNode.light!.type=SCNLightTypeOmni.Thistypeoflightistypicallyusedmorefordebuggingasthenextlightadded,ambientLightNode,wouldbeoneofthetypesusedtocreatetheatmospheretoyourgame.Asweseewiththeline,ambientLightNode.light!.color=UIColor.darkGrayColor(),wecanassignacolortothatlightincode.

MoreinformationonSCNLightscanbefoundathttps://developer.apple.com/library/prerelease/ios/documentation/SceneKit/Reference/SCNLight_Class/index.html

We’llsoonseehowtovisuallyaddlightsandotheraspectsofthedemoviewDidLoad()functiontoourscene,butit’susuallybeneficialtounderstandtheboilerplatecodebehindthescenes.

Intheline(3),letship=scene.rootNode.childNodeWithName("ship",recursively:true)!ishowweaddourshipobjecttothescene’srootnode.Thisisnottoomuchdifferentthanotherobjectsinthescene.Ittakesthestringshipfromthenameofourship.daeobjectintheart.scnassetsfolder.Therecursively:trueparameterinthechildNodeWithNamefunctiontellsthescenethatitshouldaddallchildnodesoftheobjecttothescene.Dependingonhowthe3Dobjectwasmodeledandriggedinitsoriginal3Dmodelprogram,theobjectmighthaveacomplexarrayofchildnodes.Settingrecursivelytotruewilliteratethroughnotjustthechildnodesbuttheirchildnodesaswell.

Thefollowinglongline(partofline(4))isacompactwayoftellingtheshiptorotatecontinuallybyx,y,and/orzanglesbasedonitscurrentorientation:

ship.runAction(SCNAction.repeatActionForever(SCNAction.rotateByX(0,y:2,

z:0,duration:1)))

Thiscanbebrokendownintoitsvariousparts,asit’sanSCNActionwithinanSCNAction,namely,therotateByXfunctionwrappedintoarepeatActionForeverfunctionofSCNAction.ActionsinbothSceneKit(SCNAction)andSpriteKit(SKAction)cannotonlybeaddedtoobjectsbycodebutalsoinXcode’svisualeditor,asweshallseelaterinourreviewoftheFoxdemo.

FindmoreonboththeSCNActionandSKActionclasseshere:

ForSCNAction,refertohttps://developer.apple.com/library/ios/documentation/SceneKit/Reference/SCNAction_Class/

ForSKAction,refertohttps://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKAction_Ref/

Inline(5),wecreatetheSCNViewobjectandassignitastheviewofGameViewControllerwiththelineletscnView=self.viewas!SCNView.Thesceneanditsnodesthatwecreatedwiththeobjectnamedscenebackinline(1)thengetsassignedtothesceneattributeofscnViewviascnView.scene=scene.Thereisaslightbitofambiguityasto

whichsceneisassignedtowhatnode,butthisessentiallyhastodowiththesettingupofrootNodeitself.

Thenextfewlines(of(6))showsomeofthepropertiesthatwecanusefromtheSCNViewclass;thefirstbeingtheabilitytocontrolthecamerawiththeallowsCameraControlproperty.Settingthistofalsewouldpreventtheplayerfrombeingabletomovethecameraabout.Thiscouldbegreatforin-gamecutscenesorlockingthecameraduringapartofastagewhereitwouldbenecessary.ThelinescnView.showsStatistics=truetellsthescenetoshowanyrenderingdatathatwouldbebeneficialtodebugging.Forexample,wecouldseetheframespersecond(fps)ourgameisrunningat.

ThisisequivalenttoaSpriteKitscene’scodepartofskView.showsFPSandskView.showsNodeCount,whereskViewisthenameofanSKViewobject.

Thenextline,scnView.backgroundColor=UIColor.blackColor(),allowsustosetthebackgroundcolortoblack,justthesamewayaswedidwithambientLightNode.light!.color=UIColor.darkGrayColor()usingtheUIColorclass.

SceneKitDebuggingOptionsTipAsofiOS9,evenmoredebuggingoptionsbecameavailablethroughtheuseoftheSCNDebugOptionsstructandthedebugOptionsattributeofSCNView.

Ifweweretowritethefollowing,we’dbeabletoseeourship’sboundingboxes:

scnView.debugOptions=.ShowBoundingBoxes

ThereareotheroptionssuchasShowLightInfluences,ShowPhysicsShapes,andShowWireframe.

WWDC15’sFoxDemowiththe.ShowBoundingBoxesandShowPhysicsShapesoptionsenabled

Finally,inline(7),lettapGesture=UITapGestureRecognizer(target:self,action:"handleTap:")createsaUITapGestureRecognizerobjectnamedtapGesture,whichwillcallthefunctionhandleTap(gestureRecognize:UIGestureRecognizer)whenanytapisperformedandscnView.addGestureRecognizer(tapGesture)addsthatrecognizertothescene.

HandlinguserinputinSceneKitTheUITapGestureRecognizerobjectsaregreatinordertoselectivelyorganizetheinputwereceivefromtheplayer.ThisgoesforbothSceneKitandSpriteKitscenes.Wecanhaverecognizersfortaps,swipesineachdirection,panning,pinches,andlongpresses;longpressesaregreatforwhenyou’dneedtopossiblyhandleacharacterchargingtheirattack.

Here’sthedocumentationoftheUITapGestureRecognizerclassforreference:

https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIGestureRecognizer_Class/index.html

Let’stakealookatthathandleTapsfunctionasitcontainsanobjectoftheSceneKitclass,SCNTransaction:

funchandleTap(gestureRecognize:UIGestureRecognizer){

//(1)retrievetheSCNView

letscnView=self.viewas!SCNView

//checkwhatnodesaretapped

letp=gestureRecognize.locationInView(scnView)

/(2)

lethitResults=scnView.hitTest(p,options:nil)

//checkthatweclickedonatleastoneobject

ifhitResults.count>0{

//retrievedthefirstclickedobject

letresult:AnyObject!=hitResults[0]

//getitsmaterial

letmaterial=result.node!.geometry!.firstMaterial!

//(3)//highlightit

SCNTransaction.begin()

SCNTransaction.setAnimationDuration(0.5)

//oncompletion-unhighlight

SCNTransaction.setCompletionBlock{

SCNTransaction.begin()

SCNTransaction.setAnimationDuration(0.5)

material.emission.contents=UIColor.blackColor()

SCNTransaction.commit()

}

material.emission.contents=UIColor.redColor()

SCNTransaction.commit()

}

}

Inline(1),wearejustcreatingareferencetothecurrentSCNViewobjectnamedscnView.Next,theconstantpiscreatedusinggestureRecognize.locationInView(scnView).Whatthisisdoingiscapturingthegesture’slocationintheviewwewishtokeeptabson.Inthiscase,it’stheentireview,scnView.Ifwehadsubviews,sayagame’smenuscreen,thenwecouldifwe’dwishonlytargetgesturesthereinthisfashion.

NoteIfbuildingagamewheretheplayerhastotapatthespurofthemomentandmanytimesforacharacter’smovementordodging,wedidfindthetouchesBegan()functionalitywe

spokeaboutinSpriteKittobeabitfasterthanUITapGestureRecognizer.ThismighteventuallybecomeamootpointwitheachnewandfasteriOSdevice,butifyourgame’scontrolsareheavilydependentonquicknessoftheplayer,youmightnoticesomelaginresponsetothegesturesviatheUITapGesterRecognizerapproach.Thiscouldeffectthegoalofyourgame,sotrythetouchesBegan()functiontoseewhatworksbestforyourgame.UsingtouchesBegan()forswipesandothernon-tapgesturescouldberathertricky,sothere’satrade-offthereonthedevelopmentsidetoo.

Nextinline(2),wetakeacountofhowmanyofthesegestures,tapsinourcase,werecapturedintheviewusingthehitTest()functionofSCNViewandonlycountingifthatgesturemadecontactwithanyobjectinourscenebypassingthepositionconstant,p,asaparameter.ThefunctionhitTest()returnsanarrayofeventresults,andthecountpropertythencountshowlargethatarrayis.Wecanthencaptureareferencetothefirsttapbyreferencingthefirstmemberofthatarray.Weonlyhaveasingleobjectinthisdemoprovidedforus,thespaceship,sowecanjustgetaninstanceofSwift’smostupperparentobject,AnyObject.OurhitTestobject,hitResults,isanarraycontainingreferencestoeveryobjecttappedinthiscontext.Again,thisisjustourspaceshipobject,sowecansimplytakethefirstobjectinstancedathitTest[0].Thisiswhattheresultconstantrepresents.

Thelineletmaterial=result.node!.geometry!.firstMaterial!showsushowwegetareferencetothatobject’smaterialbydrillingdownthenode’schildrenusingthedotoperatorwhilealsoimplicitlyunwrappingeachnodeviatheexclamationpoint(!).Thismaterialreferenceisneededforwhenthetapneedstomakethespaceshipturnred.

TipThisisactuallyanicebroadexampleofhowwecanselectonlycertainobjectsinourSceneKitscenetobethefocusofaplayer’sinput.Here,itjustpicksanyobjectusingthebroadtypeAnyObjectclass,butimagineagamewhereonlyacertaintypeofcharacterorcharactersareselectable;thinkofanisometrictopdownshooterorreal-timestrategy(RTS)game.Wecouldpossiblycheckwhetherthetappedobjectonlyisamemberofacertainclasstype(isKindOfClass())orconformstoacertainprotocol(conformsToProtocol())beforetakinganyactiononthoseselectedgameobjects.WanttheplayerinyourRTSgametoonlytakeactionsonTankobjects?ThencombiningthiswithamenuthattellsthegamewhichobjecttypeisthefocuscouldbewhatgivesyouthatabilityhereinSceneKit.

Inline(3),thedefaultSceneKittemplatealsohandsusthisusefulbitofcodeshowingtheuseofSCNTransaction.TheSCNTransactionclassfirstbecameavailableiniOS8,andwecanthinkofSCNTransactionasalaundrylistofchangesandanimationswewantinthescenetotakeplaceatacertainspecifiedsetoftime.AnSCNTransactionclassbeginswiththeSCNTransaction.begin()callandendsattheSCNTransaction.commit()call.Scenegraphanimationcallsthatarewithinthatblockgetcalled,bydefault,witha0seconddelay.Inmanycases,we’dwanttocontrolthedurationoftheseanimations,thusweusethesetAnimationDuration()functionatthebeginningoftheSCNTransactionblocktosetthat.ThelineSCNTransaction.setAnimationDuration(0.5)setsthetimeto

completethisblockathalfasecond.DonotethatwithinthisblockisanotherblockofcodestartingwithSCNTransaction.setCompletionBlock{…}.WhatthisdoesisexecutethecallonlyaftertheSCNTransationblockit’swithincompletes.Inthecaseofthistemplatedemo,atfirstforhalfasecond,theshipishighlightedred,asdoneinthematerial.emission.contents=UIColor.redColor()line.Afterthiscompletes,foranotherhalfasecond,theshipisbroughtbacktoit’soriginalcolorbysettingitsmaterialemissionbacktoUIColor.blackColor().Thisisabitconfusingatfirstbutthereareaslewofanimationsandtransactionswecandoforoursceneswiththismethodinjustoneblock.Checkoutthislinktothedocumentation;othertransitions/transactionscanbeforfadingin/out,camerafieldofview,rotation,translations,lighting,andmore:https://developer.apple.com/library/prerelease/ios/documentation/SceneKit/Reference/SCNTransaction_Class/index.html#//apple_ref/occ/clm/SCNTransaction/valueForKey

AsforthedefaultSceneKittemplate,that’sallthecodeusedtomakethescene.It’sabasicsceneandfarfromagame,butitshouldgiveusabasicunderstandingofwhatessentiallymakesupthemainstructureandlogicofasceneinSceneKit.BeforewelookintotheFoxdemoandthusanactualfullgameproject,let’slookatafewotherfeaturesthatwereaddedtoXcodeasofiOS9/Xcode7.

SceneKitfeaturesintroducediniOS9/Xcode7Let’sgobacktotransitionsandanimations.AsofiOS9,wecanchangeacharacterorother3Dobject’sblendmodeveryeasilyinSceneKit.

AdisplayofthevariousblendmodesinSceneKitfromWWDC2015

Blendmodescanbechangedsimplywithoneline,aSCNMaterial.blendMode=.Add,whereaSCNMaterialisanobjectrepresentingthematerialofSCNNode.Changingblendmodescancreateanumberofeffects.Somegamesuseaplayer’sghosttoshowapastrunthroughtheyaretryingtobeat,orthere’sthefadeeffectbosscharactersmakewhendefeated.CombinewithSCNTransactiontohavecharactersfadeinandoutofthesemodes.

Audionodesand3DsoundAsofiOS9,wecanplace3DsoundsintoourSceneKitscenes.TheaddAudioPlayer()functionoftheSCNNodeclassfunctionletsusappendasoundtothatnode,andwhereverthatnodeisin3Dspace,thesoundwilladhereto3Daudiomixing;thatis,iftheaudiosource’spositionalpropertyissettotrue.Here’showwe’dcreate3Dsoundwithaudionodes:

letsource=SCNAudioSource(named:"sound.caf")

letsoundEffect=SCNAudioPlayer(source:source)

node.addAudioPlayer(soundEffect)

source.positional=true

source.loops=false

Thisgivesasoundeffecttothegameobject,theSCNNodenamednode.

Toactuallyplaythesound,we’dneedtocallSCNActiononit,asshown:

letaction=SCNAction.playAudioSource(source,waitForCompletion:true)

node.runAction(action)

ThewaitForCompletionpropertymakessurethattheactiongoesaslongasthesoundis.Thismightnotbethebestforacharactersoundeffectthoughasyoumightwantitstoppedmidway(thatis,theplayerhitstheenemy,cancelingtheirpreviouslystartedchant,yell,orsomethingtothatdegree).

AmbienceandmusicToaddmusicandambience,wecouldfollowexactlythesamemethodasaddingasoundeffecttoanode:createanSCNAudioSourceobject;addthattoanSCNAudioSourceobject;andaddthistoournodewithaddAudioPlayer.Theonlydifferenceisthatwe’dloopthemusicandsetit’spositionalpropertytofalseasfollows:

source.positional=false

source.loops=true

SpriteKitscenetransitionsinSceneKitSpriteKithassomegreatscenetransitions.Wecouldmakeitlooklikeadoorisopeninguporapageisturning.Thiscouldaddextracharacterandpolishtoyourgame.BeforeiOS9,wecouldn’tdothese2Dtransitionsinour3DSceneKit,butsinceXcode7andiOS9,wecandosoinSceneKitandhere’show:

aSCNView.presentScene(aScene,withTransition:aSKTransition,

incomingPointOfView:nil,completionHandler:nil)

Again,aSCNViewisjustageneralreferencetosomeSCNViewobjectandwhenwepresentthescenetothatview,wehavetheoptionofpassinganSKTransitionobjectforthewithTransitionparameter.TheincomingPointofViewparametercanbeareferencetoacamera’spointofviewduringthetransition,andthecompletionHandlerparameteristhenameofacompletionblockthatiscalledafterthescenetransitions.Forexample,wecouldcallthefunctionsthatstartthecountupofourlaststage’sscoreinascorescenethatwastransitionedtoafterthestagecompleted.Wemightnotwanttobeginthecountingandotherfunctionsofthenewsceneuntilweknowthatthescenehasbeen100%transitionedtoor,inthiscase,afterweknowthetotalpointsfromthepriorscene.

CheckoutsomemoreexamplesofSKTransitionontheclassreferencepage,maybethere’satransitionthatcouldhelpaddtoyourgame’sdesign:

https://developer.apple.com/library/prerelease/ios/documentation/SpriteKit/Reference/SKTransition_Ref/index.html

FoxdemoWe’vebeenspendingmuchofourtimeinbothSpriteKitandhereinSceneKitontheboilerplatecodethatmakesupourgamelogic.AsXcodecontinuestoupdate,sodoesthevisualdesignfeaturesforiOSgamedesignthatdon’tinvolveastrongunderstandingofcode.There’salwayssomescriptinginvolved,butoneofthekeyfeaturesingamedesignis,well,thedesignaspectofit.AttheWWDC15event,theintroductiontoiOS9andXcode7wasagreatgamedemothatcannotonlyteachussomeofthevisualdesignfeaturesthatXcodecando,butalsogivesusabeautifulstarttoaplatforminggameinSceneKit.ThatdemoisnamedFoxandgranted,thoughitactuallystarsaredpandaandnotafox,wecouldforgivethatmixupforhowfeature-richandessentialitcanbetolearnhowtodevelopSceneKit-powerediOSgames.

TheFoxdemoimageshowingourplayercharacterandlevelassets

There’smuchmoretothisdemothanwecanshowhere,soit’sencouragedtodownloaditforyourselfandcheckoutalloftheSceneKitfeaturesitprovides.WewillfocusonafewtopicsyettobecoveredineitherSceneKitorSpriteKit,suchasparticles,physics,andthescenegraph.TheFoxdemoalsomakesuseof3Dgame/artdesignfeatures,suchasskyboxes,ambientocclusion,cubemaplighting,collisionmeshes,andmore.Itreallyisanice-qualitydemotomakebeautifulgamesiniOS.

HereisthedownloadlinkprovidedbyApple:

https://developer.apple.com/library/prerelease/ios/samplecode/Fox/Introduction/Intro.html

NoteAtthetimeofwriting,theFoxdemowaswrittenonlyinObjective-C.Wehavefocusedon

Swiftintheentiretyofthisbook,butdon’tworrytoomuchifsomeaspectsofObjective-Careforeigntoyou.ThegoalistoseethevisualtoolsXcodeprovides.Inafuturedate,theFoxdemoisboundtobeavailableinSwift,beitbyApplethemselvesorbythird-partyprogrammers.

ParticlesystemsSomeofthebasicassetsinanygame,beitSpriteKitorSceneKitbuilt,arethevariousparticleeffectswe’daddtocharacters,objects,oranentirescene.Particlescanaddtothefeelofcollectingthatitem,givetheplayerasignalthatsomethingishappeningtotheplayer,liketheyaregainingorlosinghealth,orshowthepresenceandpowerofanincomingbossfight.

CollectableparticleeffectfromtheFoxdemo

Inthepast,theprocessofmakingaparticleeffectwouldbetomanuallycreatesometimesrathercomplexparticleemittershaderobjectsusingOpenGLcode.Thiscanstillbedoneifwesochoose(usingeitherApple’sfast,low-levelAPI,Metal,orOpenGL),butovertime,theprocessofvisuallycreatingandeditingparticleeffectshasgotteneasier.NottoolongagointheiOSdevelopmenthistory,frameworkssuchasCocos2D/Cocos3Dallowedustousethird-partyparticleeffectsbuilderstoimportintoourgames.WithbothSpriteKitandSceneKit,XcodeasofaboutiOS7/iOS8,amorevisualrepresentationofparticleswascreatedinXcodethussavingusalargeamountoftimeandeffortincreatingtheeffectswewantandexpecttoseeinourgames.TheimagepreviouslyshowndisplaystheXcodeparticlesystemseditorwiththeFoxdemo’scollectablesparkleeffect.

TocreateyourownparticleeffectinSceneKit,followthesesteps:

1. CreateanewfileaswedidinthepastbynavigatingtoFile|New…orsimplythekeyboardshortcutcommand+N.

2. WethenselecttheResourcesectionunderiOSandselecttheSceneKitParticleSystemtemplate.(IfworkingwithSpriteKit,selectSpriteKitParticleFile.)

3. BoththeSpriteKitandSceneKitparticleoptionsgiveusalistofbasicparticletemplateswecanstartfrom,suchasReactor,Sparkle,orBokeh.Selectoneofyourchoosingorcheckoutacollectableonehereinthedemo.ForSpriteKit,thiscreatesanSKSfileandtheimagemaskfortheparticles.TheSceneKittemplatecreatesthe3DparticleeffectviaanSCNPfileandtheimagemask.

Let’stakealookbackattheparticlesystemwecreatedforthecollectableparticleinthedemo.Ifnotselectedalready,clickontheattributesinspectortoviewvariouscontrolswecanedittocustomizeourparticleeffects.

Feelfreetotestanumberofthevariablesandfieldswithintheinspector.There’sthebirthrate,whichcontrolshowoftentheparticlesrestarttheirstartandendanimation,theimage,whichcanmakeuptheshapeandcoloroftheparticles,andthevariousanglesthatdeterminetheoveralldirectionoftheeffects.There’salsotheLoopingdropdown,whichkeepstheparticlesrepeatingduringthelifeoftheparticlesysteminthescene.Additionally,theaffectedbygravitytoggleiswhatweusetohavetheparticlesfallbasedonthescene’sgravity.Thecollectionparticlesloopconstantlywithoutgravity,andtheconfettiparticleshappenonceandfalltogravity,aswe’dexpectconfettitobehave.Ifanobjectinourscenehasaphysicsfield,wecanalsohavetheparticlesreacttothat.

PlacingparticlesintoourpiosceneWhenwecreateSpriteKitorSceneKitparticles,wecancalltheminoursceneviacodeineithertheSpriteKitorSceneKit:

SpriteKitSpriteKitparticlesaren’tintheFoxdemobuttobacktrackabittoourtalkonSpriteKit,ifwe’dwantedtoaddparticlestoa2DSpriteKitgame,here’sanexampleofhowwe’daccomplishthat:

//(1)

varpath=NSBundle.mainBundle().pathForResource("Spark",ofType:"sks")

//(2)

varsparkParticle=NSKeyedUnarchiver.unarchiveObjectWithFile(path!)

as!SKEmitterNode

//(3)

sparkParticle.position=CGPointMake(self.size.width/2,

self.size.height)

sparkParticle.name="sparkParticle"

sparkParticle.targetNode=self.scene

self.addChild(sparkParticle)

1. Wecreateapathtoourapp’sbundlewiththeNSBundle.mainBundle().pathForResource()functioncall,andwepassthestringoftheparticlefile’sname,inthiscase,Spark,withthefiletype,SKS.

2. Next,wecreatethesparkParticleobjectusingtheNSKeyedUnarchiver.unarchiveObjectWithFile(path!)callthat,aswesee,takesthepathwecreatedinpart(1).It’scastedastheparticleobjectforSpriteKit,SKEmitterNode.NSKeyedUnarchiverisaclassusedtodecodenamedobjectsfromkeyedarchives,anencodedhierarchyofarchives.Thisclasshassomesupportofwhatisknowntypecoercion.Inshort,itcandecodeobjectsinfiles,beitwhetherina32-bitor64-bitarchitecture.Moreonthisspecialfiledecodingclasshere:https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSKeyedUnarchiver_Class/

3. Wethensetapositionandnameforthisparticleeffectandtargetittothescenewhilealsoaddingittothescenenode.

Thoughthisexampleisn’tgivenintheFoxdemo,thisisagreatexampleofhowwecantargetspecificfilesinourproject’snavigationhierarchy.

SceneKitSceneKitparticlesaremembersoftheSCNParticleSystemclass.WeaddtheseparticlestoourscenewiththeaddParticleSystemfunctionoftheSCNNodeclass.TheFoxdemodoesthisinthecollectFlower()functionwiththefollowingObjective-Cline:

[self.gameView.sceneaddParticleSystem:_collectParticles

withTransform:particlePosition];

Whatthiscodeisdoingiscallingthesceneinthedesignatedviewandaddingthe

particles,whicharedeclaredearlierintheclassas_collectParticlestoourscene.Itthentellsthesceneatwhichpointinspacethiseffectwillappear.Inthiscase,it’stheparticalPositionvariablethatwhentracedbackistakenfromtheSCNNodeparameterpassedintothecollectFlower()function.

NoteHere’showthiswouldbewritteninSwift:

scene.particleEmitNode.addParticleSystem(_collectable!)

Swift’saddParticleSystemAPIunfortunatelydoesn’thavethewithTransformparameterasinObjective-C,sowe’dhavetoaddtheparticlesystemtothenodeitwillbeemittingfrom,whichisdenotedbytheparticleEmitNodevariable.ThismostlikelywillchangeinfutureAPIchangesofSwift2.xandlater.

IntroducingSceneKitandSpriteKitphysicsWhenwelookatthecollectFlower()functionfromourparticleexample,weseethatthere’sanSCNNodeparameterpassed.ThisnodecomesfromthefunctionphysicsWorld.InbothSpriteKitandSceneKit,wecancreateanoverallsetofphysicsrulesandhandlevariousphysics-relatedinteractions,mostnotably,contactsbetweentwoormorenodes.Oneofthemostbasicaspectsofanygameistodosomethingwhengameobjectshiteachother.Thiscouldbewhentheplayertouchesacollectable,whenenemiescontacttheplayerortheplayerhitstheenemywithanattack.IniOSdevelopmentandingameengines,wecalltheseboundariesbetween2Dspritesor3Dobjectsasboundingboxes.WementionedthesephysicsobjectsbrieflyinourtalkofiOS9andlaterdebugOptionsproperty.BoundingboxesforSceneKitobjectsarecreatedautomaticallybasedonthesimplifiedversionofanobject’sgeometry,butwecanedittheseshapeswiththeSCNBoundingVolumeclass.

Moredocumentationofthisclasscanbefoundathttps://developer.apple.com/library/prerelease/ios/documentation/SceneKit/Reference/SCNBoundingVolume_Protocol/index.html

GamephysicsiniOSandgamedevelopmentingeneralaremuchlargertopicsthanwecandiscussinthischapter.Sofornow,let’sjustseehowtheFoxdemoandiOSgamesingeneralhandlethesimpleconceptoftwonodescontactingtheirboundingboxes.

funcphysicsWorld(world:SCNPhysicsWorld,didUpdateContactcontact:

SCNPhysicsContact){

if(contact.nodeA.physicsBody.categoryBitMask==

AAPLBitmaskSuperCollectable){

self.collectFlower(contact.nodeA)

}

if(contact.nodeB.physicsBody.categoryBitMask==

AAPLBitmaskSuperCollectable){

self.collectFlower(contact.nodeB)

}

PrecedingisaSwiftpseudocodeexampleoftheFoxdemo’sphysicsWorldfunction.Thefunctiontakesintwoparameters,worldofthetypeSCNPhysicsWorldthatrepresentstheentirephysicsenvironmentofasceneandtheobjectrepresentingthephysicscontactofthetypeSCNPhysicsContact.Thefunctionherechecksthebitmaskofthenodesinthecontact.Ifthefirstorsecondnodeofthecontact(nodeAornodeB)areintheflower’sspecificcategory,thenthecollectFlower()functioniscalledandthatcollectable’snodeispassedasaparameter.

Bitmaskingiswhenwedesignateasetofbitsforanothersetofbitsthatcanbecombinedtogetherusingbitwisemath.Thinkofitasusing1sand0stonotonlycategorizearangeofonesandzerosbutalsoallowustohandlesituationswheremanycategorieshappeninthesamecontext.

Forexample,wehavedifferentcategoriesofobjects/eventsinourgameandwefitthemin

theirownslotsinabyte(8bits).IntheFoxdemo,thegamecollisionsareabitshiftvalueof2,thustheyrepresent00000100inbinary.ThecategorydesignationofcollectablesintheFoxdemoabitshiftof3or00001000,theenemiesare4,00010000.

Inthedemo,weseethefollowingcodeforAAPLBitmaskSuperCollectable:

//Collisionbitmasks

typedefNS_OPTIONS(NSUInteger,AAPLBitmask){

AAPLBitmaskCollision=1UL<<2,

AAPLBitmaskCollectable=1UL<<3,

AAPLBitmaskEnemy=1UL<<4,

AAPLBitmaskSuperCollectable=1UL<<5,

AAPLBitmaskWater=1UL<<6

};

WhenthecategorybitmaskineithernodeAornodeBofthecollisionmatchtheflowercollectable(iftheslotisonpersay,orequalto1,thenweknowthecollectablewasinvolvedinthecollision).

Swiftversion1didn’treallyhaveasimilarwaytomimicbitmaskingasdoneinObjective-CwithNSOptions,butasofSwift2.0,wecanperformbitmaskinglikethedemointhefollowingway:

structAAPLBitmask:AAPLBitmaskType{

letrawValue:Int

init(rawValue:Int){self.rawValue=rawValue}

staticvarNone:AAPLBitmaskType{returnAAPLBitmask(rawValue:0)}

staticvarAAPLBitmaskCollision:AAPLBitmask{return

AAPLBitmask(rawValue:1<<2)}

staticvarAAPLBitmaskCollectable:AAPLBitmask{return

AAPLBitmask(rawValue:1<<3)}

staticvarAAPLBitmaskEnemy:AAPLBitmask{returnAAPLBitmask(rawValue:

1<<4)}

staticvarAAPLBitmaskSuperCollectable:AAPLBitmask{return

AAPLBitmask(rawValue:1<<5)}

staticvarAAPLBitmaskWater:AAPLBitmask{returnAAPLBitmask(rawValue:

1<<6)}

}

Essentially,it’sastructthatreturnsbitshiftedstaticvariablesofitself.It’snotaselegantasseeninObjective-CandinpastCimplementation,butifwewishtousebitmaskinginboilerplatecodeinSwift,thisshouldallowyoutodoso.

OnelastnoteaboutthephysicsWorld()function,inorderforthefunctiontobecalledduringthecollisionoftwophysicsbodies,weneedtosetthephysicsworlddelegate.Inmostcases,thatdelegatewouldbethecurrentgamescene.

scene.physicsWorld.contactDelegate=self

Xcodewillmostlikelytellyouthataphysicsworlddelegatewasn’tsetandifyouhaven’t,thisisthecodethatisusuallyplacedintheviewDidLoad()functionofViewController.

VisuallycomposedgamescenescgsGettingbacktothevisualaspectsoftheFoxdemo,let’slookatthegamesceneobjectscreatedintheprojectandhowwecanviewthenodesinwhat’sknownasthescenegraph.

WeseethatgameobjectsandparticleeffectsintheFoxdemocanbevisuallymanipulatedinXcodeandtogetherinoneview.Theprecedingimageshowstheflowercollectableanditscomponentsthatconsistofthe3Dmesh,lighting,boundingboxes,andtheparticleeffects.InSceneKit,wedothiswithaSceneKitscenefile(SCN).

Toviewthescene’sscenegraph,clickonthesidewindowiconfoundtowardthebottom-leftoftheXcodewindowunderthevisualeditorwindowofthescene,asseeninthefollowingscreenshot:

Thisisascreenshotofthescenegraph.Thosefamiliarwiththegameengines,suchasUnityandUnrealEngine,willbequitefamiliarwiththistypeofcomponent/gamesceneview.Thescenegraphshowsthedropdownhierarchyofalltheobjectsinthesceneincludingtheirowninternalcomponents.Theflowerpower-upconsistsofa3Dmeshmodelnamedflowerthathastwochildparticleeffectsaswellasaphysicsbody.Allthreearedenotedbythethreesymbolsseenontheright-handsideofthegraph’sobjects.

Wecanmovethemodelaroundinthescene,usingX,Y,andZmarkersseenintheprecedingimage.Wecanalsozoomin,zoomout,rotatethescene,aswellasaddmoreobjectstothescene.

Toaddmoreobjectstothescene,followthese:

1. Gotothemedialibraryfoundinthelibrarywindowsatthebottom-rightofthescreen(seeninthepriorimage).

2. Nowsearchforgrassandsimplydraganddropitintothescene.Nowthepremadegrassobjectisinthissceneasareference.

3. Thisisactuallyhowthelevel.scnfilewascomposed.4. There’salsotheoptiontoaddprimitiveobjectstothesceneandbuildthemupfrom

there,whichisagainverysimilartothedesign-centricgameengines.Simplyselectfromtheobjectlibrarytabrightnexttothemedialibraryiconandsearchgeometry.Thereareprimitiveobjects,suchasspheres,planes,andboxes.

5. Theprimitiveobjectslackthelighting,materialsandotherdetailsthatwecanseeinthegrassandotherpremadeobjectsintheprojects.Usetheevenmoredetailedinspectorwindowsfortheseobjectstoseeandeditvariousdetails,suchasthephysicsbodies,materials,bakingthelighting,andobjectnameidentificationforanyscripting/coding.

6. There’salsoactionsthatcanbeaddedtotheseobjects.Clickonthesecondaryeditoricon(theupsidedowntriangleinasquareatthebuttonrightoftheflowscene’sview).ThiswillopenthesecondaryeditorthatshowsaRotateByEuleractioniftheflowerassetisselectedinthescenegraph.

7. Whatthisactiondoesisrotatethefloweronceeverysecond.Toseethisinaction,clickonthePlaybuttonseenjustabovethesecondaryeditorwindowtimeline.Wecanseehowthisobjectwillrotatefromthisaction.

8. Theactioncanbeshortenedorextendedbyexpandingorcondensingitinthesecondaryeditortimeline.MoredetailsabouttheactioncanbeeditedintheInspectorwindow,andifwe’dlike,wecanusethelibrarytoaddmoreactionstothisobjectorremovetheoneprovidedtohaveitactinadifferentway.

Testoutafewactions,times,andpropertiesyourself.Wecanseehow,withoutanycode,wecansetupascenevisuallyanddynamicallycontrolactionsofeachobjectinthatscene.ManyofthesevisualfeaturesandactionsworkforbothSceneKitandSpriteKitscenes.

Lookatthelevel.scnfiletoseeascenewithafullycomposedlevelcameraobject(asseeninthepreviousscreenshot).Doyouwanttomakeasimilarlevelwithmaybemoreobstaclesandadifferentskybox?Copythelevelandchangethoseassetsandnameitlevel2.Thiscansaveamonumentalamountoftimeinthedesignofgamesandlevels.FromXcode7onwards,wehavetoolsdirectlyintheIDEthatoriginallywereonlyforthemultiplatformgameengines.Itreallyputsthedesignbackintogamedesign.

Muchofthemanualcodewe’vegoneovercouldgetdaunting,especiallyforthoseofuswhomaywanttogetintogamedesignbutarestillrelativelynewtocoding.

//Objective-C

SCNScene*scene=[SCNScenesceneNamed:@"game.scnassets/level.scn"];

//Swift

letscene=SCNScene(named:"game.scnassets/level.scn")!

Thisisallweneedtoreferenceascenefromthevisuallydesignedtools.Addittotheview’srootnodelikewespokeaboutintheSceneKitbasictemplateandit’sreadytogo.Usecodetoaddspawningenemies,theplayer,andthe2DSpriteKitoverlay(whichcanitselfhaveactionsandvisualdesignsinitsSKSfile),andit’safull-fledgedgame.

FormoreinformationontheSceneKitframeworkaswellasthelatestupdatesandadditionstoitslibrary,seethefulldocumentationlinkasfollows:

https://developer.apple.com/library/ios/documentation/SceneKit/Reference/SceneKit_Framework/

SummaryAtthestartofthischapter,wefirstspokebrieflyaboutthehistoryof3DgamedesigniniOSandhowSceneKitcametobefromthenecessitytohaveafirst-party,dynamicallyrobustframeworkaimedatthecomplexitiesof3Dgamedevelopment.WethenwentoverthebasicstructureofSceneKitandhowitandSpriteKitfromthepreviouschapterworkofftheconceptofnodes,startingfromtheviewandmovingontothescenenodeandchildnodesinthatscene.Next,wewentoverhowSpriteKitandSceneKitcanbeusedtogetherinthesamesceneaswethenmovedontodissectingthedefaultSceneKittemplategiventousinXcode,anditsvariousassets.Inadditiontoareviewoftemplateproject’scode,wealsoreviewedsomeofthefeatures,code,andassets,suchastheaudionodes,lendmodes,anddebugoptionsthatbecameavailableasofiOS9/Xcode7.Finally,fortheremainderofthechapter,wespokemuchabouttheFoxdemoshownduringtheWWDC15conventionandthevariousvisualgamedesignfeaturesthatbecameavailablesincetheannouncementofXcode7.

Forournextchapter,wewillgointothefeaturesoftheGameplayKitframework,whichweintroducedbrieflywhenwewentoverthebenefitsofusingcomposite-basedstructuringwhenbuildingourgames.WithGameplayKit,wecanduplicateandreusepremadegameactionsandrulesaswedidhereinthischapterwiththevisualcomponentsofourgames.

Chapter5.GameplayKitFormanyyears,videogamedevelopmenthasreliedonthetenetsofobject-orienteddesign(OOD).OfthecorefeaturesinOOD,theconceptsofinheritanceandpolymorphismhavebeenthemostusefulinthisbranchofsoftwareengineering.Itmakessensetothinkofentitiesinourgamesashomogenousgroupsofobjects;objectsthatwethenwriterulesforinhowtheyinteractwitheachother.Forexample,thankstoinheritance,allobjectsinourgamecanbegiventheclassnameofGameObject;theyhavefunctionswe’llusethroughoutthegameandthenwecanbranchthemoffintochildclasses,suchasPlayerorEnemy.Wecanthencontinuethatthoughtprocessaswecomeupwithmorespecifictypesofentities,betheyobjectssuchasPlayer,differentenemies,non-playercharacters(NPCs),orwhatevermakessenseforthegamewearemaking.Callingafunctiononthoseobjects,suchasShoot()orHealth(),couldbeuniqueforeachchildoftheparentclassandthuswemakeuseofpolymorphisminOOD.

However,asmentionedinthepreviouschapter,althoughinheritance-basedstructuringisgreatformostsoftwareapplications(includingsimplegames),theuniqueneedsandpairingsofvideogamerulesandentitiescauseinheritance-basedstructuringtobreakoneoftherulesofOOP.Thatruleisthereusabilityofourcode.Thesolutiontothatproblemistoseparatethegameobjectsandthegame’srulesintowhat’sknownascomponent-basedstructuring.Buildinggameswiththismentalitycanallowustobuilduniqueobjects,actions,andruleswiththeabilitytonotonlyshiftthemaroundthroughoutoursinglegameproject,butalsotousetheminotherprojects,cuttingtheoverlycustomizedstructuringinwhichbuildingagameviainheritance-basedstructuringcancause.

Apple’ssolutiontothisissueistheGameplayKitframework.GameplayKitisacompletelyindependentframeworkthatcanbeusedwithbothSpriteKitorSceneKitgames,aswellasgameswritteninlow-levelAPIs,suchasOpenGLandMetal.FirstannouncedforiOS9andXcode7atWWDC15,GameplayKittakesthecommonmethodologiesandconceptsusedingamedevelopmentforyearsandallowsustoworkonthoseaspectsindependentlyofwhatisbeingdrawnonthescreen.Thisframeworkdoesn’thandlewhat’sdrawnonthescreenandis,thus,madespecificallyfortheModelportionofMVC.

ThereareseveralgamedevelopmentconceptshandledbyGameplayKit,whichweshallreviewinthischapter.Theseconceptsareentitiesandcomponents,statemachines,agents,goals,behaviors,pathfinding,MinMaxAI,randomsources,andrulesystems.

EntitiesandcomponentsWecanthinkofentitiesastheobjectsinourgame.Theycanbetheplayer,anenemycharacter,anNPC,leveldecorationsandbackgrounds,oreventheUIusedtoinformtheplayeroftheirlives,power,andotherstats.Theentityisthoughtofasacontainerofcomponents.Componentsarebehaviorsthatdictatetheappearanceandactionsofanentity.Onemightask,“howisthisanydifferentfromobjectsandfunctions?”Theshortansweristhatobjectsandfunctionsininheritance-baseddesigndescribemoreofwhatourgameobjectsare,whileworkingwithcomponent-basedstructuringfocusesmoreonwhattheydo.AswedealwiththeclassesandfunctionalityoftheGameplayKitframework,wewillbeabletogetabetterhandleonthis.Inthisframework,we’llseethatentitiesandcomponentsarehandledwiththeGKEntityandGKComponentclasses,respectively.

NoteIfyouarestillabitconfusedaboutcomponent-basedstructuring,checkbackinourpreviouschapterwherewewentintothisinabitmoredetail.Youcanalsovisitthedeveloperpageaboutthisdesignmethodologyhere:https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayKit_Guide/EntityComponent.html

UsingGKEntityandGKComponentobjectsinourgamesAnyonefamiliarwithJavaorC#willunderstandtheconceptofanabstractclass.TheGKComponentclassisessentiallyanabstractclass.QuotingfromthespeakersatWWDC:thinkofcomponentsas“littleblackboxesoffunctionality.”ObjectsoftheclassGKEntityarelikeourgenericGameObjectclassmentionedbefore.However,unliketheobjectswe’vedealtwithbefore,wetypicallydon’taddtoomuchinthewayofcustomfunctionalitytothem(otherwise,we’dbeleaningtowardsinheritance-basedstructuring).

WefirstcreateagameobjectandsubclassitasamemberoftheGKEntitytype.Forthisexample,let’sjustcallourobjectclassGameEntity.Also,don’tforgettoimporttheGameplayKitAPI:

importGameplayKit

classGameEntity:GKEntity

Again,ourgoalwithanobjectofthetypeGKEntityistouseitasacontainerforGKComponentobjects.ObjectsoftheGKEntityclassinheritthefollowingfunctions:

components:ThisisapropertythatreturnsanarrayoftheGKComponentsinourGKEntityobjectaddComponent(_:):ThisisafunctionthatweusetoaddGKComponentstoourGKEntity

removeComponentForClass(_:):ThisremovesacomponentforaclassofGKEntityobjectsupdateWithDeltaTime(_:):Thisupdateswiththerender/gameloopforeachcomponentintheentity;thisiswhat’sknownasper-entityupdating

ThelastfunctionintheGKEntityclass,updateWithDeltaTime(_:),isoneofthetwomechanismsusedbyGameplayKitwhendispatchingupdatestoourgameobject’scomponents.Theupdatemechanismsareasfollows:

Per-entity:Thisisgoodforupdatingsmallergamestructureswithoutcausinglag.TheupdateWithDeltaTime(_:)functionofGKEntitycallsalloftheentityobjects’updateWithDeltaTime(_:)functionsandthendispatchesthattoallofthecomponent’supdateWithDeltaTime(_:)functions.Per-component:Thisismadeforlargerprojectsandmorecomplexgamelogic.Whenupdatingviatheper-componentmechanism,weusetheclasstypeGKComponentSystemtocategorizegroupsofcomponentsandthencallitsupdateWithDeltaTime(_:)functiontofireoffupdatesspecifictotheclassofcomponentinstancesitmanages.GKComponentSystemdoesn’tmakenoteofyourgame’sentity/componenthierarchy,sotheycanbeusedtoefficientlyupdatemorecomplexgames.

Forexample,ifwehaveaspecificwaywewanttoupdateplayerandenemyattacks,thenwecreateanobjectoftheGKComponentSystemclass,initiateitwiththeinitWithComponentClass(_:)function,andpassthatclassofcomponents(inthiscase,

Attackcomponents)tothatsystem.It’sinthatGKComponentSystemobject’supdateWithDeltaTime(_:)functionthatwespecifytheuniqueupdatelogicforthatgroupofcomponents,independentlyoftheentityupdates.Thiscancomeinhandywhendealingwithenemy/NPCAIinmorecomplexgames.

Here’savisuallookattheseclasses:

Don’tworryifthisisstillsomewhatconfusing.ThoseofyouwhomaybemorefamiliarwiththegameengineUnitywillhaveseenhowcomponents,suchasrigidbodies,materials,andscripts,canbeaddedtoobjectsplacedinagamescene.TheconceptherewithiOScomponentsandentitiesisnotthatmuchdifferent.EachcomponentinUnityandotherenginescanbeitsownindependentlyworkingfunctionality.

Let’stakealookatthecodesnippetprovidedduringtheWWDC15conference,inbothObjective-CandSwift,showinghowwe’dcreateentities,components,andcomponentsystemsinourprojects:

//Objective-C

/*Makeourarcher*/

GKEntity*archer=[GKEntityentity];

/*Archerscanmove,shoot,betargeted*/

[archeraddComponent:[MoveComponentcomponent]];

[archeraddComponent:[ShootComponentcomponent]];

[archeraddComponent:[TargetComponentcomponent]];

/*CreateMoveComponentSystem*/

GKComponentSystem*moveSystem=

[GKComponentSystemsystemWithComponentClass:MoveComponent.class];

/*Addarcher'sMoveComponenttothesystem*/

[moveSystemaddComponent:[archercomponentForClass:MoveComponent.class]];

//Swift

/*Makeourarcher*/

letarcher=GKEntity()

/*Archerscanmove,shoot,betargeted*/

letmoveComponent=MoveComponent()

letshootComponent=ShootComponent()

lettargetComponent=TargetComponent()

archer.addComponent(moveComponent)

archer.addComponent(shootComponent)

archer.addComponent(targetComponent)

/*CreateMoveComponentSystem*/

letmoveComponentSystem=GKComponentSystem(componentClass:

MoveComponent.self)

/*Addarcher'sMoveComponenttothesystem*/

moveComponentSystem.addComponent(archer.componentForClass(MoveComponent.sel

f)!)

WhatthiscodedoesiscreateourGKEntityobjects;inthiscase,thetowergameexample’sarchercharacter.NextitaddspredefinedGKComponentobjectsviatheaddComponent(_:)function.WealsocreateaGKComponentSystemobjectnamedmoveComponentSystemthatwillbeusedtoupdateonlymovementtypecomponents.Thearcher’sownmoveComponentclassisaddedtothissystemwithmoveComponentSystem.addComponent(_:).Makeanoteofhowtheparameterspassedthroughthisobjectinadditiontoitsinitializationareclasstypesofthecomponenttypesdenotedbythe.classor.selfproperties,dependingonwhichlanguagewearewritingourcodein.

NoteAsofthispublication,thecomponentForClass()functionmightnotbefullyfunctionalfortheSwiftprogramminglanguage.SoiftheSwiftimplementationisn’tworkingasexpectedforthisandotherGameplayKitobjectinitializations,theObjective-CversionofthiscodewillneedtobeusedandlinkedtoyourprojectviaanObjective-C–Swiftbridgingfile.ThiswillmorethanlikelybeironedoutinfutureupdatestoSwiftasApplecontinuestomoveawayfromObjective-Casthemainlanguageoftheplatform.Formoreinformationonhowtomakethisbridgingfile,checkoutthislink:https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html

AppleprovidesuswithaprojectnamedMazethatusestheseclassesaswellassomeotherconceptswe’llbegoingovershortly.

Here’salinktotheprojectthatcouldhelptogiveyouanevenbetterideaofentitiesandcomponents:

https://developer.apple.com/sample-code/wwdc/2015/downloads/Maze.zip

BeforewegoovermorespecificcodeuserelatedtoGKEntityandGKComponentobjects,we’lllookintoagamedevelopmentconceptthatisbestcoupledwiththeseobjects,whichistheconceptofstatemachines.

StatemachinesAvideogame,morethananyothertypeofapplication,basesmuchofitslogiconwhetherthegameorentitiesinthatgamearecurrentlyinoneofanumberofdifferentstates.

Thiscouldbecheckingwhetherthegameisintheintroscene,runninginthemaingameplaymode,theplayerhasdied,theplayerisidle,abossenemyhasappeared,thegameisover,thestageisover,thebossislowonhealth,andmuchmore.

AnexampleofstatemachinesforeitherAIorcharacteranimations

Inthepast,ithasalwaysbeencommonpracticeforgamedeveloperstowritetheirowncustomstatemachinelogicfromscratchandthenusetheupdate/rendercycletocheckonthesevariousstates.Typicallythiswouldbedoneinacustomclassorsimplyinacustom-madeenumobjectthatwillshiftthroughvariousstates,suchas.GameOver,.MainGame,.LowHealth,andsoon.Thesestatescouldalsodescribethestatusofanindividualentityinourgameanddictatewhichanimationcycletorun.Forexample,theplayercouldbechargingtheirattackandwe’dwanttousethatstateoftheplayertoanimatethecharginganimation.Objectsinthegamescenemightcheckbackonsuchstatesviaswitchstatementstomakesurethattheyarenotdoinganyactionthatwouldn’tmakesensebasedonthecontextofthestate.Itwasn’ttoolongbeforemultiplatformgameenginesmadethisapartoftheworkflow,particularlyintheanimationhandlers.Theseobjectsthatletusinformthegameandentitiesinthegameofthevariousstatesareknownasstatemachines.GameplayKitallowsustoworkwiththisconceptinconjunctionwithitscomponent/entityfunctionality.TheframeworkprovidestheabstractclassGKStateforustosubclassfromforourgame’sstates,andtheclassGKStateMachinetoutilizeforplacingthesestateobjectsintoadesignatedstatemachine.AnobjectofthetypeGKStateMachinecanonlybeinonestateatatime,soitgivesusabetterwaytouseandreusethesestates,asopposedtotheoldboilerplate/switchstatementmethodology.

ThepreviousdiagramisfromWWDC15andusesanexampleofwhataPacMan-likeghostcharacter’s,oranyothergamecharacter’s,animationandAIstatemachineswouldlooklike.Alsonotethatnotallpathscouldleadtoeachother.Forexample,theghostcan

switchbackandforthbetweenchasingandfleeing,butcanneitherbedefeatedwhilechasingnorcoulditrespawnunlessitwaspreviouslyinthedefeatedstate.Theseareknownasstatetransitionsoredgesinastatemachine.

Bydefault,alledgesarevalidandweoverridetheisValidNextState(_:)functioninourGKStateobjects/componentstotellthestatemachineifweareallowedtomovebetweencertainstates.

Here’showthisisdoneintheDemoBotssampleprogram’sTaskBotAgentControlledStateclass.DemoBotsistheiOS9SpriteKitdemomentionedinChapter3,SpriteKitand2DGameDesign:

overridefuncisValidNextState(stateClass:AnyClass)->Bool{

switchstateClass{

caseisFlyingBotPreAttackState.Type,is

GroundBotRotateToAttackState.Type,isTaskBotZappedState.Type:

returntrue

default:

returnfalse

}

}

ThistellsthestatemachinethattheTaskBotAgentControlledStatestatecantransitiontoFlyingBotPreAttackState,GroundBotRotateToAttackState,orTaskBotZappedState.ThisobjectisanotheroftheGameplayKitcomponenttypeknownasanAgent(whichwewillgoovernext),butfornownotehowwevalidatewhichtransitionscanhappenintheisValidNextState()function.

HereweseeavisualrepresentationoftheGKStateandGKStateMachineclasses.Asstatedbefore,isValidNextState()tellsuswhichstatetransitionsarevalid.ThedidEnterWithPreviousState()functioniswherewetellourcomponentswhattodowhenthestateisentered,andthewillExitWithNextState()functioniswherewetellthecomponent(s)whattodowhenthestateisexitingtothenextstate.The

updateWithDeltaTime()function,aswithpreviouslymentionedGameplayKitobjects,iswhereweputourrender/gameloopcycleupdates.Optionally,wecanalsoaddmorefunctionalitytotheseclassesthroughinheritance.Forexample,wecancreateapreviousStatepropertytocollectmoreinformationaboutthepriorstate.Wecanthenpotentiallyusethatinformationforourownhelperfunctions,suchasexitState()orexecute().

Here’sacodesnippetshowinghowtocreatestatemachinesandhowtoaddGKStateobjectstothem:

/*Makesomestates-Chase,Flee,Defeated,Respawn*/

letchase=ChaseState()

letflee=FleeState()

letdefeated=DefeatedState()

letrespawn=RespawnState()

/*Createastatemachine*/

letstateMachine=GKStateMachine(states:[chase,flee,defeated,respawn])

/*Enterourinitialstate-Chase*/

stateMachine.enterState(chase.classForCoder)

Intheprecedingcode,weseethestatescreatedfromthepremadeclassesofGKState(chase,flee,defeated,andrespawn).ThestateMachineobject,atinitialization,receivesaparameterofanarrayofGKStateobjects,asshownin:letstateMachine=GKStateMachine(states:[chase,flee,defeated,respawn]).Then,inthisexample,westartthatstatemachineatthestatechase.This,ofcourse,willbedifferentbasedonthelogicofyourowngame’scomponents.GKStateMachineobjectscanalsoreturnthecurrentState()function;thus,wecanguidevariousentitiesandcomponentsinourgamebasedonthecurrentpulseofthegame’sobjects.

FindoutmoreonGKStateandGKStateMachineinthefollowingfulldocumentation:

https://developer.apple.com/library/prerelease/ios/documentation/GameplayKit/Reference/GKState_Class/https://developer.apple.com/library/prerelease/ios/documentation/GameplayKit/Reference/GKStateMachine_Class/index.html#//apple_ref/occ/instm/GKStateMachine/canEnterState

Nextwegooveragents,goals,andbehaviors.

Agents,goals,andbehaviorsWhenwemakeentitiesinourgames,particularlythosethatarenottheplayer,wewantthemtoperformvariousactions.Theseactionsaredictatedbyartificialintelligence(AI)thatwegivethem,andarebasedonvariousstatesofthegame,theplayer,theenvironment,ortheplayerthemselves.Wecanhaveagroupofenemiesfollowacertainpath,tracktheplayer,orautomaticallymovesmoothlyaroundobstaclesusingourgame’sphysicalworld.Theframeworkallowsustomakeourgameentitiesbewhat’sknownasagents.Agentsareentitiesthatcanhavegoalsandbehaviorsattachedtothem.

AgentsinGameplayKit,whichutilizetheGKAgentclass,canhaveGKComponentobjectsthatautomaticallysetvariousbehaviorsandarebasedontheweightoftheirgoals.Theweightofagoalisusuallyafloatfrom0to1.Thehigherthegoal’sweightvalueiscomparedwithothergoals,thegreaterthechancethattheagentwillperformthosebehaviors.Forexample,ifanenemycharacterislowonhealth,we’dprobablywanttheirHealgoaltohaveahighergoalweight.Theenemywillbehaveinafashionthatshowstheurgencyofthatcurrentlowhealthsituationbyhealingmoreoftenandthusgivingtheplayeramorechallengingandintelligentopponent.Inotherwords,agents,goals,andbehaviorsareastackableandmalleableAIsystem.

Here’sanoverviewofthisfunctionalityinGameplayKit:

Abehavior,viatheGKBehaviorclass,ismadeofanarrayofGKGoalobjectsthatareeachgivenacertainweight.Forexample,wecouldhaveaGKBehaviorclassforanNPCinaracinggamenamedRacingBehavior.Thatbehaviorwouldbeacombinationoftwogoals,suchasFollowPathandAvoidAgents.TogetherthosegoalswouldmakeacharacterinourgamethatwillautomaticallymoveawayfromotherNPCswhilestayingonthecurrenttrackforthestagewearein.

Here’savisualrepresentationoftheseclasses:

AGKAgentobject,aswecanseeintheprecedingimage,hasanumberofphysics-basedproperties,suchasmass,radius,maxSpeed,andmore.LikeotherGameplayKitobjects,itutilizestheupdateWithDeltaTime()functiontosyncwiththerender/gameloopupdatesofeitherGKComponentSystemorGKEntity.Areyoustartingtoseeapatternherewiththeseobjects?Inaway,wecanalsothinkofaGKAgentobjectbeingsimilartoaSpriteKitoraSceneKitnodesincetheyworkonourgame’sphysics.However,whetherwemadeourgamewithSpriteKit,SceneKit,orourowncustomrendercomponents,suchasinOpenGLorMetal,weneedtolinkuptheseclassestowhat’sdisplayedonthescreenwiththespecialGKAgentDelegateclass.Here’sadiagramofthatclassanditsfunctions:

TheagentWillUpdate()functioniswhatweusetotelltheagentwhattodojustbeforethegame’supdate()function,andtheagentDidUpdate()functioniswhatweusetotelltheagentwhattodoonscreenaftertheupdate()function.Thiscanbe,inthecaseofaFollowGKGoalobject,havingareferencetotheplayer’spositiononthescreenbeforetheupdatetakesplace.Here’stheexampleofthisfromWWDC15,butwritteninSwiftasopposedtotheObjective-Cexamplethatwasgiven:

funcagentWillUpdate(agent:GKAgent)

{

/*Positiontheagenttomatchoursprite*/

agent.position=self.position

agent.rotation=self.zRotation

}

funcagentDidUpdate(agent:GKAgent)

{

/*Positionthespritetomatchouragent*/

self.position=agent.position

self.zRotation=agent.zRotation

}

Let’slookatanexampletoseewhataGKGoal/GKAgentinteractionlookslike.Here’sacodesnippetfoundintheDemoBotproject’sTaskBotBehavior.swiftclass,whichisachildofGKBehavior:

//(1)

letseparationGoal=GKGoal(toSeparateFromAgents:agentsToFlockWith,

maxDistance:

GameplayConfiguration.Flocking.separationRadius,maxAngle:

GameplayConfiguration.Flocking.separationAngle)

//(2)

behavior.setWeight(GameplayConfiguration.Flocking.separationWeight,

forGoal:separationGoal)

Inline(1),thetoSeparateFromAgentsparameterofGKGoalletsuspassareferencefortheGKAgentobjectswewishtokeepacertaindistancefrom.

Inline(2),thebehavior.setWeight()functionpassesthepredeterminedfloatGameplayConfiguration.Flocking.separationWeightastheweightforthisverygoal.Thehighertheweight,themorepriorityisputonthatgoal.

You’llnoticefromthefulldocumentationofGKGoallinkedtolaterthatmuchoftheGKGoalclassdealswiththeattractionorrepulsionagentshavetoeachother.CombiningdifferentcharacteristicsofthisbasicfunctionalityletsuscreateuniquegoalsthatGKAgentparametersget,asshownhere:https://developer.apple.com/library/prerelease/ios/documentation/GameplayKit/Reference/GKGoal_Class/index.html

Tobacktrackabit,hereisamorebasicwaywecancreatetheseobjects,asshownattheconferencebothinObjective-CandSwift.

//Objective-C

/*Makesomegoals,wewanttoseektheenemy,avoidobstacles,target

speed*/

GKGoal*seek=[GKGoalgoalToSeekAgent:enemyAgent];

GKGoal*avoid=[GKGoalgoalToAvoidObstacles:obstacles];

GKGoal*targetSpeed=[GKGoalgoalToReachTargetSpeed:50.0f];

/*Combinegoalsintobehavior*/

GKBehavior*behavior=[GKBehavior

behaviorWithGoals:@[seek,avoid,targetSpeed]

andWeights:@[@1.0,@5.0,@0.5]];

/*Makeanagent-addthebehaviortoit*/

GKAgent2D*agent=[[GKAgent2D*alloc]init];

agent.behavior=behavior;

//Swift

/*Makesomegoals,wewanttoseektheenemy,avoidobstacles,target

speed*/

letseek=GKGoal(toSeekAgent:enemyAgent)

letavoid=GKGoal(toAvoidObstacles:obstacles,maxPredictionTime:0.5)

lettargetSpeed=GKGoal(toReachTargetSpeed:50.0)

/*Combinegoalsintobehavior*/

letbehavior=GKBehavior(goals:[seek,avoid,targetSpeed],andWeights:

[1.0,5.0,0.5])

/*Makeanagent-addthebehaviortoit*/

letagent=GKAgent2D()

agent.behavior=behavior

Weseeintheprecedingcodethatwhenwecreategoalsweassignagentstothemthatweareeitherseekingoravoiding.Goalsonagentscanhaveatargetspeed,asseenwiththetoReachTargetSpeed:parameter,andthesecanallbebundledupintothecurrentbehaviorwithsetweightsgiventothem.

Here’smoredocumentationonGKGoal,GKAgent,GKAgentDelegate,andGKBehavior:

https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayKit_Guide/Agent.html

OneotherthingtonoteisthattheobstaclesarrayreferencepassedhereispartoftheGKObstacleclass.Thisclassreferencesobjectsonthescenethatwetellagentstousuallyavoidwhenmovingacrossthescreen,andarepartofournexttopic,Pathfinding.

PathfindingNavigationisanintegralpartofmostgames.Wecouldhaveanoverworldsceneinourgameshowingthevariouslevelstraversedoryettobevisited,withbranchingpathwaystoeachpoint,orwecouldhavea3Dactionplatformerwithaspellthatpointsoutalogicalpathtoournextquestorbattlelocation.Wecanalsoseepathfindingintop-downisometricgames.Forinstance,theplayercouldbefightingoffahoardofenemiesalllockedontheplayer’slocationonthescreen.GoodpathfindingAIwouldnotonlytelltheenemiestomovetowardtheirgoal,buttodynamicallyavoidanyimpassableobjectsintheirwayanddetourtoabetterrouteautomatically.Inourtalkonagents,goals,andbehaviors,wesomewhatcoveredthat.Behaviors,whichGKAgentobjectsadhereto,syncwithvariousgamephysicsandthuscreatesmoothAImovementstochangewithotheragents/objectsinthescene.However,itwouldbegreattoalsobeabletoinformthesecomponentswheretheycanandcan’ttraverseinascene,andthat’swherepathfindingcomesin.

TheprecedingdiagramshowswhatPathfindingisandisanin-gamevisualgiventousbyAppleduringtheWWDC15conference.Itcanbebrokendownasfollows:

Pathfindinginvolvesnodeswithtransversalpathstoandfromthosenodesinwhat’sknownasanavigationgraph.Thesenodescanbesingledirectionalorbidirectionaland,mostimportantly,therecanbeapathcalculatedwiththisgraphthatrepresentsthebestpathaGKAgentcantake.ThesquaresshownintheearlierscenerepresentGKObstacleobjectsthatareplacedinthescene(beitbycodeorvisuallyintheXcodeeditor’stools).

Here’sthefulldocumentationfortheGKObstacleclass:

https://developer.apple.com/library/prerelease/ios/documentation/GameplayKit/Reference/GKObstacle_Class/index.html

LikeotherGameplayKitfeatures,weusevariousabstractclassestochildfromforsettingupthenavigationgraphandoverallPathfindingfunctionality;thoseclassesareGKGraph,GKGridGraph,GKGridGraphNode,andGKObstacleGraph.

It’snottooforebodingwhenweseetheprecedingdiagramofclassesandgothroughthemonebyone.Themain,andmostcommon,classusedidtheGKGraphclass.Thisiswherewecanattachtoitoneoftwodifferentgraphspecificationtypes:GKGridGraphorGKObstacleGraph.GKGraphletsusaddandremovenodes,connectthem,andfindtheoptimalpathbetweennodes.Ofthetwospecificationtypes,GKGridGraphhasasimplerfunctionalitythatismeantforeasy,2D-basednavigationgraphcreation,whereasGKObstacleGraphletsussetupanavigationgraphusingGKObstacleobjects.Nodesareautomaticallycreatedaroundthoseobstaclesbasedontheirshape,andtheseclassesdomuchofthefootworkneededtocalculatethepathsouragentsneedtotakefromthestarttothefinishoftheirsetpath(s).Ifwewanttoaddevenmorefunctionalitytoournodes,sayifwewantcustomizedmovementbasedonterraintypeinadditiontoshape,thenwecouldusethenodesofGridGraphNode.

ThecostToNode()function,forexample,canbeusedtoindicatethatthoughthispathwouldbetheoptimalpathonaflat,evenandsimilartypeplane,itwouldcostmoretotraverse.Forexample,ifthere’squicksandinourgame,theplayercouldtraverseit,soitwouldn’tmakesensetomakeanimpassableGKObstacleobjectoverthequicksand.Insteadwewouldsaythatthepathacrossthatterrainbetweenthetwonodescostsmore.Thiswillmakeourgame’snavigationsmarterandwillhandlesuchcustomparameters.

NoteThecostToNode()functionisactuallyanexampleofbestpractice.Wecanchoosetonotuseit,but,ifwearenotcareful,ourgame’spathfindingAIcouldendupratherunintuitive.Thiswouldnotonlymakeapoorexperiencefortheplayer,butendupaddingmoretimefromdebuggingfaultyAIactionslateron.

Let’slookatsomecodesamplestogetabetterunderstandingoftheseclassesandhowtoworkwiththem.DonotethatthecodeasofWWDC15isinObjective-C.

/*Makeanobstacle-asimplesquare*/

vector_float2points[]={{400,400},{500,400},{500,500},{400,500}};

GKPolygonObstacle*obstacle=[[GKPolygonObstaclealloc]

initWithPoints:pointscount:4];

/*Makeanobstaclegraph*/

GKObstacleGraph*graph=[GKObstacleGraphgraphWithObstacles:@[obstacle]

bufferRadius:10.0f];

/*Makenodesforheropositionanddestination*/

GKGraphNode2D*startNode=[GKGraphNode2DnodeWithPoint:hero.position];

GKGraphNode2D*endNode=[GKGraphNode2DnodeWithPoint:goalPosition];

/*Connectstartandendnodetograph*/

[graphconnectNodeUsingObstacles:startNode];

[graphconnectNodeUsingObstacles:endNode];

/*Findpathfromstarttoend*/

NSArray*path=[graphfindPathFromNode:startNodetoNode:endNode];

ThiscodesnippetusesthefunctionalityofGKObstacleGraphbyfirstmanuallycreating2DvectorpointsinthepointsarrayandinitializingtheGKObstacleGraphobjectandgraphwiththosepoints.Next,thetwoGKGraphNode2Dobjectsarecreatedtorepresentthestartandendnodesforaherocharacterinthegame.Then,finally,theoptimalpathforthatherocharacteriscreatedandstoredintothearrayautomatically;thatis,apathusingthegraph’sfindpathFromNode:andtoNode:parametersusingthestartNodeandendNodeobjects,respectively.Thispathobjectcanthenbeusedinourhero’smovementcomponentormaybeamapvisualcomponenttomovetoorindicatetotheplayerthecorrectpathneededtotraversethegamestage’sobstacles.

ThefollowingcodesampleishowtheDemoBotsprojectworkedwiththenavigationinSwift,usingwhat’sknownasalazystoredproperty.

MoreinformationontheSwiftkeyword,lazy,canbefoundhere:

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html

SwiftexamplefromDemoBots:

lazyvargraph:GKObstacleGraph=GKObstacleGraph(obstacles:

self.polygonObstacles,bufferRadius:

GameplayConfiguration.TaskBot.pathfindingGraphBufferRadius)

lazyvarobstacleSpriteNodes:[SKSpriteNode]=self["world/obstacles/*"]

as![SKSpriteNode]

/*theabovelinecaststheobstaclesinourproject's"world/obstacles/"

folderpathasanimplicitlyunwrappedarrayofSKSpriteNodes

*/

lazyvarpolygonObstacles:[GKPolygonObstacle]=

SKNode.obstaclesFromNodePhysicsBodies(self.obstacleSpriteNodes)

Inshort,lazyvariablesarequickarrayinitializationsinwhichtheirvaluesarenotknownatfirstandarecontrolledbyoutsidesources.InthecaseofDemoBots,theseareobstaclesthatarecreatedautomaticallyfromtheboundsofSpriteKitnodes,whichisdonebytheSpriteKitnodefunctionobstaclesFromNodePhysicsBodies().Thisexample,justshowshowmuchtimecanbesavedwhenusingtheprovidedframeworks.Inthefirstexampleandmoresoinpastgamedevelopment,muchofthislogicwouldhavetobemanuallydoneviaterriblycomplexboilerplatecodelogic.

FormoreinformationonPathfindingwithGameplayKit,checkouttheexamplesanddocumentationfoundhere:

https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayKit_Guide/Pathfinding.html

MinMaxAISofar,we’vecreatedAIthat’sgreatforthecomponentsandobjectsthatareactiveinascenewiththeirmovement,behaviors,andnavigation,butwhataboutAIthatcanunderstandthegame’srulesliketheplayer?Agoodexampleofthisisagameofchessorvariousotherboard/tile-likegames.It’dbegreattocontrolhowmuchthecomputercanmakeprogressinthegamewithvariouslevelsofdifficultyfortheplayer.Wecanalsowanttoletthegamedecideforuswhatthenextbestmoveis.Somethinglikethisiscommoninthree-matchtypegames,suchasBejeweled®orCandyCrush®,inwhichyouarelookingatgridandthegamegivesyouahint.ThistypeoflogiciswhereMinMaxAIcomesin.

MinMaxAIworksbytakinganinventoryofalloftheavailablemovesforourgameandplacingthemintoadecisiontree.BasedontheparameterswegivetheAI,wecantellithowtochoosethesedecisionbranches,typicallyintermsofgamedifficulty.Thisisdonebytakingintheplayers,alistofalltheirpossiblemovesaswellastheirscores,andpluggingthemintoaGameModelprotocolthatthenusesMinMaxAltodeterminethebestmove.TheTic-Tac-ToeexamplefromWWDC15isshownintheprecedingdiagram.NotehowsomebrancheswouldleadtomorelossesthandrawsorwinsforthecomputerAI.Aharderdifficultylevelwouldmakethecomputerplayerchoosethepathsthatmorelikelyleadtoawinforit,or,inthecaseofthosethree-matchgames,givetheplayerasuggestionforthenextbestmove.

Ofcourse,asonemighthaveguessed,thistypeoflogicisbestforturn-basedortile-basedgames.MinMaxAIcanworkinanygame,butthatgame,oratleasttheimplementationofMinMaxAI,willonlyworkifthere’sasetbaseofmovesandfuturemovesforittotakeintoitsGameModelprotocol.Anactionplatformer,unlessgivensomechoiceoffeatures,wouldn’tbeabletouseMinMaxAI,forexample.What’sgreataboutthisfunctionalityinGameplayKitisthatitdoesn’tneedtoknowthedetailsofyourgame’srules;itjustneedstheabilitytolookintofuturepossiblemoves.

TheclassdiagramshowstheclassesandfunctionsusedwhendealingwithMinMaxAI.WeseeGKGameModel,whichisactuallyaprotocolforagamestate.TheGKStateobjectsthatadheretothisprotocolneedtoprovidealistofplayers,theactiveplayer,theplayer’sscore,andtheplayer’slistofmoves,thelatterviathegameModelUpdatesForPlayer()function.WethentelltheGKGameModelobjectwhattodoasitmovesontothenextgamemovewiththeapplyGameModelUpdate()function.GKGameModelUpdateisessentiallyanabstractofagame’smoveandisusedbytheGKMinMaxStrategistclasstobuildadecisiontree,whichisthusappliedtoGKGameModeltochangethatstateinthesetGameModel()function.

TheGKGameModelPlayerclassisaprotocolforaplayerofthegamewhomakesamove,asstatedpreviously,withGKGameModelUpdate.TheplayerIdpropertyisauniquenumberyoucanset,whichisusedtodifferentiatetheplayersinourgame’slogicanddealwiththeirownsetofmoves.Thisallowstheflexibilitytohavebothahintingstructurefortheplayer(orplayersinamultiplayergame)inadditiontoalsohavingthecomputerplayerhaveanAIforitsownmoves.TheplayerIDpropertyisrequiredtoadheretothisprotocolaswewouldn’tknowtheplayerwearereferencingwithoutit.

TheGKMinMaxStrategistclassistheactualAIitselfthatistiedtothegameModelpropertywecreatedwiththepriorprotocols.ThemaxLookAheadDepthpropertyishowmanymovesaheadtheAIwilllook,themorethebetterandthenitreturnsthebestmoveviathebestMoveForPlayer()function.WecanusetherandomMoveForPlayer()functiontoaddabitofrandomnesstothenextmovechoices;thiscouldbeusedparticularlyforthecomputer’sownAItomaybepurposelycauseittomakemistakesbychoosingalessoptimalmove.

AquickObjective-Csnippetshowinghowtodothisincodeisgiveninthefollowingcode.Don’tworryaboutthesyntaxifyouareonlyfamiliarwiththeSwiftlanguagewe’veprovidedinthisbook;justgetanideaonthebasicsforsettinguptheseobjects.

/*ChessGameModelimplementsGKGameModel*/

ChessGameModel*chessGameModel=[ChessGameModelnew];

GKMinmaxStrategist*minmax=[GKMinmaxStrategistnew];

minmax.gameModel=chessGameModel;

minmax.maxLookAheadDepth=6;

/*Findthebestmovefortheactiveplayer*/

ChessGameUpdate*chessGameUpdate=

[minmaxbestMoveForPlayer:chessGameModel.activePlayer];

/*Applyupdatetothegamemodel*/

[chessGameModelapplyGameModelUpdate:chessGameUpdate];

Thisisalso,likemanyofthecodesnippetsinthischapter,takenfromtheWWDC15conference.Itusesachessgameasanexample.Theintricatedetailsofsettingupachessgamemodelareabitcomplex,sosimplytakenoteofhowinthiscodeaChessGameModelobject(whichisachildoftheabstractGKGameModelclass)isfirstcreated.Then,wecreateanobjectoftheGKMinMaxStrategistclassnamedminmax,setitsgamemodel,setitsmaxLookAheadDepthpropertyto6,andpassthegame’smoveandthecurrentactiveplayertotheminMaxobject.Finally,weupdatethegame’smodelwiththeapplyGameModelUpdate()function.It’salsodoneinObjective-Catthetimeofthispublication,butcheckouttheFourInaRowdemofoundhere:https://developer.apple.com/library/prerelease/ios/samplecode/FourInARow/Introduction/Intro.html

ThisprojectwillletusseeamorecompleteimplementationofthisAI.

ForevenmoreonMinMaxAI,checkoutthefollowingdocumentationlink:

https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayKit_Guide/Minmax.html

NextwewilltalkaboutaddingcontrolledrandomnesstoourgameswithGameplayKit’srandomsources.

RandomsourcesRandomnessingameshasbeenastapleofAI,playermoves,leveldesign,andgamereplayabilitysincetheearlydaysofgamedevelopment.Therand()functioninvariousprogramminglanguages,inadditiontoarangeofnumberstoscalethatrandomness,hastypicallybeenusedtogiveourapplicationssomelesspredictableoutcomes.However,gamessometimesneedtohavewhatweliketocallcontrolledrandomness.Whendebuggingagame,wedon’twanttoeverrunintoaproblemwhereashippedproducthasanuntestedstate.Sometimes,whenusingpastconventionsofrandomness,wecanrunintoasituationwheretheonlytimesomerareeventshappenmaybeafteragameisoutandinthehandsofthousands,ifnotmillions,ofplayerswhoaddtothetestingpoolthatwedidn’thaveinthedevelopingphase.Therefore,wemaywanttocontrolthedistributionofrandomness.Inatypicalrandomselectionofoutcomes,wegetabellcurveofresultswheretheaverageormiddle-rangedoutcomeswilloccurmoreoftenthanfringeoutcomes.Thisisfineinsomegames,butratherundesirableinothers.Anotherbitabouttherand()functionisthatitsrandomnesscanvarybasedonotherfactors,suchasthesystemit’son,thecurrentdateandtime,andotheruncontrollablefactors.Whatweneed,then,isplatform-independentdeterminismandcustomizabledistribution.WithGameplayKit’srandomsources,wecanaccomplishthat.

Weseeanumberofthedifferentclasseswecanuseintheprecedingimage.ThebaseclassisGKRandomSource,whichactuallyusestheARC4typealgorithmbydefault(viaitsGKARC4RandomSourcesubclass).ARC4isaquick/lowoverheadandhasthetypicalrandomnessthatweuseinmanyinstances.It’sdifferentfromthearc4Random()CcallinwhichinstancesofGKARC4RandomSourceareindependentfromeachother.GKRandomSourcecanalsobecomeasubclasstoeithertheLinearCongruentialortheMersenneTwisteralgorithms.Theirbenefitsanddisadvantagesareshowninthediagram.

It’snotrecommendedthattheseobjectsareusedforcryptography,soit’sbesttouseothertheencryption/hashingframeworksthatApplerecommends(https://developer.apple.com/library/ios/documentation/Security/Conceptual/cryptoservices/GeneralPurposeCrypto/GeneralPurposeCrypto.html

Theremainingclassesgiveuscontroloftherandomnumber/outcomedistributionmethodologies.TheGKRandDistributionobjectsletususehelpermethodsthat,forexample,giveustheabilitytocreatex-sideddiepiecesinadditiontolettingussetitslowestandhighestrangevalues.TheGKGaussianDistributionandGKShuffledDistributionclassesalsoletususethosehelperfunctions,butGKGaussianDistributionisusedwhenwewanttohaveabell-curvetyperandomizationwherethemiddlevalueshappenmoreoftenthanthefringevalues.Itsmeananddeviationpropertiesgiveuscontrolsonthatbellcurveandifwemaybewantmoreoccurrencesoffringevalues.GKShuffledDistribution,aswecantellfromitsname,isgreatforcreatinganevenandcompleterangedistribution,forshufflingdecksofcards,ormakingsurethateveryvalueoccursevenly.Thisclass’suniformDistancepropertyisafloatbetweenthevaluesof0.0and1.0.At0.0,allshufflingiscompletelyrandom;at1.0,thedistributionofallvaluesiseven.

Addingrandomsourcestoourgamesisverysimple.Here’ssomecodeexamplesusingtheseclasses:

/*Createasix-sideddiewithitsownrandomsource*/

letd6=GKRandomDistribution.d6()

/*Getdievaluebetween1and6*/

letchoice=d6.nextInt()

/*Createacustom256-sideddiewithitsownrandomsource*/

letd256=GKRandomDistribution.die(lowest:1,highest:256)

/*Getdievaluebetween1and256*/

letchoice=d256.nextInt()

/*Createatwenty-sideddiewithabellcurvebias*/

letd20=GKGaussianDistribution.d20()

/*Getdievaluebetween1and20thatismostlikelytobearound11*/

letchoice=d20.nextInt()

/*Createatwenty-sideddiewithnoclusteredvalues—fairrandom*/

letd20=GKShuffledDistribution.d20()

/*Getdievaluebetween1and20*/

letchoice=d20.nextInt()

/*Getanotherdievaluethatisnotthesameas'choice'*/

letsecondChoice=d20.nextInt()

/*Makeadeckofcards*/

vardeck=[Ace,King,Queen,Jack,Ten]

/*Shufflethem*/

deck=GKRandomSource.sharedRandom().shuffle(deck)

/*possibleresult-[Jack,King,Ten,Queen,Ace]*/

/*Getarandomcardfromthedeck*/

letcard=deck[0]

Aswecansee,theseareveryquick,simplelinesofcodethatallusethevariousrandomsourceclasses.Mostaresimplepropertycalls,sothatwhenwecreateourobjectsinSwift,asseenintheprecedingcode,itjustneedsoneortwolinesofcodetoutilizetheseclasstypesandtheirvariousrandomizationfunctionalities.Combiningthistothegoalweightof,say,awanderortrackAIbehavior,andwegetsomediverseandmoderatelycontrolledrandomnessfortheobjectsandcharactersinourgames.

Toreadupmoreonrandomsources/randomizationinthisframework,seethe

documentationlinkhere:

https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayKit_Guide/RandomSources.html

RulesystemsLast,butnotleast,wecometoGameplayKit’srulesystems.Thisaspectoftheframeworkuseswhat’sknownasfuzzylogicorapproximations,mainlyinthecontextoftransitionsbetweengamestates.Thisisn’tsomethingalltoonewtogamedevelopment.Anyonefamiliarwithlinearinterpolationwillberightathomeasthisispracticallythesameconcept.Unlikethetypicaluseoflinearinterpolation,whichtendstorevolvearoundtransitionsbetweenphysicalactions,GameplayKit’srulesystemsperformtheseapproximatetransitionsbetweenvariousgamestates.Thinkoftheobjects/entitiesinourgamesasnouns,thecomponentsandactionsasverbs,andtheserulesastheinteractionsbetweentheseverbsandnouns.Aswe’veseenthroughoutthischapter,thiswouldverymuchdescribegamestates.Sowhyaddanextralayertothislogic?Well,let’slookatthisexamplefromtheGameplayKitannouncement.Thisiswheretransitionsbetweengamestatesand/orentity-componentactionscouldusethisfuzzylogic:

if(car.distance<5){

car.slowDown()

}

elseif(car.distance>=5){

car.speedUp()

}

ThispseudocodecouldrepresentacarNPCinourgame.Maybeacitybuildinggame,wheretherearevariouscarGKAgentobjectsthathavethiscodeaspartoftheirbehavior.Thisseemssounduntilwegettovaluesatornear5.WhatwemightnoticeinourgameareabunchofNPCcarsacceleratingandbrakinginajerkymotion.Tosolvethis,wemakethetransitionsbetweenbrakingandacceleratingnotbesofinite,butinsteadtransitioninapproximation.

Theprecedingimageisabetterillustrationofthis,withtheoriginallogicontheleftandfuzzylogicontheright.Thiscreatesasmoothtransitionbetweenactionsorstateswhererulesystemscomeintoplay;herearetheclassesweusetoimplementthistypeoflogic:

WeusetheGKRuleSystemandGKRuleclassinstancestoutilizerulesystems.GKRulerepresentsaspecificdecisiontobemadebasedonanexternalstate,andGKRuleSystemevaluatesasetofrulesagainststatedatatodetermineasetoffacts.Wecanassertfactsorretractthem,andwecangradethefuzzinessfactorbetweentheserules.

Let’stakealookatthisincodetogetabetterfeelforit:

/*Makearulesystem*/

GKRuleSystem*sys=[[GKRuleSystemalloc]init];

/*Gettingdistanceandassertingfacts*/

floatdistance=sys.state[@"distance"];

[sysassertFact:@"close"grade:1.0f-distance/kBrakingDistance];

[sysassertFact:@"far"grade:distance/kBrakingDistance];

/*Gradeourfacts-farnessandcloseness*/

floatfarness=[sysgradeForFact@"far"];

floatcloseness=[sysgradeForFact@"close"];

/*DeriveFuzzyacceleration*/

floatfuzzyAcceleration=farness-closeness;

[carapplyAcceleration:fuzzyAccelerationwithDeltaTime:seconds];

First,thesysobjectofGKRuleSystemiscreated,andwegrabthedistancestatevalueandsavethattothedistancevariable.Wethenassert/addarulenamedclosethathappensif1.0f-distance/kBrakingDistance.Thenextfiniteruleweaddisfar,whichisdefinedasdistance/kBrakingDistance,orbasicallyanydistancegreaterthan1-distance/kBrakingDistance.Wecreatenewfuzzyvaluesofcloseandfar,namedfarnessandcloseness,thatarebasedonthegradeForFactpropertyofGKRuleSystem.Then,fromthis,wegetourfuzzyAccelerationvaluefromthedifferencebetweenfarnessandclosenessandapplythataccelerationtoourcar.Thisischeckedduringtheupdaterendercycleautomaticallyandkeepsthelogictransitionssmooth,removingjerkymovementsbetweenthedifferentstates.

ThissimpleexamplecodefromWWDC15isinObjective-C,butwecanseemoreexamples(someinSwift)inthefulldocumentationpageasfollows:

https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayKit_Guide/RuleSystems.html

Wecanalsoseesomeofthisimplementedinthedemoprojectswelinkedtopreviously.

Withtheseclasses,wecancreateanumberofcomplexrulesystemsthattransitionina

morefluidfashion.

SummaryThischapterhasgoneintoagreatdealofthisdeepandindependentgame-centricframework.Wehavefirstreviewedthebasicconceptsofentitiesandcomponents,andhowGameplayKittakesadvantageofthecomponent-basedstructuring.Wethenmovedontoastapleofgamedevelopment,theconceptofstatemachines,andhowGameplayKitutilizesthem.Then,wehavereviewedwaysbywhichwecanautomaticallycontrolcomponentsandentitiesinourgameswithagents,goals,andbehaviors,aswellasPathfinding’snavigationgraphsthataddtothisautomation.WehavelearnedthatMinMaxAIletsushintfuturemovestotheplayerorgivethecomputerasmartwayofchallengingusinvariousturn-basedgames.Finally,wehaveseenhowrandomsourcesaddcontrollablevarietytooutcomesinourgames,whereasRulesystemscankeeptransitionsofvariousstatesfrombeingtoofinite.There’smuchmoretoGameplayKitthanwecouldshowhere,soit’shighlyrecommendedthatyoureadthroughsomeofthedocumentationlinksprovidedearliertogetanevenbetterfeelforwhatthisframeworkhastooffer.Inthenextchapter,wemoveontotheMetalAPIaswellassomeothertricksandtipsthataidbestinmakingthemostoutofyourgameandkeepingyourgamesatthatalltoocrucial60fps.

Chapter6.ExhibittheMetalinYourGameUptothispoint,wehavelearnedquiteabit.WelookedintoApple’sSwiftprogramminglanguage,gotanideaofthegeneralflowofaniOSapp,andhowtocontrolthatthroughcodeand/orstoryboards.Wegotanunderstandingofhow2Dgamesand2DoverlayscanbemadewithSpriteKitandhow3DgamescanbedesignedevenintheXcodeeditorwithSceneKit.Finally,wereviewedhowtocreatereusablegamelogic,components,andAIwiththevariousaspectsofGameplayKit.

Essentially,thisisallthatisneededtogetrighttoplanning,coding,andbuildingyourowngames.Ifthere’sagameideathathascometoyourmindatthistime,gorightaheadandstartplanningitout.TheframeworksandXcodefeaturesfromthepastchapterscanhelptakeyourabstractideasandstartturningthemintowhatcouldsoonbeaplayableapplication.

However,beforemovingforward,we’dliketotakethistimetogooverafewmoretips,tricks,andtopicsthatweeitherbrieflymentionedorhaveyettogoover.ThesetopicsmainlycoverthewayswecanoptimizeourgamesandgetmoreoutoftheApplehardware.Inthischapter,weshallreviewabitontheratheradvancedtopicoftheAppleMetallow-levelgraphicsAPI.

NoteJustawarningthatthetopicoflow-levelgraphicsAPIscangetratheradvanced.Thiswon’tbeanall-encompassingtutorialonthesubject;moreofanupper-levelsummaryandawaytoappreciateallthatSpriteKitandSceneKitdointhebackgroundforus.Wehopethat,attheveryleast,itmakesyouwishtopursuehowtobuildyourowncustomrenderingobjectsthatmightpotentiallyallowthedevelopmentofextremelyperformantanddetailedgames.

TheAppleMetalAPIandthegraphicspipelineOneoftherules,ifnotthegoldenruleofmodernvideogamedevelopment,istokeepourgamesrunningconstantlyat60framespersecondorgreater.IfdevelopingforVRdevicesandapplications,thisisofevenmoreimportanceasdroppedframeratescouldleadtoasickeningandgameendingexperiencefortheplayer.

Inthepast,beingleanwasthenameofthegame;hardwarelimitationspreventedmuchfromnotonlybeingwrittentothescreenbuthowmuchmemorystorageagamecouldhold.Thislimitedthenumberofscenes,characters,effects,andlevels.Inthepast,gamedevelopmentwasbuiltmorewithanengineeringmindset,sothedevelopersmadethethingsworkwithwhatlittletheyhad.Manyofthegameson8-bitsystemsandearlierhadlevelsandcharactersthatwereonlydifferentbecauseofelaboratespriteslicingandrecoloring.

Overtime,advancesinhardware,particularlythatofGPUsallowedforrichergraphicalexperiences.Thisleadstotheadventofcomputation-heavy3Dmodels,real-timelighting,robustshaders,andothereffectsthatwecanusetomakeourgamespresentanevengreaterplayerexperience;thiswhiletryingtostuffitallinthatprecious.016666second/60Hzwindow.

Togeteverythingoutofthehardwareandcombattheclashbetweenadesigner’sneedtomakethebestlookingexperienceandtheengineeringrealityofhardwarelimitationsineventoday’sCPU/GPUs,AppledevelopedtheMetalAPI.

CPU/GPUframeworklevelsMetaliswhat’sknownasalow-levelGPUAPI.WhenwebuildourgamesontheiOSplatform,therearedifferentlevelsbetweenthemachinecodeinourGPU/CPUhardwareandwhatweusetodesignourgames.Thisgoesforanypieceofcomputerhardwareweworkwith,beitAppleorothers.Forexample,ontheCPUsideofthings,attheverybaseofitallisthemachinecode.Thenextlevelupistheassemblylanguageofthechipset.AssemblylanguagediffersbasedontheCPUchipsetandallowstheprogrammertobeasdetailedasdeterminingtheindividualregisterstoswapdatainandoutofintheprocessor.Justafewlinesofafor-loopinC/C++wouldtakeupadecentnumberoflinestocodeinassembly.Thebenefitofworkinginthelowerlevelsofcodeisthatwecouldmakeourgamesrunmuchfaster.However,mostofthemid-upperlevellanguages/APIsaremadetoworkwellenoughsothatthisisn’tanecessityanymore.

NoteGamedevelopershavecodedinassemblyevenaftertheveryearlydaysofgamedevelopment.Inthelate1990’s,thegamedeveloperChrisSawyercreatedhisgame,RollercosterTycoon™,almostentirelyinthex86assemblylanguage!Assemblycanbeagreatchallengeforanyenthusiasticdeveloperwholovestotinkerwiththeinnerworkingsofcomputerhardware.

MovingupthechainwehavewhereC/C++codewouldbeandjustabovethatiswherewe’dfindSwiftandObjective-Ccode.LanguagessuchasRubyandJavaScript,whichsomedeveloperscanuseinXcode,areyetanotherlevelup.

ThatwasabouttheCPU,nowontotheGPU.TheGraphicsProcessingUnit(GPU)isthecoprocessorthatworkswiththeCPUtomakethecalculationsforthevisualsweseeonthescreen.ThefollowingdiagramshowstheGPU,theAPIsthatworkwiththeGPU,andpossibleiOSgamesthatcanbemadebasedonwhichframework/APIischosen.

LiketheCPU,thelowestlevelistheprocessor’smachinecode.ToworkasclosetotheGPU’smachinecodeaspossible,manydeveloperswoulduseSiliconGraphics’OpenGLAPI.Formobiledevices,suchastheiPhoneandiPad,itwouldbetheOpenGLsubset,OpenGLES.Appleprovidesahelperframework/librarytoOpenGLESnamedGLKit.GLKithelpssimplifysomeoftheshaderlogicandlessenthemanualworkthatgoesintoworkingwiththeGPUatthislevel.Formanygamedevelopers,thiswaspracticallytheonlyoptiontomake3DgamesontheiOSdevicefamilyoriginally;thoughsomeuseofiOS’sCoreGraphics,CoreAnimationandUIKitframeworkswereperfectlyfineforsimplergames.

NottoolongintothelifespanoftheiOSdevicefamily,third-partyframeworkscameintoplay,whichwereaimedatgamedevelopment.UsingOpenGLESasitsbase,thussittingdirectlyonelevelaboveit,istheCocos2Dframework.ThiswasactuallytheframeworkusedintheoriginalreleaseofRovio’sAngryBirds™seriesofgamesbackin2009.Eventually,Applerealizedhowimportantgamingwasforthesuccessoftheplatformandmadetheirowngame-centricframeworks,thatis,theSpriteKitandSceneKitframeworks.Theytoo,likeCocos2D/3D,satdirectlyaboveOpenGLES.WhenwemadeSKSpritenodesorSCNNodesinourXcodeprojects,upuntiltheintroductionofMetal,OpenGLoperationswerebeingusedtodrawtheseobjectsintheupdate/rendercyclebehindthescenes.AsofiOS9,SpriteKitandSceneKituseMetal’srenderingpipelinetoprocessgraphicstothescreen.Ifthedeviceisolder,theyreverttoOpenGLESastheunderlyinggraphicsAPI.

GraphicspipelineoverviewThistopiccanbeabookallonitsown,butlet’stakealookatthegraphicspipelinetogetanidea,atleastonanupperlevel,ofwhattheGPUisdoingduringasinglerenderedframe.Wecanimaginethegraphicaldataofourgamesbeingdividedintwomaincategories:

Vertexdata:Thisisthepositioninformationofwhereonthescreenthisdatacanberendered.Vector/vertexdatacanbeexpressedaspoints,lines,ortriangles.Remembertheoldsayingaboutvideogamegraphics,“everythingisatriangle.”Allofthosepolygonsinagamearejustacollectionoftrianglesviatheirpoint/vectorpositions.TheGPU’sVertexProcessingUnit(VPU)handlesthisdata.Rendering/pixeldata:ControlledbytheGPU’sRasterizer,thisisthedatathattellstheGPUhowtheobjects,positionedbythevertexdata,willbecolored/shadedonthescreen.Forexample,thisiswherecolorchannels,suchasRGBandalpha,arehandled.Inshort,it’sthepixeldataandwhatweactuallyseeonthescreen.

Here’sadiagramshowingthegraphicspipelineoverview:

Thegraphicspipelineisthesequenceofstepsittakestohaveourdatarenderedtothescreen.Thepreviousdiagramisasimplifiedexampleofthisprocess.Herearethemainsectionsthatcanmakeupthepipeline:

Bufferobjects:TheseareknownasVertexBufferObjectsinOpenGLandareoftheclassMTLBufferintheMetalAPI.ThesearetheobjectswecreateinourcodethataresentfromtheCPUtotheGPUforprimitiveprocessing.Theseobjectscontaindata,suchasthepositions,normalvectors,alphas,colors,andmore.

Primitiveprocessing:ThesearethestepsintheGPUthattakeourBufferObjects,breakdownthevariousvertexandrenderingdatainthoseobjects,andthendrawthisinformationtotheframebuffer,whichisthescreenoutputweseeonthedevice.

BeforewegooverthestepsofprimitiveprocessingdoneinMetal,weshouldfirstunderstandthehistoryandbasicsofshaders.

Whatareshaders?GPUsfirstcameintousebecauseofnoneotherthanthevideogameindustry.Arcadecabinetsinthe1970’shadGPUchipsseparatefromthemainCPUtohandlethespecializedvisualneedsofthegamescomparedwithothercomputingapplicationsatthetime.Eventually,theneedtodraw3Dgraphicsingamesinthemid-1990’sledtothemodernGPUarchitecturewehavenow.Shaderswereactuallyfirstintroducedin1988byPixarbackwhenthecompanywasrunbyApple’scofounderSteveJobs.ShadersarelittleprogramswecanwritedirectlytotheGPUtoprocessthevertexandpixeldata.Originally,APIssuchasOpenGLES1.0didn’tmakeuseofshaderprocessingbutinsteadwerewhat’sknownasfixed-functionAPIs.Infixed-functionAPIs,programmersjustreferencedsimplesetrenderingcommandstotheGPU.AsGPUsevolvedandtookmoreworkawayfromtheCPU,theuseofshadersincreased.Althougharathermoreadvancedwaytotraversethegraphicspipelinethanthefixed-functionmethodology,shadersallowforevendeepercustomizationofwhattheGPUdisplaystothescreen.Gamedevelopersand3Dartistscontinuetopushvisualeffectsingameswiththem.

FromOpenGL2.0andonwards,shaderswerebuiltintheAPI’sC-likelanguagenamedGLSL.IntheAppleMetalAPI,webuildshaderswiththeMetalShadingLanguage,whichisasubsetofC++11ofthefiletype.metalandcanrunthepipelineineitherObjective-CorSwiftwithourviewcontrollers.

TypesofshadersShaderscomeinanumberoftypesthatcontinuetogrowas3Dgamesandartanimationcontinuestoprogress.ThemostcommonlyusedareVertexshadersandFragmentshaders.Vertexshadersareusedtotransform3Dcoordinatesinto2Dcoordinatesforthescreentodisplay,inshort,thepositioningdataofourgraphics.Fragmentshaders,alsoknownasPixelshaders,arewhatareusedtoconvertcolorsandothervisualattributesofpixelsonthescreen.TheseotherattributesofFragmentShaderscanincludebumpmapping,shadows,andspecifichighlightsaswell.Weemphasizedthewordattributesbecausethat’susuallythenamegivenforthepropertiesorinputofourshaderprograms.

HereisacodesampleofasimpleVertexandFragmentshaderwrittenintheMetalShadingLanguage.

//Shaders.metal

//(1)

#include<metal_stdlib>

usingnamespacemetal;

//(2)

vertexfloat4basic_vertex(

//(3)

constdevicepacked_float3*vertex_array[[buffer(0)]],

//(4)

unsignedintvertexID[[vertex_id]]){

//(5)

returnfloat4(vertex_array[vertexID],1.0);

}

//(6)

fragmenthalf4basic_fragment(){

returnhalf4(1.0);

Thecodehereisabitdifferentthanwhatwe’veseenthroughoutthecourseofthebook.Let’sgooveritlinebyline.

1. TheMetalShadingLanguageisaC++11-likelanguage,soweseethattheMetalStandardLibraryisimportedintotheshaderfilewiththeline#include<metal_stdlib>inadditiontousingnamespacemetal;.

2. ThenextlineisthecreationofourVertexshaderusingthekeywordvertex.Thisshaderisavertexoffourfloats.Whyfourfloatswhen3Dspaceonlydealswithx,y,andzcoordinates?Tosummarize,3Dmatrixmathinvolvesafourthcomponent,w,toaccuratelyhandlethemathcalculationsof3Dspace.Inshortifw=0,thex,y,andzcoordinatesarevectors;ifw=1,thenthosecoordinatesarepoints.Thepurposeofthisshaderwillbetodrawsimplepointstothescreen,sowwillbe1.0.

3. Here,wecreateapointertoanarrayoffloat3type(holdersforourx,y,andzcoordinates)andsetittotheveryfirstbufferwiththe[[buffer(0)]]declaration.The[[]]syntaxisusedtodeclareinputs/attributesforourshaders.

4. TheunsignedintegervertexIDiswhatwenamethevertex_idattributeofthisparticulararrayofvertices.

5. Thisiswherethefloat4typeisreturned,orinthiscase,thefinalpositionofthisvertexarray.Weseethatitreturnstwosectionsoftheoutput:thefirstbeingthe

referencetothisvertexarray,identifiedbythevertex_idattributeandthewvalueof1.0,torepresentthatthesearepointsinspace.

6. Thislineiswherewecreatethefragmentshader,usingthefragmentkeyword.Thisshaderisofthedatatypehalf4,whichisanarrayof[4,4]16-bitfloats.Thisis,inthiscase,ultimatelytocreate16-bitcoloredpixels.Thedatainthis[4,4]-componentvectortypesaves16bitstoR,G,B,andalphachannels.Thisshaderisgoingtosimplyshowpurewhitepixelshadingwithnotransparency,sowesimplywritereturnhalf4(1.0);.Thissetsallofthebitsto1,whichisequivalenttorgba(1,1,1,1).

WhenwecreateaBufferObject,whichcanjustbeaStructoffloatingpointsonthescreen,wepassthatdatathroughtheseshadersandoutwouldpopupawhitetriangleorsetoftriangleshapesonthescreen.

LookingbackattheGraphicspipelinediagram,weseethatafterthevertexshaderiscalculated,theGPUdoeswhat’sknownasPrimitiveAssembly.Thisisessentiallywherethepointsandvectorsdefinedinthevertexshaderaremappedtocoordinatesinscreenspace.TheRasterizerstep,insimpleterms,thenfiguresfromthevertexdatawhereandhowwecanandcan’tcolorthatpixeldataontothescreenusingthefragmentshaderinformation.Aftertakinginthefragmentshaderinformation,theGPUthenusesthatinformationfortheblendingofthatpixeldata.Finally,thatoutputissenttoorcommittedtotheframebufferwheretheplayerseesthatoutput.Thisallhappensinasingledrawcallintherendercycle.Havingallofyourgame’slights,pixels,effects,physics,andothergraphicscyclethroughthisin.016666secondsisthenameofthegame.

We’llgooversomemoreMetalcodelaterbutunderstandfornowthatshadersarelikelittleinstructionfactoriesfordatainputwesendtotheminourSwift/Object-Ccode.OthershadertypesthathavearisenovertheyearsareGeometryShadersandTessellationShaders.

NoteBoththeVertexandFragmentshadersarepresentinthissingle.metalfile,buttypicallyshadersarewritteninseparatefiles.XcodeandMetalwillcombineall.metalfilesinyourproject,soitdoesn’tmatteriftheshadersareinonefileornot.OpenGL’sGLSLforthemostpartforcestheseparationofshadertypes.

Foryears,OpenGLworkedwellformanydifferentGPUsbutasweallsee,AppleMetalallowsustoperformdrawcallsupto10xtimesfasterthanOpenGLES.

WhyisMetalfasterthanOpenGLES?Inlate2013,AppleannouncedtheiPhone5s.Builtintothe5swastheA7Processor,thefirst64bitGPUfortheiOSdevicefamily.ItprovidedadecentgraphicalboostcomparedwithpriordevicesandreflectedhowGPUsinmobiledeviceswerequicklycatchinguptogamingconsolesreleasedjustafewyearsprior.OpenGL,thoughastapleinlow-levelgraphicsAPIs,didn’tsqueezethemostoutoftheA7chip.

Seeninthenextdiagram,theinteractionbetweentheCPUandGPUdoesn’talwaysperformtheoptimalwaywe’dwantittoforourgames.

Beittextures,shaders,orrendertargets,drawcallsusetheirownstatevector.TheCPUviathelow-levelAPIusesmuchofthattimeverifyingthestateofthedrawcall.ThisprocessisveryexpensivefortheCPU.Whathappensisthatinmanycycles,theGPUissittingidle,waitingfortheCPUtofinishitspastinstruction.Here’swhat’stakingupallofthattimeintheAPI:

Statevalidation:ConfirmingAPIusageisvalid.ThisencodesAPIstatetothehardwarestate.Shadercompilation:Runtimegenerationoftheshadermachinecode.Thisdealswithinteractionsbetweenthestateandshaders.SendingworktotheGPU:Managingresourceresidencybatchingcommands.

WhatAppledidwiththeirMetalAPIisdothesestepsinasmarterfashion.Shadercompilationisdoneduringtheapplication’sloadtime.There’snoneedtoreloadtheshaderseverycycle;thiswassimplyarelicofolderhardwarelimitations.Thisiswhyinourpreviouscodeexample,wecanbuildmorethanoneshaderinoneMetalfile,whilethiswasprohibitedinOpenGLES.Statevalidation,thoughimportant,doesn’tneedtobecheckedeverycycle.Checkingthestatevalidationcanbesettohappenonlywhennewcontentisloaded.

NoteEvenwithMetal’sadvantages,thisiswhyit’srecommendedtostore2DanimationsinSpriteSheets.WementionedSpriteSheetsbackinourdiscussionofonSpritKit.Theyareacollectionofspritesfittedontoonetexture.Thegraphicspipelinethenonlyhastodeal

withoneversionofthatcontent.InternallyunderthehoodofSpriteKit,theGPUthendoesn’thavetodoasmanystatevectorcallscomparedtohavingeachcharacteranimationbeingplacedonitsownseparatetexture.

ThelastprocessfortheCPUiswhenitsendstheinformationouttotheGPUforprocessing.Thisisgoingtobedoneduringeachdrawcall,andineitherMetalorOpenGLES,itwillstillbethisprocessthatwillhappenthemostfrequently.Hereistheresultofthisinternal,low-levelrestructuringdoneintheMetalAPI:

AsweseeinthediagramfromWWDC14,thereareupto10extradrawcallsthatcanbeaddedduringtherendercycle!Wecanusethattimesavedforotherprocessesinsteadofextradrawcalls,suchasmorephysicsorAIinourgames.

NoteThecyclediagramsshownarefromtheoriginalMetalAPIannouncementatWWDC2014andusedaframerateof30fps.IfdevelopingforVRwhere60fpsorgreaterisnecessaryforaworkinggame,thesenumbersarehalved.EitherwaythisisratherimpressiveformobiledeviceGPUs.SearchonlineforgamesmadeinMetalandyou’dbeimpressed.Withthismuchroomtoaddmoretoourgameduringeachrendercycle,there’snoreasonnottohaveanimpressivegameatthefull60fps.Additionally,asofiOS9,theSpriteKitandSceneKitframeworksbydefaultarebackedbyMetal.EveniftheMetalAPIistoomuchtounderstand,wecanstillutilizetheserendersavingbenefitsfromwhatwealreadylearnedabouttheseframeworks.

ThebasicMetalobject/codestructureTofinishoffourtalkaboutAppleMetal,let’slookatanoverviewoftheAPI’sobjectandcodestructuring.WealreadybrieflysawsomeshadercodeintheMetalShadingLanguage,solet’sseehowwecanworkwiththisAPIinourprojects.

Objects Purpose

Device ReferencetotheGPU

Commandqueue Serialsequenceofcommandbuffers

Commandbuffer ContainsGPUhardwarecommands

Commandencoder TranslatesAPIcommandstoGPUhardwarecommands

State Framebufferconfiguration,depth,samplers,blend,andsoon

Code Shaders(vertex,fragment,geometry,andtessellation)

Resources TexturesandDataBufferObjects(vertices,constants,andsoon)

Theprecedingtablerepresentsthevarioustypesofobjectsthatwe’dworkwithifwritingagamedirectlyintheMetalAPI.TheyaretheDevice,theState,theCommandBuffer,ourShaders,Textures,andmanymore.

WecanimporttheMetalAPIintoViewController.swiftclasswiththefollowing:

importMetal

importQuartzCore

ThisimportstheMetalAPI.TheQuartzCoreAPIisneededaswellsincetheCAMetalLayerobjectwewillworkwithisamemberofthatlibrary.Also,makesurethatyousetyourtargetdevicetoanactualiOSdeviceasnewornewerthantheiPhone5S,theXcodesimulatordoesnotsupportMetal.Otherwise,XcodewillgiveyoutheCouldNotBuildObjective-CmodelMetalerror.ThisistrueasofthewritingofthisbookwiththeXcode7Beta.OvertimeandprobablyaftertheofficialpublicreleaseoftheElCapitanOS,thiswillnolongerbeneeded.Fornow,totestyourowncustomMetalcode,youwillhavetotestonanactualdevice.DoingsowillinvolvehavingtopayforyourownAppleDevelopmentaccount.Moreonthisisgiveninthenextchapter.

Here’stheorderinwhichwe’dhavetoworkwiththeobjectsinthetableshownpreviouslyaswellassomecodesamplesinSwiftthataccomplishthesesteps:

1. CreatethereferencetotheDevicewiththeMTLDeviceclassas:

letdevice:MTLDevice=MTLCreateSystemDefaultDevice()

2. CreateaCAMetalLayerobjectfortheseobjectstobeplacedonthescreenas:

letmetalLayer=CAMetalLayer()

3. CreateVertexData/BufferObject(s)(VBOs)tosenddatatoshadersasfollows:

/*SimpleVertexDataobject,anarrayoffloatsthatdrawsasimple

triangletothescreen*/

letvertexData:[Float]=[

0.0,1.0,0.0,

-1.0,-1.0,0.0,

1.0,-1.0,0.0]

4. CreateourshadersthatwillworkwiththeseVBOs.

Wedidthisinourpreviousshadercodesamples.Thevertexdatacombinedwithourpreviouslymadeshaderstogethercreateasimplewhitetriangletothescreen.

5. SetupaRenderPipelineasfollows:

//Libraryobjectsthatreferenceourshaderswecreated

letlibrary=device.newDefaultLibrary()!

//constantwherewepassthevertexshaderfunction

letvertexFunction=library.newFunctionWithName("basic_vertex")

//nowthefragmentshader

letfragmentFunction=library.newFunctionWithName("basic_fragment")

/*DescribestheRenderPipelineandsetsthevertexandfragment

shadersoftheRenderPipeine*/

letpipelineStateDescriptor=MTLRenderPipelineDescriptor()

//initiatesthedescriptor'svertexandfragmentshaderfunction

propertieswiththeconstantswecreatedprior

pipelineStateDescriptor.vertexFunction=vertexFunction

pipelineStateDescriptor.fragmentFunction=fragmentFunction

//Makesthepixelformatan8bitcolorformat

pipelineStateDescriptor.colorAttachments.objectAtIndexedSubscript(0).

pixelFormat=.BGRA8Unorm

/*ChecksifwedescribedtheRenderPipelinecorrectly,otherwise,

throwsanerror.*/

varpipelineError:NSError?

pipelineState=

device.newRenderPipelineStateWithDescriptor(pipelineStateDescriptor,

error:&pipelineError)

ifpipelineState==nil{

println("Pipelinestatenotcreated,error\(pipelineError)")

6. Createacommandqueueasfollows:

varcommandQueue=device.newCommandQueue()

Toactuallyrendertheseobjectsinourgame,we’dhavetodothefollowingprocessesinourviewcontroller:

1. Createadisplaylink.Thisisatimerthatrefresheseverytimethescreenrefreshes.It’samemberoftheclassCADisplayLinkandateveryscreenrefresh,wecallthegameRenderLoopfunction.

vartimer=CADisplayLink(target:self,selector:

Selector("gameRenderLoop"))

timer.addToRunLoop(NSRunLoop.mainRunLoop(),forMode:

NSDefaultRunLoopMode)

ThegameRenderLoopfunctioncanlooklikethefollowing.Itcallsthesoon-to-befilledinfunction,render():

funcgameRenderloop(){

autoreleasepool{

self.render()

}

2. CreateaRenderPassDescriptor.Forthisexample,amostlyredtextureistobecreatedaroundourwhitetriangleasshownhere:

letpassDescriptor=MTLRenderPassDescriptor()

passDescriptor.colorAttachments[0].texture=drawable.texture

passDescriptor.colorAttachments[0].loadAction=.Clear

passDescriptor.colorAttachments[0].storeAction=.Store

passDescriptor.colorAttachments[0].clearColor=MTLClearColorMake(0.8,

0.0,0.0,1.0)

3. CreateaCommandBufferinourrender()function:

letcommandBuffer=commandQueue.commandBuffer()

4. CreateaRenderCommandEncoder.Inotherwords,asetofcommandsforcommandQueue.Inthecodeexamplegivenlater,thistellstheGPUtodrawtriangleswiththeVBOwecreatedearlier.Thisisplaced(inthisexample)intherender()function.

letrenderEncoderOpt=

commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor)

ifletrenderEncoder=renderEncoderOpt{

renderEncoder.setRenderPipelineState(pipelineState)

renderEncoder.setVertexBuffer(vertexBuffer,offset:0,atIndex:0)

renderEncoder.drawPrimitives(.Triangle,vertexStart:0,vertexCount:

3,instanceCount:1)

renderEncoder.endEncoding()

}

5. CommityourCommandBuffer.ThisessentiallytellstheGPUtodoitsdrawcallbasedonthecommandsthathavebeenpackedintothecommandBufferobject.Placethisafterthepastcode’sifstatementintherender()function.

commandBuffer.presentDrawable(drawable)

commandBuffer.commit()

Thatistheshortofit.That’sthegeneralprocessofdrawingasimpletriangletothescreenandmanuallycreatingtherenderloopontheGPU.

ShouldyouratheroptforSpriteKitandSceneKittodoallofthismanualworkforyou?Thatwouldbeunderstandable.Rememberthough,likewhenplayingagameonhard

mode,itcomeswithitsrewardstotaketheharderroute.Yes,asofiOS9,theSpriteKitandSceneKitframeworksaredefaulttoMetal.Gameengines,suchasUnityandUnrealEngine,evenimplementMetalwhenconvertingprojectstotheplatform.However,knowinghowtobuildyourgamesinalow-levelgraphicsAPI,suchasMetalorOpenGL,willgivethedevelopertheabilitytohavethepotentialformostlean/fastperforminggameforthedevicefamily.BesuretocheckoutsomeofthegamescreatedwithMetalnexttimeyousearchonline.Theycanreallygiveyourplayersagreatexperience.Atthesametime,thiscanchallengeyourskillsasagamedevelopersincebeingagamedeveloperisthecombinationofanartist,engineer,andcomputerscientist.WorkingdirectlyintheGPU’sbasicfunctionswillchallengeallofthat.

Todivemoreintotherabbitholethatislow-levelgraphicsdevelopmentwithMetal,checkouttheselinks:

https://developer.apple.com/metal/https://developer.apple.com/library/ios/documentation/Metal/Reference/MetalShadingLanguageGuide/data-types/data-types.htmlhttp://www.raywenderlich.com/77488/ios-8-metal-tutorial-swift-getting-startedhttps://realm.io/news/3d-graphics-metal-swift/

ThefirstlinkistotheofficialAppleDeveloperpageforMetal.ThenextlinkisApple’slistofdatatypesusedintheMetalAPI.ThelasttwolinksaretwoseparatetutorialstomakesimpleMetalscenesinSwift.SomeofthecodeweusedcanbefoundinthesetutorialsaswellasfullXcodeprojects.ThefirstofthesetwolinksaretotheiOStutorialsitewww.raywenderlich.com.ThelastlinkistoapagethathasagreatvideopresentationandfullinstructionsonSwiftandMetal3DgraphicsbyformerAppleEngineer,WarrenMoore.

SummaryCongratsongettingthisfar.Ifthisbookwereagame,we’dprobablyhaveearnedanachievementforthischapteralone.Aswesaw,workingwithalow-levelAPIsuchasMetalcanbeabitdaunting.Wefirstreviewedwhatitmeanswhendevelopersandengineersmentionlowerandupperlevelframeworksandcode.OntheCPUside,wesawthatthelowestlevelisthemachine’scodewithSwiftandObjective-Cinthemiddle,andaboveC/C++andAssemblycode.Next,wespokeabouttheGPUsideandwherethevisualgraphicsAPIswe’vegoneoverinthepastchaptersstandinthehierarchy.Wethengotanunderstandingofthehistoryoflower-levelgraphicsAPIssuchasOpenGLES,howthegraphicpipelinegenerallyworksunderthehood,andhowtomakebasicshaders.Finally,wereviewedwhyMetalisfasterduringtherendercyclethanOpenGL,thegeneralstructurebehindMetal,andsomeofthecode/objectsusedtomanuallysetuptherenderloop.Thischaptermerelyscratchedthesurfaceonthistopic,soifyouareuptothechallenge,it’shighlyrecommendedtocontinuereadingdocumentationonhowMetalcanmakeyourgamesstandoutfromtherest.

Atthispoint,youshouldnowhaveallthatittakestomakeagameontheiOSplatform.ThelastessentiallessonforiOSgamedevelopmentislearninghowtotest,publish,andupdateyourpublishedgameintheappstore.Inthenextchapter,let’slearnhowtogetthatgameontheAppleappstore.

Chapter7.PublishingOuriOSGameCreatingagreatgameishardwork.Ourgoalasgamedevelopersistohaveanapplicationthatcanbeplayedbythousands,ifnotmillionsofpeople.Wewantthemtoplaywhatwecraftedinthoselongweeksandmonths.Beforetheappisreleased,we’dalsoprobablywanttohaveotherstestthegametoweedoutanybugsthatmighthavebeenmissed.PublishingontheiOSplatformcanallowustodoboth.

WecanallowotherstotryoutourgamesbeforereleasethroughtheTestFlightservice,andofcourse,wecanthensubmitourgameforreleaseontheAppleAppStore.Afterrelease,wecansubmitupdates.Theseupdatesandfutureversionscouldbejusttopatchupsomeminorbugswemighthavemissedintheinitialreleases,addnewfeatures,suchaslevels,achievements,andotherAppleservices,orwemightneedtoupdateourapplaterontoadheretotheeventualupdatesthatwillhappenwiththeiOSplatform.

Inthischapter,wearegoingtocoverafewmaintopics:

SettingupourappsforeithertestingorpublishinginiTunesConnectStepstosubmitourapptobeplayedintheappstoreSummaryoftheTestFlightservicefortestingintheprereleasephaseHowtouseiTunesConnecttocreateupdatestoourapp

Wewon’ttellyouhowtomarketyourgame,asthat’sanentirebook/topiconitsownthatdependsonyourbudgetandpreferences.However,wewillsaythatifyouoryourbetatestersfoundplayingyourgamefun,thereisachancethatotherswilltoo.Submittingtotheappstoredoesnotwarrantinstantsuccess.

Evenunreleasedgamesthatgethighaccoladesattheevergrowinglistofindiegamerewardshowsorgamejamsmightnothaveseenthatpraisereflectedinsalesanddownloadsafterrelease.Wehavetorememberthatthegamedevelopmentscene,thanksinparttogaming’spositioninpopularculture,isaseaofthousandsofdevelopers,bothbigandsmall,tryingtomakethenextgreatgame.

Don’tletthatdiscourageyouthough.Ifyourgamedoeswell,whichithastheabilitytowiththeAppleAppStore,thenitcouldbealife-changingexperience.Nomattertheoutcome,lettheexperienceofbuildingyourowngameandlearningthisdevelopmentplatformhumbleyouandmakeyouwanttobeanevenbetterdeveloperforyournextproject.Eventually,thathardworkwillpayoff.

TheeverchangingprocessofappsubmissionBeforewemoveforwardinexplainingthestepsneededtopublishyourgame,wewantedtonotealittlefactaboutthissubject.ThisfactisthattheexactstepsneededtosubmitouriOSappsfortestingorpublicationisonethatchangesratheroften.Everycoupleofmonthsthisprocessmightchangefromhowwedescribeithere.

Overtheyears,sincethestartofiOSdevelopment,Applehascontinuallymadethisprocesseasierandmorestreamlined.Xcodedoesmuchmoreofthesigning/provisioningworkforusthanitdidinthepast,andtheworriesofourapptakingforevertoappearintheAppStorearehardlyanissue.

Forexample,whentheSwiftgamePikiPopwassubmittedinNovember,2014,itonlytookfivebusinessdaysbetweenthedayitwassubmittedforreviewtowhenitappearedintheAppStoreforthepublic.Thisreviewtimewillvaryforeachofus,butaslongastherearen’tanyterribleerrorsorpolicyviolationsinourapps,wecanexpectourcreationstobepublicformillionstopotentiallyplay.Tomakesurethatthepublicationofyourgamegoessmoothly,it’sbesttoreviewtheAppReviewGuidelinesfoundhere:https://developer.apple.com/app-store/review/guidelines/.

NoteWewrotethisbookinthelatesummerof2015,soifyouarereadingthisatamuchlaterdateandfeelsomeoftheseprocessesmightbeoutofdate,makesuretoseethemostrecentupdateshereonApple’sownAppsubmissiondocumentationpage:

https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html

BeforesubmittingyourappThereisonemorepotentialdevelopmentsnagwemustwarnaboutbeforeyouchoosetosubmityourapptotheappstore.Asofthetimeofthispublication,ifyoubuildyourappinabetaversionofXcode,thatappwillberejectedfromreview.

Duringthecourseofthisbook,wehavebeenbuildingourappsandgoingoverfeaturesthatcurrentlyareinthebetaversionofXcode7.ThiswasbecausethereareanumberofnewfeaturesforiOS9/Xcode7thatweren’tthereiniOS8/Xcode6,namely,theGameplayKitframeworkandvisualeditortoolsforSceneKitthatmakeXcodedevelopmentashandsonasmultiplatformgameengines.

NoteBythetimeyouarereadingthis,Xcode7shouldnolongerbeinthebetaphase.Therefore,youshouldbeabletopublishaniOS9(orlater)gamewithoutworryingifthesefeaturesarebetaonly.

WhenyoubuildyourgamesforreleasingtotheAppStore,makesuretofirstbuildtheminthecurrentnon-betaversionofXcode.UsethebetaversionsofXcodetotestthenewestunreleasedfeaturesaswellasupandcomingiOSbuildsduringtheprereleasephase.

PreparingourappsforiTunesConnectSoyouhavecoded,simulated,andhopefullyenjoyedplayingabitofthatiOSgameyouworkedsomuchon.Thenextstepistobringyourappintothebeta/prereleasephase.Thegoalofthisphaseistogetyourgameintothehandsofasmallerpoolofgamers/testerstosimulatewhattheexperiencecouldbeforthethousands,ifnotmillionsofpeoplewhocouldpotentiallyplayyourgame.Theveryfirststeptothis,ifyouhaven’talready,istosignupfortheAppleDeveloperProgram:https://developer.apple.com/programs/.

Thereisacostinvolvedandthatcostwillbebasedonyourdevelopmentgoals.Forindividual,soleproprietorbusinessaccounts,itcosts$99ayeartobeaniOSdeveloper.Ifyouareworkingaspartofagroupofdevelopers,thentheEnterpriseplanof$299.99mightbeabetterchoice.

NoteInyourdeveloperpage,youwillalsohavetomakesurethatyourprovisioningprofileissetupcorrectly.ThisstepusedtobeoneofthetoughestthingstocompleteinbeinganiOSdeveloper,butXcodehasmadethisprocessmoreautomatedwitheachnewupdate.Ifyou’vebeentestingyourappinXcodewithanactualdevice,you’veobviouslyalreadydonethisstep.Ifnot,here’smoreinformationonsettingupyourprovisionprofile(s):https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ProvisioningDevelopment.html

TheportalthatwillbeyourbestfriendintheprocessofpublishingyourappisiTunesConnecthere:

https://itunesconnect.apple.com/

iTunesConnectiswhereyoucanseeyoursubmittedapps,trackvariousappanalytics,assignTestFlightbetatesters,andviewyourapp’srevenue.Wewon’tbeabletogiveafullrundownofeveryfeatureavailableiniTunesConnect;mainlywe’lllookatthestepsneededtopost,publish,andupdateyourgame.FeelfreetodiveintoallofthefeaturesandsettingsthatiTunesConnectcanprovideforyourappasthefeaturesgrowwitheverynewiOSupdate.

Submittingyourappinthetesting/betaphaseLet’sgetrightintothestepsneededtosubmityourapp.First,weshalltalkaboutthetesting/betaphaseofyourgame.

Hereisasummaryofthestepsneededforthetesting/betaphaseofyourgame:

1. CreateaniTunesConnectapprecord.2. Updatethebuildstring.3. Archiveandvalidateyourapp.4. UploadyourapptoiTunesConnect.5. BetatestyourgamewiththeTestFlightservice.6. Analyzecrashreportsandsolicitfeedbackfromtesters.

NoteSteps1-4arethesameforboththetestingandreleasephaseofyourgame.

CreatinganiTunesConnectapprecordThesearethestepsneededtoaddyourApptotheiTunesConnectapprecord:

1. Logintoyouraccountathttps://itunesconnect.apple.com/andgototheMyAppssection.

2. Nowclickonthe+iconlocatedonthetop-leftcornerofthepageandpickNewiOSAppfromthedropdown.

3. FillintheappropriatefieldsandclickonCreateifyoualreadyknowtheinformationforthisdata.Forthoseunsurewhattoplacehere,werevieweachofthesefieldsin

thefollowingscreenshot:

NotetheSKU,theVersion,andtheBundleIDfields.TheSKUmustbeuniqueandnotinusealreadyasApplewillusethisfortheidentificationofyourappinthestore.TheVersionandBundleIDfieldsmustmatchthebuildsettingsyouhavesetinyourgame’sXcodeproject.TheBundleIDfieldisadropdownthatatfirstmightonlyshowtheWildcardApp/BundleID.

TheWildcardIDisoneoftwotypesofBundleIDs,theotherbeingtheExplicitAppID.Here’salinktoApple’sdocumentation/FAQforwhichtypeofIDwouldbebestforyourgame:https://developer.apple.com/library/ios/qa/qa1713/_index.html.Inshort,ifyouaregoingtouseAppleservices,suchasNotificationsandGameCenterachievements,youwouldneedanExplicitAppID,ifnot,thentheWildcardIDisbest.

NoteIfyouwishtousetheExplicitBundleID,youwillhavetoregisteryourapp’sBundleIDintheAppleDeveloperportal.TheIDsthatareregisteredontheDeveloperportalwillpopulatethatdropdown.Here’sthelinktothatpageinthedevelopersite:https://developer.apple.com/account/ios/identifiers/bundle/bundleCreate.action.

TheBundleIDSuffixfieldisfoundinyourproject’sinfo.plistfile.It’sauniquestringthatiscreatedbyyourXcodeproject,alsoknownastheBundleSeedID.We’llshowyouwheretofindthisandotherbundle/build-basedinformationwhenwegoovertheUpdatingthebuildstringstepnext.

TheNamefieldiswhatyourgame’snamewillbeintheAppStore.Thisiswhatpeoplesearchingforandhopefullyvisitingyourgame’slandingpagewillsee.ThePrimary

Languagedropdowniswhatyourgame’sdefaultlanguagewillbeiftheappstorecan’tlocalizeyourgame’sinformationforthatterritory.

UpdatingthebuildstringThebuildstringrepresentsaniterationofyourgame’sbundle.It’satwo-period-separatedlistofpositiveintegers,asin1.2.3.Basically,thebuildstringisanotherlayerofversioningaddedforyourgame.WhenmakinganiOSapp,asinourcase,changingthisbuildinformationwillautomaticallybeseenbyiTunesConnectduringtheuploadstep.Ifwedon’tupdatethisfield,evenifwechangeourgame’scode,iTunesconnectwillstillthinkthatyouaretryingtouploadthesamebuildandwillrejectyourupload.

Here’swhereyoucanfindthisinformationinyourXcodeproject:

Thebundleidentifier,buildstring,versionnumber,andotherappidentification/globalsettingsarefoundontheGeneraltabintheInspectorwindowwhenweclickontheproject’smainfileintheNavigationpane.Wecanalsofindthisinformationrepresentedintheinfo.plistfile.MakesurethatthesefieldsmatchyouriTunesConnectrecord.

Nowlet’smoveontouploadingourgameinXcodetoiTunesConnect.

ArchiveandvalidateyourappThenextstepintheapppublishingprocessistoarchiveyourgame’sprojectbundle.Todothis,gotothetopdropdownmenusandthennavigatetoProject|Archive.ThearchiveselectionmightbeinaccessibleifyourtestdeviceisthesimulatorastotheiOSDevice.

Oncebuilt,yourarchivedappwillbeseenintheArchivesorganizerwithotherarchivesyouhavecreatedfromthisandotherapps.Thiswindowwillopenwhenyoubuildthearchive,butitcanbeaccessedatanytimebygoingtoWindow|Organizerinthetopmenu.

Thewindowcanbeseeninthefollowingscreenshot:

Next,wevalidateyourgametomakesurethatitfitstheminimumrequirementsforsubmission.Todothis,followthesesteps:

1. ClickontheValidatebuttonfoundontherightsideoftheprecedingArchivesorganizerwindow.

2. Apop-upwindowwillshowwhereyouchoosetheDevelopmentTeamthatwoulddotheprovisioningforthisapp.(ThisisassumingyourProvisioningprofilewassetupcorrectly.)ClickonChoosetomovetothenextstep.

3. Thiswillopenmoreofthepopupshowingasummaryofyourappbeforeperformingtheactualvalidation.Informationsuchasyourapp’sBundleIDalongwiththeBundleSeedIDmentionedearliercanbeseenhereaswell.

4. ClickonValidateandiftheinformationinyourappprojectiscorrectlymatchingwhatwesetuponiTunesConnect,thenyourappshouldbevalidatedandreadyforsubmissiontoiTunesConnectandeventuallytheAppStoreitself.

Ifyourappisnotvalidated,makesurethatallofyourinformationiniTunesConnectmatches,mostimportantlytheBundleID.

TipTheAppvalidationstepcouldprobablybeskippedjustbyclickingontheUploadToAppStore…button,butisagoodwaytotestearlyonifeverythingcheckoutwithourgame.

Moreonappvalidationcanbefoundhere:

https://developer.apple.com/library/mac/recipes/xcode_help-archives_organizer/articles/ValidatingYourApp.html

UploadyourapptoiTunesConnectThisstepshouldnowberathersimple.ClickontheblueUploadToAppStore…button,andyoushouldgetthesamepromptsseenfromtheappvalidationstage.You’llbeaskedtochoosetheDevelopmentTeam;showyourapp’sdetails,andyoucanchoosetouploadyourappbyclickingonSubmit.Ifyourgamevalidatedpreviously,thenitshoulduploadsmoothlytoiTunesConnect.Nowyourgameshouldbeonestepclosertobeingavailableforeitherbetatestingorpurchase/downloadontheAppStore.

BetatestyourgamewiththeTestFlightserviceEveryappshouldhaveatleastsomeformofbetatestingbeforereleasewithvideogamesusuallybeingthetypeofappsthatneeditmorethanothers,asgamestendtohavemorevariablesandchancesforcrashingthanyourrun-of-the-millmobileprogram.Also,theAppleservices,suchasGameCenterandIn-Apppurchases,can’tbetestedcorrectlywithoutmovingtothisphase.

Inthepast,theonlywaytotestiOSappsbeforereleasewasusingtheadhocdistributionmethod,validatingindividualdeviceswiththeirUDID,andgivingthetestersadownloadwithamanifestfilethatwouldallowtheapptoactuallyworkontheirdevice.ThisiswhereApplediffersgreatlyfromotherplatformssuchasAndroid.Appleisverycarefulinkeepingwhatdevelopersliketocallawalledgardenwiththeirapplicationdistribution.

Inthepast,thiswasabitofaheadacheandledtoaratherconvolutedadhocsetupascomparedwithAndroidresultinginappbugsnotbeingnoteduntilaftertherelease.TohelpkeeptheintegrityofApple’sappdistributionandgivedevelopersabetterwayofpretestingtheirappseasilyandtohavemorepeoplethantheoriginal100devicelimit,theTestFlightservicewascreated.TheTestFlighticonisseenhere:

TestFightisanappthatanybodycandownloadfromtheAppleAppstorefortheiriOSdevice.Foryou,thedeveloper,itcanbeagreattoolforearlydistributionofyourgames.TestFlighttestersaresegmentedintotwogroups:internaltestersandexternaltesters.Internaltestersaremadeupofyourownteammembers,andyoucanhaveamaximumof25internaltesters.

IniTunesConnect,youcansetrolesforyourteamintheUsersandRolesmainsection.TheserolesincludeAdmin,Technical,Marketing,andothers.Themembersthatareinthe

AdminandTechnicalcategoryarethosewhomyoucanassignasinternaltesters.MakingthoseusersinternaltestersisaseasyasturningontheInternalTestersswitchnexttotheirname.

TohavetheseuserstestyourgameinTestFlight,locateyourgameintheMyAppssectionofiTunesConnect.Ifyourgame’sbuildwassuccessfullyaddedtoiTunesConnectfromthestepsprovidedintheprevioussection,thenyoushouldseeitlistedinthePrereleasetab.

NoteWhenyouuploadyourapptoiTunesConnecttheycanbedividedintoversions,whicharethensubdividedintotheirownbuilds.Forexample,version1.0(1)isversion1.0,build1ofyourgame,whereas1.0(1.2)wouldbeversion1.0/build1.2ofyourgame.ChangingthebuildstringinyourprojectandthenuploadingthatnewbuildishowyoucandivideyourappforthispageiniTunesConnect.Wewilldiscussmoreonthiswhilecreatinganewupdatetoyourgame,butthisistheprocessforversioningtheprereleasebuilds.

Thenextstepistoclickonthebuildorversion,whichshouldopenthebuild’sownmetadatapage.Fillinthisinformationtobetterhelpyourtestersknowwhomtocontact

andwhattotest.Thisinformationiswhatyourtesterswillseewhentheydownloadyourgame’sbetaversion.

Toallowthisbuild/versionforTestFlighttesting,simplyswitchontheTestFlightBetaTestingswitchfoundontheupper-rightsideoftheversion’slistinginthePrereleasetab.

NowtohaveyourtesterstestthisbuildintheirTestFlightapp,simplyclickontheInternalTesterstabnexttotheBuildstaboninthegame’sprereleasepage,clickonthecheckmarknexttotheirnameandthenclickonInvite.

Theyshouldgetane-mailtoacceptthatinvite,andyouwillseewhichbuildtheyaretestingoncetheyinstalleditinTestFlight.

Externaltesterinvites

TogetexternaltestersforyourgamewithTestFlightisalsoarathersimpleprocesswithonecaveat;yourappneedstobesubmittedforbetareview.DoingsoissimplethoughallyouneedtodoistoclickontheSubmitForBetaAppReviewlinkattherightsideofyourapp’sbuild;againintheBuildstabofthePrereleasesection.

AswiththeactualAppStoresubmission,itmightinvolvewaitingbeforemovingtothenextstep.Thewaitisnotaslongasthefullappsubmissionandisaverygoodsignthatallwillgowellwhenyoudothepublicrelease.Unlikeinternaltesters,allofthemetadatamustbecompletedbutyoucanhaveupto1000testers!YoucanstarttoinvitetestersoncetheSubmitForBetaAppReviewlinkistappedandyourappiswaitingforbetatestreview.

NowgototheExternalTesterstabinthePrereleasepageandthenclickonthe+buttontoaddthemwiththeire-mailaddressand(optionally)theirfirstandlastname.ClickonNexttoaddthatpersontoyourinvitelist.Notethatyouonlyhave30daysforexternaltesterstoreviewthatbuildofyourgame.

Onceyourapppassesbetareview,yourexternaltesterscantestyourappjustlikeyourinternaltesterscan.

AnalyzingcrashreportsandfeedbackfromtestersNowthatyouhavepeopletestingyourgame,takenotesfromtheire-mailsonwhatissuestheremightbeinyourgameandthengobacktoyourgame’sprojecttodotheneededfixes.UpdatethebuildnumberinthebuildstringofyourXcodeprojectandreuploadthebuildtoeasilyallowyourtesterstokeepuptodatewitheachnewprereleaseupdate.

AppcrashreportscanbeviewedintheAppAnalyticsmainsectionofiTunesConnect,asseenintheimagefromPikiPop’sinformationasfollows.However,itseemsthatthesedetailedcrashanalyticsareforafterreleaseandnotduringprerelease.

MoreonTestFlightandevenavideoexplanationcanbefoundonApple’sofficialpageonthesubjectasfollows:

https://developer.apple.com/testflight/

SubmittingyourgameforreviewThisisthepointinyourgame’sdevelopmentyou’veworkedsohardfor,submittingittotheAppleAppStore.Thegoodnewsisthatmostoftheworkhasalreadybeendone!Tosubmityourgameforreview,atthispoint,allyouhavetodoisgotoyourapp’sVersionstabandclickontheSubmitForReviewtab.

YoucanseethisinthefollowingAdventureappexampleimage:

Youwillbeaskedafewquestionsbeforetheactualsubmission,suchasaboutExportCompliance,Contentrights,andAdvertisingIdentifier(IDFA)information.MoreinformationonIDFAcanbefoundhere:

https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html#//apple_ref/doc/uid/TP40011225-CH33-SW8

NowthewaitinggamebeginswithyourgameintheWaitingForReviewstatus.Again,thewaittimeforappapprovalwillvarybutisusuallymuchlessthanitusedtobeinthepast.Hopefully,allgoeswellandyouwillseeagreenmarkstatingyourgame’ssubmittedversionnumberwiththewordsReadyforSale;asfollows:

Congrats!YourgameshouldbenowlocatedintheAppStoreforeveryonewithaniOSdevicetodownloadandplay!MakesuretocheckoutthevariousanalyticstoolsiTunesConnectprovidestokeepapulseonyourgame.

UpdatingyourgameGamestodayarealmostneveraone-shotdeal.Theytendtobealivingapplicationthroughupdates,add-ons,andfixesevenafterrelease.UpdatestoyourappwillbeworkingtoanyfutureiOSupdates,addingnewgamecontent,oracombinationofboth.Todothis,simplyrepeatmuchoftheprocessesfromthebuildstringphasestartingwiththecreationofanewversionnumber.DoingsowillcreateanewsectioninyourBuildstabunderPrereleaseasseenwithPikiPop’sownpageasfollows:

YoucanuseTestFlightbetatesttotestthenewbuildwithinternalandexternaltestersjustasyoudidbefore.Tomakereadythenewestversionforrelease,clickontheNewVersionbuttonontheVersionsmaintabandsubmitthenewestversion’snumberinthepopup.

TheVersionstabwillnowbedividedintothecurrentversionandthenewversionviaeasy-to-navigatetabs.Likeintheoriginalrelease,youcanfillinvariousmetadataaswellasinformationfortheplayersforwhatthisnewupdatewillentail.Submittheversionforreviewandonceapproved,thenewestgameupdatewillbeintheappstorethatplayerswilleitherautomaticallydownloadorbenotifiedabout,basedontheirdevice’sAppStoreupdatesettings.

Thataboutdoesit!IfmoregameframeworksandtoolscomeoutinfutureversionsofiOS,youcanhavethemaspartofyourgamewithyourupdates.Makingagreatgameevenbetterisalwaystherightchoiceforeverygamedeveloper.

SummaryThroughoutthischapter,wesawwhatwasneededtofinallytakeyourgamefromanXcodeprojecttoaplayablegameforeveryonewithaniOSdevice.WelearnedaboutthestepsneededtosetupourXcodeprojectbeforesubmissiontoiTunesConnect.Then,wegotanintroductiontoTestFlight,whichisagreatserviceforustobetatestourgamesbeforerelease.Wesawthatthosestepsalreadypreparedusformostofwhatwasneededtosubmitourgamesforreview.Finally,wesawhoweasyitwastocreateappupdatesiniTunesConnect.

Younowhaveagameappthathopefullythousandsofplayerscanenjoy.Nomatterifthegamewasbigorsmall,beproudofthefactthatyoucreatedsomethingforplayerstoenjoy.Eventhesimplestofgamescanbeaworthyaccomplishment.We’veseenthroughoutthisbookthattheprocessofmakinganiOSgame,thougheasierthanevenafewyearsago,takessomeeffortanddiligencetogetright.Thisconcludesallofthetechnicalaspectsweshalldiscuss.Next,weconcludewithaquickdiscussiononthefutureofiOSandgamedevelopmentasawhole.

Chapter8.TheFutureofiOSGameDevelopmentFortheentiretyofthisbookwehavegoneoverthefeaturesfromiOS8andtherecentannouncementsofiOS9.So,whatofthefutureofiOSgamedevelopment?Obviously,nobodycantellwhatthefuturewillbring,butwecanguessafewpossibilitiesbasedontherecentevolutionoftheiOS/Xcodeplatform,programming,andhowgamedevelopmentasawholewillchange.

AgreaterfocusonfunctionalprogrammingAsofthispublication,theSwiftprogramminglanguageisonlyayearoldbutitrepresentsarecentparadigmshiftinmuchofprogramming.Object-orientedprogramminganddesignstillholdstrue,butashifttofunctionalprogrammingiswherelanguagessuchasScalaandSwiftplacetheirfocus.Functionalprogramming,insummary,isafocusonfunctionsbeingpuremathematicalcalculationsofobjectswithanavoidanceofthestatechangesandmutabledatathatwe’veseenwithpastlanguages,suchasC++/JavaandevenApple’sownObjective-C.Insteadofdealingwithsubroutines,afunctiononlyworksontheparametersit’sgiven.Swiftdoesthiswellwithitsclosures,whichwe’veseenafewtimesinthisbook,andareoftenusedtocompactmuchofthelogicingameprogrammingforiOS.

SinceWWDC14,ApplehastolddevelopersthatSwiftisthesuccessortobothCandObjective-C.It’sacompletelyrebuiltlanguagefromthegroundupwithspeedandefficiencyasitsfocus,somethinggamedevelopersmustalwaystakeadvantageofandwhySwiftisnowthelanguageofchoicegoingforwardforiOSgamedevelopment.Objective-Cisnotgoingaway,andSwiftstillhassomegrowinguptodobeforeitcaneventakeoverallofwhatObjective-CcandoforiOSdevelopment.Swift’s2.0updatefromiOS9addedmoreforerrorcatchinganddebuggingwithkeywords,suchasthrow,catch,andguard.Thankfully,wedon’thavetoabandonanypastObjective-CprojectssincetheabilitytousebothSwiftandObjective-CinthesameprojectisverysimplethroughtheuseofanObjective-C/SwiftBridgingfile.

AswemoveontofutureversionsofiOS,expectmoredebuggingcontrolsandimprovementstoSwift’sabilitytocompactdetailedlogicintoafewlines.SomedatasortingfunctionalitiesofSwiftarefasterthanObjective-C,andintheworldofgamedevelopment,anygainsinframerateisalwaysagoodthing.DespitetheadvancesinCPU/GPUpowerandtheever-growingeaseofgamedevelopmentframeworks,suchasSpriteKitandSceneKit,thedesignaspectofgamedesigncanbeadouble-edgedswordifweforgettheengineeringaspectofthiscraft.Someofthetoolsgiventousintherecentgamedevelopmentscenecanmakealmostanybodyagamedeveloper.Thisisagoodthing.Wewantpeoplefromallwalksoflifetobegamedevelopers,butwemustnotletsomeoftherecentandfuturetoolsthatallowgamesoniOSorotherplatformsmakinguslazyandforgetthatthereisandalwayswillbeaprogramming/engineeringsidetothisindustry.TheframeworksandvisualtoolsofiOSandothergameenginesshouldalwaysbetreatedastoolsandneverasacrutch.Thebestgamesofthepast,present,andinthefuturewillbegamesthattapintoeveryaspectofgamedevelopment,particularly,thehardestaspectsofgamedevelopment,suchasthegraphicspipeline.That’swhyAppletappedintothedetailsoftheGPUwiththeMetalAPI.

TheAppleWatchAsofiOS9,theAppleWatch’splatformalreadygotanupgradewithwatchOS2.TheAppleWatchisgenerally,atthemoment,notavideogameplatform.Withouttakingthesmallscreensizeintoplay,appsmadefortheAppleWatchdon’thavemuchinthewayofmakinggame-likegraphicsupdates.Inthefuture,thismightchange.Atthemoment,appsmadeinwatchOSarelikechildappsofmainiOSapps.Eventually,wecanmakewatchOSappsseparatelywithouthavingthemattachedtoaparentiOSproject.However,somedevelopershavemadesimpletext-basedgamesfortheApplewatch.It’spossiblethatinthefuture,wecouldmakemoreaction-orientedgamesfortheAppleWatch.

Currently,it’sverymuchpossibletomakeagamethatusesthewatchforaccessoriesdata,suchasinventory,maps,andmorewithalittlebitofingenuity.OnefeatureoftheAppleWatchthatwecoulddesigngamesorgamecontrolswithisForceTouch.ForceTouchsenseshowfirmthepressgestureis.Thisisn’tsomethingnewtogamedesignasawholebutnewtoiOSwiththenextlineofiPhonesandiPadsmostlikelyhavingthisfeatureaswell.Gettingthestrengthofaplayer’stouchandtapscouldallowsomeintuitivegameplaymechanicsforthenextlineofmobilegames.

FormoreonthewatchOStopossiblyinspiresomegamedevelopmentideasforthedevice,checkoutthewatchOS2previewpageathttps://www.apple.com/watchos-2-preview/.

Component-basedstructuringWesawinthepreviouschaptersthatiOShasimpartedmuchofthecomponent-basedstructuringparadigmtotackletheuniquesoftware/programmingrequirementsthatcomefromgamedevelopment.Insteadofbuildingatallparent-childstructurethatweseefromanobject-orienteddesign,itbuildsastructurethatdoesbestbygrowingit’sstructureinwidth.Classes,suchasGKEntity,GKComponent,andotheraspectsofGameplayKit,arewhatletustakeadvantageofthesefeatures.Thistypeofstructuringisn’talltoonewingamedevelopment.Component-basedstructuringhasbeenusedbymultiplatformgameengines,suchasUnityandUnrealEngine,andcontinuestobethewaygamedeveloperslikeusmakeandreusepartsofourgames.ExpectthefutureupdatestoXcodeandiOStoutilizethesefeaturesevenmore.Inthenearfuture,wewillprobablyseeXcodelookandactevenmorelikethesegameenginesbutwiththebenefitofbeingspecificallymadefortheiOSdevices,allowingevendeeper,customintegration.DoingallofthisdirectlyinXcodeandwithiOSframeworksallowsinstantaccesstoApplefeatureswithouttheuseofpaidassettoolsorwaitingforpluginupdates.DevelopersforthenextgenerationofiOSgameswillbeabletotakeAIactions,characterabilities,HUDanimations,andotherfeaturesmadeinonegameandreusethemalmostinstantlyforacompletelydifferentgame.Component-basedstructuringmakesitwherethedevelopercanbuildalibraryofreusablefeaturesbyplacingthedesignofourgamesaheadoftypicaldevelopmenthurdles.

TheriseofVRThishasbeenatopicthatApplehasbeenratherquietaboutwhereotherplatformshavebeenrathervocal.EventhemanufacturersofApple’sA7/A8chips,Samsung,havejoinedtheVRdevelopmentenvironmentwiththeirGearVRdeviceandtheirpartnershipwithOculusontheproject.GooglehascreatedthesimpleCardboardsetup,akintotheGearVR,whichsimplyletstheuserplacetheirsmartphoneintothedeviceorboxtoexperienceVRexperiencesandgames.Mostfamously,thereistheOculusRift,whichwillhaveitsconsumermodelavailableinthefirstquarterof2016,andwilllikelybethefrontrunnerinthisnewergameenvironment.

Virtualrealityisatopicthathascomeupanumberoftimesinthepastfewdecades.Ithascomeandgone,butforthetimebeing,itseemstobegettingitsoverduefootholdintechnology.TheUnitygameengine,forexample,justrecentlyallowedfornativesupportofVR.Thethoughtprocessinmakingthesegamesisabitdifferentandhasyettobefullyfleshedout.ItispossiblethatsoonApplewillthrowtheirhatintothisarena.Ifyouhaven’talready,learninghowtomakefungamesintheVRspacemightbeaworthyactofforesight.

SummaryWehopethatthediscussionsandtutorialsseenthroughoutthisbookhelpedyoueitherlearntheplatformforthefirsttimeorenrichedwhatyoumighthavealreadyknownaboutiOS.WehopethatyoutakethisknowledgeandmakesomeamazinggamesfortheiOSfamilyofdevicesandcontinuetolearnmoreabouttheplatformandgamedevelopmentasawhole.

Intheend,alwaysrememberthatgamedesignandprogrammingisacombinationofcomputerscience,engineering,art,andlotsofhardwork.It’sacomplexcreativefieldthatisacombinationofeveryothercreativeprofessionfrommusictomoviemaking,to2Danimation,3Dsculpting,andmore.Asthecasewithothercreativefields,developersshouldneverfeeldoneandalwaysbehumbleinwhattheyknowandacknowledgethatthere’salwaysmoretolearninthisever-growingfield.Likeavideogame,beupforthechallenge.Realizewhenyoulookbackthatyouessentiallyleveledupfromwhatyouusedtoknowandtherearealwaysmoreabilitiestogain.

IndexA

A7Processor/WhyisMetalfasterthanOpenGLES?AdvertisingIdentifier(IDFA)/Submittingyourgameforreviewaffectedbygravitytoggle/Particlesystemsagents

about/Statemachines,Agents,goals,andbehaviorsAPI

statevalidation/WhyisMetalfasterthanOpenGLES?shadercompilation/WhyisMetalfasterthanOpenGLES?work,sendingtoGPU/WhyisMetalfasterthanOpenGLES?

AppleMetalAPIabout/TheAppleMetalAPIandthegraphicspipelineCPUframeworklevel/CPU/GPUframeworklevelsGPUframeworklevel/CPU/GPUframeworklevelsgraphicspipelineoverview/Graphicspipelineoverview

AppleWatchabout/TheAppleWatch

appslicingabout/Assets,sprites,andiconsURL/Assets,sprites,andicons

appsubmissionprocessabout/Theeverchangingprocessofappsubmissionprerequisites/Beforesubmittingyourappapps,preparingforiTunesConnect/PreparingourappsforiTunesConnecttesting/betaphase/Submittingyourappinthetesting/betaphase

appthinningabout/Assets,sprites,andiconsURL/Assets,sprites,andicons

arraysabout/Arrays

artificialintelligence(AI)about/Agents,goals,andbehaviors

assemblylanguage/CPU/GPUframeworklevels

Bblocks

URL/ThegameloopBoolean

about/Booleanbridgingfile

URL/UsingGKEntityandGKComponentobjectsinourgamesBufferobjects/Graphicspipelineoverview

Ccharacters

about/Charactersandstringsclasses

about/Classesclosures

URL/ThegameloopCocos2Dframework/CPU/GPUframeworklevelscollectiondata

editing/Editing/accessingcollectiondataaccessing/Editing/accessingcollectiondata

collectiontypesiteratingthrough/Iteratingthroughcollectiontypes

commentingabout/CommentinginSwift

component-basedstructuringabout/Component-basedstructuring

componentsabout/EntitiesandcomponentsURL/UsingGKEntityandGKComponentobjectsinourgames

constantsabout/Constants,Moreaboutconstants…

controlflowabout/ControlflowinSwiftif-statement/Ifstatementsfor-loops/Forloopsdo-whileloop/Do-whileloopsswitchstatements/Switchstatements

D2Darrays

about/2Darrays/matricesDemoBots

about/DemoBotsURL/DemoBots

designmethodologyURL/Entitiesandcomponents

dictionariesabout/Dictionaries

do-whileloopsabout/Do-whileloops

doublesabout/Floatsanddoubles

Eemoji

URL/Creatingourgamelogicentities

about/EntitiesandcomponentsURL/UsingGKEntityandGKComponentobjectsinourgames

Ffiledecodingclass

URL/SpriteKitfloats

about/Floatsanddoublesfor-loops

about/ForloopsForceTouch

about/TheAppleWatchFoxdemo

about/FoxdemoURL/Foxdemo

framespersecond(fps)/SceneKitprojectflowandstructurefunctionalprogramming

about/Agreaterfocusonfunctionalprogrammingfunctions

about/Functionsfuzzylogic

about/Rulesystems

Ggame

submitting,forreview/Submittingyourgameforreviewupdating/Updatingyourgame

GameBoardabout/GameBoard

gamelogiccreating/CreatingourgamelogicGameBoard/GameBoardGameScene.swift/PuttingitalltogetherinGameScene.swift

gameloopabout/ThegameloopURL/Thegameloop

GameplayKitoverview/Agents,goals,andbehaviorsguide,URL/Agents,goals,andbehaviorsrulesystems/Rulesystemsrulesystems,URL/Rulesystems

GameplayKitframeworkabout/Boolean

gamestateabout/PuttingitalltogetherinGameScene.swift

Genericsabout/2Darrays/matrices

GKAgentparametersURL/Agents,goals,andbehaviors

GKComponentobjectsusing,ingames/UsingGKEntityandGKComponentobjectsinourgames

GKEntityobjectsusing,ingames/UsingGKEntityandGKComponentobjectsinourgames

GKObstacleclassURL/Pathfinding

GKStateURL/Statemachines

GKStateMachineURL/Statemachines

GLKit/CPU/GPUframeworklevelsgraphicspipelineoverview

about/Graphicspipelineoverviewvertexdata/Graphicspipelineoverviewrendering/pixeldata/Graphicspipelineoverviewexample/GraphicspipelineoverviewBufferobjects/Graphicspipelineoverview

primitiveprocessing/GraphicspipelineoverviewGraphicsProcessingUnit(GPU)/CPU/GPUframeworklevels

HHeads-UpDisplay(HUD)

about/ConstantsHelloWorldprogram

about/HelloWorld!

Iif-statement

about/Ifstatementsifandelsestatements

about/Moreaboutconstants…imageassets

URL/Creatingourgamelogicimmutablecollections

about/Mutable/immutablecollectionsinheritance-basedstructuring

issues/Theissuewithinheritance-basedstructuringandgamedesignintegers

about/IntegersandunsignedintegersiOS9/Xcode7

SceneKit,features/SceneKitfeaturesintroducediniOS9/Xcode7iOSapplifecycle

about/AniOSapp’slifecyclemain()function/Themain()functionUIApplicationclass/TheUIApplicationclass/objectAppDelegateclass/TheAppDelegateclassviewcontrollers/ViewcontrollersViewControllertypes/Viewcontrollertypes

iOSgamedevelopmentfunctionalprogramming/AgreaterfocusonfunctionalprogrammingAppleWatch/TheAppleWatchcomponent-basedstructuring/Component-basedstructuringVRdevelopmentenvironment/TheriseofVR

iOSgamedevelopmentenginesabout/AbriefhistoryofiOSgamedevelopmentengines

iPhone5s/WhyisMetalfasterthanOpenGLES?iTunesConnect

URL/CreatinganiTunesConnectapprecord

Mmachinecode/CPU/GPUframeworklevelsmatrices

about/2Darrays/matricesMetalAPI

versusOpenGLES/WhyisMetalfasterthanOpenGLES?object/codestructure/ThebasicMetalobject/codestructure

MinMaxAIabout/MinMaxAIURL/MinMaxAI

Model-View-Controller(MVC)about/Model-View-Controller

mutablecollectionabout/Mutable/immutablecollections

Nnavigationgraph

about/Pathfinding

Oobject-orientedprogramming(OOP)

about/ObjectsinSwiftObjective-C

versusSwiftcode/Objective-CandSwiftcomparison,Swiftabout/Objective-C,UsingGKEntityandGKComponentobjectsinourgames

objectsabout/ObjectsinSwifttype-safe/Typesafetyandtypeinferencetypeinference/Typesafetyandtypeinference

OpenGLAPI/CPU/GPUframeworklevelsOpenGLES/CPU/GPUframeworklevelsoptionals

about/Optionalsunwrapping/Unwrappingoptionalsoptionalbinding/Optionalbindingandchainingoptionalchaining/Optionalbindingandchaining

Pparticles

placing,inpioscene/PlacingparticlesintoourpiosceneSpriteKitparticles/SpriteKitSceneKitparticles/SceneKit

particleseffectsabout/Particlesystemscreating,onSceneKit/Particlesystems

Pathfindingabout/PathfindingURL/Pathfinding

PrimitiveAssembly/Typesofshadersprimitiveprocessing/Graphicspipelineoverview

Rrandomsources

about/Randomsourcesreal-timestrategy(RTS)game/HandlinguserinputinSceneKitRight-HandedCoordinateSystem/SceneKitprojectflowandstructureRollercosterTycoon™/CPU/GPUframeworklevels

Sscenegraph

about/Visuallycomposedgamescenescgsobjects,adding/Visuallycomposedgamescenescgs

SceneKitbasics/SceneKitbasicsandworkingwithnodesnodes,workingwith/SceneKitbasicsandworkingwithnodesandSpriteKit,interactivity/SpriteKit/SceneKitinteractivitycoordinatediagram,URL/SceneKitprojectflowandstructureframework,URL/Visuallycomposedgamescenescgs

SceneKitfeatures,iniOS9/Xcode7about/SceneKitfeaturesintroducediniOS9/Xcode7audionodesand3Dsound/Audionodesand3Dsoundambienceandmusic/AmbienceandmusicSpriteKitscenetransitions/SpriteKitscenetransitionsinSceneKit

SceneKitparticlesabout/SceneKit

SceneKitphysicsabout/IntroducingSceneKitandSpriteKitphysics

SceneKitsceneabout/OurfirstSceneKitscene–theXcodetemplateproject,flow/SceneKitprojectflowandstructureproject,structure/SceneKitprojectflowandstructuredebugging,options/SceneKitDebuggingOptionsuserinput,handling/HandlinguserinputinSceneKit

SCNActionURL/SceneKitprojectflowandstructure

SCNBoundingVolumeclassURL/IntroducingSceneKitandSpriteKitphysics

SCNLightsURL/SceneKitprojectflowandstructure

seguesabout/SeguesShow/SeguesShowDetail/SeguesPresentmodally/SeguesPopover/SeguesCustom/Seguescreating/Seguescustomsegueclasses,creating/Segues

setsabout/Sets

shaders

about/Whatareshaders?types/TypesofshadersVertexshaders/TypesofshadersFragmentshaders/TypesofshadersPixelshaders/Typesofshaderscodesample/Typesofshaders

SKActionURL/SceneKitprojectflowandstructure

SKConstraints/ThegameloopSKNode

URL/AnoverviewoftheSpriteKitstructureandobjectsSKScenetransitions

withSKSfiles/SKScenetransitionswithSKSfilesSKTransition

URL/AnSKTransitionexample,SpriteKitscenetransitionsinSceneKitSpriteKit

gameloop/Thegameloopkeynote,URL/DemoBots

SpriteKitgamecreating/CreatingourSpriteKitgamestructure/AnoverviewoftheSpriteKitstructureandobjectsobjects/AnoverviewoftheSpriteKitstructureandobjectsscenetransitions/Scenetransitionsandthechoiceofcode,storyboards,and/orSKSfilescode,choice/Scenetransitionsandthechoiceofcode,storyboards,and/orSKSfilesstoryboards/Scenetransitionsandthechoiceofcode,storyboards,and/orSKSfilesSKSfiles/Scenetransitionsandthechoiceofcode,storyboards,and/orSKSfilesSKTransitionexample/AnSKTransitionexampleSKScene/storyboardexample/ASKScene/storyboardexampleSKScenetransitions,withSKSfiles/SKScenetransitionswithSKSfilesassets/Assets,sprites,andiconssprites/Assets,sprites,andiconsicons/Assets,sprites,andiconsspriteatlases/Spriteatlasesandanimatingspritessprites,animating/SpriteatlasesandanimatingspritesandSceneKit,interactivity/SpriteKit/SceneKitinteractivity

SpriteKitparticlesabout/SpriteKit

SpriteKitphysicsabout/IntroducingSceneKitandSpriteKitphysics

spritesheet/Spriteatlasesandanimatingsprites

SpriteSheets/WhyisMetalfasterthanOpenGLES?statemachine

about/PuttingitalltogetherinGameScene.swiftstatemachines

about/Statemachinesstoryboards

about/Storyboardsandseguesusing/Storyboardsandseguesversuscoding/Storyboardsversuscoding

StringInterpolationabout/StringInterpolationstrings,mutating/Mutatingstringsstringindices/Stringindices

stringsabout/Charactersandstrings

Swiftcommenting/CommentinginSwift

Swiftlanguagevariables/Variables,constants,andprimitivedatatypesconstants/Constants

SwiftSweeperabout/Tilegame–SwiftSweeper,WhatisSwiftSweeper?URL/WhatisSwiftSweeper?,PuttingitalltogetherinGameScene.swift

switchstatementsabout/Switchstatements

Ttesting/betaphase,appsubmissionprocess

about/Submittingyourappinthetesting/betaphaseiTunesConnectapprecord,creating/CreatinganiTunesConnectapprecordbuildstring,updating/Updatingthebuildstringapp,archiving/Archiveandvalidateyourappapp,validating/Archiveandvalidateyourappapp,uploadingtoiTunesConnect/UploadyourapptoiTunesConnectapp,testingwithTestFlightservice/BetatestyourgamewiththeTestFlightserviceexternaltesterinvites/Externaltesterinvitescrashreports,analyzing/Analyzingcrashreportsandfeedbackfromtestersfeedback,analyzing/Analyzingcrashreportsandfeedbackfromtesters

textureatlas/Spriteatlasesandanimatingspritestuples

about/Tuples

UUITapGestureRecognizerclass

URL/HandlinguserinputinSceneKitunsignedintegers

about/Integersandunsignedintegers

Vvariables

about/VariablesVertexBufferObjects/GraphicspipelineoverviewVertexProcessingUnit(VPU)/GraphicspipelineoverviewVRdevelopmentenvironment

about/TheriseofVR

WwatchOS2previewpage

URL/TheAppleWatchWWDC15

URL/DemoBots

XXCodetemplate

about/OurfirstSceneKitscene–theXcodetemplate

Recommended