iOS 9 Game Development Essentials

iOS 9 Game Development Essentials
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
iOS9GameDevelopmentEssentials
Copyright©2015PacktPublishing
Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,
ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthe
publisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.
Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyofthe
informationpresented.However,theinformationcontainedinthisbookissoldwithout
warranty,eitherexpressorimplied.Neithertheauthor,norPacktPublishing,andits
dealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecaused
directlyorindirectlybythisbook.
PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthe
companiesandproductsmentionedinthisbookbytheappropriateuseofcapitals.
However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.
Firstpublished:October2015
Productionreference:1261015
PublishedbyPacktPublishingLtd.
LiveryPlace
35LiveryStreet
BirminghamB32PB,UK.
ISBN978-1-78439-143-0
www.packtpub.com
CoverimagebyChuckGaffney
Credits
Author
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
AbouttheAuthor
ChuckGaffneyisaprogrammer,voiceactor,andgamedeveloper.Heownsacompany,
Chuck’sAnimeShrine,andhasworkedforsomestudiosinNewYork.SomeofChuck’s
recentprojectsincludeVRandUnityprojectsformajorstudiosandbusinessfirms,in
additiontoiOSandSwiftprogramming.
Iwouldliketothankmyfamilyforgivingmemyfirstvideogamesystemin1985atthe
youngageoftwo.Thewonderandmysteryofcontrollingwhat’sonthescreenhasstuck
withmeeversince.Mostimportantly,Iwouldliketothankmyfiancée,Danielle,for
keepingmeonmytoeswiththisbookandunderstandingthetimeittooktocraftit.Thank
youforbeingtherethroughtheupsanddownsthatcomefrompursuingsteadyand
worthwhileworkinthefieldofsoftwaredevelopment;particularlyduringthissummer,
whenthingsfinallychangedafteryearsofdoingnothingbutseeminglystaringatclosed
doorsandcallingouttodeafears.
AbouttheReviewers
MohitAthwaniisaself-taughtiOSdeveloperandhasbeendevelopingappssincethe
earlydaysofiOS3.Hehasworkedwithseveralclientsallaroundtheworld,andhas
carriedoutintenseresearchinthefieldoffacialdetectionandrecognitiononiOS.His
app,iRajanee,becamethenumberoneappontheIndianappstore,andhasfetchedhim
tremendoussuccess.
MohitstartedhiscompanyGeeks(http://www.geeksincorporated.net)withafriendin
2010,andhassincealsoinvolvedhimselfinconductingtrainingsessionsoniOSfor
studentsandcorporates.Hiswebsite,http://indianios.guru/,hostsalotofintroductory
videosandtutorialsondevelopingforiOSwithSwift.
IwouldliketothankmyparentsforgiftingmemyfirstMacBookandiPhonethatallowed
metobecomeaniOSdeveloper.Iwouldliketothankmyfriendsandeverybodywho
haveencouragedmetocomeupwithnewideasandconcepts,andPacktpublishingfor
givingmetheopportunitytoreviewthisbook.
RahulBorawarisacomputersciencegraduatefromJodhpurInstituteofEngineeringand
TechnologyinRajasthan,India.Heisapassionatesoftwarecraftsman,andloves
designingsoftwareformobiles.Fromthestart,hehasbeenamobileapplicationdeveloper
creatingapplicationsforiOSandAndroidplatforms.Hehasbeenworkingonmobile
developmentsince2011andhaspublishedmanyappsontheappstore,suchasCatchthe
Aliens(a2Dlevel-basedgame)andDrawYourStories(akids’appforcreatingfableswith
drawingstuffs).Heiscurrentlyworkingasasoftwaredevelopmentengineerinthemobile
teamforarealestateproduct-basedcompany(CommonFloor).Hehasreviewedonemore
bookforPacktPublications,namediOSGameProgrammingCookbook,whichcanbe
viewedathttps://www.packtpub.com/game-development/ios-game-programmingcookbook.
YoucanfollowhimonTwitter(https://twitter.com/RahulBorawar)andonGitHub
(https://github.com/Rahul2389).Youcanalsocheckhiswebsite,
http://rahulborawar.branded.me.
Firstofall,IwouldliketothankPacktPublishingforgivingmetheopportunitytoreview
thistechnology-richcookbookandenlightenmyiOSapplicationdevelopmentskills.
Secondly,thankstomyfamilyforsupportingmeinmycareerasatechnicalguy.
ChadyKassoufisanindependentiOSandwebdevelopmentexpert.Hestarted
programming23yearsagoandhasn’tstoppedsince.
Sevenyearsago,hedecidedtoleavehisjobasateamleaderinoneoftheleadingdigital
agenciesandstarthisownbusiness.
Hisinterests,besidescomputers,includearts,music,andfitness.Hecanbefoundonline
athttp://chady.net/.
JoniMikkolaiscurrentlyworkingonhisnextmobilegameinnorthernFinland.Hekeeps
hisgamedevelopingstaminaupbytrainingregularlyatthegymandeatinghealthily.
Amongdevelopinggames,heoftenreadsbooks,playsthepiano,orbakesbuns,tokeep
hisideasflowingandhismindfocused.Heconstantlykeepschallengingthestatusquo,
which,inturn,helpsinlearningnewwaystocreatethings.
Hehasdevelopedgamesprofessionallyforover4yearsmostlyformobileplatforms.He
targetscasualgamesandfocusesoncreatingsimplisticdesigns.Withonegamereleased,
heiscurrentlyworkingonhisnextgame,whichwillbereleasedinlate2015forAndroid
andiOSplatforms.
www.PacktPub.com
Supportfiles,eBooks,discountoffers,and
more
Forsupportfilesanddownloadsrelatedtoyourbook,pleasevisitwww.PacktPub.com.
DidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFand
ePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandas
aprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwith
usat<service@packtpub.com>formoredetails.
Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signup
forarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooks
andeBooks.
https://www2.packtpub.com/books/subscription/packtlib
DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigital
booklibrary.Here,youcansearch,access,andreadPackt’sentirelibraryofbooks.
Whysubscribe?
FullysearchableacrosseverybookpublishedbyPackt
Copyandpaste,print,andbookmarkcontent
Ondemandandaccessibleviaawebbrowser
FreeaccessforPacktaccountholders
IfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccess
PacktLibtodayandview9entirelyfreebooks.Simplyuseyourlogincredentialsfor
immediateaccess.
Preface
SincetheintroductionofiOS8in2014,gamedevelopmentfortheiOSplatformhasgone
throughsomemajorchanges.ThefirstofthosechangeswastheintroductionoftheSwift
programminglanguage,afunctionalprogramminglanguagemadebyAppletobesimple
tocodeandmoderninitscapabilities,allwhilebeingfastenoughtohandlemodernapp
andgamedevelopment.iOS8alsointroducedthe3Dgamedevelopmentframework,
SceneKit.SceneKitalloweddeveloperstoquicklydesign3Dgamesandworkwith3D
assetsinasimilarfashiontoiOS7’sSpriteKit.Ayearlater,inthesummerof2015,iOS9
wasintroduced,alongwithanewsetoftoolsforbothseasonedandbrandnewiOSgame
developers.Thenewframework,GameplayKit,letsdevelopershandlethegamerules,AI,
gameentities,andgamestatesseparatelyfromtheinheritancelogic.Inadditionto
GameplayKit,AppleshowedofftheFoxgameexamplethatdisplayshowXcodecannow
domuchofthesamevisualeditingfunctionalitiesseeninmultiplatformgameengines,
suchasUnityandUnrealEngine.
WewillfirstbecomefamiliarwiththeSwiftprogramminglanguageandhowitcanbe
usedinthescopeofgamedevelopment.ThegoalistounderstandiOSgamedevelopment
fromthegroundup,learningthetoughercode-centricmethodologyofmakingagame.In
additiontotakingalookatApple’sownexampleprojectsforthevariousiOSgame
frameworks,wewillseesomecodeexamplesfromtwogames,thefirstgamebeinga
publishedSwift-developed2DscrollinggamenamedPikiPopandtheotherbeingatilebasedMinesweeperclonenamedSwiftSweeper.Asweprogressthroughthebook,wewill
stillkeepcodeasthecoreofourmethodforgamedevelopment,butwilllookintothe
visualtoolsintroducediniOS9that,inadditiontoGameplayKitandthecomponentbasedstructuring,canallowustocreateagamethatisonlylimitedbyourimagination.
Wethendiveintotopicofthelow-levelAPIs,suchasOpenGLESandMetal,for
developerswhowishtogetdowndirectlytotheGPU.
Intheend,wehopethatyouunderstandhowiOScontinuestobeapowergame
developmentplatform,whetheryouareadeveloperwhocomesfromthetraditionalcodecentricschoolofcomputerscience,oryouareapartofthegrowingvisual-based/dragand-dropdesignparadigm.Ourgoalisthatwhenyouarefinishedwiththisbook,youwill
haveanumberofvastlydifferentanddetailedgameideas,whichyouthencan
immediatelybeginbuildingwithSwiftandtheiOS9platforms.
Whatthisbookcovers
Chapter1,TheSwiftProgrammingLanguage,providesanintroductionandguidanceto
theSwiftprogramminglanguage.
Chapter2,StructuringandPlanningaGameUsingStoryboardsandSegues,helpsreaders
knowthebasicflowofaniOSappbymakinguseofstoryboardsandseguesinorderto
eitherplanorpreplaniOSgames.
Chapter3,SpriteKitand2DGameDesign,introducesandexplainstheuseoftheiOS2D
gamedevelopmentframework,SpriteKit.
Chapter4,SceneKitand3DGameDesign,helpsreaderslookintotheiOS3D
developmentframework,SceneKit,andvisualtoolsintroducediniOSthatcanbeusedfor
bothSceneKitandSpriteKit.
Chapter5,Gameplaykit,introducestheGameplayKitframework,auniversalgamelogic
andAIframeworkintroducediniOS9.
Chapter6,ExhibittheMetalinyourGame,discussesaboutadvancedtopics,suchasthe
GPUgraphicspipelineandanintroductiontoApple’slow-levelAPI,Metal,forgetting
thebestperformanceoutofyourgame.
Chapter7,PublishingOuriOSGame,explainsthestepsneededtobetatestandpublish
iOSgamesbymakinguseofthetestingandqualityassuranceservice,TestFlight.
Chapter8,TheFutureofiOSGameDevelopment,discusseshowprogramming,iOS,and
gamedevelopmentasawholemightchangeorimproveinthenearfuture,andhowit
relatestothemostrecentiOSplatformsandframeworks.
Whatyouneedforthisbook
Here’swhatyouneedforthisbook:
Xcode7orlater
MacOSXYosemiteorlater
Whothisbookisfor
Thisbookisintendedforgamedeveloperswhowishtodevelop2Dand3Dgamesfor
iPhoneandiPad.Ifyouareadeveloperfromanotherplatformoragameenginesuchas
AndroidorUnity,acurrentiOSdeveloperwishingtolearnmoreaboutSwiftandthelatest
featuresofiOS9,orevenifyouarenewtogamedevelopment,thenthisbookisforyou.
Somepriorprogrammingknowledgeisrecommended,butnotrequired.
Conventions
Inthisbook,youwillfindanumberoftextstylesthatdistinguishbetweendifferentkinds
ofinformation.Herearesomeexamplesofthesestylesandanexplanationoftheir
meaning.
Codewordsintext,filenames,fileextensions,pathnames,anduserinput,areshownas
follows:“Aswecansee,theAppDelegate.swiftandtheViewController.swiftfiles
wereautomaticallycreatedforusandrightbelowthat,we’dfindtheMain.Storyboard
file.”
Ablockofcodeissetasfollows:
letscore=player.score
varscoreCountNum=0
do{
HUD.scoreText=String(scoreCountNum)
scoreCountNum=scoreCountNum*2
}whilescoreCountNum<score
Whenwewishtodrawyourattentiontoaparticularpartofacodeblock,therelevant
linesoritemsaresetinbold:
//Collisionbitmasks
typedefNS_OPTIONS(NSUInteger,AAPLBitmask){
AAPLBitmaskCollision=1UL<<2,
AAPLBitmaskCollectable=1UL<<3,
AAPLBitmaskEnemy=1UL<<4,
AAPLBitmaskSuperCollectable=1UL<<5,
AAPLBitmaskWater=1UL<<6
};
Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,for
example,inmenusordialogboxes,appearinthetextlikethis:”Alternately,imaginethat
theplayerlostalloftheirlivesandgotaGameOvermessage.”
Note
Warningsorimportantnotesappearinaboxlikethis.
Tip
Tipsandtricksappearlikethis.
Readerfeedback
Feedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthis
book—whatyoulikedordisliked.Readerfeedbackisimportantforusasithelpsus
developtitlesthatyouwillreallygetthemostoutof.
Tosendusgeneralfeedback,simplye-mail<feedback@packtpub.com>,andmentionthe
book’stitleinthesubjectofyourmessage.
Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingor
contributingtoabook,seeourauthorguideatwww.packtpub.com/authors.
Customersupport
NowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelp
youtogetthemostfromyourpurchase.
Downloadingtheexamplecode
Youcandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.com
forallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbook
elsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilesemaileddirectlytoyou.
Downloadingthecolorimagesofthisbook
WealsoprovideyouwithaPDFfilethathascolorimagesofthescreenshots/diagrams
usedinthisbook.Thecolorimageswillhelpyoubetterunderstandthechangesinthe
output.Youcandownloadthisfilefrom
http://www.packtpub.com/sites/default/files/downloads/iOS9_GameDevelopmentEssentials_Colo
Errata
Althoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdo
happen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthe
code—wewouldbegratefulifyoucouldreportthistous.Bydoingso,youcansaveother
readersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufind
anyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,
selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthe
detailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedand
theerratawillbeuploadedtoourwebsiteoraddedtoanylistofexistingerrataunderthe
Erratasectionofthattitle.
Toviewthepreviouslysubmittederrata,goto
https://www.packtpub.com/books/content/supportandenterthenameofthebookinthe
searchfield.TherequiredinformationwillappearundertheErratasection.
Piracy
PiracyofcopyrightedmaterialontheInternetisanongoingproblemacrossallmedia.At
Packt,wetaketheprotectionofourcopyrightandlicensesveryseriously.Ifyoucome
acrossanyillegalcopiesofourworksinanyformontheInternet,pleaseprovideuswith
thelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.
Pleasecontactusat<copyright@packtpub.com>withalinktothesuspectedpirated
material.
Weappreciateyourhelpinprotectingourauthorsandourabilitytobringyouvaluable
content.
Questions
Ifyouhaveaproblemwithanyaspectofthisbook,youcancontactusat
<questions@packtpub.com>,andwewilldoourbesttoaddresstheproblem.
Chapter1.TheSwiftProgramming
Language
Atthecoreofgamedevelopmentisyourgame’scode.Itisthebrainofyourprojectand
outsideoftheart,sound,andvariousassetdevelopments.Itiswhereyouwillspendmost
ofyourtimecreatingandtestingyourgame.UpuntilApple’sWorldwideDevelopers
ConferenceWWDC14inJuneof2014,thecodeofchoiceforiOSgameandapp
developmentwasObjective-C.AtWWDC14,anewandfasterprogramminglanguage,
Swift,wasannouncedandisnowtherecommendedlanguageforallcurrentandfuture
iOSgamesandgeneralappcreation.
Asofthetimeofwriting,youcanstilluseObjective-Ctodesignyourgames,but
programmers,both,newandseasoned,willseewhywritinginSwiftisnotonlyeasierfor
expressingyourgame’slogic,butevenmorepreformat.Keepingyourgamerunningat
thatcritical60fpsisdependentonfastcodeandlogic.EngineersatAppledevelopedthe
Swiftprogramminglanguagefromthegroundupwithperformanceandreadabilityin
mind,sothislanguagecanexecutecertaincodeiterationsfasterthanObjective-Cwhile
alsokeepingcodeambiguitytoaminimum.Swiftalsousesmanyofthemethodologies
andsyntaxesfoundinmoremodernlanguages,suchasScala,JavaScript,Ruby,and
Python.
So,let’sdiveintotheSwiftlanguage.
Note
Itisrecommendedthatsomebasicknowledgeofobject-orientedprogramming(OOP)be
knownpreviously,butwewilltrytokeepthebuild-upandexplanationofcodesimpleand
easytofollowaswemoveontothemoreadvancedtopicsrelatedtogamedevelopment.
HelloWorld!
It’ssomewhattraditionalwhenlearningprogramminglanguagestobeginwithaHello
Worldexample.AHelloWorldprogramissimplyusingyourcodetodisplayorlogthe
textHelloWorld.It’salwaysbeenthegeneralstartingpointbecausesometimesjust
gettingyourcodeenvironmentsetupandhavingyourcodeexecutingcorrectlyishalfthe
battle.Atleast,thiswasmorethecaseinolderprogramminglanguages.
Swiftmakesthiseasierthanever,andwithoutgoingintothestructureofaSwiftfile
(whichweshalldolateronandisalsomucheasierthanObjective-Candpastlanguages),
here’showyoucreateaHelloWorldprogram:
print("Hello,World!")
That’sit!ThatisallyouneedtohavethetextHelloWorldappearinXcode’sdebugarea
output.
Nomoresemicolons
Thoseofuswhohavebeenprogrammingforsometimemightnotethattheusuallyallimportantsemicolon(;)ismissing.Thisisn’tamistake;inSwift,wedon’thavetousea
semicolontomarktheendofanexpression.Wecanifwe’dlike,andsomeofusmight
stilldoitasaforceofhabit,butSwifthasomittedthatcommonconcern.
Note
Theuseofthesemicolontomarktheendofanexpressionstemsfromtheearliestdaysof
programmingwhencodewaswritteninsimplewordprocessorsandneededaspecial
charactertorepresentwhenthecode’sexpressionendsandthenextbegins.
Variables,constants,andprimitivedata
types
Whileprogramminganyapplication,eitherifnewtoprogrammingortryingtolearna
differentlanguage,firstweshouldgetanunderstandingofhowalanguagehandles
variables,constants,andvariousdatatypes,suchasBooleans,integers,floats,strings,and
arrays.Youcanthinkofthedatainyourprogramasboxesorcontainersofinformation.
Thosecontainerscanbeofdifferentflavorsortypes.Throughoutthelifeofyourgame,
thedatacanchange(variables,objects,andsoon)ortheycanstaythesame.
Forexample,thenumberoflivesaplayerhaswouldbestoredasavariable,asthatis
expectedtochangeduringthecourseofthegame.Thatvariablewouldthenbeofthe
primitivedatatypeinteger,whichisbasicallywholenumbers.Datathatstores,say,the
nameofacertainweaponorpower-upinyourgame,wouldbestoredinwhat’sknownas
aconstant,asthenameofthatitemisnevergoingtochange.Inagamewheretheplayer
canhaveinterchangeableweaponsorpower-ups,thebestwaytorepresentthecurrently
equippeditemwouldbetouseavariable.Avariableisapieceofdatathatisboundto
change.Thatweaponorpower-upwillalsomostlikelyhaveabitmoreinformationtoit
thanjustanameornumber;theprimitivetypeswementionedprior.Thecurrently
equippeditemwouldbemadeupofproperties,suchasitsname,power,effects,index
number,andthespriteor3Dmodelthatvisuallyrepresentsit.Thus,thecurrently
equippeditemwouldn’tjustbeavariableofaprimitivedatatype,butbewhatisknownas
atypeofobject.Objectsinprogrammingcanholdanumberofpropertiesand
functionalitiesthatcanbethoughtofasablackboxofbothfunctionandinformation.The
currentlyequippediteminourcasewouldbeasortofplaceholderthatcanholdanitemof
thattypeandinterchangeitwhenneeded,fulfillingitspurposeasareplaceableitem.
Note
Swiftiswhat’sknownasatype-safelanguage,soweshouldkeeptrackoftheexacttype
ofdataandevenit’sfutureusage(thatis,ifthedataisorwillbeNULL),asit’svery
importantwhenworkingwithSwiftcomparedwithotherlanguages.ApplemadeSwift
behavethiswaytohelpkeepruntimeerrorsandbugsinyourapplicationstoaminimum,
sowecanfindthemmuchearlierinthedevelopmentprocess.
Variables
Let’slookathowvariablesaredeclaredinSwift.
varlives=3//variableofrepresentingtheplayer'slives
lives=1//changesthatvariabletoavalueof1
ThoseofuswhohavebeendevelopinginJavaScriptwillfeelrightathomehere.Like
JavaScript,weusethekeywordvartorepresentavariable,andwenamedthevariable
lives.
Thecompilerimplicitlyknowsthatthetypeofthisvariableisawholenumber,the
primitivedatatypeInt.
Thetypecanbeexplicitlydeclaredassuch:
varlives:Int=3//variableoftypeInt
Wecanalsorepresentlivesasthefloatingpointdatatypesdoubleorfloat,asfollows:
//livesarerepresentedhereas3.0insteadof3
varlives:Double=3//oftypeDouble
varlives:Float=3//oftypeFloat
Usingacolonafterthevariable’snamedeclarationallowsustoexplicitlytypecastthe
variable.
Constants
Duringyourgame,therewillbepointsofdatathatdon’tchangethroughoutthelifeofthe
gameorthegame’scurrentlevel/scene.Thesecanbevariousdata,suchasgravity,atext
labelintheHeads-UpDisplay(HUD),thecenterpointofcharacter’s2Danimation,an
eventdeclaration,orthetimebeforeyourgamechecksfornewtouches/swipes.
Declaringconstantsisalmostthesameasdeclaringvariables.
Usingacolonafterthevariable’snamedeclarationallowsustoexplicitlytypecastthe
variable.
letgravityImplicit=-9.8//implicitdeclaration
letgravityExplicit:Float=-9.8//explicitdeclaration
Aswecansee,weusethekeywordlettodeclareconstants.
Here’sanotherexampleusingastringthatcouldrepresentamessagedisplayedonthe
screenatthestartorendofastage:
letstageMessage="Start!"
stageMessage="YouLose!"//error
SincethestringstageMessageisaconstant,wecannotchangeitonceithasbeen
declared.Somethinglikethiswouldbebetterasavariableusingvarinsteadoflet.
Tip
“Whydon’twedeclareeverythingasavariable?”
Thisisaquestionsometimesaskedbynewdevelopersandisunderstandablewhyit’s
asked,especiallysincegameappstendtohavealargenumberofvariablesandmore
interchangeablestatesthananaverageapplication.Whenthecompilerisbuildingits
internallistofyourgame’sobjectsanddata,moregoesonbehindthesceneswith
variablesthanwithconstants.
Withoutgettingtoomuchintotopics,suchastheprogram’sstackandotherdetails,in
short,havingobjects,events,anddatadeclaredasconstantswiththeletkeywordismore
efficientthanvar.Inasmallapponthenewestdevicestoday,thoughnotrecommended,
wecouldpossiblygetawaywiththiswithoutseeingagreatdealoflossinapp
performance.Whenitcomestovideogames,however,performanceiscritical.Buying
backasmuchperformanceaspossiblecanallowabetterplayerexperience.Apple
recommendsthatwhenindoubt,alwaysuseletatthetimeofdeclarationandhavethe
compilersaywhentochangetovar.
Moreaboutconstants…
AsofSwiftversion1.2,constantscanhaveaconditionallycontrolledinitialvalue.
Priortothisupdate,wehadtoinitializeaconstantwithasinglestartingvalueorbeforced
tomakethepropertyavariable.InXcode6.3andnewer,wecanperformthefollowing
logic:
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’sinitializationcanhavealayerofvariancewhilestill
keepingitunchangeable,orimmutablethroughitsuse.Here,theconstantstageBosscan
beoneoftwotypesbasedonthegame’sdifficulty:Boss.toughBoss()or
Boss.normalBoss().Thebosswon’tchangeforthecourseofthisstage,soitmakessense
tokeepitasaconstant.Moreonifandelsestatementsiscoveredlaterinthechapter.
Arrays,matrices,sets,anddictionaries
Variablesandconstantscanrepresentacollectionofvariouspropertiesandobjects.The
mostcommoncollectiontypesarearrays,matrices,sets,anddictionaries.Anarrayisan
orderedlistofdistinctobjects;amatrixis,inshort,anarrayofarrays;asetisan
unorderedlistofdistinctobjects;andadictionaryisanunorderedlistthatutilizesakey:
valueassociationwiththedata.
Arrays
Here’sanexampleofanarrayinSwift:
letstageNames:[String]=["DowntownTokyo","HeavenValley","Nether"]
TheobjectstageNamesisacollectionofstringsrepresentingthenamesofagame’s
stages.Arraysareorderedbysubscriptsfrom0toarraylength-1.So,stageNames[0]
wouldbeDowntownTokyo;stageNames[2]wouldbeNether;andstageNames[4]would
giveanerrorsincethat’sbeyondthelimitsofthearrayanddoesn’texist.Weuse[]
bracketsaroundtheclasstypeofstageNames,[String],totellthecompilerthatweare
dealingwithanarrayofstrings.Bracketsarealsousedaroundtheindividualmembersof
thisarray.
2Darrays/matrices
Acommoncollectiontypeusedinphysicscalculations,graphics,andgamedesign,
particularlygrid-basedpuzzlegames,istwo-dimensionalarrays/matrices.2Darraysare
simplyarraysthathavearraysastheirmembers.Thesearrayscanbeexpressedina
rectangularfashioninrowsandcolumns.
Forexample,the4x4(4rows,4columns)tileboardinthe15-puzzlegamecanbe
representedasfollows:
vartileBoard=[[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[13,14,15,""]]
Inthe15puzzlegame,yourgoalistoshiftthetilesusingtheoneemptyspot(represented
withtheblankstring""),toallendupinthe1-15orderaswesaw.Thegamewouldstart
withthenumbersarrangedinarandomandsolvableorder,andtheplayerwouldthenhave
toswapthenumbersandtheblankspace.
Tip
Tobetterperformvariousactionsonand/orstoreinformationabouteachtileinthe15
game(andothergames),it’dbebettertocreateatileobjectasopposedtousingraw
valuesseenhere.Forthesakeofunderstandingwhatamatrixor2Darrayis,simplymake
anoteofhowthearrayissurroundedbydoublyencapsulatedbrackets[[]].Wewilllater
useoneofourexamplegames,SwiftSweeper,tobetterunderstandhowpuzzlegamesuse
2Darraysofobjectstocreateafullgame.
Herearewaystodeclareblank2Darrayswithstricttypes:
vartwoDTileArray:[[Tiles]]=[]//blank2Darrayoftype,Tiles
varanotherArray=Array<Array<Tile>>()//samearray,usingGenerics
ThevariabletwoDTileArrayusesthedoublebrackets[[Tiles]]todeclareitasablank
2Darray/matrixforthemade-uptype,tiles.ThevariableanotherArrayisaratheroddly
declaredarraythatusesanglebracketcharacters<>forenclosures.Itutilizeswhat’s
knownasGenerics.Genericsisaratheradvancedtopicthatwewilltouchmoreonlater.
Theyallowveryflexiblefunctionalityamongawidearrayofdatatypesandclasses.For
themoment,wecanthinkofthemasacatch-allwayofworkingwithobjects.
Tofillinthedataforeitherversionofthisarray,wewouldthenusefor-loops.Moreon
loopsanditerationswillbeexplainedlaterinthechapter.
Sets
ThisishowwewouldmakeasetofvariousgameitemsinSwift:
varkeyItems=Set([Dungeon_Prize,Holy_Armor,Boss_Key,"A"])
ThissetkeyItemshasvariousobjectsandacharacterA.Unlikeanarray,asetisnot
orderedandcontainsuniqueitems.So,unlikestageNames,attemptingtogetkeyItems[1]
wouldreturnanerroranditems[1]mightnotnecessarilybetheHoly_Armorobject,asthe
placementofobjectsisinternallyrandominaset.Theadvantagesetshaveoverarraysis
thatsetsaregreatatcheckingforduplicatedobjectsandspecificcontentsearchinginthe
collectionoverall.Setsmakeuseofhashingtopinpointtheiteminthecollections,so
checkingforitemsinaset’scontentcanbemuchfasterthaninanarray.Ingame
development,agame’skeyitems,whichtheplayermayonlygetonceandshouldnever
haveduplicatesof,couldworkgreatasaset.Usingthefunction
keyItems.contains(Boss_Key)returnstheBooleanvalueoftrueinthiscase.
Note
SetswereaddedinSwift1.2andXcode6.3.Theirclassisrepresentedbythegenerictype
Set<T>,whereTistheclasstypeofthecollection.Inotherwords,theset,Set([45,66,
1233,234]).wouldbeofthetypeSet<Int>,andourexampleherewouldbea
Set<NSObject>instanceduetoithavingacollectionofvariousdatatypes.
WewilldiscussmoreonGenericsandclasshierarchylaterinthischapter.
Dictionaries
AdictionarycanberepresentedthiswayinSwift:
varplayerInventory:[Int:String]=[1:"BusterSword",43:
"Potion",22:"StrengthBooster"]
Dictionariesuseakey:valueassociation,soplayerInventory[22]returnsthevalue
StrengthBoosterbasedonthekey22.Boththekeyandvaluecouldbeinitializedto
almostanyclasstype*.Inadditiontotheinventoryexamplegiven,wecanhavethe
followingcode:
varstageReward:[Int:GameItem]=[:]//blankinitialization
//useoftheDictionaryattheendofacurrentstage
stageReward=[currentStage.score:currentStage.rewardItem]
Note
*Thevaluesofadictionary,thoughratherflexibleinSwift,dohavelimitations.Thekey
mustconformtowhat’sknownasthehashableprotocol.Basicdatatypes,suchasIntand
String,alreadyhavethisfunctionality.So,ifyouaretomakeyourownclasses/data
structuresthataretobeusedindictionaries,saymappingaplayeractionswithplayer
input,thisprotocolmustbeutilizedfirst.Wewilldiscussmoreaboutprotocolslaterinthis
chapter.
Dictionariesarelikesetsinthattheyareunorderedbutwiththeadditionallayerofhaving
akeyandavalueassociatedwiththeircontentinsteadofjustthehashkey.Likesets,
dictionariesaregreatforquickinsertionandretrievalofspecificdata.IniOSappsandin
webapplications,dictionariesareusedtoparseandselectitemsfromJavaScriptObject
Notation(JSON)data.
Intherealmofgamedevelopment,dictionariesusingJSONorviaApple’sinternaldata
class,NSUserDefaults,canbeusedtosaveandloadgamedata,setupgame
configurations,oraccessspecificmembersofagame’sAPI.
Forexample,here’sonewaytosaveaplayer’shighscoreinaniOSgameusingSwift:
letnewBestScore:Void=
NSUserDefaults.standardUserDefaults().setInteger(bestScore,forKey:
"bestScore")
ThiscodecomesdirectlyfromapublishedSwift-developedgamenamedPikiPop,which
wewillusefromtimetotimetoshowcodeusedinactualgameapplications.
Again,notethatdictionariesareunordered,butSwifthaswaystoiterateorsearchthrough
anentiredictionary.Wewillgomoreindepthinthenextsectionandlateronwhenwe
moveontoloopsandcontrolflow.
Mutable/immutablecollections
Oneratherimportantdiscussionthatwe’veleftoutishowtosubtract,edit,oraddto
arrays,sets,anddictionaries.However,beforewedothis,youshouldunderstandthe
conceptofmutableandimmutabledata/collections.
Amutablecollectionissimpledatathatcanbechanged,addedto,orsubtractedfrom,
whereasanimmutablecollectioncannotbechanged,addedto,orsubtractedfrom.
ToworkwithmutableandimmutablecollectionsefficientlyinObjective-C,wehadto
explicitlystatethemutabilityofthecollectionbeforehand.Forexample,anarrayofthe
typeNSArrayinObjective-Cisalwaysimmutable.Therearemethodswecancallon
NSArraythatwouldeditthecollection,butbehindthescenes,thiswouldbecreatingbrand
newNSArrayobjects,thuswouldberatherinefficienttodothisofteninthelifeofour
game.Objective-Chassolvedthisissuewiththeclasstype,NSMutableArray.
ThankstotheflexibilityofSwift’stypeinference,wealreadyknowhowtomakea
collectionmutableorimmutable!Theconceptofconstantsandvariableshasuscovered
whenitcomestodatamutabilityinSwift.Usingthekeywordletwhencreatinga
collectionwillmakethatcollectionimmutable,whileusingvarwillinitializeitasa
mutablecollection.
//mutableArray
varunlockedLevels:[Int]=[1,2,5,8]
//immutableDictionary
letplayersForThisRound:[PlayerNumber:PlayerUserName]=
[453:"userName3344xx5",233:"princeTrunks",6567:"noScopeMan98",211:
"egoDino"]
Thearrayofintegers,unlockedLevels,canbeeditedsimplybecauseit’savariable.The
immutabledictionaryplayersForThisRoundcan’tbechangedsinceit’salreadybeen
declaredasaconstant.Thereisnoadditionallayerofambiguityconcerningadditional
classtypes.
Editing/accessingcollectiondata
Aslongasacollectiontypeisavariable,usingthevarkeyword,wecandovariousedits
tothedata.Let’sgobacktoourunlockedLevelsarray.Manygameshavethe
functionalityofunlockinglevelsastheplayerprogresses.Let’ssaythattheplayerhas
reachedthehighscoreneededtounlockthepreviouslylockedlevel3(as3isn’tamember
ofthearray).Wecanadd3tothearrayusingtheappendfunction:
unlockedLevels.append(3)
AnotherneatattributeofSwiftisthatwecanadddatatoanarrayusingthe+=assignment
operator:
unlockedLevels+=[3]
Doingitthiswayhoweverwillsimplyadd3totheendofthearray.So,ourpreviousarray
[1,2,5,8]isnow[1,2,5,8,3].Thisprobablyisn’tadesirableorder,sotoinsert
thenumber3inthethirdspot,unlockedLevels[2],wecanusethefollowingmethod:
unlockedLevels.insert(3,atIndex:2)
Now,ourarrayofunlockedlevelsisorderedto[1,2,3,5,8].
Thisisassumingthoughthatweknowamemberofthearraypriorto3issortedalready.
TherearevarioussortingfunctionalitiesprovidedbySwiftthatcouldhelpkeepingan
arraysorted.Wewillleavethedetailsofsortingtoourdiscussionsofloopsandcontrol
flowlaterinthischapter.
Removingitemsfromanarrayisjustsimple.Let’sagainuseourunlockedLevelsarray.
Imaginethatourgamehasanoverworldfortheplayertotraveltoandfromandtheplayer
hasjustunlockedasecretthattriggeredaneventthatblockedoffaccesstolevel1.Level1
wouldnowhavetoberemovedfromtheunlockedlevels.Wecandoitlikethis:
unlockedLevels.removeAtIndex(0)//arrayisnow[2,3,5,8]
Alternately,imaginethattheplayerhaslostalloftheirlivesandgotaGameOver
message.Apenaltyforthiscouldbetolockthefurthestlevel.Thoughprobablyarather
infuriatingmethodandusknowingthatlevel8isthefurthestlevelinourarray,wecan
removeitusingthe.removeLast()functionofarraytypes.
unlockedLevels.removeLast()//arrayisnow[2,3,5]
Note
Thisisassumingthatweknowtheexactorderofthecollection.Setsordictionariesmight
bebetteratcontrollingcertainaspectsofyourgame.
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)
Iteratingthroughcollectiontypes
Wecan’tdiscusscollectiontypeswithoutmentioninghowtoiteratethroughthemen
masse.
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.Thecodewill
repeatuntilitreachestheendofthecollectioninalloftheseexamples.Inexample(c),
wealsoseetheuseoftheSwiftfunction,enumerate().Thisfunctionreturnsacompound
value,(index,value),foreachitem.Thiscompoundvalueisknownasatuple,and
Swift’suseoftuplesmakesforawidevarietyoffunctionalitiesforfunctions,loops,as
wellascodeblocks.
Wewilldelvemoreintotuples,loops,andblockslateron.
Objective-CandSwiftcomparison
Here’saquickreviewofourSwiftcodewithacomparisontotheObjective-Cequivalent.
Objective-C
Here’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];
Swift
Here’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,and
dictionaries.First,weseetheirObjective-Csyntaxandthentheequivalentdeclarations
usingSwift’ssyntax.Fromthisexample,wecanseehowcompactSwiftiscomparedwith
Objective-C.
Charactersandstrings
Forsometimeinthischapter,we’vebeenmentioningstrings.Stringsarealsoacollection
ofdatatypes,butaspeciallydealtcollectionofcharacters,oftheclasstype,string.Swift
isUnicode-compliant,sowecanhavestringslikethefollowing:
letgameOverText="GameOver!"
Wecanhavestringswithemojicharacterslikethefollowing:
letcardSuits="♠♥♣♦"
Whatwedidintheprecedingcodewascreatewhat’sknownasastringliteral.Astring
literaliswhenweexplicitlydefineastringaroundtwoquotes””.
Wecancreateemptystringvariablesforlateruseinourgamessuchas:
varemptyString=""//emptystringliteral
varanotherEmptyString=String()//usingtypeinitializer
Botharevalidwaystocreateanemptystring””.
StringInterpolation
Wecanalsocreateastringfromamixtureofotherdatatypes,knownasString
Interpolation.StringInterpolationisrathercommoningamedevelopment,debugging,
andstringuseingeneral.
Themostnotableofexamplesaredisplayingtheplayer’sscoreandlives.Thisishowone
ofourexamplegames,PikiPop,usesStringInterpolationtodisplaythecurrentplayer
stats:
//displaystheplayer'scurrentlives
varlivesLabel="x\(currentScene.player!.lives)"
//displaystheplayer'scurrentscore
varscoreText="Score:\(score)"
Takenoteofthe\(variable_name)formatting.We’veactuallyseenthisbeforeinourpast
codesnippets.Inthevariousprint()outputs,weusedthistodisplaythevariable,
collection,andsoonwewantedtogetinformationon.InSwift,thewaytooutputthe
valueofadatatypeinastringisbyusingthisformatting.
ForthoseofuswhocamefromObjective-C,it’sthesameasthefollowing:
NSString*livesLabel=@"Lives:";
intlives=3;
NSString*livesText=[NSStringstringWithFormat:@"%@(%ddaysago)",
livesLabel,lives];
NotehowSwiftmakesStringInterpolationmuchcleanerandeasiertoreadthanits
Objective-Cpredecessor.
Mutatingstrings
Therearevariouswaystochangestrings,suchasaddingcharacterstoastringaswedidto
collectionobjects.Herearesomebasicexamples:
vargameText="Theplayerentersthestage"
gameText+="andquicklylostduetonotlevelingup"
/*gameTextnowsays
"Theplayerentersthestageandlostduetonotlevelingup"*/
Sincestringsareessentiallyarraysofcharacters,likearrays,wecanusethe+=assignment
operatortoaddtothepreviousstring.
Also,akintoarrays,wecanusetheappend()functiontoaddacharactertotheendofa
string.
letexclamationMark:Character="!"
gameText.append(exclamationMark)
//gameTextnowsays"Theplayerentersthestageandlostduetonot
levelingup!"
Here’showweiteratethroughthecharactersinastring,inSwift:
forcharacterin"Start!"{
print(character)
}
//outputs:
//S
//t
//a
//r
//t
//!
Notehowagainweusethefor-inloopandevenhavetheflexibilityofusingastringliteral
ifwe’dsoliketobewhat’siteratedthroughbytheloop.
Stringindices
Anothersimilaritybetweenarraysandstringsisthefactthatastring’sindividual
characterscanbelocatedviaindices.Unlikearrays,however,sinceacharactercanbea
varyingsizeofdata,brokenin21-bitnumbersknownasUnicodescalars,theycannotbe
locatedinSwiftwithInttypeindexvalues.
Instead,wecanusethe.startIndexand.endIndexpropertiesofastringandmoveone
placeaheadoroneplacebehindtheindexwiththe.successor()and.predecessor()
functions,respectively,toretrievetheneededcharacterorcharactersofastring.
Herearesomeexamplesthatusethesepropertiesandfunctionsusingourprevious
gameTextstring:
gameText[gameText.startIndex]//=T
gameText[gameText.endIndex]//=!
gameText[gameText.startIndex.successor()]//=h
gameText[gameText.endIndex.predecessor()]//=p
Note
Therearemanywaystomanipulate,mix,remove,andretrievevariousaspectsofstrings
andcharacters.Formoreinformation,besuretocheckouttheofficialSwift
documentationoncharactersandstringsat
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_La
CommentinginSwift
Inourcodesnippetsthusfar,onemightnotenotationswithdoubleforwardslashes//or
withforwardslashesandasterisks/**/.Thesearehowwecancommentormake
notationsinourSwiftcode.Anyonewho’scodedinC++,Java,Objective-C,JavaScript,
orotherlanguageswillseethatSwiftworkspracticallythesame.
Single-linecommentsarestartedwiththedoubleforwardslashes,//,whilemultiline
commentsoracommentblockbeginswith/*andendswith*/.
Takethefollowingexample:
//Thisisasinglelinecomment
/*
Thisisacommentblock
thatwon'tenduntilitreachestheclosingasterisk/forwardslash
characters
*/
Commentingisusedtohelpnavigateyourcode,understandwhatitmightdo,and
commentoutlinesofcodewemightnotwanttoexecute,butatthesametimewantto
keepforlater(thatis,print()logcallsoralternativestartingpropertyvalues).
Note
FromXcode6Beta4onward,wecanalsoutilizethefollowingcomments:
//MARK:,//TODO:,and//FIXME.//MARKisequivalenttoObjective-C’s#pragmamark,
whichallowstheprogrammertolabelasectionofyourcodethatisaccessibleinXcode’s
topbreadcrumbdropdownlist.//TODO:and//FIXMEgiveustheabilitytosectionoff
partsofcodethatwewishtomaybeaddfeaturestointhefutureordebug.Evengames
withwell-organizedclassstructuringcanbedauntingtosiftthrough.Theadditionofthese
additionalmark-uptoolsmakesplanningandsearchingthroughourgames’codethat
mucheasiertodo.
Boolean
Anintegralpartofallprogramming,game,orotherwiseistheuseofBooleanvalues.
Booleanvaluestypicallyreturneithertrueorfalsevalues,yesorno,or0or1.InSwift,
thisisthejoboftheBoolclassofobjects.Theuseofthefunction.isEmpty()inourpast
collectiondatatypeexamplesreturnsaBooleanvalueoftrueorfalsebasedonwhether
thatcollectionisemptyornot.
Ingamedevelopment,onewaywecoulduseBooleanvaluesistohaveaglobalvariable
(avariableaccessibleinscopethroughoutourgame/app)thatchecksifthegameisover.
varisGameOver=false
Thisvariable,takenfromthePikiPopgame,startsthegameoffwithavariableoftype
boolnamedisGameOverwithastartingvalueoffalse.Iftheeventsofthegamecause
thisvaluetochangetotrue,thenthistriggerstheeventsassociatedwiththegameover
state.
Note
UnlikeBooleanvaluesinObjective-C,Swiftusesonlytrueorfalsevaluestorepresent
Booleanvariables.SwiftstricttypesafetydoesnotallowtheuseofYESandNOor0and1,
aswehaveseeninObjective-Candotherprogramminglanguages.
However,readingandcontrollingthistypeofinformationaboutourgame,knownasthe
game’sstate,isbestcontrolledwithmorethanjustasingleBooleanvalue.Thisisbecause
yourgameandthecharactersinyourgamecouldhavevariousstates,suchasgameover,
paused,spawn,idle,running,falling,andmore.Aspecialobjectknownasastatemachine
bestmanagesthistypeofinformation.Statemachinesshallbecoveredinmoredetail
whenwediscusstheGameplayKitframework.
Ints,UInts,floats,anddoubles
InadditiontoBooleanvalues,anotherbasicdatatypewehaveuptothispointbriefly
mentionedisthevariousnumericobjects,suchasintegers(Ints),unsignedintegers
(UInts),floatingpointnumbers/decimals(floats),anddoubleprecisionfloatingpoint
numbers/decimals(doubles).
Integersandunsignedintegers
Integersrepresentnegativeandpositivewholenumbers,whileunsignedintegersrepresent
positivewholenumbers.LikewithCandotherprogramminglanguages,Swiftletsus
createvarioustypesofintegersandunsignedintegersfrom8,16,32,and64bits.For
example,anInt32typeisa32-bitinteger,whileaUInt8typeisan8-bitunsignedinteger.
ThesizeofthebitsforIntsandUIntsrepresentshowmuchspaceisbeingallocatedto
storethevalues.UsingourUInt8example,anumbermadefromthistypeofunsignedInt
canonlystorethevalues0-255(or11111111inabase-2system).Thisisalsoknownas1
byte(8bits).Ifweneedtostorenumberslargerthan255ornegativenumbers,thenmaybe
anInt16typewouldsufficeasthatcanstorenumbersbetween–32767and32767.
Usually,wedon’thavetoworrytoomuchaboutthesizeallocatedbyourintegervariables
andconstants.So,usingjusttheclassnameofIntwillworkfineinmostcases.
Note
ThesizeofIntwilldifferdependingonthetypeofsystemweareworkingon.Ifweare
compilingourcodeona32-bitsystem,anintegerwillbeequaltoInt32,whilethesame
integerwouldbeanInt64ona64-bitsystem.
SwiftcanletusseewhatourminimumandmaximumvaluesareforanIntvariablewith
the.minor.maxclassvariables(thatis,Int16.max=32767andUInt.min=0).
Floatsanddoubles
Floatsare32bitfloatingpointnumbers/fractions,suchaspi(3.14),orthegoldenratio,
phi(1.61803).
Ingamedesigning,weworkwithfloatingpointvaluesandrangesratheroften,beitto
determinetheCGPointinxandyofa2Dsprite,usinglinearinterpolationforsmoothinga
game’scameramovementin3Dspace,orapplyingvariousphysicsforcesonanobjector
2D/3Dvector.Theprecisionneededforeachsituationwilldetermineifafloatisneeded
orifthe64-bitfloatingpointvalue,thedoubleisneeded.Doublescanbeaspreciseas15
decimalplaces,whileafloatissixdecimalplacesprecise.
Tip
It’sactuallybestpracticetousedoublesinsituationsthatwouldworkforeitherfloatsor
doubles.
ObjectsinSwift
Thecoreaspectofobject-orientedprogramming(OOP)isofcoursetheconceptof
objects.C++beganthisparadigminprogramming,whileJava,C#,Apple’sObjective-C,
andotherlanguageswereallessentiallybuiltfromthisfoundation.
SwiftisanOOPlanguagewiththesamedynamicobjectmodelasObjective-C,but
presentedinacleaner,type-safe,andcompactway.
Youcanthinkofanobjectexactlyasitsounds,anabstractthingorcontainer.Anobject
canbesomethingassimpleasastring,orsomethingascomplexastheplayerobjectinthe
latestvideogame.Technicallyspeaking,anobjectinaprogramisareferencetoasetof
variousdatainanallocatedchunkofmemory,butit’ssufficienttojustunderstandthatan
objectcanbeavariableorareferencetoaninstanceofaclass,Struct,orblockofcode.
Anobjectcanhavevariousdatafields/aspectsassociatedwithit,suchasproperties,
functions,parentobjects,childobjects,andprotocols.InlanguagessuchasCforexample,
anintegervariableisusuallyrepresentedasjustrawdata,buttheintegertypeinSwiftis
actuallyanobject.Thus,wecanaccessextrainformationandperformfunctionsonInt
objectsinourcode.WepreviouslysawthiswiththeInt.maxvariable,whichreturnsthe
highestnumberthatcanberepresentedbytheIntclass.Again,dependingonthemachine
youareworkingon,thiscouldbethesamevalueasInt32.maxorInt64.max.
varhighestIntNumber:Int=Int.max
Accesstofunctionsandpropertiesofanobjectusesdotnotation,aswesawwiththe
previousexample.Int.maxandInt.minareactuallyspecialpropertiesknownasclass
variables,whichrepresentallinstancesofanInttypeobject.
Let’slookathowSwiftdealswithobtainingpropertiesandfunctionsofaninstanceofan
objectusingamade-upPlayertypeobject.
letcurrentPlayer=Player(name:"Fumi")//(a)
letplayerName=currentPlayer.getName()//(b)
varplayerHealth=currentPlayer.health//(c)
currentPlayer.attackEnemy()//(d)
We’llgetbacktothesecondhalfofline(a),butjustunderstandthatitcreatesaninstance
ofanobjectofthetypePlayernamedcurrentPlayer.Line(c)createsavariablenamed
playerHealththat’ssetbythehealthpropertyofcurrentPlayer;herewiththedot
notation.Lines(b)and(d)usethedotnotationtocallthefunctionsgetName()and
attackEnemy().ThegetName()functioninthiscaseisafunctionthatreturnsastring
that’sassignedtotheconstant,playerName.Line(c)createsavariablenamed
playerHealththatiscreatedbyreferencingthehealthpropertyofcurrentPlayer,also
usingdotnotation.Line(d)isadirectcalltothePlayerclass’attackEnemy()function,
whichyoucanimaginefornowjustperformswhatwouldmakecurrentPlayerdoher
attack.Thisfunctiondoesn’treturnavalueandthusiswhat’sknownasavoidtype
function.
Asforline(a),onemightnotethatitdoesn’tusethedotnotation.ThisishowSwiftdoes
what’sknownasaclassinitializer;designatedbytheparenthesis()aftertheclassname
andwiththeparametercalledname:thatsendsastring,Fumi,totheobject’sclass
initializer.
Wewillbedivingdeeperintotheuseofobjectsmomentarilyaswemoveontofunctions
andclasses.
Typesafetyandtypeinference
Objectsand,aswe’llsee,functionsontheseobjectsinSwiftaretype-safe.Whatthis
meansisthatifweperformafunctiononastringobjectwhenthecodewasexpectingan
integer,thenthecompilerwillwarnusearlyonintheprocess.Intheveinofgamedesign,
ifweweretohavetheplayerperformanactiononlyanenemysupposedtodo,thenSwift
willknowthroughitsinherentlytype-safenature.
Swift’stypeinferenceissomethingwe’vementionedbefore.Unlikeotherlanguages
whereyouhavetodeclaretheobject’stypeeverytimeit’sinitialized,Swiftwillinferwhat
typeyoumean.Forexample,wehavethefollowing:
varplayerHealth=100
//SwiftautomaticallyinfersthatplayerHealthisanIntobject
Optionals
Aswestatedbefore,Swiftisatype-safelanguage.ApplealsocreatedSwiftwiththe
intentionofkeepingasmanypotentialerrorsandbugsinthecompilationstateof
developmentasopposedtoruntime.ThoughXcodehassomegreatdebuggingtools,from
theuseofbreaks,logging,andtheLLDBdebugger,runtimeerrors,particularlyingames
canbetoughtospot,thusbringingthedevelopmentprocesstoahalt.Tokeepeverything
type-safeandasbug-freeaspossibleduringcompilation,Swiftdealswiththeconceptof
optionals.
Optionals,inshort,areobjectsthatpotentiallycanbeorstartasnil.Nil,ofcourse,isan
objectthathasnoreference.
InObjective-C,wecoulddeclarethefollowingstringvariableforagame:
NSString*playerStatus=@"Poisoned";
playerStatus=nil;
InSwift,wewouldwritethisinthesameway,butwe’dfindoutveryquicklythatXcode
wouldgiveusacompilererrorindoingso:
varplayerStatus="Poisoned"
playerStatus=nil//error!
EvenmoreconfusingforanyonenewtoSwift,we’dalsogetanerrorifwedidsomething
assimpleasthis:
varplayerStatus:String//error
Creatingempty/undeclaredobjectsinourgamesmakessenseandissomethingwe’doften
wanttodoatthestartofourclasses.Wewantthatflexibilitytoassignavaluelateron
basedontheeventsofourgame.Swiftseemstobemakingsuchabasicconcept
impossibletodo!Noworries;Xcodewillinformyouinmostcasestosuffixaquestion
mark,?,attheendofthesenilobjects.Thisishowyoudeclareanobjectasanoptional.
So,ifwewanttoplanourgame’spropertiesandobjectsinSwift,wecandothefollowing:
varplayerStatus:String?//optionalString
varstageBoss:Boss?//optionalBossobject
Unwrappingoptionals
Let’simaginethatwewanttodisplaywhatcausedaplayertoloseinthegame.
varcausedGameOver:String?=whatKilledPlayer(enemy.recentAttack)
lettext="PlayerLostBecause:"
letgameOverMessage=text+causedGameOver//error
BecausethestringcausedGameOverisoptional,Xcodewillgiveusacompileerror
becausewedidn’tunwraptheoptional.Tounwrapthevalueinanoptional,wesuffixan
exclamationpoint!attheendoftheoptional.
Here’sourGameOvermessagecode,nowfixedusingtheunwrappedoptional:
varcausedGameOver:String?=whatKilledPlayer(enemy.recentAttack)
lettext="PlayerLostBecause:"
letgameOverMessage=text+causedGameOver!//codenowcompiles!
Wecanalsoforceunwrapoptionalsearlyatdeclarationtoallowanypotentialerrorstobe
takencareofatruntimeinsteadofwhencompiling.Thishappensoftenwith@IBOutlets
and@IBActions(objectsandfunctionslinkedtovariousstoryboardsandothertoolsthat
arebasedonmenu/viewtools).
@IBOutletvartitleLabel:UILabel!//labelfromaStoryboard
varsomeUnwrappedOptional:GameObject!//ourownunwrappedoptional
Note
Ifpossible,thoughit’srecommendedtousethebasicwrappedoptional?asmuchas
possibletoallowthecompilertofindanypotentialerrors.Usingwhat’sknownasoptional
bindingandchaining,wecandosomegreatearlylogicchecksonoptionalsthatinprior
languageswouldhaveinvolvedvariousifstatements/controlflowstatementstosimply
checkfornilobjects.
Keepingcodeclean,safe,andeasytoreadiswhatSwiftaimstodoandwhySwiftgoes
outofitswaysometimestoforcemanyoftheseruleswithoptionals.
Optionalbindingandchaining
Optionalbindingischeckingwhetheranoptionalhasavalueornot.Thisisdoneusingthe
veryhandyif-letorif-varstatements.Let’slookbackatourearliercode:
varcausedGameOver:String?=whatKilledPlayer(enemy.recentAttack)
lettext="PlayerLostBecause:"
ifletgotCauseOfDeath=causedGameOver{
letgameOverMessage=text+gotCauseOfDeath
}
Thecodeblock,ifletgotCauseOfDeath=causedGameOver{…},doestwothings.First,
usingthekeywords,iflet,itautomaticallycreatesaconstantnamedgotCauseOfDeath
andthenbindsittotheoptionalcausedGameOver.Thissimultaneouslycheckswhether
causedGameOverisnilorhasavalue.Ifit’snotnil,thentheifstatement’scodeblock
willrun;inthiscase,creatingtheconstantgameOverMessagethatcombinesthetext
constantwithgotCauseOfDeath.
Wecanuseif-vartosimplifythisevenfurther:
lettext="PlayerLostBecause:"
ifvarcausedGameOver=whatKilledPlayer(enemy.recentAttack){
letmessage=text+causedGameOver
}
Theif-varstatementcreatesatemporaryvariableusingourpreviouslyusedoptional
causedGameOveranddoesaBooleanlogiccheckbasedontheresultof
whatKilledPlayer(enemy.recentAttack).Thestatementistrueifthere’sanon-nilvalue
returned.Notehowwedon’thavetouseeitherwrapped(?)orforcedunwrapping(!)of
theoptionalinsuchacase.
Optionalchainingiswhenwequerydownintothepropertiesofanobjectusingthedot
operatorwhilealsodoinganil/valuecheckaswedidwithoptionalbinding.Forexample,
let’ssaythatwehaveagamewherecertainEnemytypescancauseaplayertolose
instantlyviaanEnemyinstancenamedcurrentEnemy.Inthisexample,
currentEnemy.typewouldbeastringthatreturnsthenameofthekindofenemythathit
theplayer.Optionalchainingusesthecustomdotmodifier?.whileaccessinga
potentiallynilcheckonaproperty.Here’sthecodetogetabetterideaofhowthisworks:
ifletenemyType=currentEnemy?.type{
ifenemyType=="OneHitKill"
{
player.loseLife()//runtheplayer'slostl
}
}
Chancesarethatwe’dprobablynotmakeanenemywithoutadesignatedtype,butforthe
sakeofunderstandingoptionalchaining,observehowthischecksforthepossiblenil
objectthat’dbereturnedbycurrentEnemy.typeusingcurrentEnemy?.type.Likehow
thedotoperatorfunctionswhereyoucandrilldownthepropertiesandpropertiesof
properties,thesamecanbedonewiththerecurring?.perpropertythatisdrilleddown.In
thiscode,wedoaBooleancomparisonwith==toseeifenemyTypeisthestring
OneHitKill.
Don’tworryifthesyntaxoftheifstatementsyntaxisabitofamystery;next,wediscuss
howSwiftusesifstatements,loops,andotherwayswecancontrolvariousobjectdata
andtheirfunctions.
ControlflowinSwift
Controlflowinanyprogramissimplytheorderofinstructionsandlogicinyourcode.
Swift,likeanyotherprogramminglanguage,usesvariousstatementsandblocksofcode
toloop,change,and/oriteratethroughyourobjectsanddata.Thisincludesblocksofcode
suchasifstatements,for-loops,do-whileloopsandSwitchstatements.Theseare
containedwithinfunctions,whichmakeuplargerstructureslikeclasses.
Ifstatements
BeforewemoveontohowSwifthandlesoneofthemaintopicsofOOP,functionsand
classes,let’squicklyrunthroughif-elsestatements.Anifstatementcheckswhethera
Booleanstatementistrueorfalse.Wehavetheexampleasfollows:
ifplayer.health<=0{
gameOver()
}
Thischeckswhetherornottheplayer’shealthislessthanorequalto0,designatedbythe
<=operator.NotethatSwiftisOKwiththerenotbeingparenthesis,butwecanusethisif
wewishorifthestatementgetsmorecomplicated,asinthisexample:
if(player.health<=0)&&(player.lives<=0){//&&="and"
gameOver()
}
Here,wechecknotjustwhethertheplayerhaslostalloftheirhealth,butalsoifallof
theirlivesaregonewiththeand(&&)operator.InSwift,likeinotherlanguages,we
separateouttheindividualBooleancheckswithparentheses,andlikeotherlanguages,we
doalogic-orcheckwithtwobarkeys(||).
HerearesomemorewaystowriteifstatementsinSwiftwiththeaddedkeywords,elseifandelse,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.Ifthisis
not,thenitwillcheckifit’sademonusingelse-if,andifthat’snotthecase,thenwe
catchallotherinstanceswiththeelsestatement.Wecouldhaveanumberofelse-if
statementsoneafteranother,butifwestarttostacktoomany,thenusingfor-loops
andSwitchstatementswouldbeabetterapproach.
(d):Usingoptionalchaining,wecreateanonlineIDconstantbasedonif;weare
abletogetanon-nilplayerIDpropertyusingif-let.
(e):Thisusesif-let,whereoptionalbindingbecameafeatureinSwift1.2.Insteadof
havingnestedif-letsandotherlogicchecks,akintohowSQLqueriesaredonein
backendwebdevelopment,wecancreateverycompact,powerfulearlylogic
checking.Inthecaseofexample(e),wehaveanenemyreceiveanattackbasedon
whattypeofattackitisandthepoweroftheplayer.
(f):Thisisanexampleofcombiningthecreationofaconstantwiththekeywordlet
anddoingashorthandversionofanifstatement.Weshorthenanifstatementin
Swiftwiththequestionmark?andcolon:.Hereistheformatforshorthandingan
ifstatement:bool?trueResult:falseResult.IfisPoweredUpistrue,then
playerPowerwillequalbasepower+250;iffalse,thenit’sbasepower+50.
Forloops
Wetouchedonfor-inloopsbeforedealingwithcollections.Hereagainisafor-inloopin
Swiftthatwilliteratethroughacollectionobject:
foritemNameininventory.values{
print("Itemname:\(itemName)")
}
Forsomeofusprogrammerswhoareusedtotheolderwayofusingfor-loops,don’t
worry,Swiftletsuswritefor-loopsintheC-style,whichmanyofusareprobablyusedto:
forvarindex=0;index<3;++index{
print("indexis\(index)")
}
Here’sanotherwayofusingafor-loopwithoutusinganindexvariable,notedwiththe
underscorecharacter_butofcourseusingaRange<Int>objecttypetodeterminehow
manytimesthefor-loopiterates:
letlimit=10
varsomeNumber=1
for_in1…limit{
someNumber*=2
}
Notethe…betweenthe1andlimit.Thismeansthatthisfor-inloopwilliteratefrom110.Ifwewantedittoiteratefrom0tolimit-1(similartoiteratingbetweentheboundsof
anarray’sindex),wecouldhaveinsteadtyped0..<limitwherelimitisequaltothe
array’s.countproperty.
Do-whileloops
Anotherverycommoniterationloopinprogrammingisthedo-whileloop.Manytimeswe
canjustutilizethewhileportionofthislogic,solet’slookintohowandwhywemightuse
awhileloop:
letscore=player.score
varscoreCountNum=0
whilescoreCountNum<score{
HUD.scoreText=String(scoreCountNum)
scoreCountNum=scoreCountNum*2
}
Ingamedevelopment,oneuseofthewhileloop(thoughexecuteddifferentlyinagame
app,thisaccommodatesiteratingonceperframe)isfordisplayingthecountingupofa
player’sscorefrom0tothescoretheplayerreached—acommonestheticofmanygames
attheendofastage.Thiswhileloopwilliterateuntilitreachestheplayer’sscore,
displayingonHUDobjectshowingtheintermediatevaluesupuntilthatscore.
Ado-whileloopispracticallythesameasthewhile-loopwiththeextracaveatofiterating
throughthecodeblockatleastonce.Theend-stagescorecountexamplecanalsoillustrate
whywewouldneedsuchaloop.Forexample,let’simaginethattheplayerdidreallybad
andgotnoscorewhenthestageended.Inthewhileloopgiven,ascoreofzerowon’tlet
usentertheblockofcodeinthewhileloopsinceitdoesn’tfulfillthelogiccheckof
scoreCountNum<score.Inthewhileloop,wealsohavecodethatdisplaysthescoretext.
Thoughmaybeembarrassingtotheplayer,wewouldwanttocountuptothescoreand
moreimportantly,stilldisplayascore.Here’sthesamecodedonewithado-whileloop:
letscore=player.score
varscoreCountNum=0
do{
HUD.scoreText=String(scoreCountNum)
scoreCountNum=scoreCountNum*2
}whilescoreCountNum<score
Nowscoretextwilldisplayeveniftheplayerscorednothing.
Switchstatements
Switchstatementsareusefulwhenwewishtocheckmanydifferentconditionsofan
objectinafullyencompassingandneatwaywithouthavingawallofelse-ifstatements.
Here’sacodesnippetfromthegamePikiPopthatusesaSwitchstatementfromthegame,
PikiPop,thatsetsthepercentageaGameCenterachievement(inthiscase,a6xcombo)
basedonthenumberoftimesthecombowasachievedbytheplayer.Don’tworrytoo
muchabouttheGameCentercode(usedwiththeGCHelpersingletonobject);that’s
somethingwewillgooverinfuturechapterswhenwemakegamesinSpriteKitand
SceneKit.
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
}
Theswitchstatementheretakesthevariableusedtocounthowmanytimestheplayerhit
a6Xcombo,comboX6_counter,andperformsdifferenttasksbasedonthevalueof
comboX6_counter.Forexample,whentheplayerhasdonea6XCombotwice,the
Piki_ComboX6achievementgets25%fulfilled.Theplayergetstheachievement(whenat
100%)whenthecounterhits10.Thepurposeofthekeywordbreakistotelltheloopto
exitatthatpoint;otherwise,thenextcaseblockwilliterate.Sometimes,thismightbe
desiredbyyourgame’slogic,butkeepinmindthatSwift,likemanyotherlanguages,will
continuethroughtheswitchstatementwithoutbreak.Thekeyworddefaultisthecatchallblockandiscalledwhenthevalueoftheitemcheckedbytheswitchstatementis
anythingbutthevariouscases.Itcanbethoughtofasanequivalenttotheelse{}block,
whileallofthecasesaresimilartoelseif(){}.ThedifferencethoughisthatSwift
requiresallcasesoftheswitchbehandled.So,thoughwecansufficewithanifwithout
anelse,wehavetohaveadefaultcaseforaswitchstatement.Again,thisisdonetokeep
Swiftcodesafeandcleanearlierinthecodingprocess.
Functionsandclasses
Upuntilthispoint,wehavekeptfromdiscussingprobablythemostimportantaspectsof
SwiftoranyOOPlanguagesforthatmatter—howthelanguagehandlesfunctionson
objectsandhowitorganizestheseobjects,objectproperties,andfunctionsandperforms
variousobject-orienteddesignconcepts,suchaspolymorphismandinheritancewith
classes,Structs,enums,protocols,andotherdatastructures.Thereismuchmoreto
discussabouthowSwiftutilizestheseconcepts,morethanwecanfitinthischapterbut
throughoutthecourseofthisbook,especiallyaswegetintohowtouseApple’sgamecentricSpriteKitandSceneKitframeworks,wewillfleshoutmoreonthesetopics.
Functions
InObjective-C,functionsarewrittenthefollowingway:
-(int)getPlayerHealth(){
returnplayer.health;
}
Thisisasimplefunctionthatreturnstheplayer’shealthasaninteger—theIntequivalent
inObjective-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/parameter
namesarefirstwiththetypessecond,separatedbythecolon(:)andwithinparenthesis.
Here’swhatatypicalvoidfunctionlookslikeinSwift.Avoid-typefunctionisafunction
thatdoesn’treturnavalue.
//withaPlayertypeasaparameter
funcdisplayPlayerName(player:Player){
print(player.name)
}
//withoutanyparameters;usingaclassproperty
funcdisplayPlayerName(){
print(currentPlayer.name)
}
Inavoidfunction,there’snoneedtowrite->returnType,butevenifthereareno
parameters,wedohavetoputinthe()parenthesisattheendofthefunctionname.
Tuples
AratherpowerfulaspectofSwiftisthatfunctionreturntypes(andconstants/variables)
canincludeacombinationofvaluesintoasinglevalue.Thesecombinationsarecalled
tuples.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-CH10ID164
Classes
InOOP,classesmakeupthebasicframeofanobject,itsfunctionalityandinteractions
withotherclasses,objects,andvariousdatastructures,suchasprotocols,Structs,
extensions,generics,andenumerations.Inthefollowingchapters,aswebegintostructure
ourgames,wewilldivedeeperintoalloftheseconcepts,butfornow,let’sunderstandthe
basicsofclassesandhowtheydifferinSwiftfromObjective-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,as
opposedtoObjective-C’stwofiles’(.h/header,.m/.mm/implementation)setup:
(a):Wecanhaveproperties(likevariables,constants,Structs,andenums)outsideof
theclassdeclaration,whichwouldmakethemglobalinscope,akaaccessible
throughouttheentireproject/game/app.
(b):Thisistheactualclassrepresentedbywhatwenamedour.swiftfile.Again,
thisisdifferentfromObjective-C’sclassname.h-classname.m/.mmdualfilesetup
forasingleclass.Aclasscanbeachildclassofanotherclass.Wedon’thaveto
declareaparent/baseclassinSwift.Classeswemakecanbetheirownbaseclasses.
WecanmakeclassesasObjective-CclassesbysubclassingthemfromNSObject.
ThebenefitofthatisgettingObjective-Cruntimemetadataandcapabilities,butwe
takeahitinperformancefromtheextrabaggage.Eitherinthesameplaceasthe
parentClassorafterthecolon:ofparentClass,wecandeclarewhichprotocols
thisclasswilladhereto.We’lldiscussmoreonprotocolslaterinthebook,butjust
thinkofthemasmakingsureyourclassutilizesthesamefunctionsastheprotocol
dictates.
(c):Thesearewherewe’dplacevariables,constants,Structs,enums,andobjects
thatarerelevantforuseinthescopeoftheclass.
(d):Initializersarespecialfunctionsweusetosetupthepropertiesinsection(c)
whenotherclassesanddatastructuresuseinstancesoftheclassvia
className(initializerparameters).Wewilldiscussmoreoninitializersmorein
thenextchapteraswestructureourgames.Theydon’thavetobeatthetopofthe
class,butit’sagoodpracticetodoso.
(e):Thesearewhereyourclassfunctionswillbedeclaredanddeveloped.Wecan
havefunctionsthatareknownasclassfunctions.Thesearedesignatedwiththe
keywordsclassfunc.Inshort,classfunctionsarepartoftheclassasawholeas
opposedtoaninstanceoftheclass.It’sbestpracticetoplacetheseabovethenext,
morecommontypeoffunction,thepublicfunctions,thatcanbeaccessedbyother
classesandpropertiesviathedotoperator(thatis,
className.function(parameters)).Usingtheprivatefunckeywords,asinC#
andJava,wecancreateprivatefunctionsthatareonlyaccessibletotheclass’sown
functionsandproperties.
(f):Thedeinit()functionisaspecialoptionalfunctionthatdealswithhowwe
cleanupthedataallocatedbyourclasswithmemorymanagementandeliminating
what’sknownasmemoryleaks.Apple’sARC(AutomatedReferenceCounting)
handlesmostofthis,buttherearekeywords,suchasweakandunowned,thatwe
willattimeshavetoputbeforevariouspropertiestomakesurethattheydon’thang
aroundafteruse.
Thisisaratherinvolvedtopic,butworthlookingintotoavoidmemoryleaksinyour
game.ARCdoestakecareofmostofthis,buttheremightbeobjectsinyourgame
thatcouldpotentiallyhangaround.It’shighlyrecommendedtoreadApple’sown
documentationonthistopic,asmemorymanagementiniOSisalwaysinthe
evolvingstage.YoucanviewthefulldocumentationonARCandmemory
managementinSwiftat
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programmin
(g):Ifwewish,wecanhaveglobalpropertiesalsoatthebottomofour.swiftfiles,
aftertheendoftheclassdeclaration.Apple’sowngameexample,Adventure
(https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programmin
placesglobalpropertiesinthisspot.
Summary
There’smuchmoreabouttheSwiftprogramminglanguagethanwecouldfithere.
Throughoutthecourseofthisbook,wewillthrowinafewextratidbitsandnuancesabout
Swiftasitbecomesrelevanttoourupcominggamingprogrammingneeds.
IfyouwishtobecomemoreversedintheSwiftprogramminglanguage,Appleactually
providesawonderfultoolinwhat’sknownasaPlayground.
PlaygroundswereintroducedwiththeSwiftprogramminglanguageatWWDC14inJune
of2014andallowustotestvariouscodeoutputsandsyntaxeswithouthavingtocreatea
project,buildit,andrunitandrepeatagain,wheninmanycaseswesimplyneededto
tweakafewvariablesandfunctionloopiterations.
ThereareanumberofresourcestocheckoutontheofficialSwiftdeveloperpage
(https://developer.apple.com/swift/resources/).
TwohighlyrecommendedPlaygroundstocheckoutareasfollows:
TheGuidedTourPlayground
(https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programmin
ThisPlaygroundcoversmanyofthetopicswementionedinthischapterandmore,
fromHelloWorldallthewaytoGenerics.
TheBalloonsPlayground
(https://developer.apple.com/swift/blog/downloads/Balloons.zip):TheBalloons
PlaygroundwasthekeynotePlaygroundsdemonstrationfromWWDC14andshows
offmanyofthefeaturesPlaygroundshavetooffer,particularlytomakeandtest
games.
Sometimes,thebestwaytolearnaprogramminglanguageistotestlivecode,andthat’s
exactlywhatPlaygroundsallowustodo.
Inadditiontotestingsnippetsofcodeinourgames,iOS9alsoallowsustoplanand
structureourgames,whichisthetopicofthenextchapter.
Chapter2.StructuringandPlanninga
GameUsingiOS9Storyboardsand
Segues
Videogamedevelopmenthashadaninterestinghistory.Itstartedasanoffshootofboth
electricalengineeringandcomputerscience.Gameswereagreatchallengeforengineers
tomakethemostoutofthelimitedhardwareand,ofcourse,makesomethingfun.Today,
videogamesandvideogamedevelopmentarestillbuiltonthosefoundationsof
technology,math,andengineeringbut,fordecades,havealsobeenmajorplayersinthe
worldofentertainment,storytelling,andmedia.
Beitifyouareamajorstudio,asmallteam,orcreatinggamesallbyyourself,planning
andstructuringyourgameprojectscangiveyouthefoundationneededtosavetimeinthe
developmentprocess,dividetheworkouttoothersifonateam,andofcourse,bringyour
gametolifeascloseaspossibletohowyouimaginedit.
StartingwithiOS5,Appletookapagefromtheentertainmentindustryinhowtostructure
andplanaproject,bigorsmall;byusingtheconceptofstoryboards.Storyboardsarea
graphicrepresentationofthevariousstepsandstructuresofaproject;beitananimation,a
movie,orinourcase,iOSgames.Storyboardswillgraphicallyshowtheflowofa
productionorapp.Inanimation,forexample,storyboardsareusedtofleshoutmajor
framesorstorypointsoftheproduction.Onceit’sagreedonastowhattheseriesofevents
inascenewillbe,animatorswillanimatearoundthosekeypoints.Dependingonwhether
theproductionisprelayorADR,voiceactingcouldalsobeplacedintothestoryboard
process,whichgivestheanimatorsevenmorespecificcontenttoworkwith.
Inthecaseoftheactualgameapplication,storyboardscanrepresentmajorpartsofyour
game,suchastheIntroscene,OpeningMenuscreen,PauseScreen,GameOverScreen,or
thegenericlookofamaingamelevel.ApplenamedthesestructuresinXcode
storyboards,andthepathsbetweenthemareknownassegues.Throughoutthischapter,
weshallbelookingintohowtomakeuseofthesefeatureswhilemakingagameapp.
TheprecedingisanexampleofasimpleiOSStoryboard.
Model-View-Controller
BeforewegetintostoryboardsiniOS9,it’sbestthatwefirstdiscussthebasicflowofan
iOSappandtheconceptofModel-View-Controller(MVC).Model-View-Controlleris
anarchitecturalparadigmusedinsoftwareengineering,programming,andevennowin
webdesign.WecanthinkofthemodelportionofMVCasthelogicorbrainsofan
application’sbehavior.Thislogicisusuallyindependentoftheuserinterfaceand
determineswhattodowiththeapp’sdata.
We’veactuallyalreadygoneoverthemodelportionofMVC!TheSwiftprogramming
languagediscussedinthepreviouschapteristhatmodel;thisisthecasewithits
Objective-CpredecessorandanyotherprogramminglanguageusediniOSoranyother
gamedevelopment.Yourgame’scodecontrolswhattodowiththeplayer,level,and
enemy/goaldata.
TheviewportionofMVCisthevisualrepresentationofthemodel.Thisofcoursewould
includethenumerousvisualaspectsofourgames,fromourplayer’sanimationframes,
variousin-gamestatsontheHUD,particleeffects,andmore.
ThecontrollerportionofMVCcanbethoughtofasthegluethatholdsthemodeland
viewtogether.Itisalsothepointatwhichtheuserofyourgameinteractswith.Beit
actions,suchasabuttonpress,abasictouch,aswipe,orothergestures,recognizedby
youriOSdevice,thecontrollertakesthatuserinput,manipulatesyourmodelandthenthe
modelupdatesyourviewaccordingly.
ThisdiagramistakenfromApple’sownAdventureGameExample.
WhenweworkwithiOSapps,thefirstrecommendedentrypointforcodeandstoryboard
infoistheRootViewController.Aswe’llcometofindout,MVCisintrinsicallybuiltinto
iOSappdevelopmentandtheXcodeIDE.Storyboardsareacollectionofdifferenttypes
ofviewcontrollerswithvaryingtasksthatarelinkedbysegues.
AniOSapp’slifecycle
Beforewemoveontoworkingwithstoryboards,segues,andthefoundationofourgame
apps,it’sbestwegoovertheoveralllifecycleofaniOSappasit’simportanttoknowthe
entrypointsofourcodeandvariousobjects/structuresofourapps.
Insertapplifecycleimageryherebeforewemoveontoworkingwithstoryboards,segues,
andthefoundationofourgameapps.It’sbestwegoovertheoveralllifecycleofaniOS
appasit’simportanttoknowtheentrypointsofourcodeandvariousobjects/structuresof
ourapps.
Source:
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammin
AnyonewhohasworkedwithC/C++,Java,orotherlanguageswillbefamiliarwiththe
main()function.Themain()functionisusedtodesignateyourprogram’smainentry
point.TheprecedingexampleishowAppledesignatesthetypicalmainfunctionforapps.
EssentiallywhatthisisdoingiscallingthefirstclassinthetypicallifecycleofiOSapps,
theAppDelegateclass.
Themain()function
Here’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.Swiftagainmakesdeclaringthe
entryofyourapplicationeasier.
@UIApplicationMain
classfirstClassCalled
{
//classcode
}
WhilebuildinganiOSappwithSwift,themain.mfileseeninpriorObjective-Cprojectsis
nolongerneeded.Instead,weuseanAttributecall,@UIApplicationMain,justbeforethe
declarationoftheclassthatisfirstcalled.
Note
Swiftattributes
Attributes,beginningwiththeatcharacter,@,areusedtoaddadditionalinformationtoa
declarationoratype.InSwift,theyhavethefollowingsyntax:
@attributename
@attributename(attributearguments)
Asinotherprogramminglanguages,attributes,dependingontheirfunctionality,canbe
usedtodescribeobjects,functions,andevenentireclasses.
Forexample,the@objcattributeisusedtodeclarecodethatisreadableinObjective-C.
Aswe’llseewhileusingandlinkingvariousobjectsinthestoryboardswithourcode,the
attributes@IBOutletand@IBActionareusedtodescribeobjectsandfunctions
representingobjectswecreateinXcode’sInterfaceBuilder.
WewilldiscussmoreonAttributesinChapter7,PublishingOuriOS9.0Game.
TheUIApplicationclass/object
UIApplicationistheobjectresponsibleforcontrollinganapp’sevent-loopaswellas
handlingotherupper-levelappprocesses.Gameappornot,thisispresentinalliOSapps
andiswhatisfirstcalledatthemainentrypointandworkstogetherwiththeAppDelegate
class.ThoughitispossibletosubclassUIApplication,it’susuallynotrecommended.
Customizationstowhatyourgamedoesduringvariousappstatesarewhatweusethe
AppDelegateclassandViewControllersfor,evenifstoryboardsarenotutilized(thatisif
youchoosetomostlyhardcodeyourgame).
TheAppDelegateclass
WecanthinkoftheAppDelegateclassasyourapp’smainhub.It’sthetoplevelofgeneral
customizationforyourgame.WhilemakinganappinSwift(gameornot),it’stheclass
thatisgiventhe@UIApplicationMainattributebecauseit’sthegeneralfirstentryofyour
game’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)thatAppleprovidesforuswhen
usingtheiOS9gamepreset.Beforewediveintostructuringourgameswithstoryboards
andthetwomainframeworks(SpriteKitandSceneKit),it’sbesttounderstandwhat
happensinthisclass.Eventsthathappentoyourgameapprelatingtothedevice,
particularlythosethatareoutsideoftheplayer’scontrol,suchasincomingphonecalls,
notifications,andthedeviceshuttingdownduetolowbatterypower,aswellasthose
controlledbytheplayer(thatispausingthegame),arehandledbythisclass.Aswesee,
Applealreadyprovidesgreatinstructionsforwhateachfunctionofthisclassdoes,sobe
suretoreviewthem.Wewillcomebacktotheseaswecreateourgamesandhandlethose
specificsituations.NotethattheAppDelegateclasshasanoptionalvariable(meaningit
canbenil)namedwindowandisofthetype,UIWindow.AUIWindowobjectisachildof
UIViewandcanallocatevariousdisplays/objectsthatcanbeputintotheviewoftheuser.
Technically,wecanuseobjectsofUIWindowandUIViewincodedirectlytocreatethe
visualsofourgame,butAppleprovidesmorerobustobjectsthathandleboththeuser’s
interactionwiththescreenandview.TheseobjectsarewhatmakeupiOSstoryboards;the
ablynamed,ViewControllers.
Viewcontrollers
ViewcontrollersareprobablyoneofthemostvitalstructuresofiOSdevelopmentandare
whatstoryboardsarevisuallyrepresentingwhendesigningtheminXcode’sInterface
Builder.Intermsoftheirtypicalentrypointorder,it’sMAIN—>AppDelegate—>
RootViewController—>[callstoanyadditionalViewControllersinstance].
WhenwecreateanewappprojectinXcode,ApplewillmakeadefaultRootView
ControllernamedViewControllerforus.Here’sit’scode:
importUIKit
classViewController:UIViewController{
overridefuncviewDidLoad(){
super.viewDidLoad()
//Doanyadditionalsetupafterloadingtheview,typicallyfroma
nib.
}
overridefuncdidReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
//Disposeofanyresourcesthatcanberecreated.
}
}
ThisisthestartercodegiventousinXcodewiththedefaultViewController.swift
class.Aswesee,it’sasubclassofUIViewControllerandthusinheritsallofitsparent
class’sfunctions.OneofthemshownhereisthefunctionviewDidLoad().InSwift,when
wewishtooverrideafunctionofaparentclass,weusethekeywordoverridebeforethe
functiondeclaration.Wealsoseethatsuper.viewDidLoad()iscalledaswell.Whatthis
doesiscalltheparent’sownversionofthisfunctionbeforeweaddourown
code/customizationsandisrecommendedwhenusinganyofthefunctionsof
UIViewController.TheUIViewControllerfunctionshandlevariousviewstates;
viewDidLoad()handleswhentheviewisfirstloadedandiscalledonceforthelifeofthe
UIViewControllerobjectduringanapp’slifecycle.Ifwewanttocallsomecodeevery
timeaviewisseen,wecanusetheviewDidAppear()functionofUIViewController
instead.
Here’savisualrepresentationoftheseviewstates.
Herestoryboardsandsegues,aswe’llsee,essentiallygiveusavisualandcustomizable
representationoftheseverystatesandthetransitionsbetweenthemwithoutusingtoo
muchcode.
TodiveevendeeperintotheUIViewControllermethods,checkoutApple’s
documentationonthesubject:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/
Note
ForanyonefamiliarwiththegamedevelopmentengineUnity(whichhasscriptswrittenin
eitherC#,JavaScript,orthePythonderivative),onewaywecanimaginethe
UIViewControllerfunctionsviewDidLoad()andviewDidAppear()isthattheyare
somewhatsimilartotheUnityfunctionsAwake()andOnEnabled(),respectively.One
functioniscalledwhenthesceneisfirstloadedandtheotherjustbeforethefirstframe
thattheobjectisvisible/enabled.TheUIViewControllerfunctionshoweverareonamore
upper-levelbasisfortheentiretyoftheappasopposedtoapergameObjectbasis.
FormoreinformationandgraphicsontheentireiOSapplifecycle,checkoutthefull
documentationhere:
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammin
Viewcontrollertypes
Viewcontrollerscomeinanumberoftypesandwecancreateourownbysubclassing
them.Thetwomaintypesarecontainerviewcontroller,whichholdotherview
controllers,andcontentviewcontrollers,whichaswecanimagine,arewhatdisplaythe
content.ContentviewcontrollersincludetheRootViewController,whichisthefirstview
controlleraccessedaftertheapp’sentrypointandisalsothefirstviewcontrollerseenin
thedefaultMain.StoryboardfileinapresetXcodeproject’sinspector.Therearealso
otherspecialtypesofviewcontrollers,liketheUITableViewController,usedtodisplay
datalistedintablecellformatsandtheNavigationController,whichcontrolsthe
navigationlogic/imageryoftheappwhenmovingbetweenotherviewcontrollers.
Foramorein-depthlookatthevariousviewcontrollersavailableinUIKit,checkoutthe
officialdocumentationseenhere:
https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/index.htm
CH2-SW1
It’sactuallyatthispointthatwecanbegintocodeourgame,albeitentirelyprogramming
theMVCmodel.InthebeginningofiOSgamedevelopment,thiswasessentiallyhowone
wouldgoaboutdevelopingagamefortheoriginaliPhone.We’dprogrammaticallywork
withtheUIWindowandViewControllerobjectsandourgame’sowncustomclassesto
crafttheapp.AsthefamilyofiOSdevicesgrew,anobviousissuebegantoarise.Though
wecan,andsometimesmighthaveto.programmaticallychangecodebasedonthedevice,
dealingwithagrowingnumberofscreensizesanddevicetypesmadeitsothatourcode
wouldalwayshavetoberefactoredandproducedeverincreasingambiguitywhenevera
newAppleiOSdevicewasannounced.Also,let’snotforgetthatgamedevelopmentisas
muchofavisualdesigner/animator’sworkasitisaprogrammer’s.Editing,positioning,
refining,andlaterupdatingvariousvisualaspectsofagamecanbeverytimeconsuming
ifdoneentirelyviacode.
Storyboardsweremadetohelpalleviatethisissuebyallowingustovisuallydesignour
gameintheprojectitselfasopposetohavingourownpossiblyhandwrittenstoryboards
thatdescribejustamodel-based,code-centricdesign.WiththeintroductionofAuto
LayoutinXcode5,wecan,withoutusinganycode,makeoneprojectandgeneralview
forallvarietiesofiOSdevices.WeshalltouchonAutoLayoutaswenowfinallymoveon
toworkingwithStoryboardsandsegues,butforamorein-depthlookonAutoLayout,
checkouttheofficialdocumentationonApple’sdeveloperportal:
https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG
Storyboardsandsegues
Let’snowfinallygettoworkingwiththesetoolsandlearnthebasicsofstructuringgame
appsonabroaderstoryboardlevel.Asofthewritingofthisbook,thelatestversionof
Xcodeavailableisversion7.0.Thiswillbetheversionweshallworkwith,butXcodeis
alwaysupdatingwithevenabetaversionavailabletoseparatelytestthenewestfeatures.
Visithttps://developer.apple.com/xcode/todownloadandreaduponallthatXcodehasto
offerforiOSdevelopers.
Tostartstructuringyourappusingstoryboards,followtheseinstructions:
1. First,openXcodeinyourApplicationsfolder(orinyourDockifyouplacedit
thereforeasyaccess).
2. Next,clickonCreateanewXcodeProject.
3. Youwillnowbeaskedtochooseatemplatepreset.
4. Forthesakeofjustunderstandingstoryboardsandsegues,selecttheSingleView
Applicationtemplate.(Don’tworry,wewillbeusingthegametemplateinthenext
chapter).
5. Nowwechooseourproject’soptions.NameyourprojectStoryBoardExample.
6. IntheLanguagedropdown,makesurethatitissettoSwiftandensuretheDevices
dropdownissettoUniversal.
7. ThereshouldbeotherfieldsfilledinbyXcode,suchasyourorganizationnameand
organizationidentifier.Thoseareinvolvedwiththeinformationthatwillbepublished
withyourappwhenitcomestodeploymentaswellasthecontentofyourcode’s
copyrightcomments.WecanfornowkeeptheseattheirdefaultsettingthatXcode
hasfilledin.
8. ClickonNextandthenselectavalidlocationinyourfilestosavethisproject.
Nowwehaveourdefaultappcreatedbythetemplate.Weshouldseeontheleft-handside,
intheFileNavigatorPane,variousfilesandfolderscreatedforus.Aswecansee,the
AppDelegate.swiftandtheViewController.swiftfileswereautomaticallycreatedfor
usandrightbelowthat,we’dfindtheMain.Storyboardfile.Thisisourstoryboardand
whenyouclickonit,youshouldseethetwopanesopenatthecenterofyourXcode
window.TheleftsideistheviewcontrollerScenedropdown,whichshowsthehierarchy
ofthescenecontrolledbytheprovidedtheviewcontroller.Therightpaneinthecenter
allowsustovisuallyseetheviewcontrollerandeventuallyelementsthatwecanplacein
it.Themainvisualpartofthestoryboardcanbezoomedinandzoomedout.Asweadd
morescenestoit,thiswillallowustoseetheentiretyofourstoryboardortheportionswe
areworkingon.
Youmighthavetozoomoutslightlytoseeit(usingyourmouseorusingthepinching
gestureonyourtrackpadwithaMacBook),buttotheleftoftheViewControllerscene
there’sagrayarrow.ThisistheentrypointandthefirstViewControllersceneattachedto
thisarrowisyourRootViewController/Initialscene.
Tip
Whenaddingmorescenestoyourstoryboard,foreitherdebuggingpurposesordesign
choice,youcansimplychangethescenethatisfirstenteredbyclickinganddraggingthat
arrowtotheleftofthatscene.
Let’sstartbycreatingaseparatesceneforourstoryboard:
1. AtthebottomoftheUtilitiespanel(thefarrightpaneloftheXcodeproject),there
arefouriconsdesignatingthevarioussnippetsandobjectswecanplaceinour
project’scodeandthestoryboard.Clickonthethirdiconfromtheleftifit’snot
alreadyselected.ThiswillopentheObjectLibrary.
2. WecanseethattheverytopoftheObjectLibraryhasaViewControllerobject.
3. Dragthisontothestoryboard’scanvas,preferablytotherightoftheinitialscene.
Note
IftheUtilitiespanelisn’topen,clickontheupperright-mosticonatthetopofyour
project’stoolbarwindow.
Note
ThethreebuttonsinyourtoolbarcanbetoggledtoclosetheNavigationpane,
Debugpane,andUtilitiespane,respectively.Closingthesewhenapplicablecanhelp
expandthegeneralview,knownasthecanvasofyourstoryboardscenes.
Nowwehavetwoscenesinourstoryboard,butnothingistheretotelluswhattheyare.
Theyarejusttwoblankscenes!
Let’sputaLabelobjectinthesescenestorepresentwhattheyareandatruntimetellus
whichonewearein.
Tokeepthisinthemindsetofdevelopingagame,let’sputalabelinthefirstonecalled
IntroScene,wherewe’dmaybehaveanintroanimationtoourgamewitha
Start/Optionsmenu,andinthenextone,putthelabelGameScenetorepresentthatthisis
wherethatactualgameplaywouldoccur.
Here’showtodothat:
1. GotothebottomoftheUtilitiespanelandusethesearchfieldtosearchlabel.This
willisolatethelabelobject,soyoudon’thavetoscrollthroughtheentirelist.
2. Dragthelabelobjecttothecanvasofthefirstscene.Ifitdoesn’tlooklikeit’strying
tosnaptothescene’scanvas,youmighthavetoselecttheViewportionofthatview
controllerscene’shierarchy,usingtheleftpaneoftheMain/Storyboard’smainview.
Alternately,youcanalsodouble-clicktheviewintheInspectortogetthescenein
focussothatyoucanplacethelabelontoit.
3. Aswedragit,trytocenterthelabelasbestaspossible.Thecanvaswillindicatethat
weareattheverticaland/orhorizontalpartofthatscenewithdottedbluelines.Drop
itinthecenter.
TheUtilitiespaneshouldhavesomefieldsvisiblewhenselectingthelabeltocontrol
variousaspectsofitstextlikefontsize,alignment,andstyle.
4. ThelabelwilljustsayLabelasthedefault,solet’srenameittoIntroSceneforthe
firstscenebyeitherdouble-clickingthelabelitselfinthecanvas,orchangingthe
nameinthesecondfielddownfromTextintheUtilitiespanel.
5. Let’smakethislabelabitmoreprominent,sosingle-clickonthelabel,clickonthe
[T]iconintheFontfield,andmakethestyleboldwithasizeof28.
Notehowthelabelisclippedfromthesizeincreaseandhardlyvisible.
6. Simplyclickonthelabelandexpandoutanyoneoftheeightscalingiconsatthe
cornersofthelabelobjectonthecanvas.
Repositionthelabeltoreturnittothecenterofthescene.
7. CreatethesamelabelforthesecondsceneweaddedbysimplytypingCommand+D
toduplicatethelabel(astonothavetorepeatallofthesteps)andthendragittothe
centeroftheotherscene.Zoomoutasneededandpossiblyclickbackontotheview
partofthehierarchyifthefocuschangepreventstheabilitytodragthelabelacross.
Thoughratherrudimentaryandwithstillsomemoreworktodowith,thisisallittakesto
createseparatescenesvisually.Ifyouhaveanideaofhowyouwanttostructureyour
game,thisiswhereyoucanstartwiththeuseofstoryboards.Ofcourse,thereisstillmore
todoherebeforewemakethisstoryboardhaveanyfunction.
WecanseethatXcodeisgivingusthefollowingwarning:
Sceneisunreachableduetolackofentrypointsanddoesnothaveanidentifierfor
runtimeaccessvia-instantiateViewControllerWithIdentifier.
ThisisreferringtotheGameSceneobjectthatisessentiallyorphanedduetono
connectiontotheIntroScenenortheapp’sentrypoint.
Thisiswhereseguescomeintoplay.Yet,beforeweworkwithseguesandcreateaflowto
thesescenesandmore,ifweweretorunthisapp,we’dnoteanotherissue.Wecouldhave
swornthatwecenteredthetext,butifsimulatingorrunningthisin,say,aniPhone6s,the
textiscompletelyofftotheupper-rightside.Thisisbecausethedefaultcanvasisa
generalizedalldevicetemplatetobeginwithviaAutoLayout.
AutoLayouthasgotteneasierwitheachnewbuildofXcode,butonecouldstillargueit’s
stillabitofahassleattimestofinetune,particularlywhencreatingconstraints(set
spaces/marginingbetweenvariousstoryboardobjects).Let’stakeaquicklookathowto
workwithconstraints.
OnequickwaytoalleviatetheissuewehavehereistojustworkwiththeBaseValues
panelfoundatthebottomcenterofthestoryboardcanvasbyclickingonthew/Anyh/Any
text.Onceclicked,apop-uptableofcellswillappear.Rollingoverwithyourmouseor
trackpadtothevariouscellswillbringupanumberofdifferentconfigurationsasoppose
tow/Anyh/Any.What’sgreataboutthisisthatyoucanchange/addanddeletevarious
objectssimplybasedonthedevicetypeusingtheseoptions.
Note
BeforestoryboardsandAutoLayout,thiswouldinvolvehugeamountsoftestingand
refactoringofcodeinaviewcontrollerorNibclassestogetthelayoutjustthewayyou’d
likevisually.Applewouldthencreatethenextdevicewithadifferentscreensizetoprior
devices,itwouldbecomeanevengreaterhassleorthedeveloperwouldriskabroken
gameonthenewestdevice.
TomakethelabelsbeinthecenterforalliPhonesinportraitmodeforexample:
1. Hoverandclickonthecenterleft-handsideoftheAutoLayoutpanelwhereit’llsay
CompactWidth|AnyHeightatthetopofthatpop-uppanel/table.
2. Thisshouldnowchangethedisplaytextatthebottomofthecanvastow/Compact
h/AnyandshrinkthewidthofthesceneasthislayoutrepresentsalliPhonesin
Portraitandofanyheight(soitcouldbeabitoffinheightonanolderiPhone4Sas
opposetotheiPhone5orlater).
3. Notehowthelabelsareoffcentertowardtheupperright.Thisiswhatwouldhave
beenseeninthesimulatororonanactualiPhoneintheportraitorientation.Drag
thembacktothecenter,andtheyshouldnowlookastheyareseeninthis
configurationofthestoryboard’scanvas.IfdesigningforiPad,thentheother
configurationswouldneedtobechangedforthat.
Note
Pinningwithconstraintscouldactuallystreamlinethisprocess.Forexample,let’ssay
thatyouwanttoplaceaPausebuttonattheupperrightcornerofyourGameScene
andyouknowthatnomattertheorientation,itwillalwaysbeatacertaindistance(in
percentagesorpixels)awayfromtherightandtopofadevice’sscreen.Wecanclick
onthepinbutton
atthebottomofthecanvastocreatetheseconstraintsinthe
w/Anyh/Anyconfigurationandskipmanuallyadjustingtheicononeveryoneofthe
baseconfigurations.
Xcodealreadygivesusascene,theLaunchScreen.xibfile,which,ifyouhave
alreadyranyourcode,wasactuallywhatwasseenfirstbeforethefirstview
controllerinthestoryboard.
TohavejustyourMain.Storyboardfilebeatstartupyoucanselectthemainproject
fileatthetopleftcornerintheNavigationpaneandintheLaunchScreen
dropdownoftheAppsIconsandLaunchImagessection,selectMain.Storyboard.
Then,youcandeletetheLaunchScreen.xibfileifnolongerneeded.Itcanbeagood
filetoseeworkingconstraints,andifsobeit,itcanbeyourinitialsplashscreenfor
yourgame.Moreonconstraintscanbefoundhereintheofficialdocumentation:
https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptua
Segues
Gameshavescenes,andallsceneshavetransitionsbetweenthem.Seguesaresimply
transitionsbetweenscenesinastoryboard.Seguescomeinvarioustypes:
Show:Thispushesthenextviewcontrollerontopofthecurrentone;italsoallows
forcallingbackifusingaUINavigationControllerinstance.
ShowDetail:WhenusingUISplitViewController,aContainerviewcontrolleris
typicallyusediniPadappstobrowsenews/emailapps,wheretheleftsideofthepage
isaUITableViewControllerobjectandtheothersideofthesamepagearethe
detailsofthattable/list.ThiscallsthedetailsfortheDetailViewcontrollerportionof
thepagewhentriggeredbyagesturefromtheselecteditemonthe
UITableViewControllerside.
Presentmodally:Thispresentsthenextviewcontrolleroverthecurrentbutinsuch
awaythatitcanbecanceled,suchasafull-pagepopup.
Popover:ThisislikePresentmodallybutwithmoreoptionsinsizingtocreatea
smallerpop-upwindowthatcanbeclosedanddisposedof.
Custom:ThisisaversionofaseguethatyoucancompletelycustomizewithOOP
code.
Thetypicalstoryboardstructurewhenbuildingsay,ane-mailapp,willmorethanlikely
needtomakeuseofanavigationcontrollerandUITableViewcontrollerstostructurethe
dataandflowoftheapp.Now,wecanverywelldothesamethingforgameapps.Game
Over,Menu,Rankings,andPausescreenscouldmakeuseoftheseviewcontrollers.For
ourexample,we’llkeepitsimpleandunrestrictedtoletyou,thedeveloper,haveabetter
startingpointtobranchfrom.
Note
Ourexamplehereisrathersimple,butinadditiontoprovidingcodeforthisproject,an
evenmoredetailedstoryboardwillbeavailableusingvariousviewcontrollersandobjects.
Let’stakecareofthatwarningandlinkupthesescenesaswellasbegintoshowthe
overallstructureofatypicalgameusingstoryboards.
1. First,intheIntroScene,placeabuttonlabeledSTARTrightundertheIntroScene
label.Placingabuttononastoryboardisdoneexactlythesameaswithalabel.
SearchforbuttonorscrolldowntheobjectsintheUtilitiespanelandthendragand
dropthebuttonontothescene.
2. NowcreatetwomorebuttonsontheGameSceneview;onebuttonlabeledPauseat
thetop-rightcornerofthesceneandanothernamedQuitoppositethePausebutton
ontheupper-leftcorner.
3. CreateanewViewControllerobjectonthescene,preferablyaboveorbelowthe
GameSceneonthecanvas.
4. OnthenewPauseScene,createalabelPAUSEDthesamewaytheGameSceneand
IntroScenelabelsweremade.
5. Then,addtwobuttons,QuitandResume,andplacethemrightunderthePAUSED
label.
Nowtocreatetheseguesvisuallyusingthestoryboard:
1. Control-ClicktheSTARTbuttonobjectontheIntroSceneandthenwhilestill
pressingControl-Click,dragtheobjecttowardtheGameSceneonthecanvas.You
shouldseeabluelinefollowyourcursorasyoudragacross.(ifyouneedmorespace,
zoomoutabitandalsotemporarilyclosetheNavigationandUtilitiespanelsusing
thetollbarbuttons).
2. Dropthispointanywhereontheviewthatisn’tanotherobject;youshouldseethe
entireviewglowbluewhiledoingso.
3. ApopupaskingforthetypeofSeguewillcomeup.SelectShow.
4. That’sit!You’vecreatedasegue,andyou’vealsotoldthestoryboardthatwhenthe
userclicksthatbutton,it’llopentheGameScene—ViewController.
5. Beforeyoumoveontocreatingmoresegues,clickonthedoor-likesymbolonthe
canvasthatrepresentsthesegue.OnthetoprightintheUtilitiespanel’sAssets
inspector,youshouldseeanemptyIdentifierfield.Wecanleavethesegueemptyif
we’dlike,butnamingitcouldbeofuseifwewishtocallthesegueincodewiththe
followingline:
performSegueWithIdentifier("segueIDNameeWithIdentifi)
6. Nowrepeatsteps1through3tocreatethefollowingsegues:
1. LinkGameScene’sQuitbuttonbacktoIntroScene.
2. LinkGameScene’sPausebuttontothePAUSEDScene.
3. LinkPAUSEDScene’sResumebuttontotheGameScene.
4. LinkPAUSEDScene’sQuitbuttontotheIntroScene.
Thewarningshouldnowbegoneasallofthescenesareconnectedwithsegues,andafter
possiblysomeAutoLayoutfixes,runningtheappnowhasagame-likescenestructure
thattransitionthewaywe’dnormallyseeinothergames.Wecangofromhereandmake
otherscenes,suchasaGameOverscene,aStageWinscene,orothers.Evenifthismight
notbethewayyou’dlikeyourfinalgame’stransitionstoendup(particularlysincethe
defaulttransitionoftheShowseguedoesaquickvertical),thiscanbeaveryquickwayof
prototypingyourgamerightoffthebat.Customseguesandseguestriggeredwithcodeare
howwecandivedeeperintofinetuningwhenthedefaultsettingmightnotmatchwithour
visionofourgames.
Here’smoredocumentationonmakingcustomsegueclassesifyoureallywanttodive
deeperintosegues:
https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIStoryboardS
CH1-SW11
SimilarlytohowweControl-Draggedthebutton’slinkagetothenextviewcontroller
scene,wecandothesametoourViewController.swiftfile.
Here’sasummeryonhowtodothatforthefirstviewcontroller:
1. Removetheprevioussegue.Onewaytodosoistoright-clickthebuttonandtoclick
onxintheTriggeredSeguessection.
2. ClickontheIntroScene’sviewinthehierarchytogetitinfocus.
3. Control-DragabluelinefromtheyellowicononthetopleftoftheIntroScene’s
viewcontrollertotheGameScene’sviewcontrollerandselecttheShowtypeof
segue.
4. Clickonthesegueiconinthecanvasandnowgivetheidentifierofthisseguethe
namestartGame.
5. OpentheAssistantEditor(thetwointerlockingcirclesbuttononthetop-rightportion
oftheXcodetoolbar);closesomepanestomakeanyneededroom.
6. Control-DragtheStartbuttonintotheViewControllerclass;preferablyatthe
bottomofthecodebutstillwithintheclass’sclosingbrackets.
7. Thiswillprompttheoutlet/actionpopup.SelecttheActionoptionintheConnection
dropdownandnameitstartButton.
8. ThiswillcreatetheIBActionfunction:@IBActionfuncstartButton(sender:
AnyObject){}.
9. Typethefollowingcodebetweenthebraces:
self.performSegueWithIdentifier("startGame",sender:nil)
10. Thistellstheviewcontrollertoperformtheseguewhenthisbuttonispromptedusing
code.
Storyboardsversuscoding
There’snosinglecorrectwaytodothedesignstructureofyourappaslongastheMVC
modelisfollowed.Actually,thereareprogrammersouttherewhoarecompletelyfine
withjustusingtheinitialviewcontrollerandneveruseasingleNiborstoryboardfile;
thuspurelybuildingtheirgamecontrolledbythelogicoftheircodeandcallstothe
variousViewobjectsprogrammatically.IniOSdevelopment,there’ssomewhatofadesign
splitbetweenthreemainbranches,hardcoding,Nibs,andstoryboards.Theoriginal
methodologywascoding;NibscameinlatertofirstallowdirectvisualeditinginXcode
andthenthatevolvedintoStoryboards,furtherbuiltuponwiththeadditionofAuto
Layout.
Thereasonthere’sasplitbetweensomedevelopersandstudiosonthevisualstructure
methodologyofaniOSappisbecauseonedrawbacktoNibsandstoryboardsaretheir
lackofportability.Ifyouwantedtoportyourgametoanotherplatform,suchasAndroid,
atdescentpace,heavyuseofstoryboardswouldmakeitarathertoughtoporttheappto
theotherplatformsincethesedesignfeaturesarespecifictotheiOSplatform.Thisis
whenpurecodewouldbemorebeneficial.Storyboardsthoughgiveusdevelopersan
editable,visualrepresentationoftheapp/gamewewishtomakeandtheabilitytodolittle
tonochangesasthefamilyofdeviceschange.
Evenothergamedevelopmentengines,suchasUnity,UnrealEngine,andmore,workon
amoresandboxing,visualrepresentationmethodologywithyourcodeactingasmoreofa
componenttothevisualasopposedtothefullstructureofeverythingthatappearsbefore
yourgamecharactersevengetrenderedtothescreen.
Summary
Inthischapter,wewentoveranumberofappprojectstructuringandintroductiontopics.
First,wewentovertheModel-View-Controllerparadigmfollowedbyallapps,gameor
not,andtheoveralllifecycleofaniOSappthatfollowsthisstructuring.Next,we
reviewedtheentrypoint(s)andpathwayofyourcodeinatypicalappaswellastheupperlevelobjectsusedalongtheway,suchastheApplicationsystemobject,theAppDelegate
class,andviewcontroller.Lastbutnotleast,wediscussedthemaintopicofthechapter—
storyboards,segues,andinstructionsonhowtocreateasimplegameflowstructure.From
here,wecanseehowrelativelyeasyandquickitcanbetostructurevariousscenesfor
yourgameandtransitionbetweenthemwithsegues.Again,notethatalthoughstoryboards
arerecommended,theycansimplystartasageneralguidetowardthefinalproduct,which
givesyou,thedeveloper,theabilitytovisualizeyourgameevenifintheendpreferringa
morecode-heavydesignchoice.
Inthenexttwochapters,wearegoingtofinallygetintoreallycodinganddesigning
actualplayablegames.Wewillstartoffwith2Dgames,andsinceiOS7,Applehasgiven
iOSdevelopersit’sownframeworktohandle2Dspritesandgamephysics.This
frameworkisamplynamedSpritekit.
Chapter3.SpriteKitand2DGameDesign
NowthatweunderstandthebasicsofcodinginSwift,thegenericflowandclassstructure
ofaniOSapp,aswellastheoptionalstructuringofappswithstoryboardsandsegues,we
canmoveontotransformingourappsintoplayablegames.
Forthischapter,wewillbeginwiththe2Dgamedesignandgamedevelopment
frameworkcreatedexclusivelybyAppleforiOSgamedevelopersknownasSpriteKit.
SpriteKitfirstbecameavailablewithiOS7tohelpsimplifythegamedevelopment
processforthefamilyofiOSdevices.Theframeworkrunsatypicalrenderingloopto
drawandupdate2Dobjects/spritestoyourgame’sscene.There’smuchgoingonbehind
thescenestorunthisloopanddrawyourgamesprites.Thankfully,Applebuiltthefirst
partygamedevelopmentframeworkstodomuchoftheheavyliftingforus.Thisway,we
canfocusmoreonmakingthegameitselfwithoutworryingtoomuchabouthowthat
gamewillconnectandrunwiththehardware,somethingdevelopersinthepasthadto
contendwith.
EveryupdateofiOSandXcodecontinuestoaddmoretoolsandframeworkstoimprove
theeaseofgamedesign,includingthecompanionframeworkintroducedfirstatWWDC15
foriOS9knownasGameplayKit.GameplayKitcanallowustoseparate,copy,and
modularizethegamelogicandevencopyforuseinfuturegameprojects,beitSpriteKit
orthe3Dframeworkofournextchapter,SceneKit.WewillgooverGameplayKitinlater
chaptersaswell.Attheendofthischapter,wewilllookatacompletegameexamplethat
isforasimplegameinitsgameplaybutsomewhatcomplexinitslogic.
AbriefhistoryofiOSgamedevelopment
engines
SpriteKitandthe3Dgameframework,SceneKit,werenotthefirstmethodsusedfor
developinggamesiniOS.We’llquicklyseewhyitbecameawelcomedadditiontothe
developertoolset.Initially,we,thegamedevelopers,hadtopracticallytalkdirectlywith
theGPUusingtheOpenGLAPItoputboth2Dand3Dgraphics/verticesontothescreen.
Ontheupperlevel,therealwayswasFoundationandCocoaTouchtointeractwithuser
gesturestomanipulateUIKitobjects,butdealingwithgamedevelopmentessentials,such
asSpriteSheets,mipmaps,normalmaps,partialemitters,boundingboxes,andculling,
involvedsomeleveloflower-levelstructuring.Applemadethosecallstovariousgraphics
buffersandVBOsslightlyeasierwhentheycreatedtheirGLKitframeworkin2011.
Thankfully,variousthird-partyframeworks,suchasCocos2D,Box2D,Sparrow,
GameMaker,Unity,UnrealEngine,andothersmadethisprocesslessengineeringintensiveinanefforttokeepthedesignaspectofgamedesignthefocus.GameMaker,
Unity,andUnrealEnginearemoresandboxing-/drag-and-drop-styledenginesakintothe
mentalitybehindstoryboardsandsegues,whileenginessuchasCocos2DandSparroware
morecode-heavy/boilerplateOOPstructuresthatshortcuttheinitialcodingbuildup.
EnginessuchasUnityandUnrealEnginearegreatinthattheyofferamorehands-on
sandboxing-typeenvironmentwithvariousfeaturesthatsimplifytheMVCmodel.Some
drawbackstosuchenginesarethattheyaresometimesclosedsource,usuallycostmoney
toutilizetotheirfullestandaren’tdevice-specific(Unityparticularlyfallsintothis
category).Workingwiththesevisualenginescouldsometimesleadtooptimizationsbeing
requiredinplatform-specificIDEssuchasXcode,duetoasometimesone-size-fits-all
methodology.Apple’sSpriteKitandthe3DAPI,SceneKitwhichwe’llseelater,giveusa
first-partyplatform-specificmiddlegroundthatgrantsthedeveloperbothupper-levelAPI
editing,butevenlower-levelgraphicAPI(OpenGL/Metal)customizations.
Note
Thenegativestosandbox/drag-and-drop-styledengineshavedecreasedovertime.Engines
usedbyAAAstudios,suchasUnrealEngine,Unity,Havok,andothershavelessened
theirupper-levelambiguitybetweentheAPIandtargeteddevices’lower-levelcode.A
goodexampleofthiswouldbeUnity’sIL2CPP,whichconvertstheupper-levelAPIcalls
directlytofastdevice-specificC++code.Thisincludescodeandgraphicspipeline
optimizationsthatmakeuseofApple’sslimMetalAPI.Thishomogenizationofupper
levelapplicationswithtraditionalboilerplatecodenowallowsdevelopersfromallskill
levelstomakeamazinggames.ThatiswhyfromiOS8,iOS9,andonwards,theApple
gamedevelopmentframeworksadoptedamorevisualdesignmethodology.Xcode7
introducedgamestatemachines,components,andtheabilitytoedit/copyandreuseplayer
actionsandanimationsthroughoutyourprojects.Thisallowsdeveloperstowork
specificallyiniOS/Xcodewhileutilizingthevisualdesignbenefitsofthedeviceindependentgameengines.
Forthischapter,wewilllearnhowtomakeatilepuzzlegamenamedSwiftSweeperusing
theSpriteKitframeworkandwithamoretraditionalboilerplatecodemethod.Thismeans
thatwewillmakeourfirstdemogameinacode-heavy/model-centricfashion.Notonly
willthisgiveusalookintotheinnerworkingsofSpriteKit’scodebutitwillalsoletus
utilizemorefromtheSwiftprogramminglanguagefromChapter1,TheSwift
ProgrammingLanguage.
WewillconcludethischapterbybrieflymentioningApple’slatestSpriteKitdemogame,
DemoBots,whichutilizesmoreofthevisualtools/frameworksfromXcode7andlater.
Seeingthemorecode-intensivemethodfirstthoughwilllaterletusappreciatethetime
savedwiththesenewertools.
Applehasgoneoutoftheirwaytomimicthevisualdesignmethodologytogamedesign
seeninotherenginessincegamedesignisasmuchaboutcode/logicasitisaboutartand
design.
Thegameloop
Thegameloopisagamedeveloper’sroadmap.Thenamesdifferdependingonthe
frameworkandplatform,butthesamerulesapply.Thegameloopcomprisesofallthe
methods,physicsupdates,anddrawcallsthatoccurduringasingleframeofyourgame
andtheirorderofexecution.Thegoldenruletogamedevelopmentistotrytokeepthis
loopalwaysspinninginfulliterationsatnoslowerthan16.6milliseconds,or60frames
persecond.
Thereareaspectsofthegameloopthatdon’thavetobecontrolledbythegamedeveloper
asmuchastheyusedtobeinthepast,thoughwedohavetheoptiontoworkdowntothe
veryGPUcallsusingOpenGL,orevenbetter,Apple’sMetalAPI.Wewilldiscussmore
onthesetopicslateron.
HereiswhattheSpriteKitgamelooplookslike:
TheprecedingisanillustrationgiventousdirectlyfromtheAppleDevelopersite.Wesee
anumberoffunctionsthatarecalledduringasingleframe.Thefirstfunctioniterated
throughisupdate().Theupdate()functioniswhereweaddmostofourowngamespecificupdatesandvariouschecksongameobjects(suchaspositionsandcharacter
statuses).
Theloopstructuregivesustheoptiontodoupdatesafterweknowacertainsetoftasksin
theframehavehappened,that’swheredidEvaluateActions(),didSimulatePhysics(),
didApplyConstraints(),anddidFinishUpdate()functionscomeinhandy.
Note
AnyonecomingfromUnitymightbefamiliarwithitsgeneralgameloopfunctions,such
asAwake(),Start(),FixedUpdate(),update(),andLateUpdate().TheSpriteKitgame
loopallowssomesimilarcode/renderflow,butaswe’llsee,therearesomeslight
differences.
Formoreonthegameloopanditsfunctions,seethefollowinglinkfromtheApple
documentationat
https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_
Utilizingtheothergameloopmethodscouldmakesurecertaincallsinyourgamedon’t
gooutoforderandcanevenhelpwiththeimportanttaskofmakingthemostoutofeach
frameinafast,efficientmanner.
Forinstance,inthepublicgamePikiPop,mentionedpreviously,here’showthegameuses
thegameloopinitsmainGameScene.swiftcode:
//Update()Example
//FrommainGameScene.swift
overridefuncupdate(currentTime:CFTimeInterval){
//Updateplayer
if(player?.isPlayable==true){
player!.update(currentTime)
}
}
TheprecedingcodefirstcheckswhethertheplayerisplayablewiththeisPlayable
Boolean.Thisstatuscanmeananumberofthings,likeiftheplayerisaliveornot,is
spawning,andsoon.Thegameloop’supdate()function,whichisbeingoverriddenfrom
itsparentupdate()functionoftheSKSceneobject,takesaparameterofthetimeutility
typeCFTimeInterval.CFTimeIntervalisaspecialCoreFoundationdoubletypethat
measurestimeinsecondsandthusupdatestheplayerobject(ifnotnull)duringeach
interval.
AsabriefsummaryofPikiPop,it’saprocedural2Dside-scrollinggamesomewhatsimilar
tothegameFlappyBird.UnlikeFlappyBird,Pikiisabletotraversethegameinall
directionsbasedonplayertapsandswipes.Pikicouldgettrappedbetweenthestage
objectsandtheedgeofthestage.
TheprecedingimageisPikigettinginjuredifpushedintotheleft-handsideofthescreen.
Edgesinthatgame’sstagesuseSpriteKit’sownspecialobjectsnamedSKConstraints.
Moreontheselater,butinshort,theydictatetherangeandorientationSpriteKitsprites
cantake.SpritesinSpriteKit(bothdeveloper-definedobjects,suchasPikiPop’sPlayer
objectandthedefaultSKSpriteNode)areallderivedfromSKNodeobjectsthatworkwith
SKConstraintsandotherphysics-basedframeworkfunctionality.
WecouldcheckwhetherPikiisbeingpushedagainstthecornerintheupdate()partof
thegameloop,butsinceconstraintsarepartoftheframework’sphysicsarchitecture,it’s
besttodothischeckduringthedidSimulatePhysics()portionoftherenderloopof
SKSceneasseenhere:
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’tmindthedetailsofthiskindofcodefor
themoment;justnotethatwechecktheplayer’spositioninxversustheedgeofthe
window’sframeinthisportionofthegameloop.
Note
Here’smoreinformationonwritingblocks/closuresinSwift:
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Progra
Tilegame–SwiftSweeper
TimetostoptalkingaboutSpriteKitandgetrightintoit!Asstatedatthebeginningofthis
chapter,wewillfirstshowyouhowtomakeasimple-lookingtilegameinSpriteKitusing
theslightlymoredifficultboilerplate/code-drive-styleddesign.Don’tworry,thisisnot
goingtoinvolvedirectcallstotheGPUwithC++andhandlingextremelytinymemory
requirementslikeveterangamedevelopersdidduringtheearlyconsoledays.However,
wewillbeusinglotsofcode-heavycallswithSpriteKitobjects,functions,andclasses.
Granted,gettingdownintothecodedirectlyiscontinuallybecominglessofthe
developer’sresponsibilityasApplecontinuestomakemoredesign-centricfunctionalities
inXcode.
Knowingthecodestructurecangiveyouanedgeoverdeveloperscominginonamore
top-downmethodologyandcodingwillalwaysbebehindcustomgamelogic.
WhatisSwiftSweeper?
SwiftSweeperisacloneoftheclassictilepuzzlegame,MineSweeper,writtenentirelyin
Swift.SwiftSweepermakesuseofSwift’sabilitytouseUnicodeemoticonssothatwe
don’thavetousemanyimageassetsandshouldgiveusagreatstartingpointtomaking
ourowntile/puzzlergamewithdifficultylevels.
Wewillbuildupmuchofthegamefromscratch,butthefullsourcecodecanbefoundat
https://github.com/princetrunks/SwiftSweeper.
Note
Asatthetimewritingofthisbook,thiswasbuiltinXcode7Beta(7A120f)fortheinitial
iOS9releaseandoptimizedforiPhone.
Thegoalofthegameistotapeverytileonthegameboardwithouthittingmineshidden
throughouttheboard.Youdogetsomehelpthough.Everytilethatisn’taminewilltell
theplayerhowmanytilesarounditaremines.Iftheplayerknowsthatatilewithouta
doubtisamineviatheprocessofelimination,theycanplantaflagonthattiletomake
surethattheydon’ttapthatspace.Tapallofthetilesthataren’taminetowinthegame!
SwiftSweeperevensavesthetimeittookyoutowinforeachdifficultylevelyouchoseto
givethegameabitofreplayvalue.
CreatingourSpriteKitgame
Nowthatweknowthegoalofourgame,here’showwegoaboutbuildingitinSpriteKit:
1. First,openXcodeandcreateanewproject.
2. NowselecttheGametemplateandclickonNext.
3. Next,fillintheproductname.WewillnamethisprojectSwiftSweeperExampleand
makesurethatthelanguageisSwiftwithSpriteKitselectedasthegametechnology
aswellasthedevicessettoiPhone.
4. Then,clickonNext,andwenowhaveabrandnewSpriteKitgameprojectwitha
numberoffilesalreadywrittenupforustogetusstarted.
5. Nowclickontheproject’smainfileinthenavigationpaneanddeselectallbutthe
PortraitselectionintheDeviceOrientationfield.
6. Sincewearegoingtoworkmostlywithcode,wecanalsoeitherignoreordeletethe
GameScene.sksfilefornow.ThesefilesareXcode’soptionforyoutovisuallydesign
yourgamescene.Wewillknowmoreonthesefileslaterwhenweworkwithour
morevisuallydesignedSpriteKitgameexample.
7. BuildandruntheapptoseeApple’sdefaultSpriteKitproject,whichhasHello
WorldwritteninChalkdusterfontandarotatingspaceshipappearswhereyouclickor
taponthescreen.
AnoverviewoftheSpriteKitstructureandobjects
Beforeweaddourcode,let’susethistemplatetogetanideaonhowSpriteKit’sbasic
objects,functions,andflowwork.
Aswestatedinthepreviouschapter,AppDelegate.swiftisthemainentrypoint.The
codethenmovestoGameViewController.swift,whichisachildofthe
UIViewControllerclassthatimportstheSpriteKitframework.Thefollowingcodeis
writtenintheviewDidLoad()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)
}
}
Tip
Downloadingtheexamplecode
Youcandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.com
forallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbook
elsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilesemaileddirectlytoyou.
Usingthekeywordoverride,thisversionofviewDidLoad()cannoweitheraddtoorwell
overridetheparentclass’sfunctionality.super.viewDidLoad()callstheparentclass’s
originalfunctionalityandthenitworksitsowncustomfunctionality.ThisishowSwift
handlestheOOPconceptofinheritance.
Next,weseehowagamesceneisfirstcreatedwithGameViewController.Amajoraspect
ofSpriteKitisthatitworksinscenesthataremembersoftheSKSceneclass,whichare
themselveschildrenoftheSKNodeclass.TheSKNodeclassesarethemainbuildingblocks
ofnearlyeveryobjectinSpriteKit.Beitsprites,lights,videos,effects,physicsfields,
audiofiles(SKAudioNodes),cameras(SKCameraNodes),orlabels/UIobjects,theyare
SKNodeclasses.Theseobjectsallholdimportantinformation,mostimportantlycoordinate
informationofobject’snodefamily.Forgames,thisallowsthedevelopertocreatecustom
classes,suchasEnemies,GameLights,Tiles,andsoon,thatallhavescreenandother
informationonbothparentandchildnodes.Forexample,wecanhiteveryenemyonthe
screenwithanattackbytheplayerbycallinganinheritedfunctioninaparentEnemyclass.
Wedon’tneedtocheckforeachindividualtypeofenemybutinsteadenumeratethrough
theparentnodesinthevariousgameloopfunctionsofSKScene:
enumerateChildNodesWithName("player",usingBlock:block)
Doyouremembertheblock/closurecallinPikiPop?Toactuallyuseitinthe
didSimulatePhysics()functionofSKScene,wecalltheenumerateChildNodesWithName
functionofSKNodetotargetonlythosenodesinthesceneandhavethatblockofcoderun
foreachmemberinthescenewiththatname.
playerNode.name="player"
ThenameissimplyastringthatcanbesetusingtheSKNode.nameproperty.Haveevery
customnodeinitiatewithagivenname(orchangeduringgameplay),andyouhavea
wholegroupofobjectsyoucansingleoutinthescene.
YoucanfindmoreonSKNodeinApple’sofficialdocumentationat
https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKNode_Ref/.
Scenetransitionsandthechoiceofcode,
storyboards,and/orSKSfiles
TheGameScene.swiftclassinourprojectinheritsfromSKScene,anditistherethatthe
gameloop/renderingfunctionswementionedearlieroccur.SpriteKitrunsonscenes,and
scenescanbetransitionedandseguedtoandfromit.
Inthepreviouschapter,weshowedhowtostructureagameusingstoryboardsandsegues.
SKScenemakesitwhereyoudon’tevenhavetousestoryboardsbutjuststraightcodeto
transition.Wecanusestoryboards,andwecanalsovisuallydesigneachindividualscene
using.sksfilesoracombinationofallthreemethods.Withcode,SKScenecantransition
withtheSKTransitionobjectsandfunctions.Actually,aswe’llseewithSwiftSweeper,
wecanjustusecodetomanuallyrefreshassetsinthescenetodotransitions.Thismethod
isratheroldfashionedandnotaselegantasSKTransitionstoryboardsandSKSfiles,so
let’stakeaquicklookathowtotransitionscenesincodewithSKTransition,storyboards,
andbrieflyintoSKSfilesviacode.Later,andinthenextchapter,wewillfocusmuch
moreonthevisualSKSfilessinceeveryupdatetoiOSandXcodecontinuestoputthe
focusonthesevisualtoolstoshortenthecodingtimeandworkflow.
AnSKTransitionexample
Thefollowingcodechangesthegame’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,the
transitionisadirectionalswitchtothenextscenewiththeSKTransitionDirection.Up
enumeratortype.AswesawinGameViewController,thenewsceneiscreatedwiththe
similarfunctionsthatcontrolthescene’sviewsizeandaspectratioandthenpresentsthat
scenetotheunwrappedviewwithself.scene!.view!.presentScene(scene,
transition:transition).
Alsonotethatthistakesplaceinthesamefunctionasweseeinourcurrentproject’s
GameScene.swiftclass,overridefunctouchesBegan(touches:Set<UITouch>,
withEventevent:UIEvent?){}.Thisisthefunctionthathandlestouchgesturesfrom
theplayerandcheckswhetherthenameofthenodetouchedmatchesthe
SceneChangeButtonstring.
MoreonSKTransitionandotherneattransitioneffectsyoucangiveyourgamescanbe
foundhereintheofficialdocumentation:
https://developer.apple.com/library/prerelease/ios/documentation/SpriteKit/Reference/SKTransiti
Note
AsofSwift2.0/iOS9,thistouchdelegatefunctiontakesinaparameterthatisasetof
UITouchesviatouches:Set<UITouch>andanoptionalUIEvent.Thisisachangefrom
pastSwiftiterationsandcouldchangeinfutureupdates.
ASKScene/storyboardexample
Here’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,usingthevisualhelpofstoryboardfilescangiveus
greatvisualroadmapstoourapps,bothgameandnon-game.Theprecedingcodeusesa
linktoan@IBActionlinkageonastoryboardfiletosetanewscene.
Storyboardsingamescanbegreatfortheprototypingphasewhenweknowjustthe
generalstructureofourgame,andcanbeperfectforthegame’smenunavigationsoreven
forallindividualgamescenes*.
Thebuttonitselfisremovedbeforethetransitionviathebutton.removeFromSuperview()
calltopreventamemoryleakcausedbythenewscenebeingdrawnoverwhatcouldhave
beenanunseenmenubutton—unseentotheplayerbutnottothegame’smemorystack.
Tip
*It’susuallythebestpracticetoonlyusestoryboardsforoverallnavigationmenusandnot
foreachindividuallevel/scene.TheSKSceneandSKNodefunctionalitycanletusreuse
similarscenestructuresandsavemuchofthecodingforsimilarlystructuredlevels.
Gameswithmanylevelscouldturnourstoryboardsintoawebofconfusingstructuresand
thusundotheirinitialpurpose.Sceneswiththeactualgameplaycouldjustbeintheirown
singleviewcontrollerinthestoryboard,andwe’dhavethepause,share,andothermenus
becontrolledbystoryboardsegues.
SKScenetransitionswithSKSfiles
A.sksfileisaspecialSpriteKitscenefilethatcanallowthecreationofasceneaswellas
theplacementoftheplayer,particles,enemies,andlevelassetsinavisual,draganddrop
way.Transitioningtoavisuallydesigned.sksfileinSwiftisthesameasourinitial
SKTransitionexample.
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)
})
}
}
ThecreationofthegameSceneconstantwiththeSKSceneinitializerfileNamedandthen
presentingthatscenetotheviewworksthesamewitheitherthe.swiftfileor.sksfile.
Thisgivesustheflexibilitytobothcodeand/orvisuallydesignourgamescenes.Inthe
caseofSwiftSweeper,wewilldothemorecode-centricmethodology,butfeelfreeto
buildonthisgameonyourownifyouwishwitheithermorecode,Storyboards,and/or
withvisuallydesignedSpriteKitScene(.sks)files.
Assets,sprites,andicons
AsofXcode7,gameassetsareplacedintheAssets.xcassetsfolder.Previousversions
ofXcodemighthavehadanImages.xcassetsfolderforthegame’siconsandsprites,but
thishaschangedandmightcontinuetochangewitheachnewiOSrelease.
AnimagefromApple’sWWDC15conference
StartingwithiOS9andXcode7,theassetsfolderwasgivenevenmoreflexibilitywith
theabilitytohandlethevariousappiconsizes,thelaunchimage,setsofimages,and
spriteatlases.Thisalsoallowsustodevelopwithvariousmemorysavingcapabilities
introducediniOS9likeappslicing/appthinningandon-demandresources.Theapp
slicing/thinningfeaturemakessurethatonlytheassetsrelevanttothedeviceare
downloaded,whichsavesspaceontheplayer’siPhoneoriPad.On-demandresourceslet
ustagassetsthatareavailableinthedevice’smemoryonlyduringcertainpartsofour
games.Thisway,wecancreateevenlargergamesforourplayerstoexperiencewithout
taxingthesometimes-limitedspaceintheApplefamilyofdevices.
Youcanfindmoreonappslicing/thinningat
https://developer.apple.com/library/prerelease/ios/documentation/IDEs/Conceptual/AppDistributi
Whensettingupyourgameforon-demandservices,somethingthatcouldbegreatto
knowintheinitialplanningofyourgames,canbefoundintheofficialdocumentationat
https://developer.apple.com/library/prerelease/ios/documentation/FileManagement/Conceptual/O
Spriteatlasesandanimatingsprites
SwiftSweeperactuallydoesn’tuseanimatingsprites;aswe’llsee,itsimplyusesUnicode
emoticoncharacterstoanimatethescreen.Yet,wecan’tdiscussSpriteKitand2Dgame
developmentwithoutmentioningsprites,animatingandoptimizingthemwithtexture
atlases/spritesheets,couldwe?Aspriteatlasisacollectionofimagesbundledintoa
singleimage,alsoknownasaspritesheetortextureatlas.Whiledeveloping2Dgames,
itishighlyrecommendedtousetextureatlasesasopposedtovariousimagesetsbecause
totherenderer,textureatlaseswillequatetofarfewerdrawcallsandthuscanmakesure
thatyourgamerunsatthatneeded60fps.TheCollectables.atlasfolderin
Assets.xcassetscouldholdallofyourgame’scollectablesandwiththeSKTextureAtlas
class,efficientlydrawthosecollectablestothescreen.Whenstoringtheimagestosaythe
player’sidle,walking,andjumpinganimations,weusetextureatlasestostorethem.
Creatingatextureatlasisverysimpleandispresentedasfollows:
1. SimplyclickonyourAssests.xcassetsfolderandright-clickonanemptypartof
thefolder’shierarchy.
2. ClickonNewSpriteAtlasandjustlikethis,wehaveafolderwherewecanstore
variousspritesforourgame.
3. Makesuretonamethefolderbasedonhowyouwishtocategorizethegroupsof
sprites.You’dneedthisnamewhenreferencingthemincode.
Tocreateareferencetothisatlasincodeandanimatethesprites,weuseSKTextureAtlas
asfollows:
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’sspriteatlasusingthe
initializerSKTextureAtlas(named:"Player.atlas").Then,wecreateanarrayoftextures
usingoneofSwift’sordersblockmap(NSRange){…}.Thisisaclosureblockthatiterates
throughthetexturesinthespriteatlasbasedontherangespecifiedinthemapcall.The
numberobjectisasimpleindexobjectwecanusetorepresenttheindexofthemapping.
Thisisdonebecauseourplayerhasthesespritenamesforthenormal/idleanimation:
"player_sprite_normal_1","player_sprite_normal_2",
"player_sprite_normal_3","player_sprite_normal_4"
Sinceweknowthatthespriteanimationsarenamedwithanindexednamingstructure,it’s
bettertouseSwift’sfunctionalprogrammingtools,suchasmap(),heretosimplifythe
code.2DSpriteswithmanyframe-by-frameanimations(gamessuchasMetalSlug)could
beiteratedthroughinsuchafashion.
SKTextureAtlasalsohasaclassfunctionnamedpreloadTextureAtlaseswecanuseto
preloadanarrayoftextureatlases:
SKTextureAtlas.preloadTextureAtlases([PIKIATLAS,BGATLAS,COLLECTABLESATLAS,H
UDATLAS,OBSTACLESATLAS])
{
//performothertaskswhileloadingTextureAtlases
}
Thisisgreattomakesurethatastage’sspritesareloadedbeforeenteringthestage.
Creatingourgamelogic
Forthesakeofsimplicity,MineSweeperwon’thavemanydifferentassetsoranysprite
textures.ItinsteadusesSwift’sUnicodeemoticoncharactercapabilitiesandUIViewcalls
todesignthegame’sgraphicsinaratherold-fashioned,veryMineSweeper-likeway.
Notonlydowedothistogiveusasomewhatsimplisticstartingpoint,buttoshowhow
SwiftcodeandSpriteKitclassescanletuscreatetheentiregame’slogicandflowwithout
theinitialneedofspriteassets.Thisway,ifdevelopingasateamorbyyourself,thegame
canbemadebeforedoingthesometimesgruelingprocessofmakingwonderfulvisual
assets.Thinkingwithcodeandstructurefirstcanensurethatyouhaveaworking
prototypethatyoucanpolishlaterwithsprites,music,andatmosphere.
We’vesofarleftSwiftSweeperwaitingasjustashelloftheSpriteKitgametemplate.It’s
abouttimewegettothegame’smodel:
1. First,let’saddourimageassets.Formoreinformation,visit
https://mega.co.nz/#!XhEgCRgJ!4QqKMl1l1P4opWU7OH2wEN_noVQ86z5mxEyLuyUrcQ
ThisisalinktotheAssets.xcassetsfolderofSwiftSweeper.Wecanaddthese
individually,butthesimplestwayistojustreplaceyourproject’sAssets.xcassets
folderdirectlyinyourcomputerwhereyourproject’sfolderislocated.Youcanhave
Xcodeopenwhileyoudothis,it’llautomaticallyupdatefromtheoriginaltemplate
files.
2. Next,let’saddthesoundfilesfromthefollowingURL:
https://mega.co.nz/#!T5dUnJZb!NUT837QQnKeQbTpI8Jd8ISJMx7TnXvucZSY7Frw5gcY
3. Addthesoundsbydoingthefollowing:
1. Right-clickontheSwiftSweeperExamplefolderthatholdstheSwiftfilesand
thengotoNew|Groupfromthemenu.
2. NamethisfolderSoundsanddragittothebottomofthefileswithinthesame
SwiftSweeperExamplefolder.
3. Right-clicktheSoundsfolderandselectAddFilesTo
"SwiftSweeperExample".
4. AddthesoundsfromtheSwiftSweeperSoundsfolder,andtheyshouldnowbe
inyourproject.
Alloftheassetsshouldbenowintheproject,sonowwecanbuildourgame.Let’sfirst
startwiththeactualtiles.
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.WeknowthateachtileinagameofMineSweeperwillbepartofarowanda
column.Thenumberoftherowandthecolumnthistilewillhaveduringgameplay
won’tchangeduringthecourseofasingleround,sowemakethemconstantswith
thekeywordletandsetthemwiththetypeIntasweknowthatyoucan’thave
fractionsofaroworacolumn,atleastintermsofthetileobjects.
2. Atilecanhaveafewdifferentstates.Itcouldbealreadytapped,itcouldhaveaflag
placedonit,andifit’saamine.Sincethesearetrue/falseproperties,wesetthem
withasBooleanvariablesisTileDown,isFlagged,andisAMine.Wesetthemto
falseinitially.
3. TilesinMineSweepercounthowmanytilesaroundthemaremines,sowecreatethe
integercounternearbyMinestoholdthatinformation.
4. Whenaninstanceofatileobjectiscreated,wewantthegametosetitsrowand
columnnumberplacementontheGameBoard,sowecreatethedefaultinitializer,
init,tohavetwoparameterinputsforboththerowandcolumn.
That’sallweneedfortheTileobjects,solet’smoveontosettingthebuttonfunctionality
oftheseTileobjectswiththeMineTileButtonclass.
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,weimporttheUIKitframeworkforthis
object.
2. Thesearethepropertiesofthisbuttonobject.WeneedaTileobjectnamedtileto
reference,aCGFloatsizenamedtileSizetorepresenttherectanglethisbuttonwill
occupy.
3. TheinitializerforthisclasstakesinaTileobjectnamedtileButtonandaCGFloat
namedsize.Weassigntheclass’sowntiletotileButtonandtileSizetosizeand
thenwemakeasquarenamedtileBoundingFramewiththeCGRectMake()method.
ThisisdonejustafterwesetanxandyvalueofCGFloattothesquarebasedonthe
tileSize.TheUIButtonparentinit(frame:)initializerusesthe
tileBoundingFrameastheparameterviasuper.init(frame:tileBoundingFrame).
4. SinceXcode5,theinitfunctionisneededmainlytokeepthecompilerhappywhile
dealingwithUIobjects.
5. ThefunctiongetTileLabelText()returnsastringbasedonthestatusofthetile
object.Ifthetileisnotamine,weknowthatwehavetoeitherplacesomethingfor
therebeingnotiles;traditionally,thisisjustablankspaceoranempty""string,but
fornow,wearejustplacing0there,leavingthelogicopenforcustomization.
Honestly,wecouldsimplyreturnthenestedif-elsestatement’sreturn\
(self.tile.nearbyMines),andit’dreturnthesameresult.Aswesee,it’sreturning
theparticularTileobject’snearbyMinesproperty.
6. Ifthetileisamine,thenwereturnthecollisionUnicodeemojicharacter.The
getTileLabelText()functioniscalledwhentheplayertapsanunflaggedtile.
7. Swift’sabilitytouseUnicodecharactersymbolscanbeagreatvisualaidinthe
planningprocessofyourgames.ThecollisionUnicodeemojiusedinline(6)is
U+1F4A5(128165).Ifyouseeonlyasquareboxandnottheredexplosion-like
character,itcanbeseeninthefullprojectdownloadmentionedearlierinthechapter
oratthefollowinglink.
Note
Findmoreinformationonthisemojiathttp://www.charbase.com/1f4a5-unicode-collisionsymbol.
GameBoard
Nowthatwehaveourtileobjectandbuttonlogicthatwillrepresenteachtileobject
namedMineTileButton,weneedtocreateanobjectrepresentingthecollectionofthese
objects,thatis,GameBoard.
ThefullGameBoard.swiftcodeisabittoolargetoshowhereinitsentirety,sowewill
summarizeitsmainfeaturesandsegments.
Wecanviewtheentirecodeeitherinthefullprojectlinkmentionedearlierinthechapter,
ordirectlybelowinordertocopytoyourcurrentgameprojectfile:
https://mega.co.nz/#!X8FB2aAK
ForourGameBoard,wearelookingtocreateatiledboardof10x10sizethatalsohasthree
levelsofdifficulty:easy,medium,andhard.Tocreatethedifficulty,wesimplyusean
enumeratornameddifficultytostorethegame’sdifficultylevels.
ThemostimportantpropertiesofGameBoardincludeboardSize_(whichissetto10inthis
case),avariablethatwillrepresentthenumberofminesthatwillbeplacednamed
mineRandomizer,thenumberofminesactiveontheboardnamedmineCount,andtheTile
objectsthatwillpopulatetheboardnamedtiles.
Makeanoteofthesyntaxusedforthetilesproperty:
vartiles:[[Tile]]=[]
Inthisway,wecancreateanordered2Darray(ormatrix)inSwift*.TheGameBoard
objectwillbasicallystoreanarrayofanarrayofTiletypeobjects.
Note
*Swiftdoeshavemorewaystoexpressmatrices,forexample,wecanuseStructsto
defineourownuniquematrices.Asatthetimeofthispublication,Swiftdoesnothaveits
owntruefunctionalityforfixedlengtharrays,asweseeinvariousClanguages.However,
usingthenestedbraces[[]]isfineforwhatwearetryingtoaccomplish.
TheinitializerforGameBoard,init(selectedDifficulty:difficulty){},takesinthe
player-selecteddifficultyasit’ssingleparameterthenbuildstheboardbasedonthe
boardSizepropertyandthenusesthefollowingnestedfor-inlooptopopulatetheentire
boardwithTileobjects:
forrowin0..<boardSize_{
vartilesRow:[Tile]=[]
forcolin0..<boardSize_{
lettile=Tile(row:row,col:col)
tilesRow.append(tile)
}
tiles.append(tilesRow)
}
Sincethetilesobjectisa2Darray,wefirstneedtoperformthisnestedloopthatfirst
createsa1DarrayofTileobjects(namedtilesRow)foreachrowandthenaddatilefor
eachcolumninthatrowwiththe.appendfunction.Themaintiles2Darrayisthen
appendedthattilesRowarray.
Tip
IfyouwishtomakeaGameBoardinstancethatisarectangleorofanothershape,you’d
havetotakeintoaccountthedifferingcolumnandrowamounts.Thiswouldmakethe
nestedfor-loophavemorecomplexitybyneedingaseparatecolumnSizeandrowSize
property.Manypuzzlegameswillmaketheirboardslookcomplextotheplayerbutmight
stillkeeptheirinternalstructuressimpletoeithersquaresorrectanglesbyinsteadfillingin
thattilewithanonplayablesectionorbackground/transparenttile.
It’sawayforadevelopertocutcornerswhileatthesametimeallowingcomplex
functionalityanddesign.It’swhywebuiltthisgamewithseparateclassesrepresentingthe
Tiles,thetilebuttonfunctionalities,andthegameboardlayout.
Usinginheritance,wecancontinuetocustomizewhateachtiledoesandthusallowa
myriadoffeaturesbasedonasimplefoundation.
It’swhyvideogameshavealwaysbeentheposterchildrentomakethemostoutofobjectorienteddesign.
Don’tworryifatfirstit’stoughtogetafullunderstandingofthis,asnestedloopstendto
bebraintwisters.Justobservehowtheinteriorfor-loopwon’texituntilit’sdonefillingin
columnsbasedontheboardSize_property.Thiskindofloopismadeeasierwiththefact
thattherowsandcolumnsareallequalat10.
TheinitializerthencallstheresetBoard()function,whichresetsthemineCountto0,and
doestwomorenestedfor-loops:
forrowin0..<boardSize_{
forcolumnin0..<boardSize_{
self.createRandomMineTiles(tiles[row][column])
tiles[row][column].isTileDown=false
}
}
Thisboard-iteratingfor-looprandomlysetswhichtilesareminesusingthe
createRandomMineTiles()functionaswellasresetsthetilestobeinguntouchedwiththe
tiles[row][column].isTileDown=falsecall.ThecreateRandomMineTiles()
functionworksoffthecurrentdifficultylevel,particularlythemineRandomizerproperty
thatisdeterminedintheimplementDifficulty()function.Thehigherthe
mineRandomizervalue,thelessofachancetheiteratedtilewillbemadeintoamine.
Thenextnestedfor-loopinresetBoard()isthefollowing:
forrowin0..<boardSize_{
forcolumnin0..<boardSize_{
self.calculateNearbyMines(tiles[row][column])
}
}
Thisiteratesthrougheverytileontheboardandsetsthenumbertheplayerwillseeif
tapped.Thatnumberofcoursebeingthenumberofminessurroundinganon-minetile,
thatis,thenearbyMinespropertyoftheTileclass.
ThisrathercomplexchainofcalculationsbeginswiththecalculateNearbyMines()
functionandrunsthroughthearray/tileindexcalculatingfunctions,getNearbyTiles()
andgetAdjacentTileLocation().Weprovidedvariousdetailedcommentsineachof
thesefunctionstogetabetterunderstandingonhowtheywork.It’sadvisedthatyouread
theintricatedetailsonhowit’sdonebuttonotmuddyanalreadycomplexgamelogic
explanation,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.The
nearbyTileOffsetobjectisanexplicitlywrittenarrayoftuples,whichcontainsevery
offsetthatcouldexistaroundasingle2Dtile.Actually,it’sbesttothinkofeachmember
ofthisarrayasan(x,y)2DVector.
Thus,ascommentedintheprecedingcode,theoffsetof(-1,-1)wouldbetothebottom
leftofthetilesincex=-1(left1)andy=-1(down1).Similarly,(1,0)istotheright,
(1,1)isthetop-rightcorner.
Wealsohavetotakeintoaccountthatsometilesareontheedgeand/orcolumnofthe
board,thussomeofthetileoffsetswon’treturnthereferencetoanothertile;they’ll
insteadreturnnil.
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-generic
explanationoftheirfunctionality.So,don’tworryifyoudon’tunderstandtheflow/order
atfirst.
Finally,forresetBoard(),wecan’twinthegamewithoutknowingiftheplayergotevery
non-minetile,sowegetthatinformationwiththeline:
numOfTappedTilesToWin_=totalTiles_-mineCount
Whentheplayer’snumberofcompletedmoves(countedintheGameSceneclass)equals
numOfTappedTilesToWin,theplayerwins!
Thisisalldonebeforetheplayermakesthefirstmove!Thisisdoneinordertohavethe
valuesalreadypredetermined.Yes,wecouldmakesomeofthesecalculationsduringthe
player’stouch,butdealingwithboilerplategamelogicisusuallyfastenoughtoprepare
thegameatloadtimesothatwecanusethegameplaytofocusoneffects,sequences,and
othervisualnotificationsduringthegameloop.
ThisfunctionalityiscontrolledbytheGameScene.swiftfile,whichwewillsummarize
next.
PuttingitalltogetherinGameScene.swift
WenowhavethecoreofSwiftSweeper’slogicsetup,butnowit’stimetopresentitinour
SKSceneprovidedbythegametemplate,GameScene.Thissceneusesthegame/rendering
loopfunctionsthatwementionedatthebeginningofthechapter.
TheSwiftSweeperversionofGameScene.swiftisratherlargeatabout800linesofcode,
solikeGameBoard,wewon’tbegoingoveritlinebylinebutinsteadwe’llbesummarizing
someoftheimportantaspectsofthescene.Asstatedpreviously,everyupdatetoXcode
andiOSbringsmorevisualwaysofsettingupthesescenes,sogettingtoknoweveryline
ofcodeinthisexampleisn’tnecessary,butstillrecommendedifyoureallywishtodive
deepintohowtousecodetopresentSpriteKitgamescenes.
Thefullcodecanbefoundinthefullprojectlinkmentionedearlierinthechapteror(if
you’vebeenbuildingitfromscratchthroughoutthechapter)atthelinkmentionedhere:
https://mega.co.nz/#!PgljBL7b
Weusedvarious//MARK:commentstosectionoffpartsofthiscode,soyoucannavigate
easier.Aftercopyingthecodeintoyourproject,youcouldbuildandruntheapp.Aslong
aseverythingwasplacedintotheprojectcorrectly,youshouldhaveaworkingversionof
SwiftSweeperrunningonyourphoneorinthephonesimulators.Playthroughitabitto
getanideawhatisbeingdoneinGameScenetopresentthegame.Sometimes,seeinga
gameinactionletsusseethecodebehinditbetter.Ifanyerrorspopup,somethingwent
wrongandifallelsefails,youcandownloadthecompletedprojectfrom
https://github.com/princetrunks/SwiftSweeper.
ThefirstvisualentrypointinGameScene,didMoveToView(),isactuallyrathersmallas
follows:
overridefuncdidMoveToView(view:SKView){
self.backgroundColor=UIColor.whiteColor()
stageView_=view
loadInstructions()
}
Wesimplysetthebackgroundcolortowhiteandloadtheinstructions.Again,wedidn’t
saythatthiswasmeanttobeabeautiful-lookinggame.
TheloadInstructions()functionmanuallyplacestheinstructionsspriteonthescreen
andsetsthecurrentGameState_enumto.Instructions.Agamestateorstate
machineiscommongamedevelopmentmethodologythatinstructscharacters,theplayer,
andthegameitselfwhatstateitisin.Thiscouldbeusedtomakesurethatcertainpartsof
thegameplaydon’thappeninpartstheyaren’tsupposeto.iOS9/Xcode7introducedthe
framework;we’lldiveintomorelaterchaptersnamedGamePlayKit,which,amongother
gamelogicfunctions,workswithstatemachinesthatcanbemodularandindependent
fromaspecificscene.ComponentsfromtheclassSKComponentsandmoremodernusage
ofSKAction,alsointroducediniOS9,workinthesameway,independentfromOOP
inheritance.Thinkofmoredynamic/usableversionsofprotocols.
ThenextoverallstepintheGameSceneisthechooseDifficultyMenu()thatcamewith
theremoveInstructions()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.Itonlychecksifwetapped
theflagbuttonorifwetappedontheinstructions.Whataboutthetiles?Well,remember
thatwemadethesetilesallmembersofUIButtonwiththeMineTileButtonclass.Here’s
thefunctionthatcontrolsthis:
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.Usingthegamestatetocheckif
it’slogicaltothescene,weeitherendtheroundifamineishitwiththemineHit()
functionorweincrementthemovesperformed(usedtocalculatethewinbycomparingit
tonumOfTappedTilesToWin_calculatedatthestartoftheround).Ifthegamestateis
.FlagPlanting,thenweinsteaddealwiththelogicbehindplantingaflagonthetiles.
Tileswithflagsdon’treactto.MineTapgamestatetapsandthus,ifyouputaflagonthe
wrongtile,youwon’tgetthewinuntilyouuncoverallofthenon-minetiles.
Throughtherestofthecode,we’llfindatimer,alertsfortheplayerbasedontheoutcome,
andeventheabilitytosavetimesperdifficultylevelsusingtheclassfunctionsofthe
NSUserDefaultsclass.
Again,it’snotexactlyallthatvisuallyelegant,butintricateincodeandmostimportantlya
fullyfunctioninggame.Weadviseyoutocheckoutmoreofthecodein
GameScene.swift,butonemajorissuetoourdesignonemighthavecausedinthe
beginningisthatthisonlyworkswithiPhones.
Usingvisualtoolssuchasautolayout,seenbrieflyinthepreviouschapter,willallow
easierdesignchangesfortheentirefamilyofiOSdevices.Sincemanyofthevisualassets
inSwiftSweeper’sGameSceneweremanuallyplacedintheview(particularlythe
instructions),we’dhavetoaccountforeverydevicetypeincode.Thisispossible,butas
thefamilyofdevicesgrows,manualcodeusedforscreenvisualscouldbebrokenrather
easilyinfutureiOSupdatesanddeviceannouncements.That’swhyinournextchapter
aboutSceneKitandlater,wewillmostlydivergefromthiscode-centricstructureand
embracethehands-ontoolsandnewerframeworkssuchasGamePlaykitfromXcode7
andlater.
DemoBots
Asattheinitialpublicationofthisbook,WWDC15recentlycompletedandgaveusagreat
newSpriteKitdemoprojectforiOS9andXcode7namedDemoBots.
DemoBotsisaSpriteKitprojectprovidedbyApplethatusescomponents,statemachines,
on-demandservices,GameplayKit,ReplayKit,andmore!
ThefullprojectdocumentationtoDemoBotscanbefoundat
https://developer.apple.com/library/prerelease/ios/samplecode/DemoBots/Introduction/Intro.html
ToseeitinactionfromWWDC15,seethevideoandPDFfilefromtheDeeperinto
GameplayKitwithDemoBotskeynote:
https://developer.apple.com/videos/wwdc/2015/?id=609
TheSpriteKitkeynotecanbefoundhere:
https://developer.apple.com/videos/wwdc/2015/?id=604
DemoBots’sgameplayevenhaseasilyeditableenemyAI/navigationschemesusesthe
SKCameraNodeintroducediniOS9thatfollowstheplayeranddoesn’tmovethescene
aroundintheviewasinpastversionsofSpriteKit.Aswementionedatthebeginningof
thechapter,mimickingthetoolsweseeinmultiplatformgameengines.
Summary
Wewentthroughanumberoftopicshereinthischapter.WefirstspokeonwhySpriteKit
wasawelcomedadditiontoiOSafteryearsofdevelopersonlyhavingthird-partygaming
frameworks,suchasCocos2DandSparrow.WediscussedhowSpriteKitfitsinthegame
developmentecosystemasratherpowerful,multiplatformgameengines,suchasUnity
andUnrealEngine,continuetobecomemoreprominent.Next,wewentintotheSpriteKit
gameloopandrenderingcyclethatisusedbySKScene.Then,webegantobuildourdemo
tilegame,SwiftSweeper,anddovemoreintothebasicstructureofSpriteKit’smost
prominentobjectclasses.TheiOS9assetsfolderwasreviewedinadditiontotexture
atlasesandhowtoanimatespritesusingtheseassettools.Then,wewentintotherather
complexlogicandcodethatgoesintomimickingatilegamesuchasMineSweeper.
Next,wemoveontoiOS’s3Dgamedevelopmentframework,SceneKit,wherewewill
divergemoretowardsthevisualtoolsApplenowbringstoussinceiOS8/iOS9.We’ll
takelessofacode-centricmethodologynowthatweknowthebasicscene/codestructure
thatbothSceneKitandSpriteKitshare.SpriteKitscenescanoverlaySceneKitscenes,so
wewillseesomeofwhatwehintedatwithApple’sownDemoBotsdemoshortly.
Chapter4.SceneKitand3DGameDesign
Forthischapter,wewillbegoingovertheiOSframeworkusedfor3Dgamedevelopment
knownasSceneKit.SceneKitfirstbecameavailableiniOS7butoriginallywasjustused
forMacOSdevelopment.Previously,developershadtocode3DgamesusingOpenGLor
third-partyframeworksandengines,suchasCocos3D,UnrealEngine,Havok,andUnity.
AsthegraphicalpowerintheiOSfamilyofdevicesimproved,sodidtheneedforan
immersive,hands-onfirst-party3Dgamedesignengine.SceneKitshortlybecame
availableforiOSgivingdevelopersanXcodebuilt-insolutiontomake3Dgames.
Inthepreviouschapter,weapproachediOSgamedevelopmentinamorecode-based
methodology.We’llstillbeworkinginsomecode,butsincetheintroductionofXcode5
andXcode6,ApplehasprovidedsomegreatdemosthatshowhowtheIDEcanbejustas
visuallydynamicofagameengineasmultiplatformgameenginesare.Thebenefitof
usingXcodeandtheSpriteKit/SceneKitframeworksoverthoseenginesisthatyouhavea
dedicateddesignenvironmentforaspecificplatform.Inourcase,thatplatformisiOSand
theApplefamilyofdevices.AsiOSfrequentlyupdatesandcontinuestogivenew
features,Xcodeandtheseframeworkswillupdatewithit.Updatestothemultiplatform
enginesusuallyoccuratalaterdatewithsometimestheadditionalneedtoinstallplugins
toensurethatyourapprunssmoothlyinfutureupdates.
Inadditiontotheverydynamicandtool-richDemoBotsSpriteKitdemo,theJune2015
WorldWideDeveloper’sConferencealsointroducedawonderfulSceneKitdemonamed
Fox.TheFoxdemoalsomakesuseoffeaturesintroducediniOS9thatwecanusefor
eitherSpriteKitorSceneKit,suchasreusableactions,components,andstatemachines.
Inthischapter,wewillgooverthebasicsofSceneKitandwewillmakeasimple
SceneKitscene(knownasSCNScene)usingbothcodeandthevisualdesigntoolsXcode
provides.Wewillthenaddphysics,lights,andparticlestoourSceneKitobjectsandscene.
WewillthenwrapupwithalookintotheWWDC15FoxDemoandsomeofthe
features/APIsituses,whichbecameavailableiniOS8andiOS9.
Note
Inthepreviouschapter,weleftoutmuchoftheseassetcreationfeaturesinourdiscussion
onSpriteKit.WithSpriteKitscenefiles,(.sks),wecanalsocreategameassets,suchas
lights,physicsfields,boundingboxes/physicsconstraints,normalmaps,textures,entire
levels,andcharactersinthesamefashionthatSceneKitscenefiles(.scn)work.Wewill
attimesshowtheSpriteKitmethodtosimilarfeatures.
SinceSpriteKitandSceneKitsceneassetsworksimilarlyandcanbetogetherinthesame
scene(thankstotheirinheritnode/treefunctionality),wethoughtthatitwasbesttosave
thevisualandassettooldiscussionforthischapter.Thepreviouschapter’stalkonthe
game/renderloopandmuchofthescenecodefunctionalitywillworkinSceneKitmuch
likeitdidpreviouslyinSpriteKit.
Soinotherwords,wearealreadysetuptodiverightintoSceneKit.
SceneKitbasicsandworkingwithnodes
LikeSpriteKit,SceneKitisbasedontheconceptofnodes.SpriteKitobjectsarechildren
oftheSKNodeclass,whileSceneKitobjectsarechildrenoftheSCNNodeclass.
TheprecedingimageistheSceneGraphhierarchyfromApple’sSceneKitintroduction.As
wesee,SceneKithasvariousnodesthatbranchofffromtheSCNSceneclass.These
includethegenericSCNNodeforlights,geometry,andthecamera.
Nodesareatreedatastructurethatcanhaveothernodesaddedtothemandhave
informationofothernodesinthestructure.Asseenintheprecedinggraph,it’sshown
withthechildNode[]arrayandparentproperties.Spatialinformation,suchasposition,
scale,andorientation,canbereceivedfromtheseproperties.Thisiswhatmakesnodes
uniquetootherparent-childstructuringinobject-orienteddesign(OOD).
InSpriteKit,we’dtypicallyaddanodetooursceneortoanothernodewithinourscene
viatheaddChild()function.InSceneKit,thesamefunctionalityisdonewith
addChildNode().Forexample,themainrootnodeinaSceneKitsceneistheSCNScene
nodethatisplacedintheSCNViewnode,thatis,theframework’suniqueversionofthe
UIViewclass.Toaddabasicsphereobjecttoourscene,we’ddothefollowing:
letsphereGeometry=SCNSphere(radius:1.0)
letsphereNode=SCNNode(geometry:sphereGeometry)
self.rootNode.addChildNode(sphereNode)
AsstatedwithSpriteKit,workingwithnodesinSpriteKitcanallowustogroupvarious
membersofourgamescenetogetherintotheirownparentnodesandmakeactionson
theminonecallalsoiteratingthroughforloopsorotheriterationcalls.
SpriteKit/SceneKitinteractivity
OnegreatfeatureofSceneKitisthatwecanhaveaSpriteKitsceneoverlayour3Dgame.
self.overlaySKScene=skScene
UsingtheSCNViewpropertyoverlaySKcene,wecantakeanalreadyestablishedSKScene
node(whichcanbeacharacter,ananimationsequence,anHUD,andmore)andhave
theminour3Dscene.
Wanttohaveacutespriteanimationoverlayyour3Dcharacter’sstagewinormaybewant
tomakea2.5Dgamewith2Dspritesandphysicsoverlayinga3Dbackground?Thenthis
ishowyoucandoit.
ThemostcommonfunctionalityofmixingSpriteKitwithSceneKitisthatSpriteKitisthe
HUDfortheSceneKitscene.Thelives,collectables,andcharactericonseenintheearlier
FoxdemoshowsaSpriteKitnodeoverlayingaSceneKitscene.
Nodesingeneralcanhelpaddafunctionalstructuretoyourgameandgamescenes.A
highrelianceonnodesandinheritanceingamedesigndoesn’tcomewithoutitsflaws
though.
Theissuewithinheritance-basedstructuringand
gamedesign
Beforegoingforward,weshouldmentionaboutacertainpitfallthatcouldplagueagame
thatreliestoomuchontheconceptofnodesandeventhegeneralconceptofinheritancebasedstructuringinOOD.Whenpossible,it’sbestnottorelytoomuchoninheritancefor
yourgamelogicandworkmorewithwhat’sknownascomposite-basedstructuring.We’ll
godeeperintothisinournextchapterwhenwetalkaboutthehelpergamedevelopment
frameworkfirstintroducediniOS9,GamePlayKit,buthere’saglancesothatweknow
thatworkingwithinheritanceandevennodesmightnotalwaysbethebestsolutioninour
games.
Atfirstglance,onemightthinkthatinheritance-basedstructuringisperfectlymadefor
gamedevelopment.ManyofusfamiliarwithOODknowthatwecanhavegenericparent
classesornodesofourgameobjects,suchasanall-encompassingGameObjectclass,and
thenuseinheritanceandpolymorphismtoworkwithuniquechildclassesfromthisbase
class.Forsmall,simplisticgamesthatwillholdtrue,butgamestendtohaveobjectsthat
couldsharesomeofthesamefunctionality,butmakenosensetohaveinaparent-child
structure.
Takethistypicalstructuringinatower-basedstrategygame:
Inatypicaltowergame,we’dhaveourbase,tower,andenemyobjectsthatcanallinherit
fromagenericGameObjectclasswedefine.Towerscanfireatenemiesbutsocanenemies
backatthetowersandotherplayer-basedobjects.Partofgoodprogramminganddesignis
tohavereusablecodeandmethods.Normally,we’ddothiswithinheritance.The
precedinggraphshowstwo-wayinheritancethatcansolvethis.Wewouldthenwanta
ShootingEnemyclassthatinheritsthemovementandshootingfunctionality.Wecan’tdo
this,asthatwouldinvolveinheritingfromtwoseparateandratherunrelatedclassesof
objects.InOOD,there’sonlyonechild-parentrelationship.Thenextsolutionshownon
therightwouldbetohavethegenericGameObjectclasshavethisfunctionality.Theissue
thatarisesisthatouroncesimpleGameObjectparentclassbecomesallbutsimpleandwe
inevitablywanttoaddadditionalfeaturesandfunctionalitiestoobjectsinourgame.Inthe
past,thiswouldinvolverefactoringtonsofcodetoaccommodatewhatessentiallyare
simpledesignadd-ons.Protocolsusedtobesomewhatofasolutiontothisasthey’dforce
ustomakeaclassinacertainway,buteventheycouldgetconfusinganddon’tinvolve
theimplementationofthesefeatures.
Thesolutionwouldbetoworkwithentitiesandcomponents.
Thisprecedingdiagramgivesanexampleofcomposite-basedstructuring.Withthis
methodology,wecanhavecomponentsthatsharesimilarfunctionality,beingusedby
multipleandusuallyunrelatedgameobjects.Thisway,thegenericGameObjectclassin
thisexampledoesn’thavetohaveeverypossiblefunctionofitschildclassandwecan
keepEnemyclassesasbeingmembersofEnemy.Thesharedfunctionalitycanbewritten
onceandthenusedthroughoutthegameandevenintheothergameswewishtomake.
iOS9’sSpriteKitdemo,DemoBots,andtheSceneKitdemomentionedearlier,Fox,both
usecomposite-basedstructuringforactionsandanimations.
It’simportantwhenthinkingwithnodesinbothSpriteKitandSceneKitthattheyareused
inthecontextoftheViewoftheMVCmodel,orinbothframeworks,thecontextoftheir
scenes.
AsforscenesinSceneKit,let’smoveontomakingaverybasicone.
OurfirstSceneKitscene–theXcode
template
3Dartandanimationisaveryin-depthtopic.Wecouldgoonadnauseamabout
materials,shaders,lighting,sculpting,PVRtextures,andallofthetopicsofwhatmakes
great3Dobjectsforgames,movies,architecture,oranyother3Dobject-based
application.
Someofthedetailsofthesetopicsarebeyondthescopeofthisbook,sofornow,let’s
keepthingssimple.
Let’sworkwiththedefaultSceneKitsceneandobjectsthatXcodegivesusasastart,as
shownintheprecedingimage:
Note
Asofthetimeofwritingthisbook,weusedtheSceneKittemplateforXcode7–Beta.
Basedontheversionyouuse,theremightbesomedifferences.
1. First,openXcode,createanewproject,andselecttheGametemplate.
2. Next,nameyourproject,makesurethattheGameTechnologyfieldsaysSceneKit,
andclickonNext.
3. TheprojectfilesandstructureareaboutthesameaswesawwithSpriteKitbutwitha
coupleofdifferences,particularlytheart.scnassetsfolder.Theonlydifferenceis
thatthereisnowanart.scnassetsfolderinadditiontoAssests.xcassets.Thisis
whereour3Dobjectsareheld.Clickonthatfoldertoseetheship.daeassetthat
Appleprovides.
WiththeSceneKiteditor,wecanviewandeditthefollowing3Dfiletypes:
DAE
OBJ
Alembic
STL
PLY
TheexamplegiventousisaspaceshipofthetypeDAEandwiththeship.daefileasthe
ship’stexturefile(texture.png).Beforewelookintothecodeandhowthesceneworks,
buildandruntheprogramoneitheryourowndeviceortheXcodedevicesimulator.
Fromthesamplescene,weseeourspaceshiprotatinginfrontofablackbackgroundand
wecanchangeitsorientationwhenweswipetheship.Tappingontheshipcausesitto
glowredforamoment.
Let’snowseewhat’sgoingonwiththecodeandthenwe’llgetintothetoolstheeditor
givesustoeditourobjectsandsceneswithoutanycode.
SceneKitprojectflowandstructure
LikeSpriteKit,aSceneKitsceneusesthesamegame-renderingloopaswesawfromthe
previouschapterandthesametypeofentrypointstructuringwementionedinChapter2,
StructuringandPlanningaGameUsingiOS9StoryboardsandSegues.Wehavethe
AppDelegate.swiftfilethatisourentrypointwiththeabilitytocontrolspecialapp
functionalitybasedonupperleveldeviceevents,suchastheappclosing,goingintothe
background,andcomingbackfrombeinginthebackground.Wealsohavethelaunch
screenandMain.storyboardfilesasseenbeforeinSpriteKit.
ThedifferencewiththeMain.storyboardfileisthatithasaSceneKitsceneicon,shown
withthecube,asseenintheprecedingscreenshot.
TheViewControllerclasstheAppDelegatemovestoistheGameViewController.swift
class.Thisiswhereallofourcodeforthedemotakesplace:
overridefuncviewDidLoad(){
super.viewDidLoad()
//createanewscene
letscene=SCNScene(named:"art.scnassets/ship.dae")!
...
WeseethatwebeginwiththeoverwrittenviewDidLoad()function.SceneKitletsus
createanentirescenewithevenaninstanceofour3Dobject/assets,asseenfromthe
unwrappedletscene=SCNScene(named:"art.scnassets/ship.dae")!call.This
simplycreatesthesceneobject.Togettheobjectseenonthescreen,westillneedtoattach
thistotheSCNViewnode,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’s
actuallyrathersimpletofollowandotherthanthehandleTap()function,doespractically
allthat’sneededtocreatethisscene.Anyonewho’screated3DgraphicsinOpenGLeither
foriOSorotherplatformswouldappreciatehowSceneKitgivesusanumberofsimple
upperlevelcontrolsforthesceneandobjects.Herearemoredetailsoftheprovidedcode:
Online(1),anSCNNodenamedcameraNodeiscreated,andweassignthecameraattribute
ofSCNNodetotheSCNCameraNodetype.Then,thecameraisplacedinathree-dimensional
spaceusingtheSCNVector3()functiononthecamera’spositionproperty.Inthiscase,
thecameraisplacedat(x:0,y:0,z:15).Inotherwords,thexandycoordinatesareset
attheoriginwhilethecameraismovedslightlybackwardsinthezaxis.
YoucanfindtheSceneKitcoordinatediagramat
https://developer.apple.com/library/ios/documentation/SceneKit/Reference/SceneKit_Framework
ThecoordinatesysteminSceneKitiswhat’sknownasaRight-HandedCoordinate
System.Onetricktounderstandthe3Dcoordinatesisifwetakeourrighthand,makea
gun-likegestureoutwithourthumbupintheairandpointerfingerstraightaheadofus
whileourmiddlefingertothesideatarightanglefromthepointerfinger,we’dhaveour
x,y,andzcoordinates.Yourmiddlefingerwouldbeonthexaxis(left/right),yourthumb
wouldbeontheyaxis(up/down),andyourpointerfingerwouldbeonthezaxis
(backward/forward).
Inthe(2)blockofcode,weareaddinglightstoourscreen.SceneKit,aswellas
SpriteKit,letsuscreateanumberofdifferentlightingeffects,fromambientocclusion,the
useofnormalmaps,andmore.Here,aninstanceofSCNNodeiscreatedwiththename
lightNode,andtheSCNNodepropertylightisassignedtheSCNLightclasstype.Thefirst
lightcreatedandaddedtothesceneiswhat’sknownasanSCNLightTypeOmnitypelight,
asseenfromtheimplicitlyunwrappedcalllightNode.light!.type=
SCNLightTypeOmni.Thistypeoflightistypicallyusedmorefordebuggingasthenext
lightadded,ambientLightNode,wouldbeoneofthetypesusedtocreatetheatmosphere
toyourgame.Asweseewiththeline,ambientLightNode.light!.color=
UIColor.darkGrayColor(),wecanassignacolortothatlightincode.
MoreinformationonSCNLightscanbefoundat
https://developer.apple.com/library/prerelease/ios/documentation/SceneKit/Reference/SCNLight_
We’llsoonseehowtovisuallyaddlightsandotheraspectsofthedemoviewDidLoad()
functiontoourscene,butit’susuallybeneficialtounderstandtheboilerplatecodebehind
thescenes.
Intheline(3),letship=scene.rootNode.childNodeWithName("ship",
recursively:true)!ishowweaddourshipobjecttothescene’srootnode.Thisisnot
toomuchdifferentthanotherobjectsinthescene.Ittakesthestringshipfromthename
ofourship.daeobjectintheart.scnassetsfolder.Therecursively:trueparameter
inthechildNodeWithNamefunctiontellsthescenethatitshouldaddallchildnodesofthe
objecttothescene.Dependingonhowthe3Dobjectwasmodeledandriggedinits
original3Dmodelprogram,theobjectmighthaveacomplexarrayofchildnodes.Setting
recursivelytotruewilliteratethroughnotjustthechildnodesbuttheirchildnodesas
well.
Thefollowinglongline(partofline(4))isacompactwayoftellingtheshiptorotate
continuallybyx,y,and/orzanglesbasedonitscurrentorientation:
ship.runAction(SCNAction.repeatActionForever(SCNAction.rotateByX(0,y:2,
z:0,duration:1)))
Thiscanbebrokendownintoitsvariousparts,asit’sanSCNActionwithinanSCNAction,
namely,therotateByXfunctionwrappedintoarepeatActionForeverfunctionof
SCNAction.ActionsinbothSceneKit(SCNAction)andSpriteKit(SKAction)cannotonly
beaddedtoobjectsbycodebutalsoinXcode’svisualeditor,asweshallseelaterinour
reviewoftheFoxdemo.
FindmoreonboththeSCNActionandSKActionclasseshere:
ForSCNAction,referto
https://developer.apple.com/library/ios/documentation/SceneKit/Reference/SCNAction_Class/
ForSKAction,referto
https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKAction_Ref/
Inline(5),wecreatetheSCNViewobjectandassignitastheviewofGameViewController
withthelineletscnView=self.viewas!SCNView.Thesceneanditsnodesthatwe
createdwiththeobjectnamedscenebackinline(1)thengetsassignedtothescene
attributeofscnViewviascnView.scene=scene.Thereisaslightbitofambiguityasto
whichsceneisassignedtowhatnode,butthisessentiallyhastodowiththesettingupof
rootNodeitself.
Thenextfewlines(of(6))showsomeofthepropertiesthatwecanusefromtheSCNView
class;thefirstbeingtheabilitytocontrolthecamerawiththeallowsCameraControl
property.Settingthistofalsewouldpreventtheplayerfrombeingabletomovethe
cameraabout.Thiscouldbegreatforin-gamecutscenesorlockingthecameraduringa
partofastagewhereitwouldbenecessary.ThelinescnView.showsStatistics=true
tellsthescenetoshowanyrenderingdatathatwouldbebeneficialtodebugging.For
example,wecouldseetheframespersecond(fps)ourgameisrunningat.
ThisisequivalenttoaSpriteKitscene’scodepartofskView.showsFPSand
skView.showsNodeCount,whereskViewisthenameofanSKViewobject.
Thenextline,scnView.backgroundColor=UIColor.blackColor(),allowsustosetthe
backgroundcolortoblack,justthesamewayaswedidwith
ambientLightNode.light!.color=UIColor.darkGrayColor()usingtheUIColorclass.
SceneKitDebuggingOptions
Tip
AsofiOS9,evenmoredebuggingoptionsbecameavailablethroughtheuseofthe
SCNDebugOptionsstructandthedebugOptionsattributeofSCNView.
Ifweweretowritethefollowing,we’dbeabletoseeourship’sboundingboxes:
scnView.debugOptions=.ShowBoundingBoxes
ThereareotheroptionssuchasShowLightInfluences,ShowPhysicsShapes,and
ShowWireframe.
WWDC15’sFoxDemowiththe.ShowBoundingBoxesandShowPhysicsShapesoptions
enabled
Finally,inline(7),lettapGesture=UITapGestureRecognizer(target:self,
action:"handleTap:")createsaUITapGestureRecognizerobjectnamedtapGesture,
whichwillcallthefunctionhandleTap(gestureRecognize:UIGestureRecognizer)
whenanytapisperformedandscnView.addGestureRecognizer(tapGesture)addsthat
recognizertothescene.
HandlinguserinputinSceneKit
TheUITapGestureRecognizerobjectsaregreatinordertoselectivelyorganizetheinput
wereceivefromtheplayer.ThisgoesforbothSceneKitandSpriteKitscenes.Wecan
haverecognizersfortaps,swipesineachdirection,panning,pinches,andlongpresses;
longpressesaregreatforwhenyou’dneedtopossiblyhandleacharacterchargingtheir
attack.
Here’sthedocumentationoftheUITapGestureRecognizerclassforreference:
https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIGestureRec
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.
Note
Ifbuildingagamewheretheplayerhastotapatthespurofthemomentandmanytimes
foracharacter’smovementordodging,wedidfindthetouchesBegan()functionalitywe
spokeaboutinSpriteKittobeabitfasterthanUITapGestureRecognizer.Thismight
eventuallybecomeamootpointwitheachnewandfasteriOSdevice,butifyourgame’s
controlsareheavilydependentonquicknessoftheplayer,youmightnoticesomelagin
responsetothegesturesviatheUITapGesterRecognizerapproach.Thiscouldeffectthe
goalofyourgame,sotrythetouchesBegan()functiontoseewhatworksbestforyour
game.UsingtouchesBegan()forswipesandothernon-tapgesturescouldberathertricky,
sothere’satrade-offthereonthedevelopmentsidetoo.
Nextinline(2),wetakeacountofhowmanyofthesegestures,tapsinourcase,were
capturedintheviewusingthehitTest()functionofSCNViewandonlycountingifthat
gesturemadecontactwithanyobjectinourscenebypassingthepositionconstant,p,asa
parameter.ThefunctionhitTest()returnsanarrayofeventresults,andthecount
propertythencountshowlargethatarrayis.Wecanthencaptureareferencetothefirst
tapbyreferencingthefirstmemberofthatarray.Weonlyhaveasingleobjectinthis
demoprovidedforus,thespaceship,sowecanjustgetaninstanceofSwift’smostupper
parentobject,AnyObject.OurhitTestobject,hitResults,isanarraycontaining
referencestoeveryobjecttappedinthiscontext.Again,thisisjustourspaceshipobject,
sowecansimplytakethefirstobjectinstancedathitTest[0].Thisiswhattheresult
constantrepresents.
Thelineletmaterial=result.node!.geometry!.firstMaterial!showsushowwe
getareferencetothatobject’smaterialbydrillingdownthenode’schildrenusingthedot
operatorwhilealsoimplicitlyunwrappingeachnodeviatheexclamationpoint(!).This
materialreferenceisneededforwhenthetapneedstomakethespaceshipturnred.
Tip
Thisisactuallyanicebroadexampleofhowwecanselectonlycertainobjectsinour
SceneKitscenetobethefocusofaplayer’sinput.Here,itjustpicksanyobjectusingthe
broadtypeAnyObjectclass,butimagineagamewhereonlyacertaintypeofcharacteror
charactersareselectable;thinkofanisometrictopdownshooterorreal-timestrategy
(RTS)game.Wecouldpossiblycheckwhetherthetappedobjectonlyisamemberofa
certainclasstype(isKindOfClass())orconformstoacertainprotocol
(conformsToProtocol())beforetakinganyactiononthoseselectedgameobjects.Want
theplayerinyourRTSgametoonlytakeactionsonTankobjects?Thencombiningthis
withamenuthattellsthegamewhichobjecttypeisthefocuscouldbewhatgivesyou
thatabilityhereinSceneKit.
Inline(3),thedefaultSceneKittemplatealsohandsusthisusefulbitofcodeshowingthe
useofSCNTransaction.TheSCNTransactionclassfirstbecameavailableiniOS8,and
wecanthinkofSCNTransactionasalaundrylistofchangesandanimationswewantin
thescenetotakeplaceatacertainspecifiedsetoftime.AnSCNTransactionclassbegins
withtheSCNTransaction.begin()callandendsattheSCNTransaction.commit()call.
Scenegraphanimationcallsthatarewithinthatblockgetcalled,bydefault,witha0
seconddelay.Inmanycases,we’dwanttocontrolthedurationoftheseanimations,thus
weusethesetAnimationDuration()functionatthebeginningoftheSCNTransaction
blocktosetthat.ThelineSCNTransaction.setAnimationDuration(0.5)setsthetimeto
completethisblockathalfasecond.Donotethatwithinthisblockisanotherblockof
codestartingwithSCNTransaction.setCompletionBlock{…}.Whatthisdoesisexecute
thecallonlyaftertheSCNTransationblockit’swithincompletes.Inthecaseofthis
templatedemo,atfirstforhalfasecond,theshipishighlightedred,asdoneinthe
material.emission.contents=UIColor.redColor()line.Afterthiscompletes,for
anotherhalfasecond,theshipisbroughtbacktoit’soriginalcolorbysettingitsmaterial
emissionbacktoUIColor.blackColor().Thisisabitconfusingatfirstbuttherearea
slewofanimationsandtransactionswecandoforoursceneswiththismethodinjustone
block.Checkoutthislinktothedocumentation;othertransitions/transactionscanbefor
fadingin/out,camerafieldofview,rotation,translations,lighting,andmore:
https://developer.apple.com/library/prerelease/ios/documentation/SceneKit/Reference/SCNTransa
AsforthedefaultSceneKittemplate,that’sallthecodeusedtomakethescene.It’sa
basicsceneandfarfromagame,butitshouldgiveusabasicunderstandingofwhat
essentiallymakesupthemainstructureandlogicofasceneinSceneKit.Beforewelook
intotheFoxdemoandthusanactualfullgameproject,let’slookatafewotherfeatures
thatwereaddedtoXcodeasofiOS9/Xcode7.
SceneKitfeaturesintroducediniOS9/
Xcode7
Let’sgobacktotransitionsandanimations.AsofiOS9,wecanchangeacharacteror
other3Dobject’sblendmodeveryeasilyinSceneKit.
AdisplayofthevariousblendmodesinSceneKitfromWWDC2015
Blendmodescanbechangedsimplywithoneline,aSCNMaterial.blendMode=.Add,
whereaSCNMaterialisanobjectrepresentingthematerialofSCNNode.Changingblend
modescancreateanumberofeffects.Somegamesuseaplayer’sghosttoshowapastrun
throughtheyaretryingtobeat,orthere’sthefadeeffectbosscharactersmakewhen
defeated.CombinewithSCNTransactiontohavecharactersfadeinandoutofthese
modes.
Audionodesand3Dsound
AsofiOS9,wecanplace3DsoundsintoourSceneKitscenes.TheaddAudioPlayer()
functionoftheSCNNodeclassfunctionletsusappendasoundtothatnode,andwherever
thatnodeisin3Dspace,thesoundwilladhereto3Daudiomixing;thatis,iftheaudio
source’spositionalpropertyissettotrue.Here’showwe’dcreate3Dsoundwithaudio
nodes:
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.
Thismightnotbethebestforacharactersoundeffectthoughasyoumightwantit
stoppedmidway(thatis,theplayerhitstheenemy,cancelingtheirpreviouslystarted
chant,yell,orsomethingtothatdegree).
Ambienceandmusic
Toaddmusicandambience,wecouldfollowexactlythesamemethodasaddingasound
effecttoanode:createanSCNAudioSourceobject;addthattoanSCNAudioSourceobject;
andaddthistoournodewithaddAudioPlayer.Theonlydifferenceisthatwe’dloopthe
musicandsetit’spositionalpropertytofalseasfollows:
source.positional=false
source.loops=true
SpriteKitscenetransitionsinSceneKit
SpriteKithassomegreatscenetransitions.Wecouldmakeitlooklikeadoorisopening
uporapageisturning.Thiscouldaddextracharacterandpolishtoyourgame.Before
iOS9,wecouldn’tdothese2Dtransitionsinour3DSceneKit,butsinceXcode7andiOS
9,wecandosoinSceneKitandhere’show:
aSCNView.presentScene(aScene,withTransition:aSKTransition,
incomingPointOfView:nil,completionHandler:nil)
Again,aSCNViewisjustageneralreferencetosomeSCNViewobjectandwhenwepresent
thescenetothatview,wehavetheoptionofpassinganSKTransitionobjectforthe
withTransitionparameter.TheincomingPointofViewparametercanbeareferencetoa
camera’spointofviewduringthetransition,andthecompletionHandlerparameteristhe
nameofacompletionblockthatiscalledafterthescenetransitions.Forexample,we
couldcallthefunctionsthatstartthecountupofourlaststage’sscoreinascorescenethat
wastransitionedtoafterthestagecompleted.Wemightnotwanttobeginthecountingand
otherfunctionsofthenewsceneuntilweknowthatthescenehasbeen100%transitioned
toor,inthiscase,afterweknowthetotalpointsfromthepriorscene.
CheckoutsomemoreexamplesofSKTransitionontheclassreferencepage,maybe
there’satransitionthatcouldhelpaddtoyourgame’sdesign:
https://developer.apple.com/library/prerelease/ios/documentation/SpriteKit/Reference/SKTransiti
Foxdemo
We’vebeenspendingmuchofourtimeinbothSpriteKitandhereinSceneKitonthe
boilerplatecodethatmakesupourgamelogic.AsXcodecontinuestoupdate,sodoesthe
visualdesignfeaturesforiOSgamedesignthatdon’tinvolveastrongunderstandingof
code.There’salwayssomescriptinginvolved,butoneofthekeyfeaturesingamedesign
is,well,thedesignaspectofit.AttheWWDC15event,theintroductiontoiOS9and
Xcode7wasagreatgamedemothatcannotonlyteachussomeofthevisualdesign
featuresthatXcodecando,butalsogivesusabeautifulstarttoaplatforminggamein
SceneKit.ThatdemoisnamedFoxandgranted,thoughitactuallystarsaredpandaand
notafox,wecouldforgivethatmixupforhowfeature-richandessentialitcanbetolearn
howtodevelopSceneKit-powerediOSgames.
TheFoxdemoimageshowingourplayercharacterandlevelassets
There’smuchmoretothisdemothanwecanshowhere,soit’sencouragedtodownloadit
foryourselfandcheckoutalloftheSceneKitfeaturesitprovides.Wewillfocusonafew
topicsyettobecoveredineitherSceneKitorSpriteKit,suchasparticles,physics,andthe
scenegraph.TheFoxdemoalsomakesuseof3Dgame/artdesignfeatures,suchas
skyboxes,ambientocclusion,cubemaplighting,collisionmeshes,andmore.Itreallyisa
nice-qualitydemotomakebeautifulgamesiniOS.
HereisthedownloadlinkprovidedbyApple:
https://developer.apple.com/library/prerelease/ios/samplecode/Fox/Introduction/Intro.html
Note
Atthetimeofwriting,theFoxdemowaswrittenonlyinObjective-C.Wehavefocusedon
Swiftintheentiretyofthisbook,butdon’tworrytoomuchifsomeaspectsofObjective-C
areforeigntoyou.ThegoalistoseethevisualtoolsXcodeprovides.Inafuturedate,the
FoxdemoisboundtobeavailableinSwift,beitbyApplethemselvesorbythird-party
programmers.
Particlesystems
Someofthebasicassetsinanygame,beitSpriteKitorSceneKitbuilt,arethevarious
particleeffectswe’daddtocharacters,objects,oranentirescene.Particlescanaddtothe
feelofcollectingthatitem,givetheplayerasignalthatsomethingishappeningtothe
player,liketheyaregainingorlosinghealth,orshowthepresenceandpowerofan
incomingbossfight.
CollectableparticleeffectfromtheFoxdemo
Inthepast,theprocessofmakingaparticleeffectwouldbetomanuallycreatesometimes
rathercomplexparticleemittershaderobjectsusingOpenGLcode.Thiscanstillbedone
ifwesochoose(usingeitherApple’sfast,low-levelAPI,Metal,orOpenGL),butover
time,theprocessofvisuallycreatingandeditingparticleeffectshasgotteneasier.Nottoo
longagointheiOSdevelopmenthistory,frameworkssuchasCocos2D/Cocos3Dallowed
ustousethird-partyparticleeffectsbuilderstoimportintoourgames.WithbothSpriteKit
andSceneKit,XcodeasofaboutiOS7/iOS8,amorevisualrepresentationofparticles
wascreatedinXcodethussavingusalargeamountoftimeandeffortincreatingthe
effectswewantandexpecttoseeinourgames.Theimagepreviouslyshowndisplaysthe
XcodeparticlesystemseditorwiththeFoxdemo’scollectablesparkleeffect.
TocreateyourownparticleeffectinSceneKit,followthesesteps:
1. CreateanewfileaswedidinthepastbynavigatingtoFile|New…orsimplythe
keyboardshortcutcommand+N.
2. WethenselecttheResourcesectionunderiOSandselecttheSceneKitParticle
Systemtemplate.(IfworkingwithSpriteKit,selectSpriteKitParticleFile.)
3. BoththeSpriteKitandSceneKitparticleoptionsgiveusalistofbasicparticle
templateswecanstartfrom,suchasReactor,Sparkle,orBokeh.Selectoneofyour
choosingorcheckoutacollectableonehereinthedemo.ForSpriteKit,thiscreates
anSKSfileandtheimagemaskfortheparticles.TheSceneKittemplatecreatesthe
3DparticleeffectviaanSCNPfileandtheimagemask.
Let’stakealookbackattheparticlesystemwecreatedforthecollectableparticleinthe
demo.Ifnotselectedalready,clickontheattributesinspectortoviewvariouscontrolswe
canedittocustomizeourparticleeffects.
Feelfreetotestanumberofthevariablesandfieldswithintheinspector.There’sthebirth
rate,whichcontrolshowoftentheparticlesrestarttheirstartandendanimation,the
image,whichcanmakeuptheshapeandcoloroftheparticles,andthevariousanglesthat
determinetheoveralldirectionoftheeffects.There’salsotheLoopingdropdown,which
keepstheparticlesrepeatingduringthelifeoftheparticlesysteminthescene.
Additionally,theaffectedbygravitytoggleiswhatweusetohavetheparticlesfallbased
onthescene’sgravity.Thecollectionparticlesloopconstantlywithoutgravity,andthe
confettiparticleshappenonceandfalltogravity,aswe’dexpectconfettitobehave.Ifan
objectinourscenehasaphysicsfield,wecanalsohavetheparticlesreacttothat.
Placingparticlesintoourpioscene
WhenwecreateSpriteKitorSceneKitparticles,wecancalltheminoursceneviacodein
eithertheSpriteKitorSceneKit:
SpriteKit
SpriteKitparticlesaren’tintheFoxdemobuttobacktrackabittoourtalkonSpriteKit,if
we’dwantedtoaddparticlestoa2DSpriteKitgame,here’sanexampleofhowwe’d
accomplishthat:
//(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’sbundlewiththe
NSBundle.mainBundle().pathForResource()functioncall,andwepassthestring
oftheparticlefile’sname,inthiscase,Spark,withthefiletype,SKS.
2. Next,wecreatethesparkParticleobjectusingthe
NSKeyedUnarchiver.unarchiveObjectWithFile(path!)callthat,aswesee,takes
thepathwecreatedinpart(1).It’scastedastheparticleobjectforSpriteKit,
SKEmitterNode.NSKeyedUnarchiverisaclassusedtodecodenamedobjectsfrom
keyedarchives,anencodedhierarchyofarchives.Thisclasshassomesupportof
whatisknowntypecoercion.Inshort,itcandecodeobjectsinfiles,beitwhetherin
a32-bitor64-bitarchitecture.Moreonthisspecialfiledecodingclasshere:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classe
3. Wethensetapositionandnameforthisparticleeffectandtargetittothescenewhile
alsoaddingittothescenenode.
Thoughthisexampleisn’tgivenintheFoxdemo,thisisagreatexampleofhowwecan
targetspecificfilesinourproject’snavigationhierarchy.
SceneKit
SceneKitparticlesaremembersoftheSCNParticleSystemclass.Weaddtheseparticlesto
ourscenewiththeaddParticleSystemfunctionoftheSCNNodeclass.TheFoxdemodoes
thisinthecollectFlower()functionwiththefollowingObjective-Cline:
[self.gameView.sceneaddParticleSystem:_collectParticles
withTransform:particlePosition];
Whatthiscodeisdoingiscallingthesceneinthedesignatedviewandaddingthe
particles,whicharedeclaredearlierintheclassas_collectParticlestoourscene.It
thentellsthesceneatwhichpointinspacethiseffectwillappear.Inthiscase,it’sthe
particalPositionvariablethatwhentracedbackistakenfromtheSCNNodeparameter
passedintothecollectFlower()function.
Note
Here’showthiswouldbewritteninSwift:
scene.particleEmitNode.addParticleSystem(_collectable!)
Swift’saddParticleSystemAPIunfortunatelydoesn’thavethewithTransformparameter
asinObjective-C,sowe’dhavetoaddtheparticlesystemtothenodeitwillbeemitting
from,whichisdenotedbytheparticleEmitNodevariable.Thismostlikelywillchangein
futureAPIchangesofSwift2.xandlater.
IntroducingSceneKitandSpriteKit
physics
WhenwelookatthecollectFlower()functionfromourparticleexample,weseethat
there’sanSCNNodeparameterpassed.ThisnodecomesfromthefunctionphysicsWorld.
InbothSpriteKitandSceneKit,wecancreateanoverallsetofphysicsrulesandhandle
variousphysics-relatedinteractions,mostnotably,contactsbetweentwoormorenodes.
Oneofthemostbasicaspectsofanygameistodosomethingwhengameobjectshiteach
other.Thiscouldbewhentheplayertouchesacollectable,whenenemiescontactthe
playerortheplayerhitstheenemywithanattack.IniOSdevelopmentandingame
engines,wecalltheseboundariesbetween2Dspritesor3Dobjectsasboundingboxes.
WementionedthesephysicsobjectsbrieflyinourtalkofiOS9andlaterdebugOptions
property.BoundingboxesforSceneKitobjectsarecreatedautomaticallybasedonthe
simplifiedversionofanobject’sgeometry,butwecanedittheseshapeswiththe
SCNBoundingVolumeclass.
Moredocumentationofthisclasscanbefoundat
https://developer.apple.com/library/prerelease/ios/documentation/SceneKit/Reference/SCNBound
GamephysicsiniOSandgamedevelopmentingeneralaremuchlargertopicsthanwe
candiscussinthischapter.Sofornow,let’sjustseehowtheFoxdemoandiOSgamesin
generalhandlethesimpleconceptoftwonodescontactingtheirboundingboxes.
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.The
functiontakesintwoparameters,worldofthetypeSCNPhysicsWorldthatrepresentsthe
entirephysicsenvironmentofasceneandtheobjectrepresentingthephysicscontactof
thetypeSCNPhysicsContact.Thefunctionherechecksthebitmaskofthenodesinthe
contact.Ifthefirstorsecondnodeofthecontact(nodeAornodeB)areintheflower’s
specificcategory,thenthecollectFlower()functioniscalledandthatcollectable’snode
ispassedasaparameter.
Bitmaskingiswhenwedesignateasetofbitsforanothersetofbitsthatcanbecombined
togetherusingbitwisemath.Thinkofitasusing1sand0stonotonlycategorizearange
ofonesandzerosbutalsoallowustohandlesituationswheremanycategorieshappenin
thesamecontext.
Forexample,wehavedifferentcategoriesofobjects/eventsinourgameandwefitthemin
theirownslotsinabyte(8bits).IntheFoxdemo,thegamecollisionsareabitshiftvalue
of2,thustheyrepresent00000100inbinary.Thecategorydesignationofcollectablesin
theFoxdemoabitshiftof3or00001000,theenemiesare4,00010000.
Inthedemo,weseethefollowingcodeforAAPLBitmaskSuperCollectable:
//Collisionbitmasks
typedefNS_OPTIONS(NSUInteger,AAPLBitmask){
AAPLBitmaskCollision=1UL<<2,
AAPLBitmaskCollectable=1UL<<3,
AAPLBitmaskEnemy=1UL<<4,
AAPLBitmaskSuperCollectable=1UL<<5,
AAPLBitmaskWater=1UL<<6
};
WhenthecategorybitmaskineithernodeAornodeBofthecollisionmatchtheflower
collectable(iftheslotisonpersay,orequalto1,thenweknowthecollectablewas
involvedinthecollision).
Swiftversion1didn’treallyhaveasimilarwaytomimicbitmaskingasdoneinObjectiveCwithNSOptions,butasofSwift2.0,wecanperformbitmaskinglikethedemointhe
followingway:
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’snotaselegantas
seeninObjective-CandinpastCimplementation,butifwewishtousebitmaskingin
boilerplatecodeinSwift,thisshouldallowyoutodoso.
OnelastnoteaboutthephysicsWorld()function,inorderforthefunctiontobecalled
duringthecollisionoftwophysicsbodies,weneedtosetthephysicsworlddelegate.In
mostcases,thatdelegatewouldbethecurrentgamescene.
scene.physicsWorld.contactDelegate=self
Xcodewillmostlikelytellyouthataphysicsworlddelegatewasn’tsetandifyouhaven’t,
thisisthecodethatisusuallyplacedintheviewDidLoad()functionofViewController.
Visuallycomposedgamescenescgs
GettingbacktothevisualaspectsoftheFoxdemo,let’slookatthegamesceneobjects
createdintheprojectandhowwecanviewthenodesinwhat’sknownasthescene
graph.
WeseethatgameobjectsandparticleeffectsintheFoxdemocanbevisuallymanipulated
inXcodeandtogetherinoneview.Theprecedingimageshowstheflowercollectableand
itscomponentsthatconsistofthe3Dmesh,lighting,boundingboxes,andtheparticle
effects.InSceneKit,wedothiswithaSceneKitscenefile(SCN).
Toviewthescene’sscenegraph,clickonthesidewindowiconfoundtowardthebottomleftoftheXcodewindowunderthevisualeditorwindowofthescene,asseeninthe
followingscreenshot:
Thisisascreenshotofthescenegraph.Thosefamiliarwiththegameengines,suchas
UnityandUnrealEngine,willbequitefamiliarwiththistypeofcomponent/gamescene
view.Thescenegraphshowsthedropdownhierarchyofalltheobjectsinthescene
includingtheirowninternalcomponents.Theflowerpower-upconsistsofa3Dmesh
modelnamedflowerthathastwochildparticleeffectsaswellasaphysicsbody.Allthree
aredenotedbythethreesymbolsseenontheright-handsideofthegraph’sobjects.
Wecanmovethemodelaroundinthescene,usingX,Y,andZmarkersseeninthe
precedingimage.Wecanalsozoomin,zoomout,rotatethescene,aswellasaddmore
objectstothescene.
Toaddmoreobjectstothescene,followthese:
1. Gotothemedialibraryfoundinthelibrarywindowsatthebottom-rightofthe
screen(seeninthepriorimage).
2. Nowsearchforgrassandsimplydraganddropitintothescene.Nowthepremade
grassobjectisinthissceneasareference.
3. Thisisactuallyhowthelevel.scnfilewascomposed.
4. There’salsotheoptiontoaddprimitiveobjectstothesceneandbuildthemupfrom
there,whichisagainverysimilartothedesign-centricgameengines.Simplyselect
fromtheobjectlibrarytabrightnexttothemedialibraryiconandsearchgeometry.
Thereareprimitiveobjects,suchasspheres,planes,andboxes.
5. Theprimitiveobjectslackthelighting,materialsandotherdetailsthatwecanseein
thegrassandotherpremadeobjectsintheprojects.Usetheevenmoredetailed
inspectorwindowsfortheseobjectstoseeandeditvariousdetails,suchasthe
physicsbodies,materials,bakingthelighting,andobjectnameidentificationforany
scripting/coding.
6. There’salsoactionsthatcanbeaddedtotheseobjects.Clickonthesecondaryeditor
icon(theupsidedowntriangleinasquareatthebuttonrightoftheflowscene’s
view).ThiswillopenthesecondaryeditorthatshowsaRotateByEuleractionifthe
flowerassetisselectedinthescenegraph.
7. Whatthisactiondoesisrotatethefloweronceeverysecond.Toseethisinaction,
clickonthePlaybuttonseenjustabovethesecondaryeditorwindowtimeline.We
canseehowthisobjectwillrotatefromthisaction.
8. Theactioncanbeshortenedorextendedbyexpandingorcondensingitinthe
secondaryeditortimeline.MoredetailsabouttheactioncanbeeditedintheInspector
window,andifwe’dlike,wecanusethelibrarytoaddmoreactionstothisobjector
removetheoneprovidedtohaveitactinadifferentway.
Testoutafewactions,times,andpropertiesyourself.Wecanseehow,withoutanycode,
wecansetupascenevisuallyanddynamicallycontrolactionsofeachobjectinthat
scene.ManyofthesevisualfeaturesandactionsworkforbothSceneKitandSpriteKit
scenes.
Lookatthelevel.scnfiletoseeascenewithafullycomposedlevelcameraobject(as
seeninthepreviousscreenshot).Doyouwanttomakeasimilarlevelwithmaybemore
obstaclesandadifferentskybox?Copythelevelandchangethoseassetsandnameit
level2.Thiscansaveamonumentalamountoftimeinthedesignofgamesandlevels.
FromXcode7onwards,wehavetoolsdirectlyintheIDEthatoriginallywereonlyforthe
multiplatformgameengines.Itreallyputsthedesignbackintogamedesign.
Muchofthemanualcodewe’vegoneovercouldgetdaunting,especiallyforthoseofus
whomaywanttogetintogamedesignbutarestillrelativelynewtocoding.
//Objective-C
SCNScene*scene=[SCNScenesceneNamed:@"game.scnassets/level.scn"];
//Swift
letscene=SCNScene(named:"game.scnassets/level.scn")!
Thisisallweneedtoreferenceascenefromthevisuallydesignedtools.Addittothe
view’srootnodelikewespokeaboutintheSceneKitbasictemplateandit’sreadytogo.
Usecodetoaddspawningenemies,theplayer,andthe2DSpriteKitoverlay(whichcan
itselfhaveactionsandvisualdesignsinitsSKSfile),andit’safull-fledgedgame.
FormoreinformationontheSceneKitframeworkaswellasthelatestupdatesand
additionstoitslibrary,seethefulldocumentationlinkasfollows:
https://developer.apple.com/library/ios/documentation/SceneKit/Reference/SceneKit_Framework
Summary
Atthestartofthischapter,wefirstspokebrieflyaboutthehistoryof3Dgamedesignin
iOSandhowSceneKitcametobefromthenecessitytohaveafirst-party,dynamically
robustframeworkaimedatthecomplexitiesof3Dgamedevelopment.Wethenwentover
thebasicstructureofSceneKitandhowitandSpriteKitfromthepreviouschapterwork
offtheconceptofnodes,startingfromtheviewandmovingontothescenenodeand
childnodesinthatscene.Next,wewentoverhowSpriteKitandSceneKitcanbeused
togetherinthesamesceneaswethenmovedontodissectingthedefaultSceneKit
templategiventousinXcode,anditsvariousassets.Inadditiontoareviewoftemplate
project’scode,wealsoreviewedsomeofthefeatures,code,andassets,suchastheaudio
nodes,lendmodes,anddebugoptionsthatbecameavailableasofiOS9/Xcode7.
Finally,fortheremainderofthechapter,wespokemuchabouttheFoxdemoshown
duringtheWWDC15conventionandthevariousvisualgamedesignfeaturesthatbecame
availablesincetheannouncementofXcode7.
Forournextchapter,wewillgointothefeaturesoftheGameplayKitframework,which
weintroducedbrieflywhenwewentoverthebenefitsofusingcomposite-based
structuringwhenbuildingourgames.WithGameplayKit,wecanduplicateandreuse
premadegameactionsandrulesaswedidhereinthischapterwiththevisualcomponents
ofourgames.
Chapter5.GameplayKit
Formanyyears,videogamedevelopmenthasreliedonthetenetsofobject-oriented
design(OOD).OfthecorefeaturesinOOD,theconceptsofinheritanceand
polymorphismhavebeenthemostusefulinthisbranchofsoftwareengineering.Itmakes
sensetothinkofentitiesinourgamesashomogenousgroupsofobjects;objectsthatwe
thenwriterulesforinhowtheyinteractwitheachother.Forexample,thanksto
inheritance,allobjectsinourgamecanbegiventheclassnameofGameObject;theyhave
functionswe’llusethroughoutthegameandthenwecanbranchthemoffintochild
classes,suchasPlayerorEnemy.Wecanthencontinuethatthoughtprocessaswecome
upwithmorespecifictypesofentities,betheyobjectssuchasPlayer,differentenemies,
non-playercharacters(NPCs),orwhatevermakessenseforthegamewearemaking.
Callingafunctiononthoseobjects,suchasShoot()orHealth(),couldbeuniquefor
eachchildoftheparentclassandthuswemakeuseofpolymorphisminOOD.
However,asmentionedinthepreviouschapter,althoughinheritance-basedstructuringis
greatformostsoftwareapplications(includingsimplegames),theuniqueneedsand
pairingsofvideogamerulesandentitiescauseinheritance-basedstructuringtobreakone
oftherulesofOOP.Thatruleisthereusabilityofourcode.Thesolutiontothatproblemis
toseparatethegameobjectsandthegame’srulesintowhat’sknownascomponent-based
structuring.Buildinggameswiththismentalitycanallowustobuilduniqueobjects,
actions,andruleswiththeabilitytonotonlyshiftthemaroundthroughoutoursingle
gameproject,butalsotousetheminotherprojects,cuttingtheoverlycustomized
structuringinwhichbuildingagameviainheritance-basedstructuringcancause.
Apple’ssolutiontothisissueistheGameplayKitframework.GameplayKitisa
completelyindependentframeworkthatcanbeusedwithbothSpriteKitorSceneKit
games,aswellasgameswritteninlow-levelAPIs,suchasOpenGLandMetal.First
announcedforiOS9andXcode7atWWDC15,GameplayKittakesthecommon
methodologiesandconceptsusedingamedevelopmentforyearsandallowsustoworkon
thoseaspectsindependentlyofwhatisbeingdrawnonthescreen.Thisframeworkdoesn’t
handlewhat’sdrawnonthescreenandis,thus,madespecificallyfortheModelportionof
MVC.
ThereareseveralgamedevelopmentconceptshandledbyGameplayKit,whichweshall
reviewinthischapter.Theseconceptsareentitiesandcomponents,statemachines,
agents,goals,behaviors,pathfinding,MinMaxAI,randomsources,andrulesystems.
Entitiesandcomponents
Wecanthinkofentitiesastheobjectsinourgame.Theycanbetheplayer,anenemy
character,anNPC,leveldecorationsandbackgrounds,oreventheUIusedtoinformthe
playeroftheirlives,power,andotherstats.Theentityisthoughtofasacontainerof
components.Componentsarebehaviorsthatdictatetheappearanceandactionsofan
entity.Onemightask,“howisthisanydifferentfromobjectsandfunctions?”Theshort
answeristhatobjectsandfunctionsininheritance-baseddesigndescribemoreofwhatour
gameobjectsare,whileworkingwithcomponent-basedstructuringfocusesmoreonwhat
theydo.AswedealwiththeclassesandfunctionalityoftheGameplayKitframework,we
willbeabletogetabetterhandleonthis.Inthisframework,we’llseethatentitiesand
componentsarehandledwiththeGKEntityandGKComponentclasses,respectively.
Note
Ifyouarestillabitconfusedaboutcomponent-basedstructuring,checkbackinour
previouschapterwherewewentintothisinabitmoredetail.Youcanalsovisitthe
developerpageaboutthisdesignmethodologyhere:
https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayK
UsingGKEntityandGKComponentobjectsinour
games
AnyonefamiliarwithJavaorC#willunderstandtheconceptofanabstractclass.The
GKComponentclassisessentiallyanabstractclass.QuotingfromthespeakersatWWDC:
thinkofcomponentsas“littleblackboxesoffunctionality.”ObjectsoftheclassGKEntity
arelikeourgenericGameObjectclassmentionedbefore.However,unliketheobjects
we’vedealtwithbefore,wetypicallydon’taddtoomuchinthewayofcustom
functionalitytothem(otherwise,we’dbeleaningtowardsinheritance-basedstructuring).
WefirstcreateagameobjectandsubclassitasamemberoftheGKEntitytype.Forthis
example,let’sjustcallourobjectclassGameEntity.Also,don’tforgettoimportthe
GameplayKitAPI:
importGameplayKit
classGameEntity:GKEntity
Again,ourgoalwithanobjectofthetypeGKEntityistouseitasacontainerfor
GKComponentobjects.ObjectsoftheGKEntityclassinheritthefollowingfunctions:
components:ThisisapropertythatreturnsanarrayoftheGKComponentsinour
GKEntityobject
addComponent(_:):ThisisafunctionthatweusetoaddGKComponentstoour
GKEntity
removeComponentForClass(_:):ThisremovesacomponentforaclassofGKEntity
objects
updateWithDeltaTime(_:):Thisupdateswiththerender/gameloopforeach
componentintheentity;thisiswhat’sknownasper-entityupdating
ThelastfunctionintheGKEntityclass,updateWithDeltaTime(_:),isoneofthetwo
mechanismsusedbyGameplayKitwhendispatchingupdatestoourgameobject’s
components.Theupdatemechanismsareasfollows:
Per-entity:Thisisgoodforupdatingsmallergamestructureswithoutcausinglag.
TheupdateWithDeltaTime(_:)functionofGKEntitycallsalloftheentityobjects’
updateWithDeltaTime(_:)functionsandthendispatchesthattoallofthe
component’supdateWithDeltaTime(_:)functions.
Per-component:Thisismadeforlargerprojectsandmorecomplexgamelogic.
Whenupdatingviatheper-componentmechanism,weusetheclasstype
GKComponentSystemtocategorizegroupsofcomponentsandthencallits
updateWithDeltaTime(_:)functiontofireoffupdatesspecifictotheclassof
componentinstancesitmanages.GKComponentSystemdoesn’tmakenoteofyour
game’sentity/componenthierarchy,sotheycanbeusedtoefficientlyupdatemore
complexgames.
Forexample,ifwehaveaspecificwaywewanttoupdateplayerandenemyattacks,then
wecreateanobjectoftheGKComponentSystemclass,initiateitwiththe
initWithComponentClass(_:)function,andpassthatclassofcomponents(inthiscase,
Attackcomponents)tothatsystem.It’sinthatGKComponentSystemobject’s
updateWithDeltaTime(_:)functionthatwespecifytheuniqueupdatelogicforthatgroup
ofcomponents,independentlyoftheentityupdates.Thiscancomeinhandywhendealing
withenemy/NPCAIinmorecomplexgames.
Here’savisuallookattheseclasses:
Don’tworryifthisisstillsomewhatconfusing.Thoseofyouwhomaybemorefamiliar
withthegameengineUnitywillhaveseenhowcomponents,suchasrigidbodies,
materials,andscripts,canbeaddedtoobjectsplacedinagamescene.Theconcepthere
withiOScomponentsandentitiesisnotthatmuchdifferent.EachcomponentinUnityand
otherenginescanbeitsownindependentlyworkingfunctionality.
Let’stakealookatthecodesnippetprovidedduringtheWWDC15conference,inboth
Objective-CandSwift,showinghowwe’dcreateentities,components,andcomponent
systemsinourprojects:
//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’s
archercharacter.NextitaddspredefinedGKComponentobjectsviatheaddComponent(_:)
function.WealsocreateaGKComponentSystemobjectnamedmoveComponentSystemthat
willbeusedtoupdateonlymovementtypecomponents.Thearcher’sownmoveComponent
classisaddedtothissystemwithmoveComponentSystem.addComponent(_:).Makeanote
ofhowtheparameterspassedthroughthisobjectinadditiontoitsinitializationareclass
typesofthecomponenttypesdenotedbythe.classor.selfproperties,dependingon
whichlanguagewearewritingourcodein.
Note
Asofthispublication,thecomponentForClass()functionmightnotbefullyfunctional
fortheSwiftprogramminglanguage.SoiftheSwiftimplementationisn’tworkingas
expectedforthisandotherGameplayKitobjectinitializations,theObjective-Cversionof
thiscodewillneedtobeusedandlinkedtoyourprojectviaanObjective-C–Swift
bridgingfile.ThiswillmorethanlikelybeironedoutinfutureupdatestoSwiftasApple
continuestomoveawayfromObjective-Casthemainlanguageoftheplatform.Formore
informationonhowtomakethisbridgingfile,checkoutthislink:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/Mix
AppleprovidesuswithaprojectnamedMazethatusestheseclassesaswellassomeother
conceptswe’llbegoingovershortly.
Here’salinktotheprojectthatcouldhelptogiveyouanevenbetterideaofentitiesand
components:
https://developer.apple.com/sample-code/wwdc/2015/downloads/Maze.zip
BeforewegoovermorespecificcodeuserelatedtoGKEntityandGKComponentobjects,
we’lllookintoagamedevelopmentconceptthatisbestcoupledwiththeseobjects,which
istheconceptofstatemachines.
Statemachines
Avideogame,morethananyothertypeofapplication,basesmuchofitslogiconwhether
thegameorentitiesinthatgamearecurrentlyinoneofanumberofdifferentstates.
Thiscouldbecheckingwhetherthegameisintheintroscene,runninginthemain
gameplaymode,theplayerhasdied,theplayerisidle,abossenemyhasappeared,the
gameisover,thestageisover,thebossislowonhealth,andmuchmore.
AnexampleofstatemachinesforeitherAIorcharacteranimations
Inthepast,ithasalwaysbeencommonpracticeforgamedeveloperstowritetheirown
customstatemachinelogicfromscratchandthenusetheupdate/rendercycletocheckon
thesevariousstates.Typicallythiswouldbedoneinacustomclassorsimplyinacustommadeenumobjectthatwillshiftthroughvariousstates,suchas.GameOver,.MainGame,
.LowHealth,andsoon.Thesestatescouldalsodescribethestatusofanindividualentity
inourgameanddictatewhichanimationcycletorun.Forexample,theplayercouldbe
chargingtheirattackandwe’dwanttousethatstateoftheplayertoanimatethecharging
animation.Objectsinthegamescenemightcheckbackonsuchstatesviaswitch
statementstomakesurethattheyarenotdoinganyactionthatwouldn’tmakesensebased
onthecontextofthestate.Itwasn’ttoolongbeforemultiplatformgameenginesmadethis
apartoftheworkflow,particularlyintheanimationhandlers.Theseobjectsthatletus
informthegameandentitiesinthegameofthevariousstatesareknownasstate
machines.GameplayKitallowsustoworkwiththisconceptinconjunctionwithits
component/entityfunctionality.TheframeworkprovidestheabstractclassGKStateforus
tosubclassfromforourgame’sstates,andtheclassGKStateMachinetoutilizeforplacing
thesestateobjectsintoadesignatedstatemachine.AnobjectofthetypeGKStateMachine
canonlybeinonestateatatime,soitgivesusabetterwaytouseandreusethesestates,
asopposedtotheoldboilerplate/switchstatementmethodology.
ThepreviousdiagramisfromWWDC15andusesanexampleofwhataPacMan-like
ghostcharacter’s,oranyothergamecharacter’s,animationandAIstatemachineswould
looklike.Alsonotethatnotallpathscouldleadtoeachother.Forexample,theghostcan
switchbackandforthbetweenchasingandfleeing,butcanneitherbedefeatedwhile
chasingnorcoulditrespawnunlessitwaspreviouslyinthedefeatedstate.Theseare
knownasstatetransitionsoredgesinastatemachine.
Bydefault,alledgesarevalidandweoverridetheisValidNextState(_:)functioninour
GKStateobjects/componentstotellthestatemachineifweareallowedtomovebetween
certainstates.
Here’showthisisdoneintheDemoBotssampleprogram’s
TaskBotAgentControlledStateclass.DemoBotsistheiOS9SpriteKitdemomentioned
inChapter3,SpriteKitand2DGameDesign:
overridefuncisValidNextState(stateClass:AnyClass)->Bool{
switchstateClass{
caseisFlyingBotPreAttackState.Type,is
GroundBotRotateToAttackState.Type,isTaskBotZappedState.Type:
returntrue
default:
returnfalse
}
}
ThistellsthestatemachinethattheTaskBotAgentControlledStatestatecantransitionto
FlyingBotPreAttackState,GroundBotRotateToAttackState,orTaskBotZappedState.
ThisobjectisanotheroftheGameplayKitcomponenttypeknownasanAgent(whichwe
willgoovernext),butfornownotehowwevalidatewhichtransitionscanhappeninthe
isValidNextState()function.
HereweseeavisualrepresentationoftheGKStateandGKStateMachineclasses.Asstated
before,isValidNextState()tellsuswhichstatetransitionsarevalid.The
didEnterWithPreviousState()functioniswherewetellourcomponentswhattodo
whenthestateisentered,andthewillExitWithNextState()functioniswherewetellthe
component(s)whattodowhenthestateisexitingtothenextstate.The
updateWithDeltaTime()function,aswithpreviouslymentionedGameplayKitobjects,is
whereweputourrender/gameloopcycleupdates.Optionally,wecanalsoaddmore
functionalitytotheseclassesthroughinheritance.Forexample,wecancreatea
previousStatepropertytocollectmoreinformationaboutthepriorstate.Wecanthen
potentiallyusethatinformationforourownhelperfunctions,suchasexitState()or
execute().
Here’sacodesnippetshowinghowtocreatestatemachinesandhowtoaddGKState
objectstothem:
/*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,receivesa
parameterofanarrayofGKStateobjects,asshownin:letstateMachine=
GKStateMachine(states:[chase,flee,defeated,respawn]).Then,inthisexample,we
startthatstatemachineatthestatechase.This,ofcourse,willbedifferentbasedonthe
logicofyourowngame’scomponents.GKStateMachineobjectscanalsoreturnthe
currentState()function;thus,wecanguidevariousentitiesandcomponentsinour
gamebasedonthecurrentpulseofthegame’sobjects.
FindoutmoreonGKStateandGKStateMachineinthefollowingfulldocumentation:
https://developer.apple.com/library/prerelease/ios/documentation/GameplayKit/Reference/G
https://developer.apple.com/library/prerelease/ios/documentation/GameplayKit/Reference/G
Nextwegooveragents,goals,andbehaviors.
Agents,goals,andbehaviors
Whenwemakeentitiesinourgames,particularlythosethatarenottheplayer,wewant
themtoperformvariousactions.Theseactionsaredictatedbyartificialintelligence(AI)
thatwegivethem,andarebasedonvariousstatesofthegame,theplayer,the
environment,ortheplayerthemselves.Wecanhaveagroupofenemiesfollowacertain
path,tracktheplayer,orautomaticallymovesmoothlyaroundobstaclesusingourgame’s
physicalworld.Theframeworkallowsustomakeourgameentitiesbewhat’sknownas
agents.Agentsareentitiesthatcanhavegoalsandbehaviorsattachedtothem.
AgentsinGameplayKit,whichutilizetheGKAgentclass,canhaveGKComponentobjects
thatautomaticallysetvariousbehaviorsandarebasedontheweightoftheirgoals.The
weightofagoalisusuallyafloatfrom0to1.Thehigherthegoal’sweightvalueis
comparedwithothergoals,thegreaterthechancethattheagentwillperformthose
behaviors.Forexample,ifanenemycharacterislowonhealth,we’dprobablywanttheir
Healgoaltohaveahighergoalweight.Theenemywillbehaveinafashionthatshowsthe
urgencyofthatcurrentlowhealthsituationbyhealingmoreoftenandthusgivingthe
playeramorechallengingandintelligentopponent.Inotherwords,agents,goals,and
behaviorsareastackableandmalleableAIsystem.
Here’sanoverviewofthisfunctionalityinGameplayKit:
Abehavior,viatheGKBehaviorclass,ismadeofanarrayofGKGoalobjectsthatareeach
givenacertainweight.Forexample,wecouldhaveaGKBehaviorclassforanNPCina
racinggamenamedRacingBehavior.Thatbehaviorwouldbeacombinationoftwogoals,
suchasFollowPathandAvoidAgents.Togetherthosegoalswouldmakeacharacterinour
gamethatwillautomaticallymoveawayfromotherNPCswhilestayingonthecurrent
trackforthestagewearein.
Here’savisualrepresentationoftheseclasses:
AGKAgentobject,aswecanseeintheprecedingimage,hasanumberofphysics-based
properties,suchasmass,radius,maxSpeed,andmore.LikeotherGameplayKitobjects,it
utilizestheupdateWithDeltaTime()functiontosyncwiththerender/gameloopupdates
ofeitherGKComponentSystemorGKEntity.Areyoustartingtoseeapatternherewith
theseobjects?Inaway,wecanalsothinkofaGKAgentobjectbeingsimilartoaSpriteKit
oraSceneKitnodesincetheyworkonourgame’sphysics.However,whetherwemade
ourgamewithSpriteKit,SceneKit,orourowncustomrendercomponents,suchasin
OpenGLorMetal,weneedtolinkuptheseclassestowhat’sdisplayedonthescreenwith
thespecialGKAgentDelegateclass.Here’sadiagramofthatclassanditsfunctions:
TheagentWillUpdate()functioniswhatweusetotelltheagentwhattodojustbefore
thegame’supdate()function,andtheagentDidUpdate()functioniswhatweusetotell
theagentwhattodoonscreenaftertheupdate()function.Thiscanbe,inthecaseofa
FollowGKGoalobject,havingareferencetotheplayer’spositiononthescreenbeforethe
updatetakesplace.Here’stheexampleofthisfromWWDC15,butwritteninSwiftas
opposedtotheObjective-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’sa
codesnippetfoundintheDemoBotproject’sTaskBotBehavior.swiftclass,whichisa
childofGKBehavior:
//(1)
letseparationGoal=GKGoal(toSeparateFromAgents:agentsToFlockWith,
maxDistance:
GameplayConfiguration.Flocking.separationRadius,maxAngle:
GameplayConfiguration.Flocking.separationAngle)
//(2)
behavior.setWeight(GameplayConfiguration.Flocking.separationWeight,
forGoal:separationGoal)
Inline(1),thetoSeparateFromAgentsparameterofGKGoalletsuspassareferencefor
theGKAgentobjectswewishtokeepacertaindistancefrom.
Inline(2),thebehavior.setWeight()functionpassesthepredeterminedfloat
GameplayConfiguration.Flocking.separationWeightastheweightforthisverygoal.
Thehighertheweight,themorepriorityisputonthatgoal.
You’llnoticefromthefulldocumentationofGKGoallinkedtolaterthatmuchofthe
GKGoalclassdealswiththeattractionorrepulsionagentshavetoeachother.Combining
differentcharacteristicsofthisbasicfunctionalityletsuscreateuniquegoalsthatGKAgent
parametersget,asshownhere:
https://developer.apple.com/library/prerelease/ios/documentation/GameplayKit/Reference/GKGo
Tobacktrackabit,hereisamorebasicwaywecancreatetheseobjects,asshownatthe
conferencebothinObjective-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
Weseeintheprecedingcodethatwhenwecreategoalsweassignagentstothemthatwe
areeitherseekingoravoiding.Goalsonagentscanhaveatargetspeed,asseenwiththe
toReachTargetSpeed:parameter,andthesecanallbebundledupintothecurrent
behaviorwithsetweightsgiventothem.
Here’smoredocumentationonGKGoal,GKAgent,GKAgentDelegate,andGKBehavior:
https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayK
Oneotherthingtonoteisthattheobstaclesarrayreferencepassedhereispartofthe
GKObstacleclass.Thisclassreferencesobjectsonthescenethatwetellagentstousually
avoidwhenmovingacrossthescreen,andarepartofournexttopic,Pathfinding.
Pathfinding
Navigationisanintegralpartofmostgames.Wecouldhaveanoverworldsceneinour
gameshowingthevariouslevelstraversedoryettobevisited,withbranchingpathwaysto
eachpoint,orwecouldhavea3Dactionplatformerwithaspellthatpointsoutalogical
pathtoournextquestorbattlelocation.Wecanalsoseepathfindingintop-down
isometricgames.Forinstance,theplayercouldbefightingoffahoardofenemiesall
lockedontheplayer’slocationonthescreen.GoodpathfindingAIwouldnotonlytellthe
enemiestomovetowardtheirgoal,buttodynamicallyavoidanyimpassableobjectsin
theirwayanddetourtoabetterrouteautomatically.Inourtalkonagents,goals,and
behaviors,wesomewhatcoveredthat.Behaviors,whichGKAgentobjectsadhereto,sync
withvariousgamephysicsandthuscreatesmoothAImovementstochangewithother
agents/objectsinthescene.However,itwouldbegreattoalsobeabletoinformthese
componentswheretheycanandcan’ttraverseinascene,andthat’swherepathfinding
comesin.
TheprecedingdiagramshowswhatPathfindingisandisanin-gamevisualgiventousby
AppleduringtheWWDC15conference.Itcanbebrokendownasfollows:
Pathfindinginvolvesnodeswithtransversalpathstoandfromthosenodesinwhat’s
knownasanavigationgraph.
Thesenodescanbesingledirectionalorbidirectionaland,mostimportantly,there
canbeapathcalculatedwiththisgraphthatrepresentsthebestpathaGKAgentcan
take.
ThesquaresshownintheearlierscenerepresentGKObstacleobjectsthatareplaced
inthescene(beitbycodeorvisuallyintheXcodeeditor’stools).
Here’sthefulldocumentationfortheGKObstacleclass:
https://developer.apple.com/library/prerelease/ios/documentation/GameplayKit/Reference/GKOb
LikeotherGameplayKitfeatures,weusevariousabstractclassestochildfromforsetting
upthenavigationgraphandoverallPathfindingfunctionality;thoseclassesareGKGraph,
GKGridGraph,GKGridGraphNode,andGKObstacleGraph.
It’snottooforebodingwhenweseetheprecedingdiagramofclassesandgothroughthem
onebyone.Themain,andmostcommon,classusedidtheGKGraphclass.Thisiswhere
wecanattachtoitoneoftwodifferentgraphspecificationtypes:GKGridGraphor
GKObstacleGraph.GKGraphletsusaddandremovenodes,connectthem,andfindthe
optimalpathbetweennodes.Ofthetwospecificationtypes,GKGridGraphhasasimpler
functionalitythatismeantforeasy,2D-basednavigationgraphcreation,whereas
GKObstacleGraphletsussetupanavigationgraphusingGKObstacleobjects.Nodesare
automaticallycreatedaroundthoseobstaclesbasedontheirshape,andtheseclassesdo
muchofthefootworkneededtocalculatethepathsouragentsneedtotakefromthestart
tothefinishoftheirsetpath(s).Ifwewanttoaddevenmorefunctionalitytoournodes,
sayifwewantcustomizedmovementbasedonterraintypeinadditiontoshape,thenwe
couldusethenodesofGridGraphNode.
ThecostToNode()function,forexample,canbeusedtoindicatethatthoughthispath
wouldbetheoptimalpathonaflat,evenandsimilartypeplane,itwouldcostmoreto
traverse.Forexample,ifthere’squicksandinourgame,theplayercouldtraverseit,soit
wouldn’tmakesensetomakeanimpassableGKObstacleobjectoverthequicksand.
Insteadwewouldsaythatthepathacrossthatterrainbetweenthetwonodescostsmore.
Thiswillmakeourgame’snavigationsmarterandwillhandlesuchcustomparameters.
Note
ThecostToNode()functionisactuallyanexampleofbestpractice.Wecanchoosetonot
useit,but,ifwearenotcareful,ourgame’spathfindingAIcouldenduprather
unintuitive.Thiswouldnotonlymakeapoorexperiencefortheplayer,butendupadding
moretimefromdebuggingfaultyAIactionslateron.
Let’slookatsomecodesamplestogetabetterunderstandingoftheseclassesandhowto
workwiththem.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];
ThiscodesnippetusesthefunctionalityofGKObstacleGraphbyfirstmanuallycreating
2DvectorpointsinthepointsarrayandinitializingtheGKObstacleGraphobjectandgraph
withthosepoints.Next,thetwoGKGraphNode2Dobjectsarecreatedtorepresentthestart
andendnodesforaherocharacterinthegame.Then,finally,theoptimalpathforthat
herocharacteriscreatedandstoredintothearrayautomatically;thatis,apathusingthe
graph’sfindpathFromNode:andtoNode:parametersusingthestartNodeandendNode
objects,respectively.Thispathobjectcanthenbeusedinourhero’smovement
componentormaybeamapvisualcomponenttomovetoorindicatetotheplayerthe
correctpathneededtotraversethegamestage’sobstacles.
ThefollowingcodesampleishowtheDemoBotsprojectworkedwiththenavigationin
Swift,usingwhat’sknownasalazystoredproperty.
MoreinformationontheSwiftkeyword,lazy,canbefoundhere:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_La
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,lazyvariablesarequickarrayinitializationsinwhichtheirvaluesarenotknown
atfirstandarecontrolledbyoutsidesources.InthecaseofDemoBots,theseareobstacles
thatarecreatedautomaticallyfromtheboundsofSpriteKitnodes,whichisdonebythe
SpriteKitnodefunctionobstaclesFromNodePhysicsBodies().Thisexample,justshows
howmuchtimecanbesavedwhenusingtheprovidedframeworks.Inthefirstexample
andmoresoinpastgamedevelopment,muchofthislogicwouldhavetobemanually
doneviaterriblycomplexboilerplatecodelogic.
FormoreinformationonPathfindingwithGameplayKit,checkouttheexamplesand
documentationfoundhere:
https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayK
MinMaxAI
Sofar,we’vecreatedAIthat’sgreatforthecomponentsandobjectsthatareactiveina
scenewiththeirmovement,behaviors,andnavigation,butwhataboutAIthatcan
understandthegame’srulesliketheplayer?Agoodexampleofthisisagameofchessor
variousotherboard/tile-likegames.It’dbegreattocontrolhowmuchthecomputercan
makeprogressinthegamewithvariouslevelsofdifficultyfortheplayer.Wecanalso
wanttoletthegamedecideforuswhatthenextbestmoveis.Somethinglikethisis
commoninthree-matchtypegames,suchasBejeweled®orCandyCrush®,inwhich
youarelookingatgridandthegamegivesyouahint.Thistypeoflogiciswhere
MinMaxAIcomesin.
MinMaxAIworksbytakinganinventoryofalloftheavailablemovesforourgameand
placingthemintoadecisiontree.BasedontheparameterswegivetheAI,wecantellit
howtochoosethesedecisionbranches,typicallyintermsofgamedifficulty.Thisisdone
bytakingintheplayers,alistofalltheirpossiblemovesaswellastheirscores,and
pluggingthemintoaGameModelprotocolthatthenusesMinMaxAltodeterminethebest
move.TheTic-Tac-ToeexamplefromWWDC15isshownintheprecedingdiagram.Note
howsomebrancheswouldleadtomorelossesthandrawsorwinsforthecomputerAI.A
harderdifficultylevelwouldmakethecomputerplayerchoosethepathsthatmorelikely
leadtoawinforit,or,inthecaseofthosethree-matchgames,givetheplayerasuggestion
forthenextbestmove.
Ofcourse,asonemighthaveguessed,thistypeoflogicisbestforturn-basedortile-based
games.MinMaxAIcanworkinanygame,butthatgame,oratleasttheimplementationof
MinMaxAI,willonlyworkifthere’sasetbaseofmovesandfuturemovesforittotake
intoitsGameModelprotocol.Anactionplatformer,unlessgivensomechoiceoffeatures,
wouldn’tbeabletouseMinMaxAI,forexample.What’sgreataboutthisfunctionalityin
GameplayKitisthatitdoesn’tneedtoknowthedetailsofyourgame’srules;itjustneeds
theabilitytolookintofuturepossiblemoves.
TheclassdiagramshowstheclassesandfunctionsusedwhendealingwithMinMaxAI.
WeseeGKGameModel,whichisactuallyaprotocolforagamestate.TheGKStateobjects
thatadheretothisprotocolneedtoprovidealistofplayers,theactiveplayer,theplayer’s
score,andtheplayer’slistofmoves,thelatterviathegameModelUpdatesForPlayer()
function.WethentelltheGKGameModelobjectwhattodoasitmovesontothenextgame
movewiththeapplyGameModelUpdate()function.GKGameModelUpdateisessentiallyan
abstractofagame’smoveandisusedbytheGKMinMaxStrategistclasstobuilda
decisiontree,whichisthusappliedtoGKGameModeltochangethatstateinthe
setGameModel()function.
TheGKGameModelPlayerclassisaprotocolforaplayerofthegamewhomakesamove,
asstatedpreviously,withGKGameModelUpdate.TheplayerIdpropertyisauniquenumber
youcanset,whichisusedtodifferentiatetheplayersinourgame’slogicanddealwith
theirownsetofmoves.Thisallowstheflexibilitytohavebothahintingstructureforthe
player(orplayersinamultiplayergame)inadditiontoalsohavingthecomputerplayer
haveanAIforitsownmoves.TheplayerIDpropertyisrequiredtoadheretothisprotocol
aswewouldn’tknowtheplayerwearereferencingwithoutit.
TheGKMinMaxStrategistclassistheactualAIitselfthatistiedtothegameModelproperty
wecreatedwiththepriorprotocols.ThemaxLookAheadDepthpropertyishowmanymoves
aheadtheAIwilllook,themorethebetterandthenitreturnsthebestmoveviathe
bestMoveForPlayer()function.WecanusetherandomMoveForPlayer()functiontoadd
abitofrandomnesstothenextmovechoices;thiscouldbeusedparticularlyforthe
computer’sownAItomaybepurposelycauseittomakemistakesbychoosingaless
optimalmove.
AquickObjective-Csnippetshowinghowtodothisincodeisgiveninthefollowing
code.Don’tworryaboutthesyntaxifyouareonlyfamiliarwiththeSwiftlanguagewe’ve
providedinthisbook;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,takenfromtheWWDC15
conference.Itusesachessgameasanexample.Theintricatedetailsofsettingupachess
gamemodelareabitcomplex,sosimplytakenoteofhowinthiscodeaChessGameModel
object(whichisachildoftheabstractGKGameModelclass)isfirstcreated.Then,wecreate
anobjectoftheGKMinMaxStrategistclassnamedminmax,setitsgamemodel,setits
maxLookAheadDepthpropertyto6,andpassthegame’smoveandthecurrentactiveplayer
totheminMaxobject.Finally,weupdatethegame’smodelwiththe
applyGameModelUpdate()function.It’salsodoneinObjective-Catthetimeofthis
publication,butcheckouttheFourInaRowdemofoundhere:
https://developer.apple.com/library/prerelease/ios/samplecode/FourInARow/Introduction/Intro.htm
ThisprojectwillletusseeamorecompleteimplementationofthisAI.
ForevenmoreonMinMaxAI,checkoutthefollowingdocumentationlink:
https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayK
NextwewilltalkaboutaddingcontrolledrandomnesstoourgameswithGameplayKit’s
randomsources.
Randomsources
RandomnessingameshasbeenastapleofAI,playermoves,leveldesign,andgame
replayabilitysincetheearlydaysofgamedevelopment.Therand()functioninvarious
programminglanguages,inadditiontoarangeofnumberstoscalethatrandomness,has
typicallybeenusedtogiveourapplicationssomelesspredictableoutcomes.However,
gamessometimesneedtohavewhatweliketocallcontrolledrandomness.When
debuggingagame,wedon’twanttoeverrunintoaproblemwhereashippedproducthas
anuntestedstate.Sometimes,whenusingpastconventionsofrandomness,wecanrun
intoasituationwheretheonlytimesomerareeventshappenmaybeafteragameisout
andinthehandsofthousands,ifnotmillions,ofplayerswhoaddtothetestingpoolthat
wedidn’thaveinthedevelopingphase.Therefore,wemaywanttocontrolthedistribution
ofrandomness.Inatypicalrandomselectionofoutcomes,wegetabellcurveofresults
wheretheaverageormiddle-rangedoutcomeswilloccurmoreoftenthanfringeoutcomes.
Thisisfineinsomegames,butratherundesirableinothers.Anotherbitabouttherand()
functionisthatitsrandomnesscanvarybasedonotherfactors,suchasthesystemit’son,
thecurrentdateandtime,andotheruncontrollablefactors.Whatweneed,then,is
platform-independentdeterminismandcustomizabledistribution.WithGameplayKit’s
randomsources,wecanaccomplishthat.
Weseeanumberofthedifferentclasseswecanuseintheprecedingimage.Thebase
classisGKRandomSource,whichactuallyusestheARC4typealgorithmbydefault(viaits
GKARC4RandomSourcesubclass).ARC4isaquick/lowoverheadandhasthetypical
randomnessthatweuseinmanyinstances.It’sdifferentfromthearc4Random()Ccallin
whichinstancesofGKARC4RandomSourceareindependentfromeachother.
GKRandomSourcecanalsobecomeasubclasstoeithertheLinearCongruentialorthe
MersenneTwisteralgorithms.Theirbenefitsanddisadvantagesareshowninthediagram.
It’snotrecommendedthattheseobjectsareusedforcryptography,soit’sbesttouseother
theencryption/hashingframeworksthatApplerecommends
(https://developer.apple.com/library/ios/documentation/Security/Conceptual/cryptoservices/Gene
Theremainingclassesgiveuscontroloftherandomnumber/outcomedistribution
methodologies.TheGKRandDistributionobjectsletususehelpermethodsthat,for
example,giveustheabilitytocreatex-sideddiepiecesinadditiontolettingussetits
lowestandhighestrangevalues.TheGKGaussianDistributionand
GKShuffledDistributionclassesalsoletususethosehelperfunctions,but
GKGaussianDistributionisusedwhenwewanttohaveabell-curvetyperandomization
wherethemiddlevalueshappenmoreoftenthanthefringevalues.Itsmeananddeviation
propertiesgiveuscontrolsonthatbellcurveandifwemaybewantmoreoccurrencesof
fringevalues.GKShuffledDistribution,aswecantellfromitsname,isgreatforcreating
anevenandcompleterangedistribution,forshufflingdecksofcards,ormakingsurethat
everyvalueoccursevenly.Thisclass’suniformDistancepropertyisafloatbetweenthe
valuesof0.0and1.0.At0.0,allshufflingiscompletelyrandom;at1.0,thedistribution
ofallvaluesiseven.
Addingrandomsourcestoourgamesisverysimple.Here’ssomecodeexamplesusing
theseclasses:
/*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,simplelinesofcodethatallusethevariousrandom
sourceclasses.Mostaresimplepropertycalls,sothatwhenwecreateourobjectsinSwift,
asseenintheprecedingcode,itjustneedsoneortwolinesofcodetoutilizetheseclass
typesandtheirvariousrandomizationfunctionalities.Combiningthistothegoalweight
of,say,awanderortrackAIbehavior,andwegetsomediverseandmoderatelycontrolled
randomnessfortheobjectsandcharactersinourgames.
Toreadupmoreonrandomsources/randomizationinthisframework,seethe
documentationlinkhere:
https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayK
Rulesystems
Last,butnotleast,wecometoGameplayKit’srulesystems.Thisaspectoftheframework
useswhat’sknownasfuzzylogicorapproximations,mainlyinthecontextoftransitions
betweengamestates.Thisisn’tsomethingalltoonewtogamedevelopment.Anyone
familiarwithlinearinterpolationwillberightathomeasthisispracticallythesame
concept.Unlikethetypicaluseoflinearinterpolation,whichtendstorevolvearound
transitionsbetweenphysicalactions,GameplayKit’srulesystemsperformthese
approximatetransitionsbetweenvariousgamestates.Thinkoftheobjects/entitiesinour
gamesasnouns,thecomponentsandactionsasverbs,andtheserulesastheinteractions
betweentheseverbsandnouns.Aswe’veseenthroughoutthischapter,thiswouldvery
muchdescribegamestates.Sowhyaddanextralayertothislogic?Well,let’slookatthis
examplefromtheGameplayKitannouncement.Thisiswheretransitionsbetweengame
statesand/orentity-componentactionscouldusethisfuzzylogic:
if(car.distance<5){
car.slowDown()
}
elseif(car.distance>=5){
car.speedUp()
}
ThispseudocodecouldrepresentacarNPCinourgame.Maybeacitybuildinggame,
wheretherearevariouscarGKAgentobjectsthathavethiscodeaspartoftheirbehavior.
Thisseemssounduntilwegettovaluesatornear5.Whatwemightnoticeinourgame
areabunchofNPCcarsacceleratingandbrakinginajerkymotion.Tosolvethis,we
makethetransitionsbetweenbrakingandacceleratingnotbesofinite,butinstead
transitioninapproximation.
Theprecedingimageisabetterillustrationofthis,withtheoriginallogicontheleftand
fuzzylogicontheright.Thiscreatesasmoothtransitionbetweenactionsorstateswhere
rulesystemscomeintoplay;herearetheclassesweusetoimplementthistypeoflogic:
WeusetheGKRuleSystemandGKRuleclassinstancestoutilizerulesystems.GKRule
representsaspecificdecisiontobemadebasedonanexternalstate,andGKRuleSystem
evaluatesasetofrulesagainststatedatatodetermineasetoffacts.Wecanassertfactsor
retractthem,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,andwegrabthedistancestatevalueand
savethattothedistancevariable.Wethenassert/addarulenamedclosethathappensif
1.0f-distance/kBrakingDistance.Thenextfiniteruleweaddisfar,whichis
definedasdistance/kBrakingDistance,orbasicallyanydistancegreaterthan1distance/kBrakingDistance.Wecreatenewfuzzyvaluesofcloseandfar,named
farnessandcloseness,thatarebasedonthegradeForFactpropertyofGKRuleSystem.
Then,fromthis,wegetourfuzzyAccelerationvaluefromthedifferencebetween
farnessandclosenessandapplythataccelerationtoourcar.Thisischeckedduringthe
updaterendercycleautomaticallyandkeepsthelogictransitionssmooth,removingjerky
movementsbetweenthedifferentstates.
ThissimpleexamplecodefromWWDC15isinObjective-C,butwecanseemore
examples(someinSwift)inthefulldocumentationpageasfollows:
https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayK
Wecanalsoseesomeofthisimplementedinthedemoprojectswelinkedtopreviously.
Withtheseclasses,wecancreateanumberofcomplexrulesystemsthattransitionina
morefluidfashion.
Summary
Thischapterhasgoneintoagreatdealofthisdeepandindependentgame-centric
framework.Wehavefirstreviewedthebasicconceptsofentitiesandcomponents,and
howGameplayKittakesadvantageofthecomponent-basedstructuring.Wethenmoved
ontoastapleofgamedevelopment,theconceptofstatemachines,andhowGameplayKit
utilizesthem.Then,wehavereviewedwaysbywhichwecanautomaticallycontrol
componentsandentitiesinourgameswithagents,goals,andbehaviors,aswellas
Pathfinding’snavigationgraphsthataddtothisautomation.Wehavelearnedthat
MinMaxAIletsushintfuturemovestotheplayerorgivethecomputerasmartwayof
challengingusinvariousturn-basedgames.Finally,wehaveseenhowrandomsources
addcontrollablevarietytooutcomesinourgames,whereasRulesystemscankeep
transitionsofvariousstatesfrombeingtoofinite.There’smuchmoretoGameplayKit
thanwecouldshowhere,soit’shighlyrecommendedthatyoureadthroughsomeofthe
documentationlinksprovidedearliertogetanevenbetterfeelforwhatthisframework
hastooffer.Inthenextchapter,wemoveontotheMetalAPIaswellassomeothertricks
andtipsthataidbestinmakingthemostoutofyourgameandkeepingyourgamesatthat
alltoocrucial60fps.
Chapter6.ExhibittheMetalinYour
Game
Uptothispoint,wehavelearnedquiteabit.WelookedintoApple’sSwiftprogramming
language,gotanideaofthegeneralflowofaniOSapp,andhowtocontrolthatthrough
codeand/orstoryboards.Wegotanunderstandingofhow2Dgamesand2Doverlayscan
bemadewithSpriteKitandhow3DgamescanbedesignedevenintheXcodeeditor
withSceneKit.Finally,wereviewedhowtocreatereusablegamelogic,components,and
AIwiththevariousaspectsofGameplayKit.
Essentially,thisisallthatisneededtogetrighttoplanning,coding,andbuildingyour
owngames.Ifthere’sagameideathathascometoyourmindatthistime,gorightahead
andstartplanningitout.TheframeworksandXcodefeaturesfromthepastchapterscan
helptakeyourabstractideasandstartturningthemintowhatcouldsoonbeaplayable
application.
However,beforemovingforward,we’dliketotakethistimetogooverafewmoretips,
tricks,andtopicsthatweeitherbrieflymentionedorhaveyettogoover.Thesetopics
mainlycoverthewayswecanoptimizeourgamesandgetmoreoutoftheApple
hardware.Inthischapter,weshallreviewabitontheratheradvancedtopicoftheApple
Metallow-levelgraphicsAPI.
Note
Justawarningthatthetopicoflow-levelgraphicsAPIscangetratheradvanced.This
won’tbeanall-encompassingtutorialonthesubject;moreofanupper-levelsummaryand
awaytoappreciateallthatSpriteKitandSceneKitdointhebackgroundforus.Wehope
that,attheveryleast,itmakesyouwishtopursuehowtobuildyourowncustom
renderingobjectsthatmightpotentiallyallowthedevelopmentofextremelyperformant
anddetailedgames.
TheAppleMetalAPIandthegraphics
pipeline
Oneoftherules,ifnotthegoldenruleofmodernvideogamedevelopment,istokeepour
gamesrunningconstantlyat60framespersecondorgreater.IfdevelopingforVRdevices
andapplications,thisisofevenmoreimportanceasdroppedframeratescouldleadtoa
sickeningandgameendingexperiencefortheplayer.
Inthepast,beingleanwasthenameofthegame;hardwarelimitationspreventedmuch
fromnotonlybeingwrittentothescreenbuthowmuchmemorystorageagamecould
hold.Thislimitedthenumberofscenes,characters,effects,andlevels.Inthepast,game
developmentwasbuiltmorewithanengineeringmindset,sothedevelopersmadethe
thingsworkwithwhatlittletheyhad.Manyofthegameson8-bitsystemsandearlierhad
levelsandcharactersthatwereonlydifferentbecauseofelaboratespriteslicingand
recoloring.
Overtime,advancesinhardware,particularlythatofGPUsallowedforrichergraphical
experiences.Thisleadstotheadventofcomputation-heavy3Dmodels,real-timelighting,
robustshaders,andothereffectsthatwecanusetomakeourgamespresentaneven
greaterplayerexperience;thiswhiletryingtostuffitallinthatprecious.016666
second/60Hzwindow.
Togeteverythingoutofthehardwareandcombattheclashbetweenadesigner’sneedto
makethebestlookingexperienceandtheengineeringrealityofhardwarelimitationsin
eventoday’sCPU/GPUs,AppledevelopedtheMetalAPI.
CPU/GPUframeworklevels
Metaliswhat’sknownasalow-levelGPUAPI.WhenwebuildourgamesontheiOS
platform,therearedifferentlevelsbetweenthemachinecodeinourGPU/CPUhardware
andwhatweusetodesignourgames.Thisgoesforanypieceofcomputerhardwarewe
workwith,beitAppleorothers.Forexample,ontheCPUsideofthings,attheverybase
ofitallisthemachinecode.Thenextlevelupistheassemblylanguageofthechipset.
AssemblylanguagediffersbasedontheCPUchipsetandallowstheprogrammertobeas
detailedasdeterminingtheindividualregisterstoswapdatainandoutofintheprocessor.
Justafewlinesofafor-loopinC/C++wouldtakeupadecentnumberoflinestocodein
assembly.Thebenefitofworkinginthelowerlevelsofcodeisthatwecouldmakeour
gamesrunmuchfaster.However,mostofthemid-upperlevellanguages/APIsaremadeto
workwellenoughsothatthisisn’tanecessityanymore.
Note
Gamedevelopershavecodedinassemblyevenaftertheveryearlydaysofgame
development.Inthelate1990’s,thegamedeveloperChrisSawyercreatedhisgame,
RollercosterTycoon™,almostentirelyinthex86assemblylanguage!Assemblycanbea
greatchallengeforanyenthusiasticdeveloperwholovestotinkerwiththeinnerworkings
ofcomputerhardware.
MovingupthechainwehavewhereC/C++codewouldbeandjustabovethatiswhere
we’dfindSwiftandObjective-Ccode.LanguagessuchasRubyandJavaScript,which
somedeveloperscanuseinXcode,areyetanotherlevelup.
ThatwasabouttheCPU,nowontotheGPU.TheGraphicsProcessingUnit(GPU)is
thecoprocessorthatworkswiththeCPUtomakethecalculationsforthevisualswesee
onthescreen.ThefollowingdiagramshowstheGPU,theAPIsthatworkwiththeGPU,
andpossibleiOSgamesthatcanbemadebasedonwhichframework/APIischosen.
LiketheCPU,thelowestlevelistheprocessor’smachinecode.Toworkasclosetothe
GPU’smachinecodeaspossible,manydeveloperswoulduseSiliconGraphics’OpenGL
API.Formobiledevices,suchastheiPhoneandiPad,itwouldbetheOpenGLsubset,
OpenGLES.Appleprovidesahelperframework/librarytoOpenGLESnamedGLKit.
GLKithelpssimplifysomeoftheshaderlogicandlessenthemanualworkthatgoesinto
workingwiththeGPUatthislevel.Formanygamedevelopers,thiswaspracticallythe
onlyoptiontomake3DgamesontheiOSdevicefamilyoriginally;thoughsomeuseof
iOS’sCoreGraphics,CoreAnimationandUIKitframeworkswereperfectlyfinefor
simplergames.
NottoolongintothelifespanoftheiOSdevicefamily,third-partyframeworkscameinto
play,whichwereaimedatgamedevelopment.UsingOpenGLESasitsbase,thussitting
directlyonelevelaboveit,istheCocos2Dframework.Thiswasactuallytheframework
usedintheoriginalreleaseofRovio’sAngryBirds™seriesofgamesbackin2009.
Eventually,Applerealizedhowimportantgamingwasforthesuccessoftheplatformand
madetheirowngame-centricframeworks,thatis,theSpriteKitandSceneKitframeworks.
Theytoo,likeCocos2D/3D,satdirectlyaboveOpenGLES.WhenwemadeSKSprite
nodesorSCNNodesinourXcodeprojects,upuntiltheintroductionofMetal,OpenGL
operationswerebeingusedtodrawtheseobjectsintheupdate/rendercyclebehindthe
scenes.AsofiOS9,SpriteKitandSceneKituseMetal’srenderingpipelinetoprocess
graphicstothescreen.Ifthedeviceisolder,theyreverttoOpenGLESastheunderlying
graphicsAPI.
Graphicspipelineoverview
Thistopiccanbeabookallonitsown,butlet’stakealookatthegraphicspipelinetoget
anidea,atleastonanupperlevel,ofwhattheGPUisdoingduringasinglerendered
frame.Wecanimaginethegraphicaldataofourgamesbeingdividedintwomain
categories:
Vertexdata:Thisisthepositioninformationofwhereonthescreenthisdatacanbe
rendered.Vector/vertexdatacanbeexpressedaspoints,lines,ortriangles.
Remembertheoldsayingaboutvideogamegraphics,“everythingisatriangle.”All
ofthosepolygonsinagamearejustacollectionoftrianglesviatheirpoint/vector
positions.TheGPU’sVertexProcessingUnit(VPU)handlesthisdata.
Rendering/pixeldata:ControlledbytheGPU’sRasterizer,thisisthedatathattells
theGPUhowtheobjects,positionedbythevertexdata,willbecolored/shadedonthe
screen.Forexample,thisiswherecolorchannels,suchasRGBandalpha,are
handled.Inshort,it’sthepixeldataandwhatweactuallyseeonthescreen.
Here’sadiagramshowingthegraphicspipelineoverview:
Thegraphicspipelineisthesequenceofstepsittakestohaveourdatarenderedtothe
screen.Thepreviousdiagramisasimplifiedexampleofthisprocess.Herearethemain
sectionsthatcanmakeupthepipeline:
Bufferobjects:TheseareknownasVertexBufferObjectsinOpenGLandareof
theclassMTLBufferintheMetalAPI.Thesearetheobjectswecreateinourcode
thataresentfromtheCPUtotheGPUforprimitiveprocessing.Theseobjects
containdata,suchasthepositions,normalvectors,alphas,colors,andmore.
Primitiveprocessing:ThesearethestepsintheGPUthattakeourBufferObjects,
breakdownthevariousvertexandrenderingdatainthoseobjects,andthendrawthis
informationtotheframebuffer,whichisthescreenoutputweseeonthedevice.
BeforewegooverthestepsofprimitiveprocessingdoneinMetal,weshouldfirst
understandthehistoryandbasicsofshaders.
Whatareshaders?
GPUsfirstcameintousebecauseofnoneotherthanthevideogameindustry.Arcade
cabinetsinthe1970’shadGPUchipsseparatefromthemainCPUtohandlethe
specializedvisualneedsofthegamescomparedwithothercomputingapplicationsatthe
time.Eventually,theneedtodraw3Dgraphicsingamesinthemid-1990’sledtothe
modernGPUarchitecturewehavenow.Shaderswereactuallyfirstintroducedin1988by
PixarbackwhenthecompanywasrunbyApple’scofounderSteveJobs.Shadersarelittle
programswecanwritedirectlytotheGPUtoprocessthevertexandpixeldata.Originally,
APIssuchasOpenGLES1.0didn’tmakeuseofshaderprocessingbutinsteadwere
what’sknownasfixed-functionAPIs.Infixed-functionAPIs,programmersjust
referencedsimplesetrenderingcommandstotheGPU.AsGPUsevolvedandtookmore
workawayfromtheCPU,theuseofshadersincreased.Althougharathermoreadvanced
waytotraversethegraphicspipelinethanthefixed-functionmethodology,shadersallow
forevendeepercustomizationofwhattheGPUdisplaystothescreen.Gamedevelopers
and3Dartistscontinuetopushvisualeffectsingameswiththem.
FromOpenGL2.0andonwards,shaderswerebuiltintheAPI’sC-likelanguagenamed
GLSL.IntheAppleMetalAPI,webuildshaderswiththeMetalShadingLanguage,
whichisasubsetofC++11ofthefiletype.metalandcanrunthepipelineineither
Objective-CorSwiftwithourviewcontrollers.
Typesofshaders
Shaderscomeinanumberoftypesthatcontinuetogrowas3Dgamesandartanimation
continuestoprogress.ThemostcommonlyusedareVertexshadersandFragmentshaders.
Vertexshadersareusedtotransform3Dcoordinatesinto2Dcoordinatesforthescreento
display,inshort,thepositioningdataofourgraphics.Fragmentshaders,alsoknownas
Pixelshaders,arewhatareusedtoconvertcolorsandothervisualattributesofpixelson
thescreen.TheseotherattributesofFragmentShaderscanincludebumpmapping,
shadows,andspecifichighlightsaswell.Weemphasizedthewordattributesbecause
that’susuallythenamegivenforthepropertiesorinputofourshaderprograms.
HereisacodesampleofasimpleVertexandFragmentshaderwrittenintheMetal
ShadingLanguage.
//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,soweseethattheMetal
StandardLibraryisimportedintotheshaderfilewiththeline#include
<metal_stdlib>inadditiontousingnamespacemetal;.
2. ThenextlineisthecreationofourVertexshaderusingthekeywordvertex.This
shaderisavertexoffourfloats.Whyfourfloatswhen3Dspaceonlydealswithx,y,
andzcoordinates?Tosummarize,3Dmatrixmathinvolvesafourthcomponent,w,to
accuratelyhandlethemathcalculationsof3Dspace.Inshortifw=0,thex,y,andz
coordinatesarevectors;ifw=1,thenthosecoordinatesarepoints.Thepurposeof
thisshaderwillbetodrawsimplepointstothescreen,sowwillbe1.0.
3. Here,wecreateapointertoanarrayoffloat3type(holdersforourx,y,andz
coordinates)andsetittotheveryfirstbufferwiththe[[buffer(0)]]declaration.
The[[]]syntaxisusedtodeclareinputs/attributesforourshaders.
4. TheunsignedintegervertexIDiswhatwenamethevertex_idattributeofthis
particulararrayofvertices.
5. Thisiswherethefloat4typeisreturned,orinthiscase,thefinalpositionofthis
vertexarray.Weseethatitreturnstwosectionsoftheoutput:thefirstbeingthe
referencetothisvertexarray,identifiedbythevertex_idattributeandthewvalueof
1.0,torepresentthatthesearepointsinspace.
6. Thislineiswherewecreatethefragmentshader,usingthefragmentkeyword.This
shaderisofthedatatypehalf4,whichisanarrayof[4,4]16-bitfloats.Thisis,in
thiscase,ultimatelytocreate16-bitcoloredpixels.Thedatainthis[4,4]-component
vectortypesaves16bitstoR,G,B,andalphachannels.Thisshaderisgoingto
simplyshowpurewhitepixelshadingwithnotransparency,sowesimplywrite
returnhalf4(1.0);.Thissetsallofthebitsto1,whichisequivalentto
rgba(1,1,1,1).
WhenwecreateaBufferObject,whichcanjustbeaStructoffloatingpointsonthe
screen,wepassthatdatathroughtheseshadersandoutwouldpopupawhitetriangleor
setoftriangleshapesonthescreen.
LookingbackattheGraphicspipelinediagram,weseethatafterthevertexshaderis
calculated,theGPUdoeswhat’sknownasPrimitiveAssembly.Thisisessentiallywhere
thepointsandvectorsdefinedinthevertexshaderaremappedtocoordinatesinscreen
space.TheRasterizerstep,insimpleterms,thenfiguresfromthevertexdatawhereand
howwecanandcan’tcolorthatpixeldataontothescreenusingthefragmentshader
information.Aftertakinginthefragmentshaderinformation,theGPUthenusesthat
informationfortheblendingofthatpixeldata.Finally,thatoutputissenttoorcommitted
totheframebufferwheretheplayerseesthatoutput.Thisallhappensinasingledrawcall
intherendercycle.Havingallofyourgame’slights,pixels,effects,physics,andother
graphicscyclethroughthisin.016666secondsisthenameofthegame.
We’llgooversomemoreMetalcodelaterbutunderstandfornowthatshadersarelike
littleinstructionfactoriesfordatainputwesendtotheminourSwift/Object-Ccode.Other
shadertypesthathavearisenovertheyearsareGeometryShadersandTessellation
Shaders.
Note
BoththeVertexandFragmentshadersarepresentinthissingle.metalfile,buttypically
shadersarewritteninseparatefiles.XcodeandMetalwillcombineall.metalfilesin
yourproject,soitdoesn’tmatteriftheshadersareinonefileornot.OpenGL’sGLSLfor
themostpartforcestheseparationofshadertypes.
Foryears,OpenGLworkedwellformanydifferentGPUsbutasweallsee,AppleMetal
allowsustoperformdrawcallsupto10xtimesfasterthanOpenGLES.
WhyisMetalfasterthanOpenGLES?
Inlate2013,AppleannouncedtheiPhone5s.Builtintothe5swastheA7Processor,the
first64bitGPUfortheiOSdevicefamily.Itprovidedadecentgraphicalboostcompared
withpriordevicesandreflectedhowGPUsinmobiledeviceswerequicklycatchingupto
gamingconsolesreleasedjustafewyearsprior.OpenGL,thoughastapleinlow-level
graphicsAPIs,didn’tsqueezethemostoutoftheA7chip.
Seeninthenextdiagram,theinteractionbetweentheCPUandGPUdoesn’talways
performtheoptimalwaywe’dwantittoforourgames.
Beittextures,shaders,orrendertargets,drawcallsusetheirownstatevector.TheCPU
viathelow-levelAPIusesmuchofthattimeverifyingthestateofthedrawcall.This
processisveryexpensivefortheCPU.Whathappensisthatinmanycycles,theGPUis
sittingidle,waitingfortheCPUtofinishitspastinstruction.Here’swhat’stakingupallof
thattimeintheAPI:
Statevalidation:ConfirmingAPIusageisvalid.ThisencodesAPIstatetothe
hardwarestate.
Shadercompilation:Runtimegenerationoftheshadermachinecode.Thisdeals
withinteractionsbetweenthestateandshaders.
SendingworktotheGPU:Managingresourceresidencybatchingcommands.
WhatAppledidwiththeirMetalAPIisdothesestepsinasmarterfashion.Shader
compilationisdoneduringtheapplication’sloadtime.There’snoneedtoreloadthe
shaderseverycycle;thiswassimplyarelicofolderhardwarelimitations.Thisiswhyin
ourpreviouscodeexample,wecanbuildmorethanoneshaderinoneMetalfile,while
thiswasprohibitedinOpenGLES.Statevalidation,thoughimportant,doesn’tneedtobe
checkedeverycycle.Checkingthestatevalidationcanbesettohappenonlywhennew
contentisloaded.
Note
EvenwithMetal’sadvantages,thisiswhyit’srecommendedtostore2Danimationsin
SpriteSheets.WementionedSpriteSheetsbackinourdiscussionofonSpritKit.Theyare
acollectionofspritesfittedontoonetexture.Thegraphicspipelinethenonlyhastodeal
withoneversionofthatcontent.InternallyunderthehoodofSpriteKit,theGPUthen
doesn’thavetodoasmanystatevectorcallscomparedtohavingeachcharacteranimation
beingplacedonitsownseparatetexture.
ThelastprocessfortheCPUiswhenitsendstheinformationouttotheGPUfor
processing.Thisisgoingtobedoneduringeachdrawcall,andineitherMetalorOpen
GLES,itwillstillbethisprocessthatwillhappenthemostfrequently.Hereistheresult
ofthisinternal,low-levelrestructuringdoneintheMetalAPI:
AsweseeinthediagramfromWWDC14,thereareupto10extradrawcallsthatcanbe
addedduringtherendercycle!Wecanusethattimesavedforotherprocessesinsteadof
extradrawcalls,suchasmorephysicsorAIinourgames.
Note
ThecyclediagramsshownarefromtheoriginalMetalAPIannouncementatWWDC2014
andusedaframerateof30fps.IfdevelopingforVRwhere60fpsorgreaterisnecessary
foraworkinggame,thesenumbersarehalved.Eitherwaythisisratherimpressivefor
mobiledeviceGPUs.SearchonlineforgamesmadeinMetalandyou’dbeimpressed.
Withthismuchroomtoaddmoretoourgameduringeachrendercycle,there’snoreason
nottohaveanimpressivegameatthefull60fps.Additionally,asofiOS9,theSpriteKit
andSceneKitframeworksbydefaultarebackedbyMetal.EveniftheMetalAPIistoo
muchtounderstand,wecanstillutilizetheserendersavingbenefitsfromwhatwealready
learnedabouttheseframeworks.
ThebasicMetalobject/codestructure
TofinishoffourtalkaboutAppleMetal,let’slookatanoverviewoftheAPI’sobjectand
codestructuring.WealreadybrieflysawsomeshadercodeintheMetalShading
Language,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’dworkwithifwriting
agamedirectlyintheMetalAPI.TheyaretheDevice,theState,theCommandBuffer,
ourShaders,Textures,andmanymore.
WecanimporttheMetalAPIintoViewController.swiftclasswiththefollowing:
importMetal
importQuartzCore
ThisimportstheMetalAPI.TheQuartzCoreAPIisneededaswellsincethe
CAMetalLayerobjectwewillworkwithisamemberofthatlibrary.Also,makesurethat
yousetyourtargetdevicetoanactualiOSdeviceasnewornewerthantheiPhone5S,the
XcodesimulatordoesnotsupportMetal.Otherwise,XcodewillgiveyoutheCouldNot
BuildObjective-CmodelMetalerror.Thisistrueasofthewritingofthisbookwiththe
Xcode7Beta.OvertimeandprobablyaftertheofficialpublicreleaseoftheElCapitan
OS,thiswillnolongerbeneeded.Fornow,totestyourowncustomMetalcode,youwill
havetotestonanactualdevice.DoingsowillinvolvehavingtopayforyourownApple
Developmentaccount.Moreonthisisgiveninthenextchapter.
Here’stheorderinwhichwe’dhavetoworkwiththeobjectsinthetableshown
previouslyaswellassomecodesamplesinSwiftthataccomplishthesesteps:
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.Thevertexdatacombinedwithour
previouslymadeshaderstogethercreateasimplewhitetriangletothescreen.
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’dhavetodothefollowingprocessesin
ourviewcontroller:
1. Createadisplaylink.Thisisatimerthatrefresheseverytimethescreenrefreshes.
It’samemberoftheclassCADisplayLinkandateveryscreenrefresh,wecallthe
gameRenderLoopfunction.
vartimer=CADisplayLink(target:self,selector:
Selector("gameRenderLoop"))
timer.addToRunLoop(NSRunLoop.mainRunLoop(),forMode:
NSDefaultRunLoopMode)
ThegameRenderLoopfunctioncanlooklikethefollowing.Itcallsthesoon-to-be
filledinfunction,render():
funcgameRenderloop(){
autoreleasepool{
self.render()
}
2. CreateaRenderPassDescriptor.Forthisexample,amostlyredtextureistobe
createdaroundourwhitetriangleasshownhere:
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,asetofcommandsfor
commandQueue.Inthecodeexamplegivenlater,thistellstheGPUtodrawtriangles
withtheVBOwecreatedearlier.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.ThisessentiallytellstheGPUtodoitsdrawcall
basedonthecommandsthathavebeenpackedintothecommandBufferobject.Place
thisafterthepastcode’sifstatementintherender()function.
commandBuffer.presentDrawable(drawable)
commandBuffer.commit()
Thatistheshortofit.That’sthegeneralprocessofdrawingasimpletriangletothescreen
andmanuallycreatingtherenderloopontheGPU.
ShouldyouratheroptforSpriteKitandSceneKittodoallofthismanualworkforyou?
Thatwouldbeunderstandable.Rememberthough,likewhenplayingagameonhard
mode,itcomeswithitsrewardstotaketheharderroute.Yes,asofiOS9,theSpriteKit
andSceneKitframeworksaredefaulttoMetal.Gameengines,suchasUnityandUnreal
Engine,evenimplementMetalwhenconvertingprojectstotheplatform.However,
knowinghowtobuildyourgamesinalow-levelgraphicsAPI,suchasMetalorOpenGL,
willgivethedevelopertheabilitytohavethepotentialformostlean/fastperforminggame
forthedevicefamily.BesuretocheckoutsomeofthegamescreatedwithMetalnext
timeyousearchonline.Theycanreallygiveyourplayersagreatexperience.Atthesame
time,thiscanchallengeyourskillsasagamedevelopersincebeingagamedeveloperis
thecombinationofanartist,engineer,andcomputerscientist.Workingdirectlyinthe
GPU’sbasicfunctionswillchallengeallofthat.
Todivemoreintotherabbitholethatislow-levelgraphicsdevelopmentwithMetal,check
outtheselinks:
https://developer.apple.com/metal/
https://developer.apple.com/library/ios/documentation/Metal/Reference/MetalShadingLangu
types/data-types.html
http://www.raywenderlich.com/77488/ios-8-metal-tutorial-swift-getting-started
https://realm.io/news/3d-graphics-metal-swift/
ThefirstlinkistotheofficialAppleDeveloperpageforMetal.ThenextlinkisApple’s
listofdatatypesusedintheMetalAPI.Thelasttwolinksaretwoseparatetutorialsto
makesimpleMetalscenesinSwift.Someofthecodeweusedcanbefoundinthese
tutorialsaswellasfullXcodeprojects.ThefirstofthesetwolinksaretotheiOStutorial
sitewww.raywenderlich.com.Thelastlinkistoapagethathasagreatvideopresentation
andfullinstructionsonSwiftandMetal3DgraphicsbyformerAppleEngineer,Warren
Moore.
Summary
Congratsongettingthisfar.Ifthisbookwereagame,we’dprobablyhaveearnedan
achievementforthischapteralone.Aswesaw,workingwithalow-levelAPIsuchas
Metalcanbeabitdaunting.Wefirstreviewedwhatitmeanswhendevelopersand
engineersmentionlowerandupperlevelframeworksandcode.OntheCPUside,wesaw
thatthelowestlevelisthemachine’scodewithSwiftandObjective-Cinthemiddle,and
aboveC/C++andAssemblycode.Next,wespokeabouttheGPUsideandwherethe
visualgraphicsAPIswe’vegoneoverinthepastchaptersstandinthehierarchy.Wethen
gotanunderstandingofthehistoryoflower-levelgraphicsAPIssuchasOpenGLES,how
thegraphicpipelinegenerallyworksunderthehood,andhowtomakebasicshaders.
Finally,wereviewedwhyMetalisfasterduringtherendercyclethanOpenGL,the
generalstructurebehindMetal,andsomeofthecode/objectsusedtomanuallysetupthe
renderloop.Thischaptermerelyscratchedthesurfaceonthistopic,soifyouareuptothe
challenge,it’shighlyrecommendedtocontinuereadingdocumentationonhowMetalcan
makeyourgamesstandoutfromtherest.
Atthispoint,youshouldnowhaveallthatittakestomakeagameontheiOSplatform.
ThelastessentiallessonforiOSgamedevelopmentislearninghowtotest,publish,and
updateyourpublishedgameintheappstore.Inthenextchapter,let’slearnhowtogetthat
gameontheAppleappstore.
Chapter7.PublishingOuriOSGame
Creatingagreatgameishardwork.Ourgoalasgamedevelopersistohaveanapplication
thatcanbeplayedbythousands,ifnotmillionsofpeople.Wewantthemtoplaywhatwe
craftedinthoselongweeksandmonths.Beforetheappisreleased,we’dalsoprobably
wanttohaveotherstestthegametoweedoutanybugsthatmighthavebeenmissed.
PublishingontheiOSplatformcanallowustodoboth.
WecanallowotherstotryoutourgamesbeforereleasethroughtheTestFlightservice,
andofcourse,wecanthensubmitourgameforreleaseontheAppleAppStore.After
release,wecansubmitupdates.Theseupdatesandfutureversionscouldbejusttopatch
upsomeminorbugswemighthavemissedintheinitialreleases,addnewfeatures,such
aslevels,achievements,andotherAppleservices,orwemightneedtoupdateourapp
laterontoadheretotheeventualupdatesthatwillhappenwiththeiOSplatform.
Inthischapter,wearegoingtocoverafewmaintopics:
SettingupourappsforeithertestingorpublishinginiTunesConnect
Stepstosubmitourapptobeplayedintheappstore
SummaryoftheTestFlightservicefortestingintheprereleasephase
HowtouseiTunesConnecttocreateupdatestoourapp
Wewon’ttellyouhowtomarketyourgame,asthat’sanentirebook/topiconitsownthat
dependsonyourbudgetandpreferences.However,wewillsaythatifyouoryourbeta
testersfoundplayingyourgamefun,thereisachancethatotherswilltoo.Submittingto
theappstoredoesnotwarrantinstantsuccess.
Evenunreleasedgamesthatgethighaccoladesattheevergrowinglistofindiegame
rewardshowsorgamejamsmightnothaveseenthatpraisereflectedinsalesand
downloadsafterrelease.Wehavetorememberthatthegamedevelopmentscene,thanks
inparttogaming’spositioninpopularculture,isaseaofthousandsofdevelopers,both
bigandsmall,tryingtomakethenextgreatgame.
Don’tletthatdiscourageyouthough.Ifyourgamedoeswell,whichithastheabilityto
withtheAppleAppStore,thenitcouldbealife-changingexperience.Nomatterthe
outcome,lettheexperienceofbuildingyourowngameandlearningthisdevelopment
platformhumbleyouandmakeyouwanttobeanevenbetterdeveloperforyournext
project.Eventually,thathardworkwillpayoff.
Theeverchangingprocessofapp
submission
Beforewemoveforwardinexplainingthestepsneededtopublishyourgame,wewanted
tonotealittlefactaboutthissubject.Thisfactisthattheexactstepsneededtosubmitour
iOSappsfortestingorpublicationisonethatchangesratheroften.Everycoupleof
monthsthisprocessmightchangefromhowwedescribeithere.
Overtheyears,sincethestartofiOSdevelopment,Applehascontinuallymadethis
processeasierandmorestreamlined.Xcodedoesmuchmoreofthesigning/provisioning
workforusthanitdidinthepast,andtheworriesofourapptakingforevertoappearin
theAppStorearehardlyanissue.
Forexample,whentheSwiftgamePikiPopwassubmittedinNovember,2014,itonly
tookfivebusinessdaysbetweenthedayitwassubmittedforreviewtowhenitappeared
intheAppStoreforthepublic.Thisreviewtimewillvaryforeachofus,butaslongas
therearen’tanyterribleerrorsorpolicyviolationsinourapps,wecanexpectourcreations
tobepublicformillionstopotentiallyplay.Tomakesurethatthepublicationofyour
gamegoessmoothly,it’sbesttoreviewtheAppReviewGuidelinesfoundhere:
https://developer.apple.com/app-store/review/guidelines/.
Note
Wewrotethisbookinthelatesummerof2015,soifyouarereadingthisatamuchlater
dateandfeelsomeoftheseprocessesmightbeoutofdate,makesuretoseethemost
recentupdateshereonApple’sownAppsubmissiondocumentationpage:
https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesCon
Beforesubmittingyourapp
Thereisonemorepotentialdevelopmentsnagwemustwarnaboutbeforeyouchooseto
submityourapptotheappstore.Asofthetimeofthispublication,ifyoubuildyourapp
inabetaversionofXcode,thatappwillberejectedfromreview.
Duringthecourseofthisbook,wehavebeenbuildingourappsandgoingoverfeatures
thatcurrentlyareinthebetaversionofXcode7.Thiswasbecausethereareanumberof
newfeaturesforiOS9/Xcode7thatweren’tthereiniOS8/Xcode6,namely,the
GameplayKitframeworkandvisualeditortoolsforSceneKitthatmakeXcode
developmentashandsonasmultiplatformgameengines.
Note
Bythetimeyouarereadingthis,Xcode7shouldnolongerbeinthebetaphase.
Therefore,youshouldbeabletopublishaniOS9(orlater)gamewithoutworryingif
thesefeaturesarebetaonly.
WhenyoubuildyourgamesforreleasingtotheAppStore,makesuretofirstbuildthem
inthecurrentnon-betaversionofXcode.UsethebetaversionsofXcodetotestthenewest
unreleasedfeaturesaswellasupandcomingiOSbuildsduringtheprereleasephase.
PreparingourappsforiTunesConnect
Soyouhavecoded,simulated,andhopefullyenjoyedplayingabitofthatiOSgameyou
workedsomuchon.Thenextstepistobringyourappintothebeta/prereleasephase.The
goalofthisphaseistogetyourgameintothehandsofasmallerpoolofgamers/testersto
simulatewhattheexperiencecouldbeforthethousands,ifnotmillionsofpeoplewho
couldpotentiallyplayyourgame.Theveryfirststeptothis,ifyouhaven’talready,isto
signupfortheAppleDeveloperProgram:https://developer.apple.com/programs/.
Thereisacostinvolvedandthatcostwillbebasedonyourdevelopmentgoals.For
individual,soleproprietorbusinessaccounts,itcosts$99ayeartobeaniOSdeveloper.If
youareworkingaspartofagroupofdevelopers,thentheEnterpriseplanof$299.99
mightbeabetterchoice.
Note
Inyourdeveloperpage,youwillalsohavetomakesurethatyourprovisioningprofileis
setupcorrectly.Thisstepusedtobeoneofthetoughestthingstocompleteinbeingan
iOSdeveloper,butXcodehasmadethisprocessmoreautomatedwitheachnewupdate.If
you’vebeentestingyourappinXcodewithanactualdevice,you’veobviouslyalready
donethisstep.Ifnot,here’smoreinformationonsettingupyourprovisionprofile(s):
https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/RemoteN
TheportalthatwillbeyourbestfriendintheprocessofpublishingyourappisiTunes
Connecthere:
https://itunesconnect.apple.com/
iTunesConnectiswhereyoucanseeyoursubmittedapps,trackvariousappanalytics,
assignTestFlightbetatesters,andviewyourapp’srevenue.Wewon’tbeabletogiveafull
rundownofeveryfeatureavailableiniTunesConnect;mainlywe’lllookatthesteps
neededtopost,publish,andupdateyourgame.Feelfreetodiveintoallofthefeaturesand
settingsthatiTunesConnectcanprovideforyourappasthefeaturesgrowwitheverynew
iOSupdate.
Submittingyourappinthetesting/betaphase
Let’sgetrightintothestepsneededtosubmityourapp.First,weshalltalkaboutthe
testing/betaphaseofyourgame.
Hereisasummaryofthestepsneededforthetesting/betaphaseofyourgame:
1. CreateaniTunesConnectapprecord.
2. Updatethebuildstring.
3. Archiveandvalidateyourapp.
4. UploadyourapptoiTunesConnect.
5. BetatestyourgamewiththeTestFlightservice.
6. Analyzecrashreportsandsolicitfeedbackfromtesters.
Note
Steps1-4arethesameforboththetestingandreleasephaseofyourgame.
CreatinganiTunesConnectapprecord
ThesearethestepsneededtoaddyourApptotheiTunesConnectapprecord:
1. Logintoyouraccountathttps://itunesconnect.apple.com/andgototheMyApps
section.
2. Nowclickonthe+iconlocatedonthetop-leftcornerofthepageandpickNewiOS
Appfromthedropdown.
3. FillintheappropriatefieldsandclickonCreateifyoualreadyknowtheinformation
forthisdata.Forthoseunsurewhattoplacehere,werevieweachofthesefieldsin
thefollowingscreenshot:
NotetheSKU,theVersion,andtheBundleIDfields.TheSKUmustbeuniqueandnot
inusealreadyasApplewillusethisfortheidentificationofyourappinthestore.The
VersionandBundleIDfieldsmustmatchthebuildsettingsyouhavesetinyourgame’s
Xcodeproject.TheBundleIDfieldisadropdownthatatfirstmightonlyshowthe
WildcardApp/BundleID.
TheWildcardIDisoneoftwotypesofBundleIDs,theotherbeingtheExplicitAppID.
Here’salinktoApple’sdocumentation/FAQforwhichtypeofIDwouldbebestforyour
game:https://developer.apple.com/library/ios/qa/qa1713/_index.html.Inshort,ifyouare
goingtouseAppleservices,suchasNotificationsandGameCenterachievements,you
wouldneedanExplicitAppID,ifnot,thentheWildcardIDisbest.
Note
IfyouwishtousetheExplicitBundleID,youwillhavetoregisteryourapp’sBundleID
intheAppleDeveloperportal.TheIDsthatareregisteredontheDeveloperportalwill
populatethatdropdown.Here’sthelinktothatpageinthedevelopersite:
https://developer.apple.com/account/ios/identifiers/bundle/bundleCreate.action.
TheBundleIDSuffixfieldisfoundinyourproject’sinfo.plistfile.It’sauniquestring
thatiscreatedbyyourXcodeproject,alsoknownastheBundleSeedID.We’llshowyou
wheretofindthisandotherbundle/build-basedinformationwhenwegooverthe
Updatingthebuildstringstepnext.
TheNamefieldiswhatyourgame’snamewillbeintheAppStore.Thisiswhatpeople
searchingforandhopefullyvisitingyourgame’slandingpagewillsee.ThePrimary
Languagedropdowniswhatyourgame’sdefaultlanguagewillbeiftheappstorecan’t
localizeyourgame’sinformationforthatterritory.
Updatingthebuildstring
Thebuildstringrepresentsaniterationofyourgame’sbundle.It’satwo-period-separated
listofpositiveintegers,asin1.2.3.Basically,thebuildstringisanotherlayerof
versioningaddedforyourgame.WhenmakinganiOSapp,asinourcase,changingthis
buildinformationwillautomaticallybeseenbyiTunesConnectduringtheuploadstep.If
wedon’tupdatethisfield,evenifwechangeourgame’scode,iTunesconnectwillstill
thinkthatyouaretryingtouploadthesamebuildandwillrejectyourupload.
Here’swhereyoucanfindthisinformationinyourXcodeproject:
Thebundleidentifier,buildstring,versionnumber,andotherappidentification/global
settingsarefoundontheGeneraltabintheInspectorwindowwhenweclickonthe
project’smainfileintheNavigationpane.Wecanalsofindthisinformationrepresentedin
theinfo.plistfile.MakesurethatthesefieldsmatchyouriTunesConnectrecord.
Nowlet’smoveontouploadingourgameinXcodetoiTunesConnect.
Archiveandvalidateyourapp
Thenextstepintheapppublishingprocessistoarchiveyourgame’sprojectbundle.To
dothis,gotothetopdropdownmenusandthennavigatetoProject|Archive.The
archiveselectionmightbeinaccessibleifyourtestdeviceisthesimulatorastotheiOS
Device.
Oncebuilt,yourarchivedappwillbeseenintheArchivesorganizerwithotherarchives
youhavecreatedfromthisandotherapps.Thiswindowwillopenwhenyoubuildthe
archive,butitcanbeaccessedatanytimebygoingtoWindow|Organizerinthetop
menu.
Thewindowcanbeseeninthefollowingscreenshot:
Next,wevalidateyourgametomakesurethatitfitstheminimumrequirementsfor
submission.Todothis,followthesesteps:
1. ClickontheValidatebuttonfoundontherightsideoftheprecedingArchives
organizerwindow.
2. Apop-upwindowwillshowwhereyouchoosetheDevelopmentTeamthatwoulddo
theprovisioningforthisapp.(ThisisassumingyourProvisioningprofilewassetup
correctly.)ClickonChoosetomovetothenextstep.
3. Thiswillopenmoreofthepopupshowingasummaryofyourappbeforeperforming
theactualvalidation.Informationsuchasyourapp’sBundleIDalongwiththe
BundleSeedIDmentionedearliercanbeseenhereaswell.
4. ClickonValidateandiftheinformationinyourappprojectiscorrectlymatching
whatwesetuponiTunesConnect,thenyourappshouldbevalidatedandreadyfor
submissiontoiTunesConnectandeventuallytheAppStoreitself.
Ifyourappisnotvalidated,makesurethatallofyourinformationiniTunesConnect
matches,mostimportantlytheBundleID.
Tip
TheAppvalidationstepcouldprobablybeskippedjustbyclickingontheUploadToApp
Store…button,butisagoodwaytotestearlyonifeverythingcheckoutwithourgame.
Moreonappvalidationcanbefoundhere:
https://developer.apple.com/library/mac/recipes/xcode_helparchives_organizer/articles/ValidatingYourApp.html
UploadyourapptoiTunesConnect
Thisstepshouldnowberathersimple.ClickontheblueUploadToAppStore…button,
andyoushouldgetthesamepromptsseenfromtheappvalidationstage.You’llbeasked
tochoosetheDevelopmentTeam;showyourapp’sdetails,andyoucanchoosetoupload
yourappbyclickingonSubmit.Ifyourgamevalidatedpreviously,thenitshouldupload
smoothlytoiTunesConnect.Nowyourgameshouldbeonestepclosertobeingavailable
foreitherbetatestingorpurchase/downloadontheAppStore.
BetatestyourgamewiththeTestFlightservice
Everyappshouldhaveatleastsomeformofbetatestingbeforereleasewithvideogames
usuallybeingthetypeofappsthatneeditmorethanothers,asgamestendtohavemore
variablesandchancesforcrashingthanyourrun-of-the-millmobileprogram.Also,the
Appleservices,suchasGameCenterandIn-Apppurchases,can’tbetestedcorrectly
withoutmovingtothisphase.
Inthepast,theonlywaytotestiOSappsbeforereleasewasusingtheadhocdistribution
method,validatingindividualdeviceswiththeirUDID,andgivingthetestersadownload
withamanifestfilethatwouldallowtheapptoactuallyworkontheirdevice.Thisis
whereApplediffersgreatlyfromotherplatformssuchasAndroid.Appleisverycarefulin
keepingwhatdevelopersliketocallawalledgardenwiththeirapplicationdistribution.
Inthepast,thiswasabitofaheadacheandledtoaratherconvolutedadhocsetupas
comparedwithAndroidresultinginappbugsnotbeingnoteduntilaftertherelease.To
helpkeeptheintegrityofApple’sappdistributionandgivedevelopersabetterwayof
pretestingtheirappseasilyandtohavemorepeoplethantheoriginal100devicelimit,the
TestFlightservicewascreated.TheTestFlighticonisseenhere:
TestFightisanappthatanybodycandownloadfromtheAppleAppstorefortheiriOS
device.Foryou,thedeveloper,itcanbeagreattoolforearlydistributionofyourgames.
TestFlighttestersaresegmentedintotwogroups:internaltestersandexternaltesters.
Internaltestersaremadeupofyourownteammembers,andyoucanhaveamaximumof
25internaltesters.
IniTunesConnect,youcansetrolesforyourteamintheUsersandRolesmainsection.
TheserolesincludeAdmin,Technical,Marketing,andothers.Themembersthatareinthe
AdminandTechnicalcategoryarethosewhomyoucanassignasinternaltesters.Making
thoseusersinternaltestersisaseasyasturningontheInternalTestersswitchnextto
theirname.
TohavetheseuserstestyourgameinTestFlight,locateyourgameintheMyApps
sectionofiTunesConnect.Ifyourgame’sbuildwassuccessfullyaddedtoiTunesConnect
fromthestepsprovidedintheprevioussection,thenyoushouldseeitlistedinthe
Prereleasetab.
Note
WhenyouuploadyourapptoiTunesConnecttheycanbedividedintoversions,whichare
thensubdividedintotheirownbuilds.Forexample,version1.0(1)isversion1.0,build1
ofyourgame,whereas1.0(1.2)wouldbeversion1.0/build1.2ofyourgame.Changing
thebuildstringinyourprojectandthenuploadingthatnewbuildishowyoucandivide
yourappforthispageiniTunesConnect.Wewilldiscussmoreonthiswhilecreatinga
newupdatetoyourgame,butthisistheprocessforversioningtheprereleasebuilds.
Thenextstepistoclickonthebuildorversion,whichshouldopenthebuild’sown
metadatapage.Fillinthisinformationtobetterhelpyourtestersknowwhomtocontact
andwhattotest.Thisinformationiswhatyourtesterswillseewhentheydownloadyour
game’sbetaversion.
Toallowthisbuild/versionforTestFlighttesting,simplyswitchontheTestFlightBeta
Testingswitchfoundontheupper-rightsideoftheversion’slistinginthePrereleasetab.
NowtohaveyourtesterstestthisbuildintheirTestFlightapp,simplyclickonthe
InternalTesterstabnexttotheBuildstaboninthegame’sprereleasepage,clickonthe
checkmarknexttotheirnameandthenclickonInvite.
Theyshouldgetane-mailtoacceptthatinvite,andyouwillseewhichbuildtheyare
testingoncetheyinstalleditinTestFlight.
Externaltesterinvites
TogetexternaltestersforyourgamewithTestFlightisalsoarathersimpleprocesswith
onecaveat;yourappneedstobesubmittedforbetareview.Doingsoissimplethoughall
youneedtodoistoclickontheSubmitForBetaAppReviewlinkattherightsideof
yourapp’sbuild;againintheBuildstabofthePrereleasesection.
AswiththeactualAppStoresubmission,itmightinvolvewaitingbeforemovingtothe
nextstep.Thewaitisnotaslongasthefullappsubmissionandisaverygoodsignthatall
willgowellwhenyoudothepublicrelease.Unlikeinternaltesters,allofthemetadata
mustbecompletedbutyoucanhaveupto1000testers!Youcanstarttoinvitetestersonce
theSubmitForBetaAppReviewlinkistappedandyourappiswaitingforbetatest
review.
NowgototheExternalTesterstabinthePrereleasepageandthenclickonthe+button
toaddthemwiththeire-mailaddressand(optionally)theirfirstandlastname.Clickon
Nexttoaddthatpersontoyourinvitelist.Notethatyouonlyhave30daysforexternal
testerstoreviewthatbuildofyourgame.
Onceyourapppassesbetareview,yourexternaltesterscantestyourappjustlikeyour
internaltesterscan.
Analyzingcrashreportsandfeedbackfromtesters
Nowthatyouhavepeopletestingyourgame,takenotesfromtheire-mailsonwhatissues
theremightbeinyourgameandthengobacktoyourgame’sprojecttodotheneeded
fixes.UpdatethebuildnumberinthebuildstringofyourXcodeprojectandreuploadthe
buildtoeasilyallowyourtesterstokeepuptodatewitheachnewprereleaseupdate.
AppcrashreportscanbeviewedintheAppAnalyticsmainsectionofiTunesConnect,as
seenintheimagefromPikiPop’sinformationasfollows.However,itseemsthatthese
detailedcrashanalyticsareforafterreleaseandnotduringprerelease.
MoreonTestFlightandevenavideoexplanationcanbefoundonApple’sofficialpageon
thesubjectasfollows:
https://developer.apple.com/testflight/
Submittingyourgameforreview
Thisisthepointinyourgame’sdevelopmentyou’veworkedsohardfor,submittingitto
theAppleAppStore.Thegoodnewsisthatmostoftheworkhasalreadybeendone!To
submityourgameforreview,atthispoint,allyouhavetodoisgotoyourapp’sVersions
tabandclickontheSubmitForReviewtab.
YoucanseethisinthefollowingAdventureappexampleimage:
Youwillbeaskedafewquestionsbeforetheactualsubmission,suchasaboutExport
Compliance,Contentrights,andAdvertisingIdentifier(IDFA)information.More
informationonIDFAcanbefoundhere:
https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesCon
CH33-SW8
NowthewaitinggamebeginswithyourgameintheWaitingForReviewstatus.Again,
thewaittimeforappapprovalwillvarybutisusuallymuchlessthanitusedtobeinthe
past.Hopefully,allgoeswellandyouwillseeagreenmarkstatingyourgame’ssubmitted
versionnumberwiththewordsReadyforSale;asfollows:
Congrats!YourgameshouldbenowlocatedintheAppStoreforeveryonewithaniOS
devicetodownloadandplay!MakesuretocheckoutthevariousanalyticstoolsiTunes
Connectprovidestokeepapulseonyourgame.
Updatingyourgame
Gamestodayarealmostneveraone-shotdeal.Theytendtobealivingapplication
throughupdates,add-ons,andfixesevenafterrelease.Updatestoyourappwillbe
workingtoanyfutureiOSupdates,addingnewgamecontent,oracombinationofboth.
Todothis,simplyrepeatmuchoftheprocessesfromthebuildstringphasestartingwith
thecreationofanewversionnumber.DoingsowillcreateanewsectioninyourBuilds
tabunderPrereleaseasseenwithPikiPop’sownpageasfollows:
YoucanuseTestFlightbetatesttotestthenewbuildwithinternalandexternaltestersjust
asyoudidbefore.Tomakereadythenewestversionforrelease,clickontheNewVersion
buttonontheVersionsmaintabandsubmitthenewestversion’snumberinthepopup.
TheVersionstabwillnowbedividedintothecurrentversionandthenewversionvia
easy-to-navigatetabs.Likeintheoriginalrelease,youcanfillinvariousmetadataaswell
asinformationfortheplayersforwhatthisnewupdatewillentail.Submittheversionfor
reviewandonceapproved,thenewestgameupdatewillbeintheappstorethatplayers
willeitherautomaticallydownloadorbenotifiedabout,basedontheirdevice’sAppStore
updatesettings.
Thataboutdoesit!Ifmoregameframeworksandtoolscomeoutinfutureversionsof
iOS,youcanhavethemaspartofyourgamewithyourupdates.Makingagreatgame
evenbetterisalwaystherightchoiceforeverygamedeveloper.
Summary
Throughoutthischapter,wesawwhatwasneededtofinallytakeyourgamefroman
XcodeprojecttoaplayablegameforeveryonewithaniOSdevice.Welearnedaboutthe
stepsneededtosetupourXcodeprojectbeforesubmissiontoiTunesConnect.Then,we
gotanintroductiontoTestFlight,whichisagreatserviceforustobetatestourgames
beforerelease.Wesawthatthosestepsalreadypreparedusformostofwhatwasneeded
tosubmitourgamesforreview.Finally,wesawhoweasyitwastocreateappupdatesin
iTunesConnect.
Younowhaveagameappthathopefullythousandsofplayerscanenjoy.Nomatterifthe
gamewasbigorsmall,beproudofthefactthatyoucreatedsomethingforplayersto
enjoy.Eventhesimplestofgamescanbeaworthyaccomplishment.We’veseen
throughoutthisbookthattheprocessofmakinganiOSgame,thougheasierthanevena
fewyearsago,takessomeeffortanddiligencetogetright.Thisconcludesallofthe
technicalaspectsweshalldiscuss.Next,weconcludewithaquickdiscussiononthe
futureofiOSandgamedevelopmentasawhole.
Chapter8.TheFutureofiOSGame
Development
FortheentiretyofthisbookwehavegoneoverthefeaturesfromiOS8andtherecent
announcementsofiOS9.So,whatofthefutureofiOSgamedevelopment?Obviously,
nobodycantellwhatthefuturewillbring,butwecanguessafewpossibilitiesbasedon
therecentevolutionoftheiOS/Xcodeplatform,programming,andhowgame
developmentasawholewillchange.
Agreaterfocusonfunctional
programming
Asofthispublication,theSwiftprogramminglanguageisonlyayearoldbutitrepresents
arecentparadigmshiftinmuchofprogramming.Object-orientedprogrammingand
designstillholdstrue,butashifttofunctionalprogrammingiswherelanguagessuchas
ScalaandSwiftplacetheirfocus.Functionalprogramming,insummary,isafocuson
functionsbeingpuremathematicalcalculationsofobjectswithanavoidanceofthestate
changesandmutabledatathatwe’veseenwithpastlanguages,suchasC++/Javaandeven
Apple’sownObjective-C.Insteadofdealingwithsubroutines,afunctiononlyworkson
theparametersit’sgiven.Swiftdoesthiswellwithitsclosures,whichwe’veseenafew
timesinthisbook,andareoftenusedtocompactmuchofthelogicingameprogramming
foriOS.
SinceWWDC14,ApplehastolddevelopersthatSwiftisthesuccessortobothCand
Objective-C.It’sacompletelyrebuiltlanguagefromthegroundupwithspeedand
efficiencyasitsfocus,somethinggamedevelopersmustalwaystakeadvantageofand
whySwiftisnowthelanguageofchoicegoingforwardforiOSgamedevelopment.
Objective-Cisnotgoingaway,andSwiftstillhassomegrowinguptodobeforeitcan
eventakeoverallofwhatObjective-CcandoforiOSdevelopment.Swift’s2.0update
fromiOS9addedmoreforerrorcatchinganddebuggingwithkeywords,suchasthrow,
catch,andguard.Thankfully,wedon’thavetoabandonanypastObjective-Cprojects
sincetheabilitytousebothSwiftandObjective-Cinthesameprojectisverysimple
throughtheuseofanObjective-C/SwiftBridgingfile.
AswemoveontofutureversionsofiOS,expectmoredebuggingcontrolsand
improvementstoSwift’sabilitytocompactdetailedlogicintoafewlines.Somedata
sortingfunctionalitiesofSwiftarefasterthanObjective-C,andintheworldofgame
development,anygainsinframerateisalwaysagoodthing.Despitetheadvancesin
CPU/GPUpowerandtheever-growingeaseofgamedevelopmentframeworks,suchas
SpriteKitandSceneKit,thedesignaspectofgamedesigncanbeadouble-edgedswordif
weforgettheengineeringaspectofthiscraft.Someofthetoolsgiventousintherecent
gamedevelopmentscenecanmakealmostanybodyagamedeveloper.Thisisagood
thing.Wewantpeoplefromallwalksoflifetobegamedevelopers,butwemustnotlet
someoftherecentandfuturetoolsthatallowgamesoniOSorotherplatformsmakingus
lazyandforgetthatthereisandalwayswillbeaprogramming/engineeringsidetothis
industry.TheframeworksandvisualtoolsofiOSandothergameenginesshouldalways
betreatedastoolsandneverasacrutch.Thebestgamesofthepast,present,andinthe
futurewillbegamesthattapintoeveryaspectofgamedevelopment,particularly,the
hardestaspectsofgamedevelopment,suchasthegraphicspipeline.That’swhyApple
tappedintothedetailsoftheGPUwiththeMetalAPI.
TheAppleWatch
AsofiOS9,theAppleWatch’splatformalreadygotanupgradewithwatchOS2.The
AppleWatchisgenerally,atthemoment,notavideogameplatform.Withouttakingthe
smallscreensizeintoplay,appsmadefortheAppleWatchdon’thavemuchinthewayof
makinggame-likegraphicsupdates.Inthefuture,thismightchange.Atthemoment,apps
madeinwatchOSarelikechildappsofmainiOSapps.Eventually,wecanmakewatchOS
appsseparatelywithouthavingthemattachedtoaparentiOSproject.However,some
developershavemadesimpletext-basedgamesfortheApplewatch.It’spossiblethatin
thefuture,wecouldmakemoreaction-orientedgamesfortheAppleWatch.
Currently,it’sverymuchpossibletomakeagamethatusesthewatchforaccessoriesdata,
suchasinventory,maps,andmorewithalittlebitofingenuity.OnefeatureoftheApple
WatchthatwecoulddesigngamesorgamecontrolswithisForceTouch.ForceTouch
senseshowfirmthepressgestureis.Thisisn’tsomethingnewtogamedesignasawhole
butnewtoiOSwiththenextlineofiPhonesandiPadsmostlikelyhavingthisfeatureas
well.Gettingthestrengthofaplayer’stouchandtapscouldallowsomeintuitive
gameplaymechanicsforthenextlineofmobilegames.
FormoreonthewatchOStopossiblyinspiresomegamedevelopmentideasforthe
device,checkoutthewatchOS2previewpageathttps://www.apple.com/watchos-2preview/.
Component-basedstructuring
WesawinthepreviouschaptersthatiOShasimpartedmuchofthecomponent-based
structuringparadigmtotackletheuniquesoftware/programmingrequirementsthatcome
fromgamedevelopment.Insteadofbuildingatallparent-childstructurethatweseefrom
anobject-orienteddesign,itbuildsastructurethatdoesbestbygrowingit’sstructurein
width.Classes,suchasGKEntity,GKComponent,andotheraspectsofGameplayKit,are
whatletustakeadvantageofthesefeatures.Thistypeofstructuringisn’talltoonewin
gamedevelopment.Component-basedstructuringhasbeenusedbymultiplatformgame
engines,suchasUnityandUnrealEngine,andcontinuestobethewaygamedevelopers
likeusmakeandreusepartsofourgames.ExpectthefutureupdatestoXcodeandiOSto
utilizethesefeaturesevenmore.Inthenearfuture,wewillprobablyseeXcodelookand
actevenmorelikethesegameenginesbutwiththebenefitofbeingspecificallymadefor
theiOSdevices,allowingevendeeper,customintegration.Doingallofthisdirectlyin
XcodeandwithiOSframeworksallowsinstantaccesstoApplefeatureswithouttheuseof
paidassettoolsorwaitingforpluginupdates.DevelopersforthenextgenerationofiOS
gameswillbeabletotakeAIactions,characterabilities,HUDanimations,andother
featuresmadeinonegameandreusethemalmostinstantlyforacompletelydifferent
game.Component-basedstructuringmakesitwherethedevelopercanbuildalibraryof
reusablefeaturesbyplacingthedesignofourgamesaheadoftypicaldevelopment
hurdles.
TheriseofVR
ThishasbeenatopicthatApplehasbeenratherquietaboutwhereotherplatformshave
beenrathervocal.EventhemanufacturersofApple’sA7/A8chips,Samsung,havejoined
theVRdevelopmentenvironmentwiththeirGearVRdeviceandtheirpartnershipwith
Oculusontheproject.GooglehascreatedthesimpleCardboardsetup,akintothe
GearVR,whichsimplyletstheuserplacetheirsmartphoneintothedeviceorboxto
experienceVRexperiencesandgames.Mostfamously,thereistheOculusRift,which
willhaveitsconsumermodelavailableinthefirstquarterof2016,andwilllikelybethe
frontrunnerinthisnewergameenvironment.
Virtualrealityisatopicthathascomeupanumberoftimesinthepastfewdecades.Ithas
comeandgone,butforthetimebeing,itseemstobegettingitsoverduefootholdin
technology.TheUnitygameengine,forexample,justrecentlyallowedfornativesupport
ofVR.Thethoughtprocessinmakingthesegamesisabitdifferentandhasyettobefully
fleshedout.ItispossiblethatsoonApplewillthrowtheirhatintothisarena.Ifyou
haven’talready,learninghowtomakefungamesintheVRspacemightbeaworthyactof
foresight.
Summary
Wehopethatthediscussionsandtutorialsseenthroughoutthisbookhelpedyoueither
learntheplatformforthefirsttimeorenrichedwhatyoumighthavealreadyknownabout
iOS.WehopethatyoutakethisknowledgeandmakesomeamazinggamesfortheiOS
familyofdevicesandcontinuetolearnmoreabouttheplatformandgamedevelopmentas
awhole.
Intheend,alwaysrememberthatgamedesignandprogrammingisacombinationof
computerscience,engineering,art,andlotsofhardwork.It’sacomplexcreativefieldthat
isacombinationofeveryothercreativeprofessionfrommusictomoviemaking,to2D
animation,3Dsculpting,andmore.Asthecasewithothercreativefields,developers
shouldneverfeeldoneandalwaysbehumbleinwhattheyknowandacknowledgethat
there’salwaysmoretolearninthisever-growingfield.Likeavideogame,beupforthe
challenge.Realizewhenyoulookbackthatyouessentiallyleveledupfromwhatyouused
toknowandtherearealwaysmoreabilitiestogain.
Index
A
A7Processor/WhyisMetalfasterthanOpenGLES?
AdvertisingIdentifier(IDFA)/Submittingyourgameforreview
affectedbygravitytoggle/Particlesystems
agents
about/Statemachines,Agents,goals,andbehaviors
API
statevalidation/WhyisMetalfasterthanOpenGLES?
shadercompilation/WhyisMetalfasterthanOpenGLES?
work,sendingtoGPU/WhyisMetalfasterthanOpenGLES?
AppleMetalAPI
about/TheAppleMetalAPIandthegraphicspipeline
CPUframeworklevel/CPU/GPUframeworklevels
GPUframeworklevel/CPU/GPUframeworklevels
graphicspipelineoverview/Graphicspipelineoverview
AppleWatch
about/TheAppleWatch
appslicing
about/Assets,sprites,andicons
URL/Assets,sprites,andicons
appsubmissionprocess
about/Theeverchangingprocessofappsubmission
prerequisites/Beforesubmittingyourapp
apps,preparingforiTunesConnect/PreparingourappsforiTunesConnect
testing/betaphase/Submittingyourappinthetesting/betaphase
appthinning
about/Assets,sprites,andicons
URL/Assets,sprites,andicons
arrays
about/Arrays
artificialintelligence(AI)
about/Agents,goals,andbehaviors
assemblylanguage/CPU/GPUframeworklevels
B
blocks
URL/Thegameloop
Boolean
about/Boolean
bridgingfile
URL/UsingGKEntityandGKComponentobjectsinourgames
Bufferobjects/Graphicspipelineoverview
C
characters
about/Charactersandstrings
classes
about/Classes
closures
URL/Thegameloop
Cocos2Dframework/CPU/GPUframeworklevels
collectiondata
editing/Editing/accessingcollectiondata
accessing/Editing/accessingcollectiondata
collectiontypes
iteratingthrough/Iteratingthroughcollectiontypes
commenting
about/CommentinginSwift
component-basedstructuring
about/Component-basedstructuring
components
about/Entitiesandcomponents
URL/UsingGKEntityandGKComponentobjectsinourgames
constants
about/Constants,Moreaboutconstants…
controlflow
about/ControlflowinSwift
if-statement/Ifstatements
for-loops/Forloops
do-whileloop/Do-whileloops
switchstatements/Switchstatements
D
2Darrays
about/2Darrays/matrices
DemoBots
about/DemoBots
URL/DemoBots
designmethodology
URL/Entitiesandcomponents
dictionaries
about/Dictionaries
do-whileloops
about/Do-whileloops
doubles
about/Floatsanddoubles
E
emoji
URL/Creatingourgamelogic
entities
about/Entitiesandcomponents
URL/UsingGKEntityandGKComponentobjectsinourgames
F
filedecodingclass
URL/SpriteKit
floats
about/Floatsanddoubles
for-loops
about/Forloops
ForceTouch
about/TheAppleWatch
Foxdemo
about/Foxdemo
URL/Foxdemo
framespersecond(fps)/SceneKitprojectflowandstructure
functionalprogramming
about/Agreaterfocusonfunctionalprogramming
functions
about/Functions
fuzzylogic
about/Rulesystems
G
game
submitting,forreview/Submittingyourgameforreview
updating/Updatingyourgame
GameBoard
about/GameBoard
gamelogic
creating/Creatingourgamelogic
GameBoard/GameBoard
GameScene.swift/PuttingitalltogetherinGameScene.swift
gameloop
about/Thegameloop
URL/Thegameloop
GameplayKit
overview/Agents,goals,andbehaviors
guide,URL/Agents,goals,andbehaviors
rulesystems/Rulesystems
rulesystems,URL/Rulesystems
GameplayKitframework
about/Boolean
gamestate
about/PuttingitalltogetherinGameScene.swift
Generics
about/2Darrays/matrices
GKAgentparameters
URL/Agents,goals,andbehaviors
GKComponentobjects
using,ingames/UsingGKEntityandGKComponentobjectsinourgames
GKEntityobjects
using,ingames/UsingGKEntityandGKComponentobjectsinourgames
GKObstacleclass
URL/Pathfinding
GKState
URL/Statemachines
GKStateMachine
URL/Statemachines
GLKit/CPU/GPUframeworklevels
graphicspipelineoverview
about/Graphicspipelineoverview
vertexdata/Graphicspipelineoverview
rendering/pixeldata/Graphicspipelineoverview
example/Graphicspipelineoverview
Bufferobjects/Graphicspipelineoverview
primitiveprocessing/Graphicspipelineoverview
GraphicsProcessingUnit(GPU)/CPU/GPUframeworklevels
H
Heads-UpDisplay(HUD)
about/Constants
HelloWorldprogram
about/HelloWorld!
I
if-statement
about/Ifstatements
ifandelsestatements
about/Moreaboutconstants…
imageassets
URL/Creatingourgamelogic
immutablecollections
about/Mutable/immutablecollections
inheritance-basedstructuring
issues/Theissuewithinheritance-basedstructuringandgamedesign
integers
about/Integersandunsignedintegers
iOS9/Xcode7
SceneKit,features/SceneKitfeaturesintroducediniOS9/Xcode7
iOSapplifecycle
about/AniOSapp’slifecycle
main()function/Themain()function
UIApplicationclass/TheUIApplicationclass/object
AppDelegateclass/TheAppDelegateclass
viewcontrollers/Viewcontrollers
ViewControllertypes/Viewcontrollertypes
iOSgamedevelopment
functionalprogramming/Agreaterfocusonfunctionalprogramming
AppleWatch/TheAppleWatch
component-basedstructuring/Component-basedstructuring
VRdevelopmentenvironment/TheriseofVR
iOSgamedevelopmentengines
about/AbriefhistoryofiOSgamedevelopmentengines
iPhone5s/WhyisMetalfasterthanOpenGLES?
iTunesConnect
URL/CreatinganiTunesConnectapprecord
M
machinecode/CPU/GPUframeworklevels
matrices
about/2Darrays/matrices
MetalAPI
versusOpenGLES/WhyisMetalfasterthanOpenGLES?
object/codestructure/ThebasicMetalobject/codestructure
MinMaxAI
about/MinMaxAI
URL/MinMaxAI
Model-View-Controller(MVC)
about/Model-View-Controller
mutablecollection
about/Mutable/immutablecollections
N
navigationgraph
about/Pathfinding
O
object-orientedprogramming(OOP)
about/ObjectsinSwift
Objective-C
versusSwiftcode/Objective-CandSwiftcomparison,Swift
about/Objective-C,UsingGKEntityandGKComponentobjectsinourgames
objects
about/ObjectsinSwift
type-safe/Typesafetyandtypeinference
typeinference/Typesafetyandtypeinference
OpenGLAPI/CPU/GPUframeworklevels
OpenGLES/CPU/GPUframeworklevels
optionals
about/Optionals
unwrapping/Unwrappingoptionals
optionalbinding/Optionalbindingandchaining
optionalchaining/Optionalbindingandchaining
P
particles
placing,inpioscene/Placingparticlesintoourpioscene
SpriteKitparticles/SpriteKit
SceneKitparticles/SceneKit
particleseffects
about/Particlesystems
creating,onSceneKit/Particlesystems
Pathfinding
about/Pathfinding
URL/Pathfinding
PrimitiveAssembly/Typesofshaders
primitiveprocessing/Graphicspipelineoverview
R
randomsources
about/Randomsources
real-timestrategy(RTS)game/HandlinguserinputinSceneKit
Right-HandedCoordinateSystem/SceneKitprojectflowandstructure
RollercosterTycoon™/CPU/GPUframeworklevels
S
scenegraph
about/Visuallycomposedgamescenescgs
objects,adding/Visuallycomposedgamescenescgs
SceneKit
basics/SceneKitbasicsandworkingwithnodes
nodes,workingwith/SceneKitbasicsandworkingwithnodes
andSpriteKit,interactivity/SpriteKit/SceneKitinteractivity
coordinatediagram,URL/SceneKitprojectflowandstructure
framework,URL/Visuallycomposedgamescenescgs
SceneKitfeatures,iniOS9/Xcode7
about/SceneKitfeaturesintroducediniOS9/Xcode7
audionodesand3Dsound/Audionodesand3Dsound
ambienceandmusic/Ambienceandmusic
SpriteKitscenetransitions/SpriteKitscenetransitionsinSceneKit
SceneKitparticles
about/SceneKit
SceneKitphysics
about/IntroducingSceneKitandSpriteKitphysics
SceneKitscene
about/OurfirstSceneKitscene–theXcodetemplate
project,flow/SceneKitprojectflowandstructure
project,structure/SceneKitprojectflowandstructure
debugging,options/SceneKitDebuggingOptions
userinput,handling/HandlinguserinputinSceneKit
SCNAction
URL/SceneKitprojectflowandstructure
SCNBoundingVolumeclass
URL/IntroducingSceneKitandSpriteKitphysics
SCNLights
URL/SceneKitprojectflowandstructure
segues
about/Segues
Show/Segues
ShowDetail/Segues
Presentmodally/Segues
Popover/Segues
Custom/Segues
creating/Segues
customsegueclasses,creating/Segues
sets
about/Sets
shaders
about/Whatareshaders?
types/Typesofshaders
Vertexshaders/Typesofshaders
Fragmentshaders/Typesofshaders
Pixelshaders/Typesofshaders
codesample/Typesofshaders
SKAction
URL/SceneKitprojectflowandstructure
SKConstraints/Thegameloop
SKNode
URL/AnoverviewoftheSpriteKitstructureandobjects
SKScenetransitions
withSKSfiles/SKScenetransitionswithSKSfiles
SKTransition
URL/AnSKTransitionexample,SpriteKitscenetransitionsinSceneKit
SpriteKit
gameloop/Thegameloop
keynote,URL/DemoBots
SpriteKitgame
creating/CreatingourSpriteKitgame
structure/AnoverviewoftheSpriteKitstructureandobjects
objects/AnoverviewoftheSpriteKitstructureandobjects
scenetransitions/Scenetransitionsandthechoiceofcode,storyboards,and/or
SKSfiles
code,choice/Scenetransitionsandthechoiceofcode,storyboards,and/orSKS
files
storyboards/Scenetransitionsandthechoiceofcode,storyboards,and/orSKS
files
SKSfiles/Scenetransitionsandthechoiceofcode,storyboards,and/orSKS
files
SKTransitionexample/AnSKTransitionexample
SKScene/storyboardexample/ASKScene/storyboardexample
SKScenetransitions,withSKSfiles/SKScenetransitionswithSKSfiles
assets/Assets,sprites,andicons
sprites/Assets,sprites,andicons
icons/Assets,sprites,andicons
spriteatlases/Spriteatlasesandanimatingsprites
sprites,animating/Spriteatlasesandanimatingsprites
andSceneKit,interactivity/SpriteKit/SceneKitinteractivity
SpriteKitparticles
about/SpriteKit
SpriteKitphysics
about/IntroducingSceneKitandSpriteKitphysics
spritesheet/Spriteatlasesandanimatingsprites
SpriteSheets/WhyisMetalfasterthanOpenGLES?
statemachine
about/PuttingitalltogetherinGameScene.swift
statemachines
about/Statemachines
storyboards
about/Storyboardsandsegues
using/Storyboardsandsegues
versuscoding/Storyboardsversuscoding
StringInterpolation
about/StringInterpolation
strings,mutating/Mutatingstrings
stringindices/Stringindices
strings
about/Charactersandstrings
Swift
commenting/CommentinginSwift
Swiftlanguage
variables/Variables,constants,andprimitivedatatypes
constants/Constants
SwiftSweeper
about/Tilegame–SwiftSweeper,WhatisSwiftSweeper?
URL/WhatisSwiftSweeper?,PuttingitalltogetherinGameScene.swift
switchstatements
about/Switchstatements
T
testing/betaphase,appsubmissionprocess
about/Submittingyourappinthetesting/betaphase
iTunesConnectapprecord,creating/CreatinganiTunesConnectapprecord
buildstring,updating/Updatingthebuildstring
app,archiving/Archiveandvalidateyourapp
app,validating/Archiveandvalidateyourapp
app,uploadingtoiTunesConnect/UploadyourapptoiTunesConnect
app,testingwithTestFlightservice/BetatestyourgamewiththeTestFlight
service
externaltesterinvites/Externaltesterinvites
crashreports,analyzing/Analyzingcrashreportsandfeedbackfromtesters
feedback,analyzing/Analyzingcrashreportsandfeedbackfromtesters
textureatlas/Spriteatlasesandanimatingsprites
tuples
about/Tuples
U
UITapGestureRecognizerclass
URL/HandlinguserinputinSceneKit
unsignedintegers
about/Integersandunsignedintegers
V
variables
about/Variables
VertexBufferObjects/Graphicspipelineoverview
VertexProcessingUnit(VPU)/Graphicspipelineoverview
VRdevelopmentenvironment
about/TheriseofVR
W
watchOS2previewpage
URL/TheAppleWatch
WWDC15
URL/DemoBots
X
XCodetemplate
about/OurfirstSceneKitscene–theXcodetemplate
Was this manual useful for you? yes no
Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Download PDF

advertising