Top Banner
842

Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Jul 18, 2018

Download

Documents

dinhnhan
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac
Page 2: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

DevelopingGamesWithRuby

Forthosewhowritecodeforliving

TomasVaraneckas

Page 3: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Thisbookisforsaleathttp://leanpub.com/developing-games-with-ruby

Thisversionwaspublishedon2014-12-16

Page 4: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

*****

ThisisaLeanpubbook.LeanpubempowersauthorsandpublisherswiththeLeanPublishingprocess.LeanPublishingistheactofpublishinganin-progressebookusinglightweighttoolsandmanyiterationstogetreaderfeedback,pivotuntilyouhavetherightbookandbuildtractiononceyoudo.

Page 5: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

*****

©2014TomasVaraneckas

Page 6: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

TableofContents

ABoyWhoWantedToCreateWorlds

WhyRuby?

Page 7: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

WhatYouShouldKnowBeforeReadingThisBook

WhatAreWeGoingToBuild?

GraphicsGameDevelopmentLibrary

Page 8: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ThemeAndMechanics

PreparingTheTools

GettingGosutorunonMacOsX

GettingTheSampleCode

OtherTools

Page 9: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

GosuBasicsHelloWorldScreenCoordinatesAndDepthMainLoopMovingThingsWithKeyboardImagesAndAnimationMusicAndSound

Page 10: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

WarmingUpUsingTilesetsIntegratingWithTexturePackerCombiningTilesIntoAMapUsingTiledToCreateMapsLoadingTiledMapsWith

Page 11: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

GosuGeneratingRandomMapWithPerlinNoisePlayerMovementWithKeyboardAndMouseGameCoordinateSystem

Page 12: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

PrototypingTheGame

SwitchingBetweenGameStatesImplementingMenuStateImplementingPlayStateImplementingWorldMap

Page 13: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingFloatingCameraImplementingTheTankImplementingBulletsAndExplosionsRunningThePrototype

OptimizingGame

Page 14: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

PerformanceProfilingRubyCodeToFindBottlenecksAdvancedProfilingTechniquesOptimizingInefficientCodeProfilingOnDemand

Page 15: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

AdjustingGameSpeedForVariablePerformanceFrameSkipping

RefactoringThePrototype

GameProgrammingPatterns

Page 16: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

WhatIsWrongWithCurrentDesignDecouplingUsingComponentPattern

SimulatingPhysics

AddingEnemy

Page 17: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ObjectsAddingBoundingBoxesAndDetectingCollisionsCatchingBulletsImplementingTurnSpeedPenaltiesImplementingTerrainSpeed

Page 18: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Penalties

ImplementingHealthAndDamage

AddingHealthComponentInflictingDamageWithBullets

Page 19: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

CreatingArtificialIntelligence

DesigningAIUsingFiniteStateMachineImplementingAIVisionControllingTankGunImplementingAIInput

Page 20: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingTankMotionStatesWiringTankMotionStatesIntoFiniteStateMachine

MakingThePrototypePlayable

DrawingWaterBeyond

Page 21: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

MapBoundariesGeneratingTreeClustersGeneratingRandomObjectsImplementingARadarDynamicSoundVolumeAndPanning

Page 22: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

GivingEnemiesIdentityRespawningTanksAndRemovingDeadOnesDisplayingExplosionDamageTrailsDebuggingBulletPhysics

Page 23: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

MakingCameraLookAheadReviewingTheChanges

DealingWithThousandsOfGameObjects

SpatialPartitioningImplementingAQuadtree

Page 24: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

IntegratingObjectPoolWithQuadTreeMovingObjectsInQuadTree

ImplementingPowerups

ImplementingBasePowerup

Page 25: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingPowerupGraphicsImplementingPowerupSoundsImplementingRepairDamagePowerupImplementingHealthBoost

Page 26: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingFireRateBoostImplementingTankSpeedBoostSpawningPowerupsOnMapRespawningPowerupsAfterPickup

Page 27: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingHeadsUpDisplay

DesignConsiderationsRenderingTextWithCustomFontImplementingHUDClass

Page 28: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingGameStatistics

TrackingKills,DeathsandDamageMakingDamagePersonalTrackingDamageFromChainReactions

Page 29: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

DisplayingGameScore

BuildingAdvancedAI

ImprovingTankNavigationImplementingDemoStateToObserveAI

Page 30: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

VisualAIDebuggingMakingAICollectPowerupsSeekingHealthPowerupsAfterHeavyDamageEvadingCollisions

Page 31: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

AndGettingUnstuck

WrappingItUpLessonsLearned

SpecialThanks

Page 32: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ABoyWhoWantedToCreateWorlds

Oncetherewasaboywhofellinlovewiththismagicaldevicethatcouldbringthingstolifeinsideaglaringscreen.Hespentendlesshoursexploringimaginaryworlds,

Page 33: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

fightingstrangecreatures,shootingpixelatedspaceships,racingboxycars.Theboykeptpondering.“Howisthismade?Iwanttocreatemyownworlds…”.

Thenhediscoveredprogramming.“Icanfinallydoit!”-hethought.Andhetried.Andfailed.Thenhetriedharder.Hefailedagainandagain.Hewastoonaivetorealizethatthoseworldshe

Page 34: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

wastryingtocreateweretoosophisticated,andhisknowledgewastoolimited.Hegaveupcreatingthoseworlds.

Whathedidn’tgiveupiswritingcodeforthismagicaldevice.Herealizedheisn’tsmartenoughtocreateworlds,yethefoundouthecouldcreatesimplerthingslikesmallapplications-web,desktop,serversideor

Page 35: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

whatnot.Fewyearslaterhefoundhimselfgettingpaidtomakethose.

Applicationsgotincreasinglybigger,theyspannedacrossmultipleservers,integratedwitheachother,becamepatsofhugeinfrastructures.Theboy,nowagrownman,wasallintoit.Itwasfunandchallengingenoughtospendover10000hourslearning

Page 36: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

andbuildingwhatotherswantedhimtobuild.

Someofthesethingswereuseful,somewhereboringandpointless.Somewereneverfinished.Therewerethingshewasproudof,therewereothersthathewouldn’twanttotalkabout,nonethelesseverythinghebuiltmadehimabetterbuilder.Yetheneverfoundthetime,courageorreasonto

Page 37: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

buildwhathereallywantedtobuildsincehewasalittleboy-hisownworlds.

Untilonedayherealizedthatnoonecanstophimfromfollowinghisdream.Hefeltthatequippedwithhiscurrentknowledgeandexperiencehewillbeabletolearntocreateworldsofhisown.Andhewentforit.

Page 38: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Thisboymustliveinmanysoftwaredevelopers,whodreamaboutcreatinggames,butinsteadselltheirsoftwarecraftsmanshipskillstothosewhoneedsomethingelse.Thisboyisme,andyou.Andit’stimetosethimfree.

Welcometotheworldofgamedevelopmentthatwaswaitingforyoualltheseyears.

Page 39: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

WhyRuby?

Whenitcomestogamedevelopment,everyonewilltellyouthatyoushouldgowithC++orsomeotherstaticallytypedlanguagethatcompilesdowntobaremetalinstructions.Orthatyoushouldgowithfullblowngamedevelopmentplatform

Page 40: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

likeUnity.Slow,dynamiclanguageslikeRubyseemlikethelastchoiceanysanegamedeveloperwouldgofor.

Afriendofminesaid“There’slittlereasontodevelopadesktopgamewithRuby”,andhewasabsolutelyright.Perhapsthisisthereasonwhytherearenobooksaboutit.Allthecasualgameactionhappensinmobiledevices,anddesktop

Page 41: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

gamesareforseasonedgamerswhodemandfastanddetailed3Dgraphics,motion-capturedanimationsandsophisticatedgamemechanics-thingsweknowwearenotgoingtobeabletobuildonourown,withoutmillionsfromVCpocketsandHollywoodgradeequipment.

Now,bearwithme.Yourgamewillnotbea3D

Page 42: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

MMORPGsetinhuge,photorealisticrepresentationofMiddle-earth.Let’sleavethosethingstoBethesda,UbisoftandRockstarGames.Afterall,everyonehastostartsomewhere,andyouhavetobesmartenoughtounderstand,thateventhoughthatlittleboyinyouwantstocreateanimprovedversionofGrandTheftAutoV,wewillhavetogoforsomethingthat

Page 43: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

resembleslesserknownSuperNintendotitlesinstead.

Whynotgomobilethen?Thosedevicesseemperfectforsimplergames.Ifyouareatruegameratheart,youwillagreethattouchscreengamesyoufindinmodernphonesandtabletsareonlygoodforkilling10minutesofyourtimewhiletakingadump.Youhavetofeeltheresistancewhenyouclicka

Page 44: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

button!Screensizealsodoesmatter.Playinganythingonmobilephoneisatortureforthosewhoknowwhatplayingrealgamesshouldfeellike.

So,yourgamewillhavetobesmallenoughforyoutobeabletocompleteit,itwillhavetohavesimple2Dgraphics,andwouldnotrequirethelatestGeForcewithatleast512MBofRAM.Thisfactgivesyouthe

Page 45: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

benefitofchoice.Youdon’thavetoworryaboutperformancethatmuch.Youcanchooseafriendlyandproductivelanguagethatisdesignedforprogrammerhappiness.AndthisiswhereRubystartstoshine.It’sbeautiful,simpleandelegant.Itisclosetopoetry.

Page 46: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

WhatYouShouldKnowBeforeReadingThisBook

Asyoucanreadonthecover,thisbookis“forthosewhowritecodeforliving”.It’snotarequirement,andyouwill

Page 47: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

mostlikelybeabletounderstandeverythingevenifyouareastudentorhobbyist,butthisbookwillnotteachyouhowtobeagoodprogrammer.Ifyouwanttolearnthat,startwithtimelessclassic:ThePragmaticProgrammer:FromJourneymantoMaster.

YoushouldunderstandRubyatleasttosomeextent.Thereareplentyofbooksand

Page 48: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

resourcescoveringthatsubject.TryWhy’sPoignantGuideToRubyorEloquentRuby.Youcanalsolearnitwhilereadingthisbook.Itshouldn’tbetoohard,especiallyifyoualreadywritecodeforliving.Afterallprogramminglanguageismerelyatool,andwhenyoulearnone,othersarerelativelyeasytoswitchto.

Page 49: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Youshouldknowhowtousethecommandline.BasicknowledgeofGitcanalsobehandy.

Youdon’thavetoknowhowtodraworcomposemusic.Wewillusemediathatisavailableforfree.However,knowledgeofgraphicsandaudioeditingsoftwarewon’thurt.

Page 50: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

WhatAreWeGoingToBuild?

Thisquestionisofparamountimportance.Theanswerwillusuallydetermineifyouwilllikelytosucceed.Ifyouwanttooverstepyourboundaries,youwillfail.Itshouldn’tbetooeasyeither.Ifyouknowsomethingabout

Page 51: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

programmingalready,IbetyoucanimplementTicTacToe,butwillyoufeelproudaboutit?Willyoubeabletosay“I’vebuiltaworld!”.Iwouldn’t.

GraphicsTobeginwith,weneedtoknowwhatkindofgraphicsweareaimingfor.Wewillinstantlyruleout3Dforseveralreasons:

Page 52: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Wedon’twanttoincreasethescopeandcomplexityRubymaynotbefastenoughfor3DgamesLearningproper3Dgraphicsprogrammingrequiresreadingaseparatebookthatisseveraltimesthickerthanthisone.

Now,wehavetoswallowourprideandacceptthefactthat

Page 53: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

thegamewillhavesimple2Dgraphics.Therearethreechoicestogofor:

ParallelProjectionTopDownSide-Scrolling

ParallelProjection(thinkFallout1&2)isprettycloseto3Dgraphics,itrequiresdetailedartifyouwantittolookdecent,sowewould

Page 54: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

havearoughstartifwewentforit.

TopDownview(oldtitlesofLegendofZelda)offersplentyoffreedomtoexploretheenvironmentinalldirectionsandrequireslessgraphicaldetail,sincethingslooksimplerfromabove.

SideScrollinggames(SuperMarioBros.)usuallyinvolvesomephysicsrelatedto

Page 55: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

jumpingandrequiremoreefforttolookgood.Feelingofexplorationislimited,sinceyouusuallymovefromlefttorightmostofthetime.

GoingwithTopDownviewwillgiveusachancetocreateourgameworldasopenforexplorationaspossible,whilehavingsimplegraphicsandmovementmechanics.Soundslikethebestchoiceforus.

Page 56: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

IfyouareasbadatdrawingthingsasIam,youcouldstillwonderhowwearegoingtogetourgraphics.Thankfully,thereisthisopengameart.org.It’slikeGitHubofgamemedia,wewillsurelyfindsomethingthere.Italsocontainsaudiosamplesandtracks.

GameDevelopmentLibrary

Page 57: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Implementitallyourselforharnessthepowerofsomegamedevelopmentlibrarythatoffersyouboilerplatesandconvenientaccesstocommonfunctions?Ifyou’relikeme,youwoulddefinitelywanttoimplementitallyourself,butthatmaybethereasonwhyIfailedtomakeadecentgamesomanytimes.

Ifyouwilltrytoimplementitallyourself,youwillmost

Page 58: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

likelyendupreimplementingsomeexistinggamelibrary,poorly.Itwon’ttakelongwhileyoureachapointwhereyouneedtointerfacewithunderlyingoperatingsystemlibrariestogetgraphics.Andguessifthosebindingswillworkinadifferentoperatingsystem?

So,swallowyourprideagain,becausewearegoingtouseanexistinggame

Page 59: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

developmentlibrary.Goodnewsisthatyouwillbeabletoactuallyfinishthegame,anditwillbeportabletoWindows,MacandLinux.Wewillstillhavetobuildourowngameengineforourselvesontopofit,sodon’tthinkitwon’tbefun.

ThereareseveralgamelibrariesavailableforRuby,butit’sasimplechoice,becauseGosuisheadand

Page 60: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

shouldersaboveothers.It’sverymature,hasalargeandactivecommunity,anditismainlywritteninC++buthasfirstclassRubysupport,soitwillbebothfastandconvenienttouse.

ManyofotherRubygamelibrariesarebuiltontopofGosu,soit’sasolidchoice.

Page 61: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ThemeAndMechanicsChoosingtherightthemeisundoubtedlyimportant.Itshouldbesomethingthatappealstoyou,somethingyouwillwanttoplay,anditshouldnotimplydifficultgamemechanics.IloveMMORPGs,andIalwaysdreamedofmakinganopenworldgamewhereyoucan

Page 62: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

roamaround,meetotherplayers,fightmonstersandlevelup.GuesshowmanytimesIstartedbuildingsuchagame?EvenifIwouldn’thavelostthecount,Iwouldn’tbeproudtosaythenumber.

Thistime,equippedwithlogicandsanity,I’vepickedsomethingchallengingenough,yetstillprettysimpletobuild.Areyouready?

Page 63: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Drumroll…

Wewillbebuildingamultidirectionalshooterarcadegamewhereyoucontrolatank,roamaroundanisland,shootenemytanksandtrynottogetdestroyedbyothers.

IfyouhaveplayedBattleCityorTankForce,youshouldeasilygettheidea.Ibelievethatimplementingsuchagame(withseveraltwists)

Page 64: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

wouldexposeustoperfectlevelofdifficultyandprovidesubstantialamountofexperience.

Wewilluseasubsetofthesegorgeousgraphicswhichareavailableonopengameart.org,generouslyprovidedbyCsabaFelvegi.

Page 65: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

PreparingTheTools

Whilewritingthisbook,IwillbeusingMacOSX(10.9),butitshouldbepossibletorunalltheexamplesonotheroperatingsystemstoo.

Page 66: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

GosuWikihas“GettingStarted”pagesforMac,LinuxandWindows,soIwillnotbegoingintomuchdetailhere.

GettingGosutorunonMacOsXIfyouhaven’tsetupyourMacfordevelopment,firstinstallXcodeusingAppStore.SystemRubyshould

Page 67: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

workjustfine,butyoumaywanttouseRbenvorRVMtoavoidpollutingsystemRuby.I’vehadtroubleinstallingGosuwithRVM,butyourexperiencemayvary.

Toinstallthegem,simplyrun:

$geminstallgosu

Youmayneedtoprefixitwithsudoifyouareusing

Page 68: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

systemRuby.

Totestifgemwasinstalledcorrectly,youshouldbeabletorunthistoproduceanemptyblackwindow:

$irbirb(main):001:0>require'gosu'=>trueirb(main):002:0>Gosu::Window.new(320,240,false).show=>nil

Page 69: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

MostdeveloperswhouseMaceverydaywillalsorecommendinstallingHomebrewpackagemanager,replaceTerminalappwithiTerm2anduseOh-My-ZshtomanageZSHconfiguration.

Page 70: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

GettingTheSampleCode

YoucanfindsamplecodeatGitHub:https://github.com/spajus/ruby-gamedev-book-examples.

Cloneittoaconvenientlocation:

Page 71: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

$cd~/[email protected]:spajus/ruby-gamedev-book-examples.git

Thesourcecodeoffinalproductcanbefoundathttps://github.com/spajus/tank_island

Page 72: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

OtherTools

Allyouneedforthisadventureisagoodtexteditor,terminalandprobablysomegraphicseditor.TryGIMPifyouwantafreeone.I’musingPixelmator,it’swonderful,butforMaconly.Anoteworthyfactisthat

Page 73: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

PixelmatorwasbuiltbyfellowLithuanians.

Whenitcomestoeditors,Idon’tleavehomewithoutVim,butaslongaswhatyouusemakesyouproductive,itdoesn’tmakeanydifference.Vim,EmacsorSublimeareallgoodenoughtowritecode,justhavesomegoodpluginsthatsupportRuby,andyou’reset.IfyoureallyfeelyouneedanIDE,which

Page 74: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

maybethecaseifyouarecomingfromastaticlanguage,youcan’tgowrongwithRubyMine.

Page 75: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

GosuBasics

BynowGosushouldbeinstalledandreadyforaspin.Butbeforewerushintobuildingourgame,wehavetogetacquaintedwithourlibrary.Wewillgothroughseveralsimpleexamples,familiarizeourselveswithGosuarchitectureandcore

Page 76: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

principles,andtakeacoupleofbabystepstowardsunderstandinghowtoputeverythingtogether.

Tomakethischaptereasiertoreadandunderstand,IrecommendwatchingWritingGamesWithRubytalkgivenbyMikeMooreatLARubyConference2014.Infact,thistalkpushedmetowardsrethinkingthiscrazyideaofusingRubyforgame

Page 77: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

development,sothisbookwouldn’texistwithoutit.Thankyou,Mike.

HelloWorldTohonorthetraditions,wewillstartbywriting“HelloWorld”togetatasteofwhatGosufeelslike.ItisbasedonRubyTutorialthatyoucanfindinGosuWiki.01-hello/hello_world.rb

Page 78: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1require'gosu'23classGameWindow<Gosu::Window4definitialize(width=320,height=240,fullscreen=false)5super6self.caption='Hello'7@message=Gosu::Image.from_text(8self,'Hello,World!',Gosu.default_font_name,30)[email protected](10,10,0)13end14end1516window=GameWindow.new17window.show

Page 79: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Runthecode:

$ruby01-hello/hello_world.rb

Youshouldseeaneatsmallwindowwithyourmessage:

Page 80: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

HelloWorld

Seehoweasythatwas?Nowlet’strytounderstandwhatjusthappenedhere.

Page 81: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

WehaveextendedGosu::WindowwithourownGameWindowclass,initializingitas320x240window.superpassedwidth,heightandfullscreeninitializationparametersfromGameWindowtoGosu::Window.

Thenwedefinedourwindow’scaption,andcreated@messageinstancevariablewithanimagegeneratedfromtext"Hello,

Page 82: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

World!"usingGosu::Image.from_text.

WehaveoverriddenGosu::Window#drawinstancemethodthatgetscalledeverytimeGosuwantstoredrawourgamewindow.Inthatmethodwecalldrawonour@messagevariable,providingxandyscreencoordinatesbothequalto10,andz(depth)valueequalto0.

Page 83: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ScreenCoordinatesAndDepthJustlikemostconventionalcomputergraphicslibraries,Gosutreatsxashorizontalaxis(lefttoright),yasverticalaxis(toptobottom),andzasorder.

Page 84: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Screencoordinatesanddepth

xandyaremeasuredinpixels,andvalueofzisarelativenumberthatdoesn’tmeananythingonit’sown.Thepixelintop-leftcornerof

Page 85: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

thescreenhascoordinatesof0:0.

zorderinGosuisjustlikez-indexinCSS.Itdoesnotdefinezoomlevel,butincasetwoshapesoverlap,onewithhigherzvaluewillbedrawnontop.

MainLoopTheheartofGosulibraryisthemainloopthathappensin

Page 86: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Gosu::Window.ItisexplainedfairlywellinGosuwiki,sowewillnotbediscussingithere.

MovingThingsWithKeyboardWewillmodifyour“Hello,World!”exampletolearnhowtomovethingsonscreen.Thefollowingcodewillprintcoordinatesofthe

Page 87: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

messagealongwithnumberoftimesscreenwasredrawn.ItalsoallowsexitingtheprogrambyhittingEscbutton.01-hello/hello_movement.rb1require'gosu'23classGameWindow<Gosu::Window4definitialize(width=320,height=240,fullscreen=false)5super6self.caption='HelloMovement'7@x=@y=108@draws=0

Page 88: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

9@buttons_down=010end1112defupdate13@x-=1ifbutton_down?(Gosu::KbLeft)14@x+=1ifbutton_down?(Gosu::KbRight)15@y-=1ifbutton_down?(Gosu::KbUp)16@y+=1ifbutton_down?(Gosu::KbDown)17end1819defbutton_down(id)20closeifid==Gosu::KbEscape21@buttons_down+=122end2324defbutton_up(id)

Page 89: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

25@buttons_down-=126end2728defneeds_redraw?29@draws==0||@buttons_down>030end3132defdraw33@draws+=134@message=Gosu::Image.from_text(35self,info,Gosu.default_font_name,30)[email protected](@x,@y,0)37end3839private4041definfo42"[x:#{@x};y:#

Page 90: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

{@y};draws:#{@draws}]"43end44end4546window=GameWindow.new47window.show

Runtheprogramandtrypressingarrowkeys:

$ruby01-hello/hello_movement.rb

Themessagewillmovearoundaslongasyoukeeparrowkeyspressed.

Page 91: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Usearrowkeystomovethemessagearound

Wecouldwriteashorterversion,butthepointhereisthatifwewouldn’toverride

Page 92: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

needs_redraw?thisprogramwouldbeslowerbyorderofmagnitude,becauseitwouldcreate@messageobjecteverytimeitwantstoredrawthewindow,eventhoughnothingwouldchange.

Hereisascreenshotoftopdisplayingtwoversionsofthisprogram.Secondscreenhasneeds_redraw?methodremoved.Seethedifference?

Page 93: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

RedrawingonlywhennecessaryVSredrawingeverytime

Rubyisslow,soyouhavetouseitwisely.

ImagesAndAnimation

Page 94: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

It’stimetomakesomethingmoreexciting.Ourgamewillhavetohaveexplosions,thereforeweneedtolearntoanimatethem.Wewillsetupabackgroundsceneandtriggerexplosionsontopofitwithourmouse.01-hello/hello_animation.rb1require'gosu'23defmedia_path(file)4File.join(File.dirname(File.dirname

Page 95: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

5__FILE__)),'media',file)6end78classExplosion9FRAME_DELAY=10#ms10SPRITE=media_path('explosion.png')1112defself.load_animation(window)13Gosu::Image.load_tiles(14window,SPRITE,128,128,false)15end1617definitialize(animation,x,y)18@animation=animation19@x,@y=x,y20@current_frame=0

Page 96: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

21end2223defupdate24@current_frame+=1ifframe_expired?25end2627defdraw28returnifdone?29image=current_frame30image.draw([email protected]/2.0,[email protected]/2.0,330)34end3536defdone?37@done||=@[email protected]

Page 97: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

38end3940private4142defcurrent_frame43@animation[@current_frame%@animation.size]44end4546defframe_expired?47now=Gosu.milliseconds48@last_frame||=now49if(now-@last_frame)>FRAME_DELAY50@last_frame=now51end52end53end5455classGameWindow<

Page 98: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Gosu::Window56BACKGROUND=media_path('country_field.png')5758definitialize(width=800,height=600,fullscreen=false)59super60self.caption='HelloAnimation'61@background=Gosu::Image.new(62self,BACKGROUND,false)63@animation=Explosion.load_animation(self)64@explosions=[][email protected]!(&:done?)

Page 99: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected](&:update)70end7172defbutton_down(id)73closeifid==Gosu::KbEscape74ifid==Gosu::[email protected](76Explosion.new(77@animation,mouse_x,mouse_y))78end79end8081defneeds_cursor?82true83end8485defneeds_redraw?86!@scene_ready||

Page 100: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@explosions.any?87end8889defdraw90@scene_ready||[email protected](0,0,0)[email protected](&:draw)93end94end9596window=GameWindow.new97window.show

Runitandclickaroundtoenjoythosebeautifulspecialeffects:

Page 101: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

$ruby01-hello/hello_animation.rb

Page 102: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Multipleexplosionsonscreen

Nowlet’sfigureouthowitworks.OurGameWindowinitializeswith@backgroundGosu::Imageand

Page 103: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@animation,thatholdsarrayofGosu::Imageinstances,oneforeachframeofexplosion.Gosu::Image.load_tiles

handlesitforus.

Explosion::SPRITEpointsto“tileset”image,whichisjustaregularimagethatcontainsequallysizedsmallerimageframesarrangedinorderedsequence.Rowsofframesare

Page 104: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

readlefttoright,likeyouwouldreadabook.

Page 105: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Explosiontileset

Giventhatexplosion.pngtilesetis1024x1024pixels

Page 106: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

big,andithas8rowsof8tilesperrow,itiseasytotellthatthereare64tiles128x128pixelseach.So,@animation[0]holds128x128Gosu::Imagewithtop-lefttile,and@animation[63]-thebottom-rightone.

Gosudoesn’thandleanimation,it’ssomethingyouhavefullcontrolover.Wehavetodraweachtileina

Page 107: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

sequenceourselves.YoucanalsousetilestoholdmapgraphicsThelogicbehindthisisprettysimple:

1. Explosionknowsit’s@current_frame

number.Itbeginswith0.2. Explosion#frame_expired?

checksthelasttimewhen@current_framewasrendered,andwhenitisolderthanExplosion::FRAME_DELAY

Page 108: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

milliseconds,@current_frameisincreased.

3. WhenGameWindow#updateiscalled,@[email protected],explosionsthathavefinishedtheiranimation(displayedthelastframe)areremovedfrom@explosionsarray.

Page 109: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

4. GameWindow#drawdrawsbackgroundimageandall@explosionsdrawtheircurrent_frame.

5. Again,wearesavingresourcesandnotredrawingwhenthereareno@explosionsinprogress.needs_redraw?handlesit.

Itisimportanttounderstandthatupdateanddraworderis

Page 110: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

unpredictable,thesemethodscanbecalledbyyoursystematdifferentrate,youcan’ttellwhichonewillbecalledmoreoftenthantheotherone,soupdateshouldonlybeconcernedwithadvancingobjectstate,anddrawshouldonlydrawcurrentstateonscreenifitisneeded.Theonlyreliablethinghereistime,consultGosu.millisecondstoknowhowmuchtimehavepassed.

Page 111: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Ruleofthethumb:drawshouldbeaslightweightaspossible.Prepareallcalculationsinupdateandyouwillhaveresponsive,smoothgraphics.

MusicAndSoundOurpreviousprogramwasclearlymissingasoundtrack,sowewilladdone.Abackgroundmusicwillbe

Page 112: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

looping,andeachexplosionwillbecomeaudible.01-hello/hello_sound.rb1require'gosu'23defmedia_path(file)4File.join(File.dirname(File.dirname

5__FILE__)),'media',file)6end78classExplosion9FRAME_DELAY=10#ms10SPRITE=media_path('explosion.png')11

Page 113: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

12defself.load_animation(window)13Gosu::Image.load_tiles(14window,SPRITE,128,128,false)15end1617defself.load_sound(window)18Gosu::Sample.new(19window,media_path('explosion.mp3'))20end2122definitialize(animation,sound,x,y)23@animation=animation24sound.play25@x,@y=x,y26@current_frame=027end

Page 114: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

2829defupdate30@current_frame+=1ifframe_expired?31end3233defdraw34returnifdone?35image=current_frame36image.draw([email protected]/2.0,[email protected]/2.0,390)40end4142defdone?43@done||=@[email protected]

Page 115: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]_frame53@animation[@current_frame%@animation.size]54end5556defframe_expired?57now=Gosu.milliseconds58@last_frame||=now59if(now-@last_frame)>FRAME_DELAY60@last_frame=now61end

Page 116: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

62end63end6465classGameWindow<Gosu::Window66BACKGROUND=media_path('country_field.png')6768definitialize(width=800,height=600,fullscreen=false)69super70self.caption='HelloAnimation'71@background=Gosu::Image.new(72self,BACKGROUND,false)73@music=Gosu::Song.new(74self,media_path('menu_music.mp3'))

Page 117: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected][email protected](true)77@animation=Explosion.load_animation(self)78@sound=Explosion.load_sound(self)79@explosions=[][email protected]!(&:done?)[email protected](&:update)85end8687defbutton_down(id)88closeifid==Gosu::KbEscape89ifid==Gosu::[email protected](

Page 118: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

91Explosion.new(92@animation,@sound,mouse_x,mouse_y))93end94end9596defneeds_cursor?97true98end99100defneeds_redraw?101!@scene_ready||@explosions.any?102end103104defdraw105@scene_ready||[email protected](0,0,0)[email protected](&:draw)108end

Page 119: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

109end110111window=GameWindow.new112window.show

Runitandenjoythecinematicexperience.Addingsoundreallymakesadifference.

$ruby01-hello/hello_sound.rb

Weonlyaddedcoupleofthingsoverpreviousexample.

Page 120: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

72@music=Gosu::Song.new(73self,media_path('menu_music.mp3'))[email protected][email protected](true)

GameWindowcreatesGosu::Songwithmenu_music.mp3,adjuststhevolumesoit’salittlemorequietandstartsplayinginaloop.

16defself.load_sound(window)17Gosu::Sample.new(18window,

Page 121: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

media_path('explosion.mp3'))19end

Explosionhasnowgotload_soundmethodthatloadsexplosion.mp3soundeffectGosu::Sample.ThissoundeffectisloadedonceinGameWindowconstructor,andpassedintoeverynewExplosion,whereitsimplystartsplaying.

Page 122: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

HandlingaudiowithGosuisverystraightforward.UseGosu::Songtoplaybackgroundmusic,andGosu::Sampletoplayeffectsandsoundsthatcanoverlap.

Page 123: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

WarmingUp

Beforewestartbuildingourgame,wewanttoflexourskillslittlemore,gettoknowGosubetterandmakesureourtoolswillbeabletomeetourexpectations.

UsingTilesets

Page 124: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

AfterplayingaroundwithGosuforawhile,weshouldbecomfortableenoughtoimplementaprototypeoftop-downviewgamemapusingthetilesetofourchoice.Thisgroundtilesetlookslikeagoodplacetostart.

IntegratingWithTexturePacker

Page 125: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Afterdownloadingandextractingthetileset,it’sobviousthatGosu::Image#load_tiles

willnotsuffice,sinceitonlysupportstilesofsamesize,andthereisatilesetinthepackagethatlookslikethis:

Page 126: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac
Page 127: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tilesetwithtilesofirregularsize

AndthereisalsoaJSONfilethatcontainssomemetadata:

{"frames":{"aircraft_1d_destroyed.png":{"frame":{"x":451,"y":102,"w":57,"h":42},

"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":57,"h":42},"sourceSize":{"w":57,"h":42}},"aircraft_2d_destroyed.png":{"frame":

Page 128: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

{"x":2,"y":680,"w":63,"h":47},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":63,"h":47},"sourceSize":{"w":63,"h":47}},...}},"meta":{ "app":"http://www.texturepacker.com", "version":"1.0", "image":"decor.png", "format":"RGBA8888", "size":{"w":512,"h":1024}, "scale":"1", "smartupdate":"$TexturePacker:SmartUpdate:2e6b6964f24c7abfaa85a804e2dc1b05$"

Page 129: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

}

LookslikethesetileswerepackedwithTexturePacker.AftersomediggingI’vediscoveredthatGosudoesn’thaveanyintegrationwithit,soIhadthesechoices:

1. Cuttheoriginaltilesetimageintosmallerimages.

Page 130: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

2. ParseJSONandharnessthebenefitsofTexturePacker.

Firstoptionwastoomuchworkandwouldprovetobelessefficient,becauseloadingmanysmallfilesisalwaysworsethanloadingonebiggerfile.Therefore,secondoptionwasthewinner,andIalsothought“whynotwriteagemwhileI’matit”.Andthat’sexactlywhatIdid,and

Page 131: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

youshoulddothesameinsuchasituation.ThegemisavailableonGitHub:

https://github.com/spajus/gosu-texture-packer

Youcaninstallthisgemusinggeminstallgosu_texture_packer.Ifyouwanttoexaminethecode,easiestwayistocloneitonyourcomputer:

Page 132: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]:spajus/gosu-texture-packer.git

Let’sexaminethemainideabehindthisgem.Hereisaslightlysimplifiedversionthatdoeshandleseverythinginunder20linesofcode:02-warmup/tileset.rb1require'json'2classTileset3definitialize(window,json)4@json=JSON.parse(File.read(json))

Page 133: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

5image_file=File.join(6File.dirname(json),@json['meta']['image'])7@main_image=Gosu::Image.new(8@window,image_file,true)9end1011defframe(name)12f=@json['frames'][name]['frame']13@main_image.subimage(14f['x'],f['y'],f['w'],f['h'])15end16end

Page 134: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

IfbynowyouarefamiliarwithGosudocumentation,youwillwonderwhatthehellisGosu::Image#subimage.Atthepointofwritingitwasnotdocumented,andIaccidentallydiscovereditwhilediggingthroughGosusourcecode.

I’mluckythisfunctionexisted,becauseIwasreadytobringouttheheavyartilleryanduseRMagickto

Page 135: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

extractthosetiles.WewillprobablyneedRMagickatsomepointoftimelater,butit’sbettertoavoiddependenciesaslongaspossible.

CombiningTilesIntoAMapWithtilesetloadingissueoutoftheway,wecanfinallyget

Page 136: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

backtodrawingthatcoolmapofours.

Thefollowingprogramwillfillthescreenwithrandomtiles.02-warmup/random_map.rb1require'gosu'2require'gosu_texture_packer'34defmedia_path(file)5File.join(File.dirname(File.dirname

6__FILE__)),'media',

Page 137: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

file)7end89classGameWindow<Gosu::Window10WIDTH=80011HEIGHT=60012TILE_SIZE=1281314definitialize15super(WIDTH,HEIGHT,false)16self.caption='RandomMap'17@tileset=Gosu::TexturePacker.load_json(18self,media_path('ground.json'),:precise)19@redraw=true20end

Page 138: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

2122defbutton_down(id)23closeifid==Gosu::KbEscape24@redraw=trueifid==Gosu::KbSpace25end2627defneeds_redraw?28@redraw29end3031defdraw32@redraw=false33(0..WIDTH/TILE_SIZE).eachdo|x|34(0..HEIGHT/TILE_SIZE).eachdo|y|[email protected]([email protected]_list.sample).draw

Page 139: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

37x*(TILE_SIZE),38y*(TILE_SIZE),390)40end41end42end43end4445window=GameWindow.new46window.show

Runit,thenpressspacebartorefillthescreenwithrandomtiles.

$ruby02-warmup/random_map.rb

Page 140: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Mapfilledwithrandomtiles

Theresultdoesn’tlookseamless,sowewillhavetofigureoutwhat’swrong.Afterplayingaroundfora

Page 141: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

while,I’venoticedthatit’sanissuewithGosu::Image.

Whenyouloadatilelikethis,itworksperfectly:

Gosu::Image.new(self,image_path,true,0,0,128,128)Gosu::Image.load_tiles(self,image_path,128,128,true)

Andthefollowingproducessocalled“texturebleeding”:

Page 142: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Gosu::Image.new(self,image_path,true)Gosu::Image.new(self,image_path,true).subimage(0,0,128,128)

Goodthingwe’renotbuildingourgameyet,right?Welcometotheintricaciesofsoftwaredevelopment!

Now,Ihavereportedmyfindings,butuntilitgetsfixed,weneedaworkaround.Andtheworkaroundwasto

Page 143: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

useRMagick.Iknewwewon’tgettoofarawayfromit.Butourrandommapnowlooksgorgeous:

Page 144: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Mapfilledwithseamlessrandomtiles

UsingTiledToCreateMaps

Page 145: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Whilelowlevelapproachtodrawingtilesinscreenmaybeappropriateinsomescenarios,likerandomlygeneratedmaps,wewillexploreanotheralternatives.Oneofthemisthisgreat,opensource,crossplatform,generictilemapeditorcalledTiled.

Ithassomelimitations,forinstance,alltilesintilesethavetobeofsame

Page 146: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

proportions.Ontheupside,itwouldbeeasytoloadTiledtilesetswithGosu::Image#load_tiles.

Page 147: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tiled

Tiledusesit’sowncustom,XMLbasedtmxformatforsavingmaps.ItalsoallowsexportingmapstoJSON,whichiswaymore

Page 148: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

convenient,sinceparsingXMLinRubyisusuallydonewithNokogiri,whichisheavierandit’snativeextensionsusuallycausemoretroublethanonesJSONparseruses.So,let’sseehowthatJSONlookslike:02-warmup/tiled_map.json1{"height":10,2"layers":[3{4"data":[65,65,65,65,65,65,65,65,65,65,65,65,65,0,0,65,6\

Page 149: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

55,65,65,65,65,65,65,0,0,65,65,65,65,65,65,65,65,0,0,0,65,65\6,65,65,65,65,65,0,0,0,0,65,65,65,65,65,65,0,0,0,0,65,65,65\7,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65\8,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65\9],10"height":10,11"name":"Water",12"opacity":1,13"type":"tilelayer",14"visible":true,15"width":10,16"x":0,17"y":0

Page 150: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

18},19{20"data":[0,0,7,5,57,43,0,0,0,0,0,0,28,1,1,42,0,0,0,0,\210,0,44,1,1,42,0,0,0,0,0,0,28,1,1,27,43,0,0,0,0,0,28,1,1\22,1,27,43,0,0,0,0,28,1,1,1,59,16,0,0,0,0,48,62,61,61,16,0,\230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\24,0,0,0,0,0],25"height":10,26"name":"Ground",27"opacity":1,28"type":"tilelayer",29"visible":true,30"width":10,

Page 151: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

31"x":0,32"y":033}],34"orientation":"orthogonal",35"properties":36{3738},39"tileheight":128,40"tilesets":[41{42"firstgid":1,43"image":"media\/ground.png",44"imageheight":1024,45"imagewidth":1024,46"margin":0,47"name":"ground",48"properties":49{50

Page 152: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

51},52"spacing":0,53"tileheight":128,54"tilewidth":12855},56{57"firstgid":65,58"image":"media\/water.png",59"imageheight":128,60"imagewidth":128,61"margin":0,62"name":"water",63"properties":64{6566},67"spacing":0,68"tileheight":128,69"tilewidth":12870}],

Page 153: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

71"tilewidth":128,72"version":1,73"width":1074}

Therearefollowingthingslistedhere:

Twodifferenttilesets,“ground”and“water”Mapwidthandheightintilecount(10x10)Layerswithdataarraycontainstilenumbers

Page 154: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

CoupleofextrathingsthatTiledmapscanhave:

ObjectlayerscontaininglistsofobjectswiththeircoordinatesPropertieshashontilesandobjects

Thisdoesn’tlooktoodifficulttoparse,sowe’regoingtoimplementaloaderforTiledmaps.Andmakeitopensource,ofcourse.

Page 155: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

LoadingTiledMapsWithGosuProbablytheeasiestwaytoloadTiledmapistotakeeachlayerandrenderitonscreen,tilebytile,likeacake.Wewillnotcareaboutcachingatthispoint,andtheonlyoptimizationwouldbenotdrawingthingsthatareoutofscreenboundaries.

Page 156: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Aftercoupleofdaysoftestdrivendevelopment,I’veendedupwritinggosu_tiledgem,thatallowsyoutoloadTiledmapswithjustafewlinesofcode.

Iwillnotgothroughdescribingtheimplementation,butifyouwanttoexaminethethoughtprocess,takealookatgosu_tiledgem’sgitcommithistory.

Page 157: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tousethegem,dogeminstallgosu_tiledandexaminethecodethatshowsamapoftheislandthatyoucanscrollaroundwitharrowkeys:02-warmup/island.rb1require'gosu'2require'gosu_tiled'34classGameWindow<Gosu::Window5MAP_FILE=File.join(File.dirname(6__FILE__),'island.json')

Page 158: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

7SPEED=589definitialize10super(640,480,false)11@map=Gosu::Tiled.load_json(self,MAP_FILE)12@x=@y=013@first_render=true14end1516defbutton_down(id)17closeifid==Gosu::KbEscape18end1920defupdate21@x-=SPEEDifbutton_down?(Gosu::KbLeft)22@x+=SPEEDifbutton_down?(Gosu::KbRight)

Page 159: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

23@y-=SPEEDifbutton_down?(Gosu::KbUp)24@y+=SPEEDifbutton_down?(Gosu::KbDown)25self.caption="#{Gosu.fps}FPS.Usearrowkeystopan"26end2728defdraw29@[email protected](@x,@y)31end3233defneeds_redraw?34[Gosu::KbLeft,35Gosu::KbRight,36Gosu::KbUp,37Gosu::KbDown].eachdo|b|38returntrueif

Page 160: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

button_down?(b)39end40@first_render41end42end4344GameWindow.new.show

Runit,usearrowkeystoscrollthemap.

$ruby02-warmup/island.rb

Theresultisquitesatisfying,anditscrollssmoothlywithoutanyoptimizations:

Page 161: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ExploringTiledmapinGosu

GeneratingRandomMapWithPerlin

Page 162: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

NoiseInsomecasesrandomgeneratedmapsmakeallthedifference.WormsandDiablowouldprobablybejustaveragegamesifitwasn’tforthosealwaysunique,procedurallygeneratedmaps.

Wewilltrytomakeaveryprimitivemapgeneratorourselves.Tobeginwith,we

Page 163: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

willbeusingonly3differenttiles-water,sandandgrass.Forimplementingfullytilededges,thegeneratormustbeawareofavailabletilesetsandknowhowtocombinetheminvalidways.Wemaycomebacktoit,butfornowlet’skeepthingssimple.

Now,generatingnaturallylookingrandomnessissomethingworthhavingabookofit’sown,soinstead

Page 164: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

oftryingtopoorlyreinventwhatotherpeoplehavealreadydone,wewilluseawellknownalgorithmperfectlysuitedforthistask-Perlinnoise.

IfyouhaveeverusedPhotoshop’sCloudfilter,youalreadyknowhowPerlinnoiselookslike:

Page 165: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Perlinnoise

Now,wecouldimplementthealgorithmourselves,butthere

Page 166: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

isperlin_noisegemalreadyavailable,itlooksprettysolid,sowewilluseit.

Thefollowingprogramgenerates100x100mapwith30%chanceofwater,15%chanceofsandand55%chanceofgrass:02-warmup/perlin_noise_map.rb1require'gosu'2require'gosu_texture_packer'3require'perlin_noise'4

Page 167: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

5defmedia_path(file)6File.join(File.dirname(File.dirname

7__FILE__)),'media',file)8end910classGameWindow<Gosu::Window11MAP_WIDTH=10012MAP_HEIGHT=10013WIDTH=80014HEIGHT=60015TILE_SIZE=1281617definitialize18super(WIDTH,HEIGHT,false)19load_tiles20@map=generate_map

Page 168: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

21@zoom=0.222end2324defbutton_down(id)25closeifid==Gosu::KbEscape26@map=generate_mapifid==Gosu::KbSpace27end2829defupdate30adjust_zoom(0.005)ifbutton_down?(Gosu::KbDown)31adjust_zoom(-0.005)ifbutton_down?(Gosu::KbUp)32set_caption33end3435defdraw36tiles_x.timesdo|x|37tiles_y.timesdo|y|

Page 169: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

38@map[x][y].draw(39x*TILE_SIZE*@zoom,40y*TILE_SIZE*@zoom,410,42@zoom,43@zoom)44end45end46end4748private4950defset_caption51self.caption='PerlinNoise.'<<52"Zoom:#{'%.2f'%@zoom}."<<53'UseUp/Downtozoom.Spacetoregenerate.'

Page 170: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

54end5556defadjust_zoom(delta)57new_zoom=@zoom+delta58ifnew_zoom>0.07&&new_zoom<259@zoom=new_zoom60end61end6263defload_tiles64tiles=Gosu::Image.load_tiles(65self,media_path('ground.png'),128,128,true)66@sand=tiles[0]67@grass=tiles[8]68@water=Gosu::Image.new(

Page 171: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

69self,media_path('water.png'),true)70end7172deftiles_x73count=(WIDTH/(TILE_SIZE*@zoom)).ceil+174[count,MAP_WIDTH].min75end7677deftiles_y78count=(HEIGHT/(TILE_SIZE*@zoom)).ceil+179[count,MAP_HEIGHT].min80end8182defgenerate_map83noises=Perlin::Noise.new(2)84contrast=Perlin::Curve.contrast(

Page 172: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

85Perlin::Curve::CUBIC,2)86map={}87MAP_WIDTH.timesdo|x|88map[x]={}89MAP_HEIGHT.timesdo|y|90n=noises[x*0.1,y*0.1]91n=contrast.call(n)92map[x][y]=choose_tile(n)93end94end95map96end9798defchoose_tile(val)99caseval100when0.0..0.3#30%

Page 173: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]#15%chance,wateredges103@sand104else#55%chance105@grass106end107end108109end110111window=GameWindow.new112window.show

Runtheprogram,zoomwithup/downarrowsand

Page 174: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

regenerateeverythingwithspacebar.

$ruby02-warmup/perlin_noise_map.rb

Page 175: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

MapgeneratedwithPerlinnoise

Thisisalittlelongerthanourpreviousexamples,sowewillanalyzesomepartstomakeitclear.

Page 176: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

81defgenerate_map82noises=Perlin::Noise.new(2)83contrast=Perlin::Curve.contrast(84Perlin::Curve::CUBIC,2)85map={}86MAP_WIDTH.timesdo|x|87map[x]={}88MAP_HEIGHT.timesdo|y|89n=noises[x*0.1,y*0.1]90n=contrast.call(n)91map[x][y]=choose_tile(n)92end93end94map95end

Page 177: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

generate_mapistheheartofthisprogram.ItcreatestwodimensionalPerlin::Noisegenerator,thenchoosesarandomtileforeachlocationofthemap,accordingtonoisevalue.Tomakethemapalittlesharper,cubiccontrastisappliedtonoisevaluebeforechoosingthetile.Trycommentingoutcontrastapplication-itwilllooklikeaboringgolfcourse,since

Page 178: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

noisevalueswillkeepbuzzingaroundthemiddle.

97defchoose_tile(val)98caseval99when0.0..0.3#30%[email protected]#15%chance,wateredges102@sand103else#55%chance104@grass105end106end

Herewecouldgocrazyifwehadmoredifferenttilesto

Page 179: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

use.Wecouldadddeepwatersat0.0..0.1,mountainsat0.9..0.95andsnowcapsat0.95..1.0.Andallthiswouldhavebeautifultransitions.

PlayerMovementWithKeyboardAndMouseWehavelearnedtodrawmaps,butweneeda

Page 180: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

protagonisttoexplorethem.ItwillbeatankthatyoucanmovearoundtheislandwithWASDkeysanduseyourmousetotargetit’sgunatthings.Thetankwillbedrawnontopofourislandmap,anditwillbeaboveground,butbelowtreelayer,soitcansneakbehindpalmtrees.That’sasclosetorealdealasitgets!02-warmup/player_movement.rb

Page 181: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1require'gosu'2require'gosu_tiled'3require'gosu_texture_packer'45classTank6attr_accessor:x,:y,:body_angle,:gun_angle78definitialize(window,body,shadow,gun)9@x=window.width/210@y=window.height/211@window=window12@body=body13@shadow=shadow14@gun=gun15@body_angle=0.016@gun_angle=0.017end18

Page 182: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

19defupdate20atan=Math.atan2([email protected]_x,[email protected]_y)22@gun_angle=-atan*180/Math::PI23@body_angle=change_angle(@body_angle,24Gosu::KbW,Gosu::KbS,Gosu::KbA,Gosu::KbD)[email protected]_rot(@x-1,@y-1,0,@body_angle)[email protected]_rot(@x,@y,1,@body_angle)[email protected]_rot(@x,@y,2,@gun_angle)31end

Page 183: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

3233private3435defchange_angle(previous_angle,up,down,right,left)[email protected]_down?(up)[email protected]_down?(left)[email protected]_down?(right)[email protected]_down?(down)[email protected]_down?(left)[email protected]_down?(right)44elsif

Page 184: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@window.button_down?(left)[email protected]_down?(up)[email protected]_down?(down)[email protected]_down?(right)[email protected]_down?(up)[email protected]_down?(down)52end53angle||previous_angle54end55end5657classGameWindow<Gosu::Window58MAP_FILE=

Page 185: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

File.join(File.dirname(59__FILE__),'island.json')60UNIT_FILE=File.join(File.dirname(File.dirname

61__FILE__)),'media','ground_units.json')62SPEED=56364definitialize65super(640,480,false)66@map=Gosu::Tiled.load_json(self,MAP_FILE)67@units=Gosu::TexturePacker.load_json(68self,UNIT_FILE,:precise)69@tank=Tank.new(self,70

Page 186: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@units.frame('tank1_body.png'),[email protected]('tank1_body_shadow.png'

[email protected]('tank1_dualgun.png'

73@x=@y=074@first_render=true75@buttons_down=076end7778defneeds_cursor?79true80end8182defbutton_down(id)83closeifid==Gosu::KbEscape84@buttons_down+=185end

Page 187: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

8687defbutton_up(id)88@buttons_down-=189end9091defupdate92@x-=SPEEDifbutton_down?(Gosu::KbA)93@x+=SPEEDifbutton_down?(Gosu::KbD)94@y-=SPEEDifbutton_down?(Gosu::KbW)95@y+=SPEEDifbutton_down?(Gosu::KbS)[email protected]="#{Gosu.fps}FPS."<<98'UseWASDandmousetocontroltank'99end100

Page 188: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

101defdraw102@[email protected](@x,@y)[email protected]()105end106end107108GameWindow.new.show

Tankspriteisrenderedinthemiddleofscreen.Itconsistsofthreelayers,bodyshadow,bodyandgun.Bodyandit’sshadowarealwaysrenderedinsameangle,oneontopofanother.Theangleis

Page 189: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

determinedbykeysthatarepressed.Itsupports8directions.

Gunisalittlebitdifferent.Itfollowsmousecursor.Todeterminetheanglewehadtousesomemath.Theformulatogetangleindegreesisarctan(delta_x/delta_y)

*180/PI.Youcanseeitexplainedinmoredetailonstackoverflow.

Page 190: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Runitandstrollaroundtheisland.Youcanstillmoveonwaterandintothedarkness,awayfromthemapitself,butwewillhandleitlater.

$ruby02-warmup/player_movement.rb

Seethattankhidingbetweenthebushes,readytogoin8directionsandblowthingsupwiththatpreciselyaimeddoublecannon?

Page 191: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tankmovingaroundandaimingguns

GameCoordinateSystem

Page 192: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Bynowwemaystartrealizing,thatthereisonekeycomponentmissinginourdesigns.Wehaveavirtualmap,whichisbiggerthanourscreenspace,andweshouldperformallcalculationsusingthatmap,andonlythencutouttherequiredpieceandrenderitinourgamewindow.

Therearethreedifferentcoordinatesystemsthathave

Page 193: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

tomapwitheachother:

1. Gamecoordinates2. Viewportcoordinates3. Screencoordinates

Page 194: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Coordinatesystems

GameCoordinates

Page 195: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Thisiswherealllogicwillhappen.Playerlocation,enemylocations,poweruplocations-allthiswillhavegamecoordinates,anditshouldhavenothingtodowithyourscreenposition.

ViewportCoordinatesViewportisthepositionofvirtualcamera,thatis“filming”worldinaction.Don’tconfuseitwithscreen

Page 196: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

coordinates,becauseviewportwillnotnecessarilybemappedpixeltopixeltoyourgamewindow.Imaginethis:youhaveahugeworldmap,yourplayerisstandinginthemiddle,andgamewindowdisplaystheplayerwhileslowlyzoomingin.Inthisscenario,viewportisconstantlyshrinking,whilegamemapstaysthesame,andgamewindowalsostaysthesame.

Page 197: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ScreenCoordinatesThisisyourgamedisplay,pixelbypixel.Youwilldrawstaticinformation,likeyourHUDdirectlyonit.

HowToPutItAllTogetherInourgameswewillwanttoseparategamecoordinatesfromviewportandscreenasmuchaspossible.Basically,wewillprogramourselvesa“cameraman”whowillbe

Page 198: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

busyfollowingtheaction,zoominginandout,perhapschangingtheviewanglenowandthen.

Let’simplementaprototypethatwillallowustonavigateandzoomaroundabigmap.Wewillonlydrawobjectsthatarevisibleinviewport.Somemathwillbeunavoidable,butinmostcasesit’sprettybasic-that’sthebeautyof2Dgames:

Page 199: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

02-warmup/coordinate_system.rb1require'gosu'23classWorldMap4attr_accessor:on_screen,:off_screen56definitialize(width,height)7@images={}8(0..width).step(50)do|x|9@images[x]={}10(0..height).step(50)do|y|11img=Gosu::Image.from_text(12$window,"#{x}:#{y}",13

Page 200: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Gosu.default_font_name,15)14@images[x][y]=img15end16end17end1819defdraw(camera)20@on_screen=@[email protected]|x,row|22row.eachdo|y,val|23ifcamera.can_view?(x,y,val)24val.draw(x,y,0)25@on_screen+=126else27@off_screen+=128end29end30end

Page 201: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

31end32end3334classCamera35attr_accessor:x,:y,:zoom3637definitialize38@x=@y=039@zoom=140end4142defcan_view?(x,y,obj)43x0,x1,y0,y1=viewport44(x0-obj.width..x1).include?(x)&&45(y0-obj.height..y1).include?(y)46end47

Page 202: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

48defviewport49x0=@x-($window.width/2)/@zoom50x1=@x+($window.width/2)/@zoom51y0=@y-($window.height/2)/@zoom52y1=@y+($window.height/2)/@zoom53[x0,x1,y0,y1]54end5556defto_s57"FPS:#{Gosu.fps}."<<58"#{@x}:#{@y}@#{'%.2f'%@zoom}."<<59'WASDtomove,arrowstozoom.'60end6162defdraw_crosshair

Page 203: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

63$window.draw_line(64@x-10,@y,Gosu::Color::YELLOW,65@x+10,@y,Gosu::Color::YELLOW,100)66$window.draw_line(67@x,@y-10,Gosu::Color::YELLOW,68@x,@y+10,Gosu::Color::YELLOW,100)69end70end717273classGameWindow<Gosu::Window74SPEED=107576definitialize77super(800,600,false)78$window=self

Page 204: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

79@map=WorldMap.new(2048,1024)80@camera=Camera.new81end8283defbutton_down(id)84closeifid==Gosu::KbEscape85ifid==Gosu::[email protected][email protected][email protected][email protected]=SPEEDifbutton_down?(Gosu::KbA)[email protected]+=SPEEDifbutton_down?(Gosu::KbD)[email protected]=SPEEDif

Page 205: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

button_down?(Gosu::KbW)[email protected]+=SPEEDifbutton_down?(Gosu::KbS)[email protected]>0?0.01:1.099100ifbutton_down?(Gosu::KbUp)[email protected]=zoom_delta102end103ifbutton_down?(Gosu::KbDown)[email protected][email protected]_s107end108

Page 206: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]+width/[email protected]+height/[email protected][email protected](off_x,off_y)[email protected][email protected](zoom,zoom,cam_x,cam_y)[email protected](@camera)119end120end121info='Objectson/offscreen:'<<122"#{@map.on_screen}/#{@map.off_screen}"

Page 207: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

123info_img=Gosu::Image.from_text(124self,info,Gosu.default_font_name,30)125info_img.draw(10,10,1)126end127end128129GameWindow.new.show

Runit,useWASDtonavigate,up/downarrowstozoomandspacebartoresetthecamera.

Page 208: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

$ruby02-warmup/coordinate_system.rb

Itdoesn’tlookimpressive,butunderstandingtheconceptofdifferentcoordinatesystemsandbeingabletostitchthemtogetherisparamounttothesuccessofourfinalproduct.

Page 209: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Prototypeofseparatecoordinatesystems

Luckilyforus,GosuhelpsusbyprovidingGosu::Window#translate

Page 210: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

thathandlescameraoffset,Gosu::Window#scalethataidszooming,andGosu::Window#rotatethatwasnotusedyet,butwillbegreatforshakingtheviewtoemphasizeexplosions.

Page 211: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

PrototypingTheGame

Warmingupwasreallyimportant,butlet’scombineeverythingwelearned,addsomenewchallenges,andbuildasmallprototypewithfollowingfeatures:

Page 212: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1. Cameralooselyfollowstank.

2. Camerazoomsautomaticallydependingontankspeed.

3. Youcantemporarilyoverrideautomaticcamerazoomusingkeyboard.

4. Musicandsoundeffects.5. Randomlygenerated

map.6. Twomodes:menuand

gameplay.

Page 213: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

7. TankmovementwithWADSkeys.

8. Tankaimingandshootingwithmouse.

9. Collisiondetection(tanksdon’tswim).

10. Explosions,visiblebullettrajectories.

11. Bulletrangelimiting.

Soundsfun?Hellyes!However,beforewestart,weshouldplanaheadalittleandthinkhowourgame

Page 214: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

architecturewilllooklike.Wewillalsostructureourcodealittle,soitwillnotbesmashedintoonerubyclass,aswedidinearlierexamples.Booksshouldshowgoodmanners!

SwitchingBetweenGameStatesFirst,let’sthinkhowtohookintoGosu::Window.Sincewe

Page 215: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

willhavetwogamestates,Statepatternnaturallycomestomind.

So,ourGameWindowclasscouldlooklikethis:03-prototype/game_window.rb1classGameWindow<Gosu::Window23attr_accessor:state45definitialize6super(800,600,false)7end8

Page 216: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]@[email protected]_redraw?19end2021defbutton_down(id)[email protected]_down(id)23end2425end

Page 217: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Ithascurrent@state,andallusualmainloopactionsareexecutedonthatstateinstance.Wewilladdbaseclassthatallgamestateswillextend.Let’snameitGameState:03-prototype/states/game_state.rb1classGameState23defself.switch(new_state)4$window.state&&$window.state.leave5$window.state=new_state6new_state.enter

Page 218: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

7end89defenter10end1112defleave13end1415defdraw16end1718defupdate19end2021defneeds_redraw?22true23end2425defbutton_down(id)26end27end

Page 219: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ThisclassprovidesGameState.switch,thatwillchangethestateforourGosu::Window,andallenterandleavemethodswhenappropriate.Thesemethodswillbeusefulforthingslikeswitchingmusic.

NoticethatGosu::Windowisaccessedusingglobal$windowvariable,whichwill

Page 220: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

beconsideredananti-patternbymostgoodprogrammers,butthereissomelogicbehindthis:

1. TherewillbeonlyoneGosu::Windowinstance.

2. Itlivesaslongasthegameruns.

3. Itisusedinsomewaybynearlyallotherclasses,sowewouldhavetopassitaroundallthetime.

Page 221: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

4. AccessingitusingSingletonorstaticutilityclasswouldnotgiveanyclearbenefits,justaddmorecomplexity.

Chingu,anothergameframeworkbuiltontopofGosu,alsousesglobal$window,soit’sprobablynottheworstideaever.

Wewillalsoneedanentrypointthatwouldfireupthe

Page 222: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

gameandenterthefirstgamestate-themenu.03-prototype/main.rb1require'gosu'2require_relative'states/game_state'3require_relative'states/menu_state'4require_relative'states/play_state'5require_relative'game_window'67moduleGame8defself.media_path(file)9File.join(File.dirname(File.dirname

Page 223: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

10__FILE__)),'media',file)11end12end1314$window=GameWindow.new15GameState.switch(MenuState.instance

16$window.show

InourentrypointwealsohaveasmallhelperwhichwillhelploadingimagesandsoundsusingGame.media_path.

Page 224: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Therestisobvious:wecreateGameWindowinstanceandstoreitin$windowvariable,asdiscussedbefore.ThenweuseGameState.switch)toloadMenuState,andshowthegamewindow.

ImplementingMenuStateThisishowsimpleMenuStateimplementation

Page 225: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

lookslike:03-prototype/states/menu_state.rb1require'singleton'2classMenuState<GameState3includeSingleton4attr_accessor:play_state56definitialize7@message=Gosu::Image.from_text(8$window,"TanksPrototype",9Gosu.default_font_name,100)10end1112defenter13music.play(true)14music.volume=1

Page 226: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

15end1617defleave18music.volume=019music.stop20end2122defmusic23@@music||=Gosu::Song.new(24$window,Game.media_path('menu_music.mp3'

25end2627defupdate28continue_text=@play_state?"C=Continue,":""29@info=Gosu::Image.from_text(

Page 227: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

30$window,"Q=Quit,#{continue_text}N=NewGame",31Gosu.default_font_name,30)[email protected](36$window.width/[email protected]/2,37$window.height/[email protected]/2,3810)[email protected](40$window.width/[email protected]/2,41$window.height/[email protected]/2+200,4210)43end44

Page 228: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

45defbutton_down(id)46$window.closeifid==Gosu::KbQ47ifid==Gosu::KbC&&@play_state48GameState.switch(@play_state)49end50ifid==Gosu::KbN51@play_state=PlayState.new52GameState.switch(@play_state)53end54end55end

It’saSingleton,sowecanalwaysgetitwith

Page 229: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

MenuState.instance.

Itstartsplayingmenu_music.mp3whenyouenterthemenu,andstopthemusicwhenyouleaveit.InstanceofGosu::Songiscachedin@@musicclassvariabletosaveresources.

Wehavetoknowifplayisalreadyinprogress,sowecanaddapossibilitytogobacktothegame.That’swhy

Page 230: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

MenuStatehas@play_statevariable,andeitherallowscreatingnewPlayStatewhenNkeyispressed,orswitchestoexisting@play_stateifCkeyispressed.

Herecomestheinterestingpart,implementingtheplaystate.

Page 231: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingPlayStateBeforewestartimplementingactualgameplay,weneedtothinkwhatgameentitieswewillbebuilding.WewillneedaMapthatwillholdourtilesandprovideworldcoordinatesystem.WewillalsoneedaCamerathatwillknowhowtofloataroundandzoom.TherewillbeBullets

Page 232: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

flyingaround,andeachbulletwilleventuallycauseanExplosion.

Havingallthattakencareof,PlayStateshouldlookprettysimple:03-prototype/states/play_state.rb1require_relative'../entities/map'2require_relative'../entities/tank'3require_relative'../entities/camera'4require_relative'../entities/bullet'

Page 233: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

5require_relative'../entities/explosion'6classPlayState<GameState78definitialize9@map=Map.new10@tank=Tank.new(@map)11@camera=Camera.new(@tank)12@bullets=[]13@explosions=[][email protected](@camera)18@bullets<<[email protected](&:update)[email protected]!(&:done?)

Page 234: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]$window.caption='TanksPrototype.'<<23"[FPS:#{Gosu.fps}.Tank@#{@tank.x.round}:#{@tank.y.round}]"[email protected][email protected]_x=$window.width/2-cam_x30off_y=$window.height/2-cam_y31$window.translate(off_x,off_y)[email protected]$window.scale(zoom,zoom,cam_x,cam_y)[email protected](@camera)

Page 235: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]@bullets.map(&:draw)[email protected]_crosshair40end4142defbutton_down(id)43ifid==Gosu::[email protected](*@camera.mouse_coords

45@bullets<<bulletifbullet46end47$window.closeifid==Gosu::KbQ48ifid==Gosu::KbEscape49GameState.switch(MenuState.instance

Page 236: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

50end51end5253end

Updateanddrawcallsarepassedtotheunderlyinggameentities,sotheycanhandlethemthewaytheywantitto.Suchencapsulationreducescomplexityofthecodeandallowsdoingeverypieceoflogicwhereit

Page 237: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

belongs,whilekeepingitshortandsimple.

[email protected]@tank.shootmayproduceanewbullet,ifyourtank’sfirerateisnotexceeded,andifleftmousebuttoniskeptdown,hencetheupdate.Ifbulletisproduced,itisaddedto@bulletsarray,andtheylivetheirownlittlelifecycle,

Page 238: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]!(&:done?)

cleansupthegarbage.

PlayState#[email protected]@camera.ypointstogamecoordinateswhereCameraiscurrentlylookingat.Gosu::Window#translatecreatesablockwithinwhichallGosu::Imagedrawoperationsaretranslatedby

Page 239: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

givenoffset.Gosu::Window#scaledoesthesamewithCamerazoom.

Crosshairisdrawnwithouttranslatingandscalingit,becauseit’srelativetoscreen,nottoworldmap.

Basically,thisdrawmethodistheplacethattakescaredrawingonlywhat@cameracansee.

Page 240: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Ifit’shardtounderstandhowthisworks,getbackto“GameCoordinateSystem”chapterandletitsinkin.

ImplementingWorldMapWewillstartanalyzinggameentitieswithMap.03-prototype/entities/map.rb1require'perlin_noise'2require'gosu_texture_packer'

Page 241: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

34classMap5MAP_WIDTH=1006MAP_HEIGHT=1007TILE_SIZE=12889definitialize10load_tiles11@map=generate_map12end1314deffind_spawn_point15whiletrue16x=rand(0..MAP_WIDTH*TILE_SIZE)17y=rand(0..MAP_HEIGHT*TILE_SIZE)18ifcan_move_to?(x,y)19return[x,y]20else21puts"Invalidspawn

Page 242: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

point:#{[x,y]}"22end23end24end2526defcan_move_to?(x,y)27tile=tile_at(x,y)28tile&&tile!=@water29end3031defdraw(camera)[email protected]|x,row|33row.eachdo|y,val|34tile=@map[x][y]35map_x=x*TILE_SIZE36map_y=y*TILE_SIZE37ifcamera.can_view?(map_x,map_y,tile)38tile.draw(map_x,

Page 243: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

map_y,0)39end40end41end42end4344private4546deftile_at(x,y)47t_x=((x/TILE_SIZE)%TILE_SIZE).floor48t_y=((y/TILE_SIZE)%TILE_SIZE).floor49row=@map[t_x]50row[t_y]ifrow51end5253defload_tiles54tiles=Gosu::Image.load_tiles(55$window,

Page 244: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Game.media_path('ground.png'),56128,128,true)57@sand=tiles[0]58@grass=tiles[8]59@water=Gosu::Image.new(60$window,Game.media_path('water.png'),true)61end6263defgenerate_map64noises=Perlin::Noise.new(2)65contrast=Perlin::Curve.contrast(66Perlin::Curve::CUBIC,2)67map={}68MAP_WIDTH.timesdo|x|69map[x]={}

Page 245: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

70MAP_HEIGHT.timesdo|y|71n=noises[x*0.1,y*0.1]72n=contrast.call(n)73map[x][y]=choose_tile(n)74end75end76map77end7879defchoose_tile(val)80caseval81when0.0..0.3#30%[email protected]#15%chance,wateredges84@sand85else#55%chance

Page 246: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

86@grass87end88end89end

ThisimplementationisverysimilartotheMapwehadbuiltin“GeneratingRandomMapWithPerlinNoise”,withsomeextraadditions.can_move_to?verifiesiftileundergivencoordinatesisnotwater.Prettysimple,butit’senoughforourprototype.

Page 247: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Also,whenwedrawthemapwehavetomakesureiftileswearedrawingarecurrentlyvisiblebyourcamera,otherwisewewillendupdrawingoffscreen.camera.can_view?handlesit.Currentimplementationwillprobablybecausingabottleneck,sinceitbruteforcesthroughallthemapratherthancherry-pickingthevisibleregion.Wewill

Page 248: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

probablyhavetogetbackandchangeitlater.

find_spawn_pointisonemoreaddition.Itkeepspickingarandompointonmapandverifiesifit’snotwaterusingcan_move_to?.Whensolidtileisfound,itreturnsthecoordinates,soourTankwillbeabletospawnthere.

Page 249: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingFloatingCameraIfyouplayedtheoriginalGrandTheftAutoorGTA2,youshouldrememberhowfascinatingthecamerawas.Itbackedawaywhenyouweredrivingathighspeeds,closedinwhenyouwerewalkingonfoot,andfloatedaroundasifasmartdronewasfollowingyourprotagonistfromabove.

Page 250: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ThefollowingCameraimplementationisfarinferiortotheoneGTAhadnearlytwodecadesago,butit’sastart:03-prototype/entities/camera.rb1classCamera2attr_accessor:x,:y,:zoom34definitialize(target)5@target=target6@x,@y=target.x,target.y7@zoom=18end9

Page 251: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

10defcan_view?(x,y,obj)11x0,x1,y0,y1=viewport12(x0-obj.width..x1).include?(x)&&13(y0-obj.height..y1).include?(y)14end1516defmouse_coords17x,[email protected]+19(x+$window.mouse_x-($window.width/2))/@[email protected]+21(y+$window.mouse_y-($window.height/2))/@zoom22[mouse_x_on_map,

Page 252: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

mouse_y_on_map].map(&:round)23end2425defupdate26@[email protected]@x<@target.x-$window.width/427@[email protected]@x>@target.x+$window.width/428@[email protected]@y<@target.y-$window.height/429@[email protected]@y>@target.y+$window.height/43031zoom_delta=@zoom>0?0.01:1.032if$window.button_down?(Gosu::KbUp)

Page 253: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

33@zoom-=zoom_deltaunless@zoom<0.734elsif$window.button_down?(Gosu::KbDown)35@zoom+=zoom_deltaunless@zoom>[email protected]>1.1?0.85:1.038if@zoom<=(target_zoom-0.01)39@zoom+=zoom_delta/340elsif@zoom>(target_zoom+0.01)41@zoom-=zoom_delta/342end43end

Page 254: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

44end4546defto_s47"FPS:#{Gosu.fps}."<<48"#{@x}:#{@y}@#{'%.2f'%@zoom}."<<49'WASDtomove,arrowstozoom.'50end5152deftarget_delta_on_screen53[(@[email protected])*@zoom,(@[email protected])*@zoom]54end5556defdraw_crosshair57x=$window.mouse_x58y=$window.mouse_y59$window.draw_line(60x-10,y,

Page 255: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Gosu::Color::RED,61x+10,y,Gosu::Color::RED,100)62$window.draw_line(63x,y-10,Gosu::Color::RED,64x,y+10,Gosu::Color::RED,100)65end6667private6869defviewport70x0=@x-($window.width/2)/@zoom71x1=@x+($window.width/2)/@zoom72y0=@y-($window.height/2)/@zoom73y1=@y+($window.height/2)/@zoom

Page 256: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

74[x0,x1,y0,y1]75end76end

OurCamerahas@targetthatittriestofollow,@xand@ythatitcurrentlyislookingat,and@zoomlevel.

Allthemagichappensinupdatemethod.Itkeepstrackofthedistancebetween@targetandadjustitselftostaynearby.Andwhen

Page 257: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@target.speedshowssomemovementmomentum,cameraslowlybacksaway.

Cameraalsotelsifyoucan_view?anobjectatsomecoordinates,sowhenotherentitiesdrawthemselves,theycancheckifthereisaneedforthat.

Anothernoteworthymethodismouse_coords.Ittranslatesmousepositiononscreento

Page 258: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

mousepositiononmap,sothegamewillknowwhereyouaretargetingyourguns.

ImplementingTheTankMostofourtankcodewillbetakenfrom“PlayerMovementWithKeyboardAndMouse”:03-prototype/entities/tank.rb

Page 259: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1classTank2attr_accessor:x,:y,:body_angle,:gun_angle3SHOOT_DELAY=50045definitialize(map)6@map=map7@units=Gosu::TexturePacker.load_json(8$window,Game.media_path('ground_units.json':precise)9@[email protected]('tank1_body.png')10@[email protected]('tank1_body_shadow.png'

11@[email protected]('tank1_dualgun.png'

12@x,@y=

Page 260: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@map.find_spawn_point13@body_angle=0.014@gun_angle=0.015@last_shot=016sound.volume=0.317end1819defsound20@@sound||=Gosu::Song.new(21$window,Game.media_path('tank_driving.mp3'

22end2324defshoot(target_x,target_y)25ifGosu.milliseconds-@last_shot>SHOOT_DELAY26@last_shot=Gosu.milliseconds

Page 261: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

27Bullet.new(@x,@y,target_x,target_y).fire(100)28end29end3031defupdate(camera)32d_x,d_y=camera.target_delta_on_screen33atan=Math.atan2(($window.width/2)-d_x-$window.mouse_x,34($window.height/2)-d_y-$window.mouse_y)35@gun_angle=-atan*180/Math::PI36new_x,new_y=@x,@y37new_x-=speedif$window.button_down?(Gosu::KbA)38new_x+=speedif$window.button_down?(Gosu::KbD)

Page 262: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

39new_y-=speedif$window.button_down?(Gosu::KbW)40new_y+=speedif$window.button_down?(Gosu::KbS)[email protected]_move_to?(new_x,new_y)42@x,@y=new_x,new_y43else44@speed=1.045end46@body_angle=change_angle(@body_angle,47Gosu::KbW,Gosu::KbS,Gosu::KbA,Gosu::KbD)4849ifmoving?50sound.play(true)51else52sound.pause53end54

Page 263: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

55if$window.button_down?(Gosu::MsLeft)56shoot(*camera.mouse_coords)57end58end5960defmoving?61any_button_down?(Gosu::KbA,Gosu::KbD,Gosu::KbW,Gosu::KbS)[email protected]_rot(@x-1,@y-1,0,@body_angle)[email protected]_rot(@x,@y,1,@body_angle)[email protected]_rot(@x,@y,2,@gun_angle)68end

Page 264: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

6970defspeed71@speed||=1.072ifmoving?73@speed+=0.03if@speed<574else75@speed=1.076end77@speed78end7980private8182defany_button_down?(*buttons)83buttons.eachdo|b|84returntrueif$window.button_down?(b)85end86false

Page 265: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

87end8889defchange_angle(previous_angle,up,down,right,left)90if$window.button_down?(up)91angle=0.092angle+=45.0if$window.button_down?(left)93angle-=45.0if$window.button_down?(right)94elsif$window.button_down?(down)95angle=180.096angle-=45.0if$window.button_down?(left)97angle+=45.0if$window.button_down?(right)98elsif$window.button_down?(left)

Page 266: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

99angle=90.0100angle+=45.0if$window.button_down?(up)101angle-=45.0if$window.button_down?(down)102elsif$window.button_down?(right)103angle=270.0104angle-=45.0if$window.button_down?(up)105angle+=45.0if$window.button_down?(down)106end107angle||previous_angle108end109end

TankhastobeawareoftheMaptocheckwhereit’s

Page 267: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

moving,anditusesCameratofindoutwheretoaimtheguns.Whenitshoots,itproducesinstancesofBullet,thataresimplyreturnedtothecaller.Tankwon’tkeeptrackofthem,it’s“fireandforget”.

ImplementingBulletsAndExplosionsBulletswillrequiresomesimplevectormath.Youhave

Page 268: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

apointthatmovesalongthevectorwithsomespeed.Italsoneedstolimitthemaximumvectorlength,soifyoutrytoaimtoofar,thebulletwillonlygoasfarasitcanreach.03-prototype/entities/bullet.rb1classBullet2COLOR=Gosu::Color::BLACK3MAX_DIST=3004START_DIST=2056definitialize(source_x,source_y,target_x,target_y)7@x,@y=source_x,

Page 269: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

source_y8@target_x,@target_y=target_x,target_y9@x,@y=point_at_distance(START_DIST)10iftrajectory_length>MAX_DIST11@target_x,@target_y=point_at_distance(MAX_DIST)12end13sound.play14end1516defdraw17unlessarrived?18$window.draw_quad(@x-2,@y-2,COLOR,19@x+2,@y-2,COLOR,20@x-2,@y+2,COLOR,

Page 270: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

21@x+2,@y+2,COLOR,221)23else24@explosion||=Explosion.new(@x,@y)[email protected]_distance=(Gosu.milliseconds-@fired_at)*0.001*@speed31@x,@y=point_at_distance(fly_distance)32@explosion&&@explosion.update33end3435defarrived?

Page 271: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

36@x==@target_x&&@y==@target_y37end3839defdone?40exploaded?41end4243defexploaded?44@explosion&&@explosion.done?45end4647deffire(speed)48@speed=speed49@fired_at=Gosu.milliseconds50self51end5253private

Page 272: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

5455defsound56@@sound||=Gosu::Sample.new(57$window,Game.media_path('fire.mp3'))58end5960deftrajectory_length61d_x=@target_x-@x62d_y=@[email protected](d_x*d_x+d_y*d_y)64end6566defpoint_at_distance(distance)67return[@target_x,@target_y]ifdistance>trajectory_length68distance_factor=

Page 273: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

distance.to_f/trajectory_length69p_x=@x+(@target_x-@x)*distance_factor70p_y=@y+(@target_y-@y)*distance_factor71[p_x,p_y]72end73end

PossiblythemostinterestingpartofBulletimplementationispoint_at_distancemethod.Itreturnscoordinatesofpointthatisbetweenbulletsource,

Page 274: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

whichispointthatbulletwasfiredfrom,andit’starget,whichisthedestinationpoint.Thereturnedpointisasfarawayfromsourcepointasdistancetellsitto.

Afterbullethasdoneflying,itexplodeswithfanfare.InourprototypeExplosionisapartofBullet,becauseit’stheonlythingthattriggersit.ThereforeBullethastwostagesofit’slifecycle.Firstit

Page 275: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

fliestowardsthetarget,thenit’sexploding.ThatbringsustoExplosion:03-prototype/entities/explosion.rb1classExplosion2FRAME_DELAY=10#ms34defanimation5@@animation||=6Gosu::Image.load_tiles(7$window,Game.media_path('explosion.png'),128,128,false)8end910defsound11@@sound||=Gosu::Sample.new(

Page 276: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

12$window,Game.media_path('explosion.mp3'))

13end1415definitialize(x,y)16sound.play17@x,@y=x,y18@current_frame=019end2021defupdate22@current_frame+=1ifframe_expired?23end2425defdraw26returnifdone?27image=current_frame28image.draw([email protected]/2+

Page 277: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

3,[email protected]/2-35,3120)32end3334defdone?35@done||=@current_frame==animation.size36end3738private3940defcurrent_frame41animation[@current_frame%animation.size]42end4344defframe_expired?45now=Gosu.milliseconds46@last_frame||=now

Page 278: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

47if(now-@last_frame)>FRAME_DELAY48@last_frame=now49end50end51end

Thereisnothingfancyaboutthisimplementation.Mostofitistakenfrom“ImagesAndAnimation”chapter.

RunningThePrototype

Page 279: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Wehavewalkedthroughallthecode.YoucangetitatGitHub.

Nowit’stimetogiveitaspin.ThereisavideoofmeplayingitavailableonYouTube,butit’salwaysbesttoexperienceitfirsthand.Runmain.rbtostartthegame:

$ruby03-prototype/main.rb

Page 280: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

HitNtostartnewgame.

Page 281: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

TanksPrototypemenu

Timetogocrazy!

Page 282: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

TanksPrototypegameplay

Onethingshouldbebuggingyouatthispoint.FPSshowsonly30,ratherthan60.Thatmeansourprototypeisslow.

Page 283: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Wewillputitbackto60FPSinnextchapter.

Page 284: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

OptimizingGamePerformance

Tomakegamesthatarefastanddon’trequireapowerhousetorun,wemustlearnhowtofindandfixbottlenecks.Goodnewsisthatifyouwasn’tthinking

Page 285: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

aboutperformancetobeginwith,yourprogramcanusuallybeoptimizedtoruntwiceasfastjustbyeliminatingoneortwobiggestbottlenecks.

Wewillbeusingacopyoftheprototypecodetokeepbothoptimizedandoriginalversion,thereforeifyouareexploringsamplecode,lookat04-prototype-optimized.

Page 286: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ProfilingRubyCodeToFindBottlenecksWewilltrytofindbottlenecksinourTanksprototypegamebyprofilingitwithruby-prof.

It’sarubygem,justinstallitlikethis:

$geminstallruby-prof

Page 287: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Thereareseveralwaysyoucanuseruby-prof,sowewillbeginwiththeeasiestone.Insteadofrunningthegamewithruby,wewillrunitwithruby-prof:

$ruby-prof03-prototype/main.rb

Thegamewillrun,buteverythingwillbetentimesslowerasusual,becauseeverycalltoeveryfunctionis

Page 288: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

beingrecorded,andafteryouexittheprogram,profilingoutputwillbedumpeddirectlytoyourconsole.

Downsideofthisapproachisthatwearegoingtoprofileeverythingthereis,includingthesuper-slowmapgenerationthatusesPerlinNoise.Wedon’twanttooptimizethat,soinordertofindbottlenecksinourplaystateratherthanmap

Page 289: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

generation,wehavetokeepplayingatdreadful2FPSforatleast30seconds.

Thiswastheoutputoffirst“naive”profilingsession:

Page 290: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Initialprofilingresults

It’sobvious,thatCamera#viewportandCamera#can_view?aretopCPUburners.Thismeanseitherthatour

Page 291: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

implementationiseitherverybad,ortheassumptionthatcheckingifcameracanviewobjectisslowerthandrawingtheobjectoffscreen.

Herearethoseslowmethods:

classCamera#...defcan_view?(x,y,obj)x0,x1,y0,y1=viewport(x0-obj.width..x1).include?(x)&&(y0-obj.height..y1).include?(y)end

Page 292: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...defviewportx0=@x-($window.width/2)/@zoomx1=@x+($window.width/2)/@zoomy0=@y-($window.height/2)/@zoomy1=@y+($window.height/2)/@zoom[x0,x1,y0,y1]end#...end

Itdoesn’tlookfundamentallybroken,sowewilltryour“checkingisslowerthan

Page 293: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

rendering”hypothesisbyshort-circuitingcan_view?toreturntrueeverytime:

classCamera#...defcan_view?(x,y,obj)returntrue#shortcircuitingx0,x1,y0,y1=viewport(x0-obj.width..x1).include?(x)&&(y0-obj.height..y1).include?(y)end#...end

Page 294: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Aftersavingcamera.rbandrunningthegamewithoutprofiling,youwillnoticeasignificantspeedup.Hypothesiswascorrect,checkingvisibilityismoreexpensivethansimplyrenderingit.ThatmeanswecanthrowawayCamera#can_view?andcallstoit.

Butbeforedoingthat,let’sprofileonceagain:

Page 295: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Profilingresultsaftershort-circuitingCamera#can_view?

WecanseeCamera#can_view?isstillintop3,sowewillremoveifcamera.can_view?(map_x,

Page 296: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

map_y,tile)fromMap#drawandfornowkeepitlikethis:

classMap#...defdraw(camera)@map.eachdo|x,row|row.eachdo|y,val|tile=@map[x][y]map_x=x*TILE_SIZEmap_y=y*TILE_SIZEtile.draw(map_x,map_y,0)endendend#...end

Page 297: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

AftercompletelyremovingCamera#can_view?,profilingsessionlookslikedead-end-nomorelowhangingfruitsontop:

Page 298: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ProfilingresultsafterremovingCamera#can_view?

Thegamestilldoesn’tfeelfastenough,FPSoccasionallykeepsdroppingdownto~45,

Page 299: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

sowewillhavetodoprofileourcodeinsmarterway.

AdvancedProfilingTechniquesWewouldgetmoreaccuracywhenprofilingonlywhatwewanttooptimize.InourcaseitiseverythingthathappensinPlayState,exceptforMapgeneration.Thistimewewill

Page 300: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

havetouseruby-profAPItohookintoplacesweneed.

MapgenerationhappensinPlayStateinitializer,sowewillleverageGameState#enterandGameState#leavetostartandstopprofiling,sinceithappensafterstateisinitialized.Hereishowwehookin:

require'ruby-prof'classPlayState<GameState

Page 301: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...defenterRubyProf.startend

defleaveresult=RubyProf.stopprinter=RubyProf::FlatPrinter.new(result

printer.print(STDOUT)end#...end

Thenwerunthegameasusual:

Page 302: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

$ruby04-prototype-optimized/main.rb

Now,afterwepressNtostartnewgame,Mapgenerationhappensrelativelyfast,andthenprofilingkicksin,FPSdropsto15.AftermovingaroundandshootingforawhilewehitEsctoreturntothemenu,andatthatpointPlayState#leavespitsprofilingresultsouttotheconsole:

Page 303: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ProfilingresultsforPlayState

WecanseethatGosu::Image#drawtakesupto20%ofallexecutiontime.ThengoesGosu::Window#caption,but

Page 304: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

weneedittomeasureFPS,sowewillleaveitalone,andfinallywecanseeHash#each,whichisguaranteedtobetheonefromMap#draw,andittriggersallthoseGosu::Image#drawcalls.

OptimizingInefficientCodeAccordingtoprofilingresults,weneedtooptimize

Page 305: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

thismethod:

classMap#...defdraw(camera)@map.eachdo|x,row|row.eachdo|y,val|tile=@map[x][y]map_x=x*TILE_SIZEmap_y=y*TILE_SIZEtile.draw(map_x,map_y,0)endendend#...end

Page 306: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Butwehavetooptimizeitinmorecleverwaythanwedidbefore.Ifinsteadofloopingthroughallmaprowsandcolumnsandblindlyrenderingeverytileorcheckingiftileisvisiblewecouldcalculatetheexactmapcellsthatneedtobedisplayed,wewouldreducemethodcomplexityandgetmajorperformanceboost.Let’sdothat.

Page 307: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

WewilluseCamera#viewporttoreturnmapboundariesthatarevisiblebycamera,thendividethoseboundariesbyMap#TILE_SIZEtogettilenumbersinsteadofpixels,andretrievethemfromthemap.

classMap#...defdraw(camera)viewport=camera.viewportviewport.map!{|p|p/TILE_SIZE}

Page 308: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

x0,x1,y0,y1=viewport.map(&:to_i)(x0..x1).eachdo|x|(y0..y1).eachdo|y|row=@map[x]ifrowtile=@map[x][y]map_x=x*TILE_SIZEmap_y=y*TILE_SIZEtile.draw(map_x,map_y,0)endendendend

Thisoptimizationyieldedastoundingresults.Wearenowgettingnearlystable60

Page 309: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

FPSevenwhenprofilingthecode!Comparethatto2FPSwhileprofilingwhenwestarted.

Page 310: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ProfilingresultsforPlayStateafterMap#drawoptimization

NowwejusthavetodosomethingaboutthatGosu::Window#caption,becauseitisconsuming1/3

Page 311: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ofourCPUcycles!Eventhoughgameisalreadyflyingsofastthatwewillhavetoreducetankandbulletspeedstomakeitlookmorerealistic,wecannotletourselvesleavethislowhangingfruitremainunpicked.

Wewillupdatethecaptiononcepersecond,itshouldremovethebottleneck:

classPlayState<GameState#...

Page 312: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

defupdate#...update_captionend#...private

defupdate_captionnow=Gosu.millisecondsifnow-(@caption_updated_at||0)>1000$window.caption='TanksPrototype.'<<"[FPS:#{Gosu.fps}."<<"Tank@#{@tank.x.round}:#{@tank.y.round}]"@caption_updated_at=nowend

Page 313: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

endend

Nowit’sgettinghardtogetFPStodropbelow58,andprofilingresultsshowthattherearenomorebottlenecks:

Page 314: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ProfilingresultsforPlayStateafterintroducingGosu::Window#caption

cache

Wecannowsleepwellatnight.

Page 315: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ProfilingOnDemandWhenyoudevelopagame,youmaywanttoturnonprofilingnowandthen.Toavoidcommentingoutoraddingandremovingprofilingeverytimeyouwanttodoso,usethistrick:

#...require'ruby-prof'ifENV['ENABLE_PROFILING']classPlayState<GameState#...defenter

Page 316: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

RubyProf.startifENV['ENABLE_PROFILING']end

defleaveifENV['ENABLE_PROFILING']result=RubyProf.stopprinter=RubyProf::FlatPrinter.new(result

printer.print(STDOUT)endend

defbutton_down(id)#...ifid==Gosu::KbQleave$window.closeendend

Page 317: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...end

Now,toenableprofiling,simplystartyourgamewithENABLE_PROFILING=1

environmentalvariable,likethis:

$ENABLE_PROFILING=1ruby-prof03-prototype/main.rb

AdjustingGameSpeedForVariable

Page 318: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

PerformanceYoushouldhavenoticedthatouroptimizedTanksprototyperunswaytoofast.Tanksandbulletsshouldtravelsamedistancenomatterhowfastorslowthecodeis.

OnewouldexpectGosu::Window#update_interval

tobedesignedexactlyforthatpurpose,butitreturns

Page 319: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

16.6666inbothoriginalandoptimizedversionoftheprototype,soyoucanguessitisthedesiredinterval,nottheactualone.

Tofindoutactualupdateinterval,wewilluseGosu.millisecondsandcalculateitourselves.Todothat,wewillintroduceGame#track_update_interval

thatwillbecalledinGameWindow#update,and

Page 320: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Game#update_interval

whichwillretrieveactualupdateinterval,sowecanuseittoadjustourrunspeed.

WewillalsoaddGame#adjust_speedmethodthatwilltakearbitraryspeedvalueandshiftitsoisasfastasitwaswhenthegamewasrunningat30FPS.Theformulaissimple,if60FPSexpectstocallGosu::Window#updateevery

Page 321: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

16.66ms,ourspeedadjustmentwilldivideactualupdateratefrom33.33,whichroughlyequalsto16.66*2.So,ifbulletwouldfly100pixelsperupdatein30FPS,adjustedspeedwillchangeitto50pixelsat60FPS.

Hereistheimplementation:

#04-prototype-optimized/main.rbmoduleGame

Page 322: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...defself.track_update_intervalnow=Gosu.milliseconds@update_interval=(now-(@last_update||=0)).to_f@last_update=nowend

defself.update_interval@update_interval||=$window.update_intervalend

defself.adjust_speed(speed)speed*update_interval/33.33endend

#04-prototype-

Page 323: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

optimized/game_window.rbclassGameWindow<Gosu::Window#[email protected]#...end

Now,tofixthatspeedproblem,wewillneedtoapplyGame.adjust_speedtotank,bulletandcameramovements.

Page 324: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Hereareallthechangesneededtomakeourgamerunatroughlysamespeedindifferentconditions:

#04-prototype-optimized/entities/tank.rbclassTank#...defupdate(camera)#...shift=Game.adjust_speed(speed)new_x-=shiftif$window.button_down?(Gosu::KbA)new_x+=shiftif$window.button_down?(Gosu::KbD)new_y-=shiftif$window.button_down?(Gosu::KbW)

Page 325: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

new_y+=shiftif$window.button_down?(Gosu::KbS)#...end#...end

#04-prototype-optimized/entities/bullet.rbclassBullet#...defupdate#...fly_speed=Game.adjust_speed(@speed)fly_distance=(Gosu.milliseconds-@fired_at)*0.001*fly_speed@x,@y=point_at_distance(fly_distance)#...

Page 326: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

end#...end

#04-prototype-optimized/entities/camera.rbclassCamera#...defupdateshift=Game.adjust_speed(@target.speed)

@x+=shiftif@x<@target.x-$window.width/4@x-=shiftif@x>@target.x+$window.width/4@y+=shiftif@y<@target.y-$window.height/4@y-=shiftif@y>@target.y+$window.height/4

Page 327: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

zoom_delta=@zoom>0?0.01:1.0zoom_delta=Game.adjust_speed(zoom_delta)#...end#...end

ThereisonemoretricktomakethegameplayableevenatverylowFPS.Youcansimulatesuchconditionsbyaddingsleep0.3toGameWindow#drawmethod.Atthatframerategamecursoris

Page 328: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

veryunresponsive,soyoumaywanttostartshowingnativemousecursorwhenthingsgetugly,i.e.whenupdateintervalexceeds200milliseconds:

#04-prototype-optimized/game_window.rbclassGameWindow<Gosu::Window#...defneeds_cursor?Game.update_interval>200end#...end

Page 329: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

FrameSkippingYouwillseestrangethingshappeningatverylowframerates.Forexample,bulletexplosionsareshowingupframebyframe,soexplosionspeedseemswaytooslowandunrealistic.Toavoidthat,wewillmodifyourExplosionclasstoemployframeskippingifupdaterateistooslow:

Page 330: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#04-prototype-optimized/explosion.rbclassExplosionFRAME_DELAY=16.66#ms#...defupdateadvance_frameend

defdone?@done||=@current_frame>=animation.sizeend#...private#...defadvance_framenow=Gosu.millisecondsdelta=now-(@last_frame||=now)ifdelta>FRAME_DELAY

Page 331: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@last_frame=nowend@current_frame+=(delta/FRAME_DELAY).floorendend

Nowourprototypeisplayableevenatlowerframerates.

Page 332: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

RefactoringThePrototype

Atthispointyoumaybethinkingwheretogonext.Wewanttoimplementenemies,collisiondetectionandAI,butdesignofcurrentprototypeisalreadylimiting.Codeisbecomingtightlycoupled,thereisnoclean

Page 333: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

separationbetweendifferentdomains.

Ifweweretocontinuebuildingontopofourprototype,thingswouldgetuglyquickly.Thuswewilluntanglethespaghettiandrewritesomepartsfromscratchtoachieveelegance.

GameProgrammingPatterns

Page 334: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

IwouldliketotipmyhattoRobertNystrom,whowrotethisamazingbookcalledGameProgrammingPatterns.Thebookisavailableonlineforfree,itisarelativelyquickread-I’vedevoureditwithpleasureinroughly4hours.Ifyouareguessingthatthischapterisinspiredbythatbook,youareabsolutelyright.

Page 335: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Componentpatternisespeciallynoteworthy.Wewillbeusingittodomajorhousekeeping,anditisgreattimetodoso,becausewehaven’timplementedmuchofthegameyet.

WhatIsWrongWithCurrentDesignUntilthispointwehavebeenbuildingthecodein

Page 336: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

monolithicfashion.Tankclassholdsthecodethat:

1. Loadsallgroundunitsprites.Ifsomeotherclasshandledit,wecouldreusethecodetoloadotherunits.

2. Handlessoundeffects.3. UsesGosu::Songfor

movingsounds.Thatlimitsonlyonetankmovementsoundper

Page 337: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

wholegame.Basically,weabusedGosuhere.

4. Handleskeyboardandmouse.IfweweretocreateAIthatcontrolsthetank,wewouldnotbeabletoreuseTankclassbecauseofthis.

5. Drawsgraphicsonscreen.

6. Calculatesphysicalproperties,likespeed,acceleration.

Page 338: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

7. Detectsmovementcollisions.

Bulletisnotperfecteither:

1. Itrendersit’sgraphics.2. Ithandlesit’smovement

trajectoriesandotherphysics.

3. IttreatsExplosionaspartofit’sownlifecycle.

4. Drawsgraphicsonscreen.

5. Handlessoundeffects.

Page 339: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

EventherelativelysmallExplosionclassistoomonolithic:

1. Itloadsit’sgraphics.2. Ithandlesrendering,

animationandframeskipping

3. Itloadsandplaysit’ssoundeffects.

DecouplingUsingComponentPattern

Page 340: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Bestdesignseparatesconcernsincodesothateverythinghasit’sownplace,andeveryclasshandlesonlyonething.Let’strysplittingupTankclassintocomponentsthathandlespecificdomains:

DecoupledTank

Page 341: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

WewillintroduceGameObjectclasswillcontainsharedfunctionalityforallgameobjects(Tank,Bullet,Explosion),eachofthemwouldhaveit’sownsetofcomponents.Everycomponentwillhaveit’sparentobject,soitwillbeabletointeractwithit,changeit’sattributes,orpossiblyinvokeothercomponentsifitcomestothat.

Page 342: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Gameobjectsandtheircomponents

AlltheseobjectswillbeheldwithinObjectPool,whichwouldnotcaretoknowifobjectisatankorabullet.PurposeofObjectPoolisa

Page 343: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

littledifferentinRuby,sinceGCwilltakecareofmemoryfragmentationforus,butwestillneedasingleplacethatknowsabouteveryobjectinthegame.

Page 344: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ObjectPool

PlayStatewouldtheniteratethrough@object_pool.objectsand

Page 345: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

invokeupdateanddrawmethods.

Now,let’sbeginbyimplementingbaseclassforGameObject:05-refactor/entities/game_object.rb1classGameObject2definitialize(object_pool)3@components=[]4@object_pool=object_pool5@object_pool.objects<<self6end

Page 346: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

78defcomponents9@[email protected](&:update)14end1516defdraw(viewport)[email protected]{|c|c.draw(viewport)}18end1920defremovable?21@removable22end2324defmark_for_removal25@removable=true

Page 347: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

26end2728protected2930defobject_pool31@object_pool32end33end

WhenGameObjectisinitialized,itregistersitselfwithObjectPoolandpreparesempty@componentsarray.ConcreteGameObjectclassesshouldinitialize

Page 348: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Componentssothatarraywouldnotbeempty.

updateanddrawmethodswouldcyclethrough@componentsanddelegatethosecallstoeachoftheminasequence.Itisimportanttoupdateallcomponentsfirst,andonlythendrawthem.Keepinmindthat@componentsarrayorderhassignificance.Firstelements

Page 349: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

willalwaysbeupdatedanddrawnbeforelastones.

Wewillalsoprovideremovable?methodthatwouldreturntrueforobjectsthatmark_for_removalwasinvokedon.ThiswaywewillbeabletoweedoutoldbulletsandexplosionsandfeedthemtoGC.

Nextup,baseComponentclass:

Page 350: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

05-refactor/entities/components/component.rb1classComponent2definitialize(game_object=nil)3self.object=game_object4end56defupdate7#override8end910defdraw(viewport)11#override12end1314protected1516defobject=(obj)

Page 351: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

17ifobj18@object=obj19obj.components<<[email protected]@object.y29end3031defobject32@object33end34end

Page 352: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ItregistersitselfwithGameObject#components,providessomeprotectedmethodstoaccessparentobjectandit’smostoftencalledproperties-xandy.

RefactoringExplosionExplosionwasprobablythesmallestclass,sowewillextractit’scomponentsfirst.05-refactor/entities/explosion.rb

Page 353: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1classExplosion<GameObject2attr_accessor:x,:y34definitialize(object_pool,x,y)5super(object_pool)6@x,@y=x,y7ExplosionGraphics.new(self)8ExplosionSounds.play9end10end

Itismuchcleanerthanbefore.ExplosionGraphicswillbeaComponentthathandlesanimation,and

Page 354: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ExplosionSoundswillplayasound.05-refactor/entities/components/explosion_graphics.rb1classExplosionGraphics<Component2FRAME_DELAY=16.66#ms34definitialize(game_object)5super6@current_frame=07end89defdraw(viewport)10image=current_frame11image.draw(12x-image.width/2+

Page 355: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

3,13y-image.height/2-35,1420)15end1617defupdate18now=Gosu.milliseconds19delta=now-(@last_frame||=now)20ifdelta>FRAME_DELAY21@last_frame=now22end23@current_frame+=(delta/FRAME_DELAY).floor24object.mark_for_removalifdone?25end2627private28

Page 356: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

29defcurrent_frame30animation[@current_frame%animation.size]31end3233defdone?34@done||=@current_frame>=animation.size35end3637defanimation38@@animation||=39Gosu::Image.load_tiles(40$window,Utils.media_path('explosion.png'

41128,128,false)42end43end

Page 357: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Everythingthatisrelatedtoanimatingtheexplosionisnowclearlyseparated.mark_for_removaliscalledontheexplosionafterit’sanimationisdone.05-refactor/entities/components/explosion_sounds.rb1classExplosionSounds2class<<self3defplay4sound.play5end67private8

Page 358: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

9defsound10@@sound||=Gosu::Sample.new(11$window,Utils.media_path('explosion.mp3'

12end13end14end

Sinceexplosionsoundsaretriggeredonlyonce,whenitstartstoexplode,ExplosionSoundsisastaticclasswithplaymethod.

Page 359: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

RefactoringBulletNow,let’sgoupalittleandreimplementourBullet:05-refactor/entities/bullet.rb1classBullet<GameObject2attr_accessor:x,:y,:target_x,:target_y,:speed,:fired_at34definitialize(object_pool,source_x,source_y,target_x,target_y)5super(object_pool)6@x,@y=source_x,source_y7@target_x,@target_y=

Page 360: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

target_x,target_y8BulletPhysics.new(self)9BulletGraphics.new(self)10BulletSounds.play11end1213defexplode14Explosion.new(object_pool,@x,@y)15mark_for_removal16end1718deffire(speed)19@speed=speed20@fired_at=Gosu.milliseconds21end22end

Page 361: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Allphysics,graphicsandsoundsareextractedintoindividualcomponents,andinsteadofmanagingExplosion,itjustregistersanewExplosionwithObjectPoolandmarksitselfforremovalinexplodemethod.05-refactor/entities/components/bullet_physics.rb1classBulletPhysics<Component2START_DIST=20

Page 362: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

3MAX_DIST=30045definitialize(game_object)6super7object.x,object.y=point_at_distance(START_DIST)8iftrajectory_length>MAX_DIST9object.target_x,object.target_y=point_at_distance(MAX_DIST)10end11end1213defupdate14fly_speed=Utils.adjust_speed(object.speed)

15fly_distance=(Gosu.milliseconds-

Page 363: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

object.fired_at)*0.001*fly_speed16object.x,object.y=point_at_distance(fly_distance)17object.explodeifarrived?18end1920deftrajectory_length21d_x=object.target_x-x22d_y=object.target_y-y23Math.sqrt(d_x*d_x+d_y*d_y)24end2526defpoint_at_distance(distance)27ifdistance>trajectory_length

Page 364: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

28return[object.target_x,object.target_y]29end30distance_factor=distance.to_f/trajectory_length31p_x=x+(object.target_x-x)*distance_factor32p_y=y+(object.target_y-y)*distance_factor33[p_x,p_y]34end3536private3738defarrived?39x==object.target_x&&y==object.target_y

Page 365: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

40end41end

BulletPhysicsiswherethemostofBulletendedupat.ItdoesallthecalculationsandtriggersBullet#explodewhenready.Whenwewillbeimplementingcollisiondetection,theimplementationwillgosomewherehere.05-refactor/entities/components/bullet_graphics.rb

Page 366: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1classBulletGraphics<Component2COLOR=Gosu::Color::BLACK34defdraw(viewport)5$window.draw_quad(x-2,y-2,COLOR,6x+2,y-2,COLOR,7x-2,y+2,COLOR,8x+2,y+2,COLOR,91)10end1112end

Page 367: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

AfterpullingawayBulletgraphicscode,itlooksverysmallandelegant.Wewillprobablyneverhavetoeditanythinghereagain.05-refactor/entities/components/bullet_sounds.rb1classBulletSounds2class<<self3defplay4sound.play5end67private89defsound

Page 368: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

10@@sound||=Gosu::Sample.new(11$window,Utils.media_path('fire.mp3'))12end13end14end

JustlikeExplosionSounds,BulletSoundsarestatelessandstatic.Wecouldmakeitjustlikearegularcomponent,butconsideritourlittleoptimization.

RefactoringTank

Page 369: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

TimetotakealookatfreshlydecoupledTank:05-refactor/entities/tank.rb1classTank<GameObject2SHOOT_DELAY=5003attr_accessor:x,:y,:throttle_down,:direction,:gun_angle,:sounds,:physics45definitialize(object_pool,input)6super(object_pool)7@[email protected](self)9@physics=TankPhysics.new(self,object_pool)10@graphics=

Page 370: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

TankGraphics.new(self)11@sounds=TankSounds.new(self)12@direction=@gun_angle=0.013end1415defshoot(target_x,target_y)16ifGosu.milliseconds-(@last_shot||0)>SHOOT_DELAY17@last_shot=Gosu.milliseconds18Bullet.new(object_pool,@x,@y,target_x,target_y).fire(100)19end20end21end

Page 371: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tankclasswasreducedover5times.WecouldgofurtherandextractGuncomponent,butfornowit’ssimpleenoughalready.Now,thecomponents.05-refactor/entities/components/tank_physics.rb1classTankPhysics<Component2attr_accessor:speed34definitialize(game_object,object_pool)5super(game_object)

Page 372: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

6@object_pool=object_pool7@map=object_pool.map8game_object.x,[email protected]_spawn_point9@speed=0.010end1112defcan_move_to?(x,y)[email protected]_move_to?(x,y)14end1516defmoving?17@speed>018end1920defupdate21ifobject.throttle_down22accelerate23else

Page 373: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

24decelerate25end26if@speed>027new_x,new_y=x,y28shift=Utils.adjust_speed(@speed)[email protected]_i30when031new_y-=shift32when4533new_x+=shift34new_y-=shift35when9036new_x+=shift37when13538new_x+=shift39new_y+=shift40when18041new_y+=shift42when225

Page 374: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

43new_y+=shift44new_x-=shift45when27046new_x-=shift47when31548new_x-=shift49new_y-=shift50end51ifcan_move_to?(new_x,new_y)52object.x,object.y=new_x,new_y53else54object.sounds.collideif@speed>155@speed=0.056end57end58end59

Page 375: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

60private6162defaccelerate63@speed+=0.08if@speed<564end6566defdecelerate67@speed-=0.5if@speed>068@speed=0.0if@speed<0.01#damp69end70end

Whilewehadtoripplayerinputawayfromit’smovement,wegotourselves

Page 376: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

abenefit-tanknowbothacceleratesanddecelerates.Whendirectionalbuttonsarenolongerpressed,tankkeepsmovinginlastdirection,butquicklydeceleratesandstops.AnotheradditionthatwouldhavebeenmoredifficulttoimplementonpreviousTankiscollisionsound.WhenTankabruptlystopsbyhittingsomething(fornowit’sonlywater),collisionsoundisplayed.Wewillhavetofix

Page 377: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

that,becausemetalbangisnotappropriatewhenyoustopontheedgeofariver,butwenowdiditforthesakeofscience.05-refactor/entities/components/tank_graphics.rb1classTankGraphics<Component2definitialize(game_object)3super(game_object)4@body=units.frame('tank1_body.png')5@shadow=units.frame('tank1_body_shadow.png'

Page 378: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

6@gun=units.frame('tank1_dualgun.png')

7end89defdraw(viewport)[email protected]_rot(x-1,y-1,0,object.direction)[email protected]_rot(x,y,1,object.direction)[email protected]_rot(x,y,2,object.gun_angle)13end1415private1617defunits18@@units=Gosu::TexturePacker.load_json(19$window,

Page 379: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Utils.media_path('ground_units.json':precise)20end21end

Again,graphicsareneatlypackedandseparatedfromeverythingelse.Eventuallyweshouldoptimizedrawtotakeviewportintoconsideration,butit’sgoodenoughfornow,especiallywhenwehaveonlyonetankinthegame.

Page 380: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

05-refactor/entities/components/tank_sounds.rb1classTankSounds<Component2defupdate3ifobject.physics.moving?4if@driving&&@[email protected]@driving.nil?7@driving=driving_sound.play(1,1,true)8end9else10if@driving&&@[email protected]

Page 381: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1516defcollide17crash_sound.play(1,0.25,false)18end1920private2122defdriving_sound23@@driving_sound||=Gosu::Sample.new(24$window,Utils.media_path('tank_driving.mp3'

25end2627defcrash_sound28@@crash_sound||=Gosu::Sample.new(29$window,Utils.media_path('crash.ogg'))

Page 382: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

30end31end

UnlikeExplosionandBullet,Tanksoundsarestateful.Wehavetokeeptrackoftank_driving.mp3,whichisnolongerGosu::Song,butGosu::Sample,likeitshouldhavebeen.

WhenGosu::Sample#playisinvoked,

Page 383: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Gosu::SampleInstanceisreturned,andwehavefullcontroloverit.Nowwearereadytoplaysoundsformorethanonetankatonce.05-refactor/entities/components/player_input.rb1classPlayerInput<Component2definitialize(camera)3super(nil)4@camera=camera5end67defcontrol(obj)8self.object=obj

Page 384: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

9end1011defupdate12d_x,[email protected]_delta_on_screen13atan=Math.atan2(($window.width/2)-d_x-$window.mouse_x,14($window.height/2)-d_y-$window.mouse_y)15object.gun_angle=-atan*180/Math::PI16motion_buttons=[Gosu::KbW,Gosu::KbS,Gosu::KbA,Gosu::KbD]1718ifany_button_down?(*motion_buttons)19object.throttle_down=true

Page 385: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

20object.direction=change_angle(object.direction,*motion_buttons)21else22object.throttle_down=false23end2425ifUtils.button_down?(Gosu::MsLeft)26object.shoot(*@camera.mouse_coords

27end28end2930private3132defany_button_down?(*buttons)33buttons.eachdo|b|

Page 386: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

34returntrueifUtils.button_down?(b)35end36false37end3839defchange_angle(previous_angle,up,down,right,left)40ifUtils.button_down?(up)41angle=0.042angle+=45.0ifUtils.button_down?(left)43angle-=45.0ifUtils.button_down?(right)44elsifUtils.button_down?(down)45angle=180.046angle-=45.0ifUtils.button_down?(left)

Page 387: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

47angle+=45.0ifUtils.button_down?(right)48elsifUtils.button_down?(left)49angle=90.050angle+=45.0ifUtils.button_down?(up)51angle-=45.0ifUtils.button_down?(down)52elsifUtils.button_down?(right)53angle=270.054angle-=45.0ifUtils.button_down?(up)55angle+=45.0ifUtils.button_down?(down)56end57angle=(angle+360)%360ifangle&&angle<058(angle||previous_angle)

Page 388: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

59end60end

WefinallycometoaplacewherekeyboardandmouseinputishandledandconvertedtoTankcommands.WecouldhaveusedCommandpatterntodecoupleeverythingevenfurther.

RefactoringPlayState05-refactor/game_states/play_state.rb

Page 389: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1require'ruby-prof'ifENV['ENABLE_PROFILING']2classPlayState<GameState3attr_accessor:update_interval45definitialize6@map=Map.new7@camera=Camera.new8@object_pool=ObjectPool.new(@map)9@tank=Tank.new(@object_pool,PlayerInput.new(@camera))[email protected][email protected]['ENABLE_PROFILING']15end

Page 390: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1617defleave18ifENV['ENABLE_PROFILING']19result=RubyProf.stop20printer=RubyProf::FlatPrinter.new(result

21printer.print(STDOUT)22end23end2425defupdate26@object_pool.objects.map(&:update

27@object_pool.objects.reject!(&:removable?)[email protected]_caption

Page 391: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected][email protected]_x=$window.width/2-cam_x36off_y=$window.height/[email protected]$window.translate(off_x,off_y)[email protected]$window.scale(zoom,zoom,cam_x,cam_y)[email protected](viewport)42@object_pool.objects.map{|o|o.draw(viewport)}43end

Page 392: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]_crosshair46end4748defbutton_down(id)49ifid==Gosu::KbQ50leave51$window.close52end53ifid==Gosu::KbEscape54GameState.switch(MenuState.instance

55end56end5758private5960defupdate_caption61now=Gosu.milliseconds62ifnow-

Page 393: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

(@caption_updated_at||0)>100063$window.caption='TanksPrototype.'<<64"[FPS:#{Gosu.fps}."<<65"Tank@#{@tank.x.round}:#{@tank.y.round}]"66@caption_updated_at=now67end68end69end

ImplementationofPlayStateisnowalsoalittlesimpler.Itdoesn’tupdate@tankor

Page 394: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@bulletsindividuallyanymore.Instead,itusesObjectPoolanddoesallobjectoperationsinbulk.

OtherImprovements05-refactor/main.rb1#!/usr/bin/envruby23require'gosu'45root_dir=File.dirname(__FILE__)6require_pattern=File.join(root_dir,'**/*.rb')7@failed=[]8

Page 395: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

9#Dynamicallyrequireeverything10Dir.glob(require_pattern).eachdo|f|11nextiff.end_with?('/main.rb')12begin13require_relativef.gsub("#{root_dir}/",'')14rescue15#Mayfailifparentclassnotrequiredyet16@failed<<f17end18end1920#[email protected]|f|22require_relativef.gsub("#{root_dir}/",'')

Page 396: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

23end2425$window=GameWindow.new26GameState.switch(MenuState.instance

27$window.show

Finally,wemadesomeimprovementstomain.rb-itnowrecursivelyrequiresall*.rbfileswithinsamedirectory,sowedon’thavetoworryaboutitinotherclasses.

Page 397: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

05-refactor/utils.rb1moduleUtils2defself.media_path(file)3File.join(File.dirname(File.dirname

4__FILE__)),'media',file)5end67defself.track_update_interval8now=Gosu.milliseconds9@update_interval=(now-(@last_update||=0)).to_f10@last_update=now11end1213defself.update_interval14@update_interval||=

Page 398: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

$window.update_interval15end1617defself.adjust_speed(speed)18speed*update_interval/33.3319end2021defself.button_down?(button)22@buttons||={}23now=Gosu.milliseconds24now=now-(now%150)25if$window.button_down?(button)26@buttons[button]=now27true28elsif@buttons[button]29ifnow==@buttons[button]

Page 399: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected](button)33false34end35end36end37end

AnothernotablechangeisrenamingGamemoduleintoUtils.Thenamefinallymakesmoresense,IhavenoideawhyIpututilitymethodsintoGamemoduleinthefirst

Page 400: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

place.Also,Utilsreceivedbutton_down?method,thatsolvestheissueofchangingtankdirectionwhenbuttonisimmediatelyreleased.Itmadeverydifficulttostopatdiagonalangle,becausewhenyoudepressedtwobuttons,16mswasenoughforGosutothink“hereleasedW,andSisstillpressed,solet’schangedirectiontoS”.Utils#button_down?givesasoft150mswindowto

Page 401: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

synchronizebuttonrelease.Nowcontrolsfeelmorenatural.

Page 402: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

SimulatingPhysics

Tomakethegamemorerealistic,wewillspicethingsupwithsomephysics.Thisisthefeaturesetwearegoingtoimplement:

1. Collisiondetection.Tankwillbumpinto

Page 403: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

otherobjects-stationarytanks.Bulletswillnotgothroughthemeither.

2. Terraineffects.Tankwillgofastongrass,sloweronsand.

AddingEnemyObjectsIt’sboringtoplayalone,sowewillmakeaquickchangeandspawnsomestationary

Page 404: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

tanksthatwillbedeployedrandomlyaroundthemap.Theywillbestationaryinthebeginning,butwewillstillneedadummyAIclasstoreplacePlayerInput:06-physics/entities/components/ai_input.rb1classAiInput<Component2defcontrol(obj)3self.object=obj4end5end

Page 405: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

AquickanddirtywaytospawnsometankswouldbewheninitializingPlayState:

classPlayState<GameState#...definitialize@map=Map.new@camera=Camera.new@object_pool=ObjectPool.new(@map)@tank=Tank.new(@object_pool,PlayerInput.new(@camera))@camera.target=@tank#...50.timesdoTank.new(@object_pool,AiInput.new)

Page 406: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

endend#...end

Andunlesswewantallstationarytanksfacesamedirection,wewillrandomizeit:

classTank<GameObject#...definitialize(object_pool,input)#...@direction=rand(0..7)*45@gun_angle=rand(0..360)

Page 407: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

end#...end

Fireupthegame,andwanderaroundfrozentanks.Youcanpassthroughthemasiftheywereghosts,butwewillfixthatinamoment.

Page 408: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Braindeadenemies

AddingBoundingBoxesAndDetecting

Page 409: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

CollisionsWewantourcollisiondetectiontobepixelperfect,thatmeansweneedtohaveaboundingboxandcheckcolisionsagainstit.Getreadyforsomemath!

First,weneedtofindacorrectwaytoconstructaboundingbox.Tankhasit’sbodyimage,solet’sseehowit’sboundarieslooklike.We

Page 410: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

willaddsomecodetoTankGraphicscomponenttoseeit:

classTankGraphics<Componentdefdraw(viewport)#...draw_bounding_boxend

defdraw_bounding_box$window.rotate(object.direction,x,y)[email protected][email protected]$window.draw_quad(x-w/2,y-h/2,Gosu::Color::RED,

Page 411: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

x+w/2,y-h/2,Gosu::Color::RED,x+w/2,y+h/2,Gosu::Color::RED,x-w/2,y+h/2,Gosu::Color::RED,100)endend#...end

Resultisprettygood,wehavetankshapedbox,sowewillbeusingbodyimagedimensionstodetermineourboundingboxcorners:

Page 412: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tank’sboundingboxvisualized

Thereisoneproblemherethough.Gosu::Window#rotatedoestherotationmathforus,and

Page 413: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

weneedtoperformthesecalculationsonourown.Wehavefourpointsthatwewanttorotatearoundacenterpoint.It’snotverydifficulttofindhowtodothis.HereisaRubymethodforyou:

moduleUtils#...defself.rotate(angle,around_x,around_y,*points)result=[]points.each_slice(2)do|x,y|r_x=Math.cos(angle)*(x-around_x)-

Page 414: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Math.sin(angle)*(y-around_y)+around_xr_y=Math.sin(angle)*(x-around_x)+Math.cos(angle)*(y-around_y)+around_yresult<<r_xresult<<r_yendresultend#...end

Wecannowcalculateedgesofourboundingbox,butweneedonemorefunctionwhichtellsifpointisinsidea

Page 415: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

polygon.Thisproblemhasbeensolvedmilliontimesbefore,sojustpoketheinternetforitanddrinkfromtheinformationfirehoseuntilyouunderstandhowtodothis.

Ifyouwasn’tfamiliarwiththetermyet,bynowyoushoulddiscoverwhatvertexis.Ingeometry,avertex(pluralvertices)isaspecialkindofpointthatdescribes

Page 416: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

thecornersorintersectionsofgeometricshapes.

Here’swhatIendedupwriting:

moduleUtils#...#http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html

defself.point_in_poly(testx,testy,*poly)nvert=poly.size/2#Numberofverticesinpolyvertx=[]verty=[]poly.each_slice(2)do|x,

Page 417: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

y|vertx<<xverty<<yendinside=falsej=nvert-1(0..nvert-1).eachdo|i|if(((verty[i]>testy)!=(verty[j]>testy))&&(testx<(vertx[j]-vertx[i])*(testy-verty[i])/(verty[j]-verty[i])+vertx[i]))inside=!insideendj=iendinsideend#...

Page 418: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ItisJordancurvetheoremreimplementedinRuby.Looksugly,butitactuallyworks,andisprettyfasttoo.

Also,thisworksonmoresophisticatedpolygons,andourtankisshapedmorelikeanHratherthanarectangle,sowecoulddefineapixelperfectpolygon.Somepenandpaperwillhelp.

classTankPhysics<Component#...

Page 419: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#TankboxlookslikeH.Vertices:#1256#34##109#121187defboxw=box_width/2-1h=box_height/2-1tw=8#trackwidthfd=8#frontdepthrd=6#reardepthUtils.rotate(object.direction,x,y,x+w,y+h,#1x+w-tw,y+h,#2

Page 420: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

x+w-tw,y+h-fd,#3

x-w+tw,y+h-fd,#4x-w+tw,y+h,#5x-w,y+h,#6

x-w,y-h,#7x-w+tw,y-h,#8x-w+tw,y-h+rd,#9

x+w-tw,y-h+rd,#10x+w-tw,y-h,#11

Page 421: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

x+w,y-h,#12)end#...end

Tovisuallyseeit,wewillimproveourdraw_bounding_boxmethod:

classTankGraphics<Component#...DEBUG_COLORS=[Gosu::Color::RED,Gosu::Color::BLUE,Gosu::Color::YELLOW,Gosu::Color::WHITE

Page 422: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

]#...defdraw_bounding_boxi=0object.box.each_slice(2)do|x,y|color=DEBUG_COLORS[i]$window.draw_triangle(x-3,y-3,color,x,y,color,x+3,y-3,color,100)i=(i+1)%4endend#...

Nowwecanvisuallytestboundingboxedgesandsee

Page 423: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

thattheyactuallyarewheretheybelong.

Page 424: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Highprecisionboundingboxes

TimetopimpourTankPhysicstodetectthosecollisions.Whileouralgorithmisprettyfast,it

Page 425: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

doesn’tmakesensetocheckcollisionsforobjectsthatareprettyfarapart.ThisiswhyweneedourObjectPooltoknowhowtoqueryobjectsincloseproximity.

classObjectPool#...defnearby(object,max_distance)@objects.selectdo|obj|distance=Utils.distance_between(obj.x,obj.y,object.x,object.y)obj!=object&&distance<max_distance

Page 426: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

endendend

BacktoTankPhysics:

classTankPhysics<Component#...defcan_move_to?(x,y)old_x,old_y=object.x,[email protected]_move_to?(x,y)@object_pool.nearby(object,100).eachdo|obj|ifcollides_with_poly?(obj.box)#Allowtogetunstuck

Page 427: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

old_distance=Utils.distance_between(obj.x,obj.y,old_x,old_y)new_distance=Utils.distance_between(obj.x,obj.y,x,y)returnfalseifnew_distance<old_distanceendendtrueensureobject.x=old_xobject.y=old_yend#...private

defcollides_with_poly?(poly)ifpoly

Page 428: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

poly.each_slice(2)do|x,y|returntrueifUtils.point_in_poly(x,y,*box)endbox.each_slice(2)do|x,y|returntrueifUtils.point_in_poly(x,y,*poly)endendfalseend#...end

It’sprobablynotthemostelegantsolutionyoucould

Page 429: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

comeupwith,butcan_move_to?temporarilychangesTanklocationtomakeacollisiontest,andthenrevertsoldcoordinatesjustbeforereturningtheresult.Nowourtanksstopwithbangingsoundwhentheyhiteachother.

Page 430: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tankscolliding

CatchingBullets

Page 431: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Rightnowbulletsflyrightthroughourtanks,andwewantthemtocollide.It’saprettysimplechange,whichmostlyaffectsBulletPhysicsclass:

#06-physics/entities/components/bullet_physics.rb

classBulletPhysics<Component#...defupdate#...check_hitobject.explodeifarrived?end#...

Page 432: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

private

defcheck_hit@object_pool.nearby(object,50).eachdo|obj|nextifobj==object.source#Don'thitsourcetankifUtils.point_in_poly(x,y,*obj.box)object.target_x=xobject.target_y=yreturnendendend#...end

Page 433: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Nowbulletsfinallyhit,butdon’tdoanydamageyet.Wewillcomebacktothatsoon.

Page 434: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Bullethittingenemytank

ImplementingTurnSpeedPenalties

Page 435: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tankscannotmaketurnsandgointoreverseatfullspeedwhilekeepingit’sinertia,right?Itiseasytoimplement.Sinceit’srelatedtophysics,wewilldelegatechangingTank’s@directiontoourTankPhysicsclass:

#06-physics/entities/components/player_input.rb

classPlayerInput<Component#...defupdate#...

Page 436: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

motion_buttons=[Gosu::KbW,Gosu::KbS,Gosu::KbA,Gosu::KbD]

ifany_button_down?(*motion_buttons)object.throttle_down=trueobject.physics.change_direction(

change_angle(object.direction,*motion_buttons))elseobject.throttle_down=falseend#...end#...

Page 437: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

end

#06-physics/entities/components/tank_physics.rb

classTankPhysics<Component#...defchange_direction(new_direction)change=(new_direction-object.direction+360)%360change=360-changeifchange>180ifchange>90@speed=0elsifchange>45@speed*=0.33elsifchange>0@speed*=0.66endobject.direction=

Page 438: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

new_directionend#...end

ImplementingTerrainSpeedPenaltiesNow,let’sseehowcanwemaketerraininfluenceourmovement.ItsoundsreasonableforTankPhysics

Page 439: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

toconsultwithMapaboutspeedpenaltyofcurrenttile:

#06-physics/entities/map.rbclassMap#...defmovement_penalty(x,y)tile=tile_at(x,y)[email protected]#...end

#06-physics/entities/components/tank_physics.rb

Page 440: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

classTankPhysics<Component#...defupdate#...speed=apply_movement_penalty(@speed)shift=Utils.adjust_speed(speed)#...end#...

private

defapply_movement_penalty(speed)speed*([email protected]_penalty(x,y))end

Page 441: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...end

Thismakesalltanksmove33%sloweronsand.

Page 442: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingHealthAndDamage

Iknowyouhavebeenwaitingforthis.Wewillbeimplementinghealthsystemandmostimportantly,damage.Soowewillbereadytoblowthingsup.

Page 443: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Toimplementthis,weneedto:

1. AddTankHealthcomponent.Startwith100health.

2. Rendertankhealthnexttotankitself.

3. Inflictdamagetotankwhenitisinexplosionzone

4. Renderdifferentspritefordeadtank.

Page 444: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

5. Cutoffplayerinputwhentankisdead.

AddingHealthComponentIfwedidn’thaveComponentsysteminplace,itwouldbewaymoredifficult.Nowwejustkickinanewclass:07-damage/entities/components/tank_health.rb

Page 445: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1classTankHealth<Component2attr_accessor:health34definitialize(object,object_pool)5super(object)6@object_pool=object_pool7@health=1008@health_updated=true9@last_damage=Gosu.milliseconds10end1112defupdate13update_image14end1516defupdate_image17if@health_updated18ifdead?

Page 446: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

19text='✝'[email protected]_s23font_size=1824end25@image=Gosu::Image.from_text(26$window,text,27Gosu.default_font_name,font_size)28@health_updated=false29end30end3132defdead?33@health<134end35

Page 447: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

36definflict_damage(amount)37if@health>038@health_updated=true39@health=[@health-amount.to_i,0].max40if@health<141Explosion.new(@object_pool,x,y)42end43end44end4546defdraw(viewport)[email protected]([email protected]/2,49y-object.graphics.height/[email protected],100)51end52end

Page 448: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Ithooksitselfintothegamerightaway,afterweinitializeitinTankclass:

classTank<GameObjectattr_accessor:health#...definitialize(object_pool,input)#...@health=TankHealth.new(self,object_pool)#..end#..end

Page 449: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

InflictingDamageWithBulletsTherearetwowaystoinflictdamage-directlyandindirectly.Whenbullethitsenemytank(collideswithtankboundingbox),weshouldinflictdirectdamage.ItcanbedoneinBulletPhysics#check_hit

methodthatwealreadyhad:

Page 450: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

classBulletPhysics<Component#...defcheck_hit@object_pool.nearby(object,50).eachdo|obj|nextifobj==object.source#Don'thitsourcetankifUtils.point_in_poly(x,y,*obj.box)#Directhit-extradamageobj.health.inflict_damage(20)object.target_x=xobject.target_y=yreturnendendend

Page 451: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...end

Finally,Explosionitselfshouldinflictadditionaldamagetoanythingthatarenearby.Theeffectwillbediminishinganditwillbedeterminedbyobjectdistance.

classExplosion<GameObject#...definitialize(object_pool,x,y)#...

Page 452: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

inflict_damageend

private

definflict_damageobject_pool.nearby(self,100).eachdo|obj|ifobj.class==Tankobj.health.inflict_damage(Math.sqrt(3*100-Utils.distance_between(obj.x,obj.y,x,y)))endendendend

Page 453: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Thisisit,wearereadytodealdamage.Butwewanttoseeifweactuallykilledsomebody,soTankGraphicsshouldbeawareofhealthandshoulddrawdifferentsetofspriteswhentankisdead.HereiswhatweneedtochangeinourcurrentTankGraphicstoachievetheresult:

classTankGraphics<Component#...definitialize(game_object)super(game_object)

Page 454: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@body_normal=units.frame('tank1_body.png')@shadow_normal=units.frame('tank1_body_shadow.png'

@gun_normal=units.frame('tank1_dualgun.png')

@body_dead=units.frame('tank1_body_destroyed.png'

@shadow_dead=units.frame('tank1_body_destroyed_shadow.png'

@gun_dead=nilend

defupdateifobject.health.dead?@body=@body_dead@gun=@gun_dead

Page 455: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@shadow=@shadow_deadelse@body=@body_normal@gun=@gun_normal@shadow=@shadow_normalendend

defdraw(viewport)@shadow.draw_rot(x-1,y-1,0,object.direction)@body.draw_rot(x,y,1,object.direction)@gun.draw_rot(x,y,2,object.gun_angle)if@gunend#...end

Page 456: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Nowwecanblowthemupandenjoytheview:

Page 457: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Targetpractice

Butwhatifweblowourselvesupbyshootingnearby?Wewouldstillbeabletomovearound.Tofix

Page 458: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

this,wewillsimplycutoutplayerinputwhenwearedead:

classPlayerInput<Component#...defupdatereturnifobject.health.dead?#...end#...end

Andtopreventtankfromthrottlingforeverifthepedalwasdownbeforeitgotkilled:

Page 459: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

classTankPhysics<Component#...defupdateifobject.throttle_down&&!object.health.dead?accelerateelsedecelerateend#...end#...end

That’sit.Allweneedrightnowissomeresistancefromthosebraindeadenemies.We

Page 460: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

willsparksomelifeintotheminnextchapter.

Page 461: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

CreatingArtificialIntelligence

ArtificialIntelligenceisasubjectsovastthatwewillbarelyscratchthesurface.AIinVideoGamesisusuallyheavilysimplifiedandthereforeeasiertoimplement.

Page 462: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ThereisthiswonderfulseriesofarticlescalledDesigningArtificialIntelligenceforGamesthatIhighlyrecommendreadingtogetafeelinghowgameAIshouldbedone.Wewillbecontinuingourworkontopofwhatwealreadyhave,examplecodeforthischapterwillbein08-ai.

Page 463: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

DesigningAIUsingFiniteStateMachineNonplayertanksinourgamewillbelonerangers,huntingeverythingthatmoveswhiletryingtosurvive.WewilluseFiniteStateMachinetoimplementtankbehavior.

First,weneedtothink“whatwouldatankdo?”Howaboutthisscenario:

Page 464: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1. Tankwandersaround,mindingit’sownbusiness.

2. Tankencountersanothertank.Itthenstartsdoingevasivemovesandtrieshittingtheenemy.

3. Enemytooksomedamageandstarteddrivingaway.Tankstartschasingtheenemytryingtofinishit.

4. Anothertankappearsandfiresacoupleof

Page 465: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

accurateshots,dealingseriousdamage.Ourtankstartsrunningaway,becauseifitkeptreceivingdamageatsuchrate,itwoulddieverysoon.

5. Tankkeepsfleeingandlookingforsafetyuntilitgetscorneredortheopponentlooksdamagedtoo.Thentankgoesintoit’sfinalbattle.

Page 466: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

WecannowdrawaFiniteStateMachineusingthisscenario:

VigilanteTankFSM

Ifyouareonapathtobecomeagamedeveloper,FSMshouldnotstandfor

Page 467: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

FlyingSpaghettiMonsterforyouanymore.

ImplementingAIVisionTomakeopponentsrealistic,wehavetogivethemsenses.Let’screateaclassforthat:08-ai/entities/components/ai/vision.rb1classAiVision2CACHE_TIMEOUT=5003attr_reader:in_sight

Page 468: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

45definitialize(viewer,object_pool,distance)6@viewer=viewer7@object_pool=object_pool8@distance=distance9end1011defupdate12@in_sight=@object_pool.nearby(@viewer,@distance)13end1415defclosest_tank16now=Gosu.milliseconds17@closest_tank=nil18ifnow-(@cache_updated_at||=0)>CACHE_TIMEOUT

Page 469: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

19@closest_tank=nil20@cache_updated_at=now21end22@closest_tank||=find_closest_tank23end2425private2627deffind_closest_tank28@in_sight.selectdo|o|29o.class==Tank&&!o.health.dead?30end.sortdo|a,b|31x,[email protected],@viewer.y32d1=Utils.distance_between(x,y,a.x,a.y)33d2=

Page 470: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Utils.distance_between(x,y,b.x,b.y)34d1<=>d235end.first36end37end

ItusesObjectPooltoputnearbyobjectsinsight,andgetsashorttermfocusononeclosesttank.Closesttankiscachedfor500millisecondsfortworeasons:

Page 471: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1. Performance.UncachedversionwoulddoArray#selectandArray#sort60timespersecond,nowitwilldo2times.

2. Focus.Whenyouchooseatarget,youshouldkeepitalittlelonger.Thisshouldalsoavoid“jitters”,whentankwouldshakebetweentwonearbytargetsthat

Page 472: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

arewithinsamedistance.

ControllingTankGunAfterwemadeAiVision,wecannowuseittoautomaticallyaimandshootatclosesttank.Itshouldworklikethis:

Page 473: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1. Everyinstanceofthegunhasit’sownuniquecombinationofspeed,accuracyandaggressiveness.

2. Gunwillautomaticallytargetclosesttankinsight.

3. Ifnoothertankisinsight,gunwilltargetinsamedirectionastank’sbody.

4. Ifothertankisaimedatandwithinshooting

Page 474: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

distance,gunwillmakeadecisiononceinawhilewhetheritshouldshootornot,basedonaggressivenesslevel.Aggressivetankswillbetriggerhappyallthetime,whilelessaggressiveoneswillmakesmallrandompausesbetweenshots.

5. Gunwillhavea“desired”anglethatitwillbeautomatically

Page 475: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

adjustingto,accordingtoit’sspeed.

Hereistheimplementation:08-ai/entities/components/ai/gun.rb1classAiGun2DECISION_DELAY=10003attr_reader:target,:desired_gun_angle45definitialize(object,vision)6@object=object7@vision=vision8@desired_gun_angle=rand(0..360)9@retarget_speed=

Page 476: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

rand(1..5)10@accuracy=rand(0..10)11@aggressiveness=rand(1..5)12end1314defadjust_angle15adjust_desired_angle16adjust_gun_angle17end1819defupdate20if@[email protected]_tank!=@target22change_target(@vision.closest_tank

23end24else

Page 477: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

25@target=nil26end2728if@target29if(0..10-rand(0..@accuracy)).include?(30(@[email protected]_angle).abs.round)31distance=distance_to_target32ifdistance-50<=BulletPhysics::MAX_DIST33target_x,target_y=Utils.point_at_distance([email protected],@object.y,@object.gun_angle,35distance+10-rand(0..@accuracy))36ifcan_make_new_decision?&&

Page 478: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@object.can_shoot?&&[email protected](target_x,target_y)39end40end41end42end43end4445defdistance_to_target46Utils.distance_between([email protected],@object.y,@target.x,@target.y)48end495051defshould_shoot?52rand*@aggressiveness>0.5

Page 479: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

53end5455defcan_make_new_decision?56now=Gosu.milliseconds57ifnow-(@last_decision||=0)>DECISION_DELAY58@last_decision=now59true60end61end6263defadjust_desired_angle64@[email protected]_between([email protected],@object.y,@target.x,@target.y)67else

Page 480: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]_target(new_target)73@target=new_target74adjust_desired_angle75end7677defadjust_gun_angle78actual=@object.gun_angle79desired=@desired_gun_angle80ifactual>desired81ifactual-desired>180#0->[email protected]_angle=(actual+@retarget_speed)%360

Page 481: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]_angle<[email protected]_angle=desired#[email protected]_angle=[actual-@retarget_speed,desired].max88end89elsifactual<desired90ifdesired-actual>180#360->[email protected]_angle=(360+actual-@retarget_speed)%[email protected]_angle>[email protected]_angle=desired#damp94end

Page 482: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]_angle=[actual+@retarget_speed,desired].min97end98end99end100end

Thereissomemathinvolved,butitisprettystraightforward.Weneedtofindoutananglebetweentwopoints,toknowwhereourgunshouldpoint,andtheotherthingweneedis

Page 483: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

coordinatesofpointwhichisinsomedistanceawayfromsourceatgivenangle.Herearethosefunctions:

moduleUtils#...defself.angle_between(x,y,target_x,target_y)dx=target_x-xdy=target_y-y(180-Math.atan2(dx,dy)*180/Math::PI)+360%360end

defself.point_at_distance(source_x,source_y,angle,distance)angle=(90-angle)*

Page 484: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Math::PI/180x=source_x+Math.cos(angle)*distancey=source_y-Math.sin(angle)*distance[x,y]end#...end

ImplementingAIInputAtthispointourtankscanalreadydefendthemselves,eventhroughmotionisnot

Page 485: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

yetimplemented.Let’swireeverythingwehaveinAiInputclassthatwehadpreparedearlier.WewillneedablankTankMotionFSMclasswith3argumentinitializerandemptyupdate,on_collision(with)andon_damage(amount)methodsforittowork:08-ai/entities/components/ai_input.rb1classAiInput<Component2UPDATE_RATE=200#ms

Page 486: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

34definitialize(object_pool)5@object_pool=object_pool6super(nil)7@last_update=Gosu.milliseconds8end910defcontrol(obj)11self.object=obj12@vision=AiVision.new(obj,@object_pool,13rand(700..1200))14@gun=AiGun.new(obj,@vision)15@motion=TankMotionFSM.new(obj,@vision,@gun)

Page 487: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

16end1718defon_collision(with)[email protected]_collision(with)20end2122defon_damage(amount)[email protected]_damage(amount)[email protected]_angle29now=Gosu.milliseconds30returnifnow-@last_update<UPDATE_RATE31@[email protected]

Page 488: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]@motion.update35end36end

Itadjustgunangleallthetime,butdoesupdatesatUPDATE_RATEtosaveCPUpower.AIisusuallyoneofthemostCPUintensivethingsingames,soit’sacommonpracticetoexecuteitlessoften.Refreshingenemy

Page 489: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

brains5persecondisenoughtomakethemdeadly.

MakesureyouspawnsomeAIcontrolledtanksinPlayStateandtrykillingthemnow.Ibettheywilleventuallygetyouevenwhilestandingstill.YoucanalsomaketanksspawnbelowmousecursorwhenyoupressTkey:

classPlayState<GameState#...

Page 490: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

definitialize#...10.timesdo|i|Tank.new(@object_pool,AiInput.new(@object_pool))endend#...defbutton_down(id)#...ifid==Gosu::KbTt=Tank.new(@object_pool,AiInput.new(@object_pool))t.x,[email protected]_coordsend#...end

Page 491: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...end

ImplementingTankMotionStatesThisistheplacewherewewillneedFiniteStateMachinetogetthingsright.Wewilldesignitlikethis:

1. TankMotionFSMwilldecidewhichmotionstatetankshouldbein,

Page 492: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

consideringvariousparameters,e.g.existenceoftargetorlackthereof,health,etc.

2. TherewillbeTankMotionStatebaseclassthatwilloffercommonmethodslikedrive,waitandon_collision.

3. Concretemotionclasseswillimplementupdate,change_directionandothermethods,thatwill

Page 493: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

fiddlewithTank#throttle_down

andTank#directiontomakeitmoveandturn.

WewillbeginwithTankMotionState:08-ai/entities/components/ai/tank_motion_state.rb1classTankMotionState2definitialize(object,vision)3@object=object4@vision=vision5end

Page 494: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

67defenter8#Overrideifnecessary9end1011defchange_direction12#Override13end1415defwait_time16#Overrideandreturnanumber17end1819defdrive_time20#Overrideandreturnanumber21end2223defturn_time24#Overrideandreturna

Page 495: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

number25end2627defupdate28#Override29end3031defwait32@sub_state=:waiting33@started_waiting=Gosu.milliseconds34@[email protected]_down=false36end3738defdrive39@sub_state=:driving40@started_driving=Gosu.milliseconds

Page 496: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

41@[email protected]_down=true43end4445defshould_change_direction?46returntrueunless@changed_direction_at47Gosu.milliseconds-@changed_direction_at>48@will_keep_direction_for49end5051defsubstate_expired?52now=Gosu.milliseconds53case@sub_state54when:waiting55trueifnow-

Page 497: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@started_waiting>@will_wait_for56when:driving57trueifnow-@started_driving>@will_drive_for58else59true60end61end6263defon_collision(with)64change=caserand(0..100)65when0..3066-9067when30..60689069when60..707013571when80..90

Page 498: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]_direction

[email protected]+change)78end79end

Nothingextraordinaryhere,andweneedaconcreteimplementationtogetafeelinghowitwouldwork,thereforelet’sexamine

Page 499: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

TankRoamingState.Itwillbethedefaultstatewhichtankwouldbeiniftherewerenoenemiesaround.

TankRoamingState08-ai/entities/components/ai/tank_roaming_state.rb1classTankRoamingState<TankMotionState2definitialize(object,vision)3super4@object=object5@vision=vision6end

Page 500: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

78defupdate9change_directionifshould_change_direction?10ifsubstate_expired?11rand>0.3?drive:wait12end13end1415defchange_direction16change=caserand(0..100)17when0..3018-4519when30..60204521when60..70229023when80..9024-90

Page 501: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]_direction

[email protected]+change)31end32@changed_direction_at=Gosu.milliseconds33@will_keep_direction_for=turn_time34end3536defwait_time37rand(500..2000)38end3940defdrive_time

Page 502: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

41rand(1000..5000)42end4344defturn_time45rand(2000..5000)46end47end

Thelogichere:

1. Tankwillrandomlychangedirectioneveryturn_timeinterval,whichisbetween2and5seconds.

Page 503: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

2. Tankwillchoosetodrive(80%chance)ortostandstill(20%chance).

3. Iftankchosetodrive,itwillkeepdrivingfordrive_time,whichisbetween1and5seconds.

4. Samegoeswithwaiting,butwait_time(0.5-2seconds)willbeusedforduration.

5. Directionchangesanddriving/waitingare

Page 504: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

independent.

Thiswillmakeanimpressionthatourtankisdrivingaroundlookingforenemies.

TankFightingStateWhentankfinallyseesanopponent,itwillstartfighting.Fightingmotionshouldbemoreenergeticthanroaming,wewillneedasharpersetofchoicesin

Page 505: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

change_directionamongotherthings.08-ai/entities/components/ai/tank_fighting_state.rb1classTankFightingState<TankMotionState2definitialize(object,vision)3super4@object=object5@vision=vision6end78defupdate9change_directionifshould_change_direction?10ifsubstate_expired?11rand>0.2?drive:

Page 506: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

wait12end13end1415defchange_direction16change=caserand(0..100)17when0..2018-4519when20..40204521when40..60229023when60..8024-9025when80..902613527when90..10028-13529end30

Page 507: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@object.physics.change_direction

[email protected]+change)32@changed_direction_at=Gosu.milliseconds33@will_keep_direction_for=turn_time34end3536defwait_time37rand(300..1000)38end3940defdrive_time41rand(2000..5000)42end4344defturn_time45rand(500..2500)

Page 508: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

46end47end

Wewillhavemuchlesswaitingandmuchmoredrivingandturning.

TankChasingStateIfopponentisfleeing,wewillwanttosetourdirectiontowardstheopponentandhitpedaltothemetal.Nowaitinghere.AiGun#desired_gun_angle

Page 509: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

willpointdirectlytoourenemy.08-ai/entities/components/ai/tank_chasing_state.rb1classTankChasingState<TankMotionState2definitialize(object,vision,gun)3super(object,vision)4@object=object5@vision=vision6@gun=gun7end89defupdate10change_directionifshould_change_direction?11drive

Page 510: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]_direction

[email protected][email protected]_gun_angle%45)1819@changed_direction_at=Gosu.milliseconds20@will_keep_direction_for=turn_time21end2223defdrive_time241000025end26

Page 511: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

27defturn_time28rand(300..600)29end30end

TankFleeingStateNow,ifourhealthislow,wewilldotheoppositeofchasing.Gunwillbepointingandshootingattheopponent,butwewantbodytomoveaway,sowewon’tgetourselveskilled.ItisverysimilartoTankChasingState

Page 512: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

wherechange_directionaddsextra180degreestotheequation,butthereisonemorething.Tankcanonlyfleeforawhile.Thenitgetsitselftogetherandgoesintofinalbattle.That’swhyweprovidecan_flee?methodthatTankMotionFSMwillconsultwithbeforeenteringfleeingstate.

Wehaveimplementedallthestates,thatmeansweare

Page 513: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

momentsawayfromactuallyplayableprototypewithtankbotsrunningaroundandfightingwithyouandeachother.

WiringTankMotionStatesIntoFiniteStateMachineImplementingTankMotionFSMafterwehaveallmotion

Page 514: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

statesreadyissurprisinglyeasy:08-ai/entities/components/ai/tank_motion_fsm.rb1classTankMotionFSM2STATE_CHANGE_DELAY=50034definitialize(object,vision,gun)5@object=object6@vision=vision7@gun=gun8@roaming_state=TankRoamingState.new(object,vision)9@fighting_state=TankFightingState.new(object,vision)

Page 515: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

10@fleeing_state=TankFleeingState.new(object,vision,gun)11@chasing_state=TankChasingState.new(object,vision,gun)12set_state(@roaming_state)13end1415defon_collision(with)16@current_state.on_collision(with

17end1819defon_damage(amount)20if@current_state==@roaming_state21set_state(@fighting_state)

Page 516: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

22end23end2425defupdate26choose_state27@current_state.update28end2930defset_state(state)31returnunlessstate32returnifstate==@current_state33@last_state_change=Gosu.milliseconds34@current_state=state35state.enter36end3738defchoose_state39returnunlessGosu.milliseconds-

Page 517: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

40(@last_state_change)>[email protected]@object.health.health>[email protected]_to_target>BulletPhysics::MAX_DIST44new_state=@chasing_state45else46new_state=@fighting_state47end48else49if@fleeing_state.can_flee?50new_state=@fleeing_state51else52new_state=

Page 518: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@fighting_state53end54end55else56new_state=@roaming_state57end58set_state(new_state)59end60end

Allthelogicisinchoose_statemethod,whichisprettyuglyandprocedural,butitdoesthejob.Thecodeshouldbeeasytounderstand,

Page 519: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

soinsteadofdescribingit,hereisapictureworththousandwords:

Page 520: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Firstrealbattle

Youmaynoticeanewcrosshair,whichreplacedtheoldonethatwasnevervisible:

Page 521: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

classCamera#...defdraw_crosshairfactor=0.5x=$window.mouse_xy=$window.mouse_yc=crosshairc.draw(x-c.width*factor/2,y-c.height*factor/2,1000,factor,factor)end#...private

defcrosshair@crosshair||=Gosu::Image.new($window,

Page 522: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Utils.media_path('c_dot.png'),false)endend

Howeverthisnewcrosshairdidn’thelpmewin,Igotmyasskickedbadly.Increasinggamewindowsizehelped,butweobviouslyneedtofinetunemanythingsinthisAI,tomakeitsmartandchallengingratherthandumbanddeadlyaccurate.

Page 523: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

MakingThePrototypePlayable

Rightnowwehaveasomewhatplayable,butboringprototypewithoutanyscoresorwinningconditions.Youcanjustrunaroundandshootothertanks.Nobody

Page 524: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

wouldplayagamelikethis,henceweneedtotoaddthemissingparts.Thereisacrazyamountofthem.Itistimetogiveitathoroughplaythroughandwritedownalltheideasandpainpointsabouttheprototype.

Hereismylist:

1. Enemytanksdonotrespawn.

Page 525: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

2. Enemytanksshootatmycurrentlocation,notatwhereIwillbewhenbullethitsme.

3. Enemytanksdon’tavoidcollisions.

4. Randommapsareboringandlackdetail,couldusemoretilesorrandomenvironmentobjects.

5. Bulletsarehardtoseeongreensurface.

6. Hardtotellwhereenemiesarecoming

Page 526: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

from,radarwouldhelp.7. Soundsplayatfull

volumeevenwhensomethinghappensacrossthewholemap.

8. Mytankshouldrespawnafterit’sdead.

9. Motionandfiringmechanicsseemclumsy.

10. Mapboundariesarevisiblewhenyoucometotheedge.

11. Enemytankmovementpatternsneedpolishing

Page 527: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

andimprovement.12. Bothmytankand

enemiesdon’thaveanyidentity.Sometimeshardtodistinguishwhoiswho.

13. Noideawhohasmostkills.HUDwithscoreandsomestatethatdisplaysscoredetailswouldhelp.

14. Wouldbegreattohaverandompowerupslikehealth,extradamage.

Page 528: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

15. Explosionsdon’tleaveatrace.

16. Tankscouldleavetrails.17. Deadtankskeeppiling

upandclutteringthemap.

18. Camerashouldbescoutingaheadofyouwhenyoumove,notdraggingbehind.

19. Bulletsseemtoaccelerate.

Page 529: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Thiswillkeepusbusyforawhile,butintheendwewillprobablyhavesomethingthatwillhopefullybeabletoentertainpeopleformorethan3minutes.

Someitemsonthislistareeasyfixes.AfterplayingaroundwithPixelmatorfor15minutes,Iendedupwithabulletthatisvisibleonbothlightanddarkbackgrounds:

Page 530: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Highlyvisiblebullet

Motionandfiringmechanicswilleitherhavetobetunedsettingbysetting,orrewrittenfromscratch.Implementing

Page 531: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

scoresystem,powerupsandimprovingenemyAIdeservetohavechaptersoftheirown.Therestcanbetakencareofrightaway.

DrawingWaterBeyondMapBoundariesWedon’twanttoseedarknesswhenwecometotheedgeofgameworld.

Page 532: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Luckily,itisatrivialfix.InMap#drawwecheckiftileexistsinmapbeforedrawingit.Whentiledoesnotexist,wecandrawwaterinstead.AndwecanalwaysfallbacktowatertileinMap#tile_at:

classMap#...defdraw(viewport)viewport.map!{|p|p/TILE_SIZE}x0,x1,y0,y1=viewport.map(&:to_i)(x0..x1).eachdo|x|(y0..y1).eachdo|y|

Page 533: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

row=@map[x]map_x=x*TILE_SIZEmap_y=y*TILE_SIZEifrowtile=@map[x][y]iftiletile.draw(map_x,map_y,0)[email protected](map_x,map_y,0)[email protected](map_x,map_y,0)endendendend#...private

Page 534: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...deftile_at(x,y)t_x=((x/TILE_SIZE)%TILE_SIZE).floort_y=((y/TILE_SIZE)%TILE_SIZE).floorrow=@map[t_x]row?row[t_y]:@waterend#...end

Nowtheedgelooksmuchbetter:

Page 535: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Mapedge

GeneratingTreeClusters

Page 536: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tomakethemapmorefuntoplayat,wewillgeneratesometrees.Let’sstartwithTreeclass:09-polishing/entities/tree.rb1classTree<GameObject2attr_reader:x,:y,:health,:graphics34definitialize(object_pool,x,y,seed)5super(object_pool)6@x,@y=x,y7@graphics=TreeGraphics.new(self,seed)8@health=

Page 537: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Health.new(self,object_pool,30,false)9@angle=rand(-15..15)10end1112defon_collision(object)[email protected](object.direction

14end1516defbox17[x,y]18end19end

Nothingfancyhere,wewantittoshakeoncollision,andit

Page 538: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

hasgraphicsandhealth.seedwillusedtogenerateclustersofsimilartrees.Let’stakealookatTreeGraphics:09-polishing/entities/components/tree_graphics.rb1classTreeGraphics<Component2SHAKE_TIME=1003SHAKE_COOLDOWN=2004SHAKE_DISTANCE=[2,1,0,-1,-2,-1,0,1,0,-1,0]5definitialize(object,seed)6super(object)7load_sprite(seed)8end

Page 539: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

910defshake(direction)11now=Gosu.milliseconds12returnif@shake_start&&13now-@shake_start<SHAKE_TIME+SHAKE_COOLDOWN14@shake_start=now15@shake_direction=direction16@shaking=true17end1819defadjust_shake(x,y,shaking_for)20elapsed=[shaking_for,SHAKE_TIME].min/SHAKE_TIME.to_f21frame=((SHAKE_DISTANCE.length-1)*elapsed).floor

Page 540: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

22distance=SHAKE_DISTANCE[frame]23Utils.point_at_distance(x,y,@shake_direction,distance)24end2526defdraw(viewport)27if@shaking28shaking_for=Gosu.milliseconds-@shake_start29shaking_x,shaking_y=adjust_shake(30center_x,center_y,shaking_for)[email protected](shaking_x,shaking_y,5)32ifshaking_for>=SHAKE_TIME33@shaking=false

Page 541: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected](center_x,center_y,5)37end38Utils.mark_corners(object.box)[email protected]@tree.width47end4849private5051defload_sprite(seed)

Page 542: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

52frame_list=trees.frame_list53frame=frame_list[(frame_list.size*seed).round]54@tree=trees.frame(frame)55end5657defcenter_x58@center_x||[email protected]/259end6061defcenter_y62@center_y||[email protected]/263end6465deftrees66@@trees||=

Page 543: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Gosu::TexturePacker.load_json($window

67Utils.media_path('trees_packed.json'

68end69end

Shakingisprobablythemostinterestingparthere.Whenshakeiscalled,graphicswillstartdrawingtreeshiftedingivendirectionbyamountdefinedinSHAKE_DISTANCEarray.drawwillbestepping

Page 544: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

throughSHAKE_DISTANCEdependingonSHAKE_TIME,anditwillnotbeshakenagainforSHAKE_COOLDOWNperiod,toavoidinfiniteshakingwhiledrivingintoit.

WealsoneedsomeadjustmentstoTankPhysicsandTanktobeabletohittrees.First,wewanttocreateanemptyon_collision(object)

methodinGameObjectclass,

Page 545: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

soallgameobjectswillbeabletocollide.

Then,TankPhysicsstartscallingTank#on_collisionwhencollisionisdetected:

classTank<GameObject#...defon_collision(object)returnunlessobject#Avoidrecursionifobject.class==Tank#InformAIabouthitobject.input.on_collision(object

else

Page 546: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#Callonlyonnon-tankstoavoidrecursionobject.on_collision(self)end#BulletsshouldnotslowTanksdownifobject.class!=Bullet@[email protected]>1endend#...end

ThefinalingredienttoourTreeisHealth,whichisextractedfromTankHealthto

Page 547: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

reduceduplication.TankHealthnowextendsit:09-polishing/entities/components/health.rb1classHealth<Component2attr_accessor:health34definitialize(object,object_pool,health,explodes)5super(object)6@explodes=explodes7@object_pool=object_pool8@initial_health=@health=health9@health_updated=true10end11

Page 548: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

12defrestore13@health=@initial_health14@health_updated=true15end1617defdead?18@health<119end2021defupdate22update_image23end2425definflict_damage(amount)26if@health>027@health_updated=true28@health=[@health-amount.to_i,0].max29after_deathifdead?30end

Page 549: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

31end3233defdraw(viewport)34returnunlessdraw?35@image&&@image.draw([email protected]/2,37y-object.graphics.height/[email protected],100)39end4041protected4243defdraw?44$debug45end4647defupdate_image48returnunlessdraw?49if@[email protected]_s

Page 550: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

51font_size=1852@image=Gosu::Image.from_text(53$window,text,54Gosu.default_font_name,font_size)55@health_updated=false56end57end5859defafter_death60if@explodes61ifThread.list.count<862Thread.newdo63sleep(rand(0.1..0.3))64Explosion.new(@object_pool,x,

Page 551: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

y)65sleep0.366object.mark_for_removal67end68else69Explosion.new(@object_pool,x,y)70object.mark_for_removal71end72else73object.mark_for_removal74end75end76end

Page 552: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Yes,youcanmaketreeexplodewhenit’sdestroyed.Anditcausescoolchainreactionsblowingupwholetreeclusters.Butlet’snotdothat,becausewewilladdsomethingmoreappropriateforexplosions.

OurTreeisreadytofillthelandscape.WewilldoitinMapclass,whichwillnowneedtoknowabout

Page 553: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ObjectPool,becausetreeswillgothere.

classMap#...definitialize(object_pool)load_tiles@object_pool=object_poolobject_pool.map=self@map=generate_mapgenerate_treesend#...defgenerate_treesnoises=Perlin::Noise.new(2)contrast=Perlin::Curve.contrast(Perlin::Curve::CUBIC,2)trees=0

Page 554: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

target_trees=rand(300..500)whiletrees<target_treesdox=rand(0..MAP_WIDTH*TILE_SIZE)y=rand(0..MAP_HEIGHT*TILE_SIZE)n=noises[x*0.001,y*0.001]n=contrast.call(n)iftile_at(x,y)==@grass&&n>0.5Tree.new(@object_pool,x,y,n*2-1)trees+=1endendend#...end

Page 555: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Perlinnoiseisusedinsimilarfashionasitwaswhenwegeneratedmaptiles.Weallowcreatingtreesonlyifnoiselevelisabove0.5,andusenoiselevelasseedvalue-n*2-1willbeanumberbetween0and1whennisin0.5..1range.Andweonlyallowcreatingtreesongrasstiles.

Nowourmaplooksalittlebetter:

Page 556: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Hidingamongprocedurallygeneratedtrees

GeneratingRandomObjects

Page 557: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Treesaregreat,butwewantmoredetail.Let’sspicethingsupwithexplosiveboxesandbarrels.Theywillbeusingthesameclasswithsinglespritesheet,sowhilethespritewillbechosenrandomly,behaviorwillbethesame.ThisnewclasswillbecalledBox:09-polishing/entities/box.rb1classBox<GameObject2attr_reader:x,:y,:health,:graphics,:angle

Page 558: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

34definitialize(object_pool,x,y)5super(object_pool)6@x,@y=x,y7@graphics=BoxGraphics.new(self)8@health=Health.new(self,object_pool,10,true)9@angle=rand(-15..15)10end1112defon_collision(object)13returnunlessobject.physics.speed>1.014@x,@y=Utils.point_at_distance(@x,@y,object.direction,2)15@box=nil16end

Page 559: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1718defbox19return@boxif@[email protected]/[email protected]/222#Boundingboxadjustedtotrimshadows23@box=[x-w+4,y-h+8,24x+w,y-h+8,25x+w,y+h,26x-w+4,y+h]27@box=Utils.rotate(@angle,@x,@y,*@box)28end29end

Page 560: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Itwillbegeneratedwithslightrandomangle,topreserverealisticshadowsbutgiveanimpressionofchaoticplacement.Tankswillalsobeabletopushboxesalittleoncollision,butonlywhengoingfastenough.HealthcomponentisthesameonethatTreehas,butinitializedwithlesshealthandexplosiveflagistrue,sotheboxwillblowupafteronehitanddeal

Page 561: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

extradamagetothesurroundings.

BoxGraphicsisnothingfancy,itjustloadsrandomspriteuponinitialization:09-polishing/entities/components/box_graphics.rb1classBoxGraphics<Component2definitialize(object)3super(object)4load_sprite5end67defdraw(viewport)

Page 562: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]_rot(x,y,0,object.angle)9Utils.mark_corners(object.box)[email protected]@box.width18end1920private2122defload_sprite23frame=boxes.frame_list.sample24@box=

Page 563: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

boxes.frame(frame)25end2627defcenter_x28@center_x||=x-width/229end3031defcenter_y32@center_y||=y-height/233end3435defboxes36@@boxes||=Gosu::TexturePacker.load_json($window

37Utils.media_path('boxes_barrels.json'

Page 564: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

38end39end

TimetogenerateboxesinourMap.Itwillbesimilartotrees,butwewon’tneedPerlinnoise,sincetherewillbewayfewerboxesthantrees,sowedon’tneedtoformpatterns.Allweneedtodoistocheckifwe’renotgeneratingboxonwater.

classMap#...

Page 565: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

definitialize(object_pool)#...generate_boxesend#...defgenerate_boxesboxes=0target_boxes=rand(10..30)whileboxes<target_boxesdox=rand(0..MAP_WIDTH*TILE_SIZE)y=rand(0..MAP_HEIGHT*TILE_SIZE)iftile_at(x,y)[email protected](@object_pool,x,y)boxes+=1endend

Page 566: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

end#...end

Nowgiveitago.Beautiful,isn’tit?

Page 567: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Boxesandbarrelsinthejungle

ImplementingARadar

Page 568: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Withallthevisualnoiseitisgettingincreasinglydifficulttoseeenemytanks.That’swhywewillimplementaRadartohelpourselves.09-polishing/entities/radar.rb1classRadar2UPDATE_FREQUENCY=10003WIDTH=1504HEIGHT=1005PADDING=106#Blackwith33%transparency7BACKGROUND=Gosu::Color.new(255*0.33,0,0,0)8attr_accessor:target

Page 569: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

910definitialize(object_pool,target)11@object_pool=object_pool12@target=target13@last_update=014end1516defupdate17ifGosu.milliseconds-@last_update>UPDATE_FREQUENCY18@nearby=nil19end20@nearby||=@object_pool.nearby(@target,2000).selectdo|o|21o.class==Tank&&!o.health.dead?22end23end

Page 570: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

2425defdraw26x1,x2,y1,y2=radar_coords27$window.draw_quad(28x1,y1,BACKGROUND,29x2,y1,BACKGROUND,30x2,y2,BACKGROUND,31x1,y2,BACKGROUND,32200)33draw_tank(@target,Gosu::Color::GREEN)34@nearby&&@nearby.eachdo|t|35draw_tank(t,Gosu::Color::RED)36end37end3839private40

Page 571: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

41defdraw_tank(tank,color)42x1,x2,y1,y2=radar_coords43tx=x1+WIDTH/2+([email protected])/2044ty=y1+HEIGHT/2+([email protected])/2045if(x1..x2).include?(tx)&&(y1..y2).include?(ty)46$window.draw_quad(47tx-2,ty-2,color,48tx+2,ty-2,color,49tx+2,ty+2,color,50tx-2,ty+2,color,51300)52end53end

Page 572: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

5455defradar_coords56x1=$window.width-WIDTH-PADDING57x2=$window.width-PADDING58y1=$window.height-HEIGHT-PADDING59y2=$window.height-PADDING60[x1,x2,y1,y2]61end62end

Radar,likeCamera,alsohasatarget.ItusesObjectPooltoquerynearbyobjectsandfiltersoutinstancesofalive

Page 573: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tank.Thenitdrawsatransparentblackbackgroundandsmalldotsforeachtank,greenfortarget,redfortherest.

ToavoidqueryingObjectPooltoooften,Radarupdatesitselfonlyonceeverysecond.

Itisinitialized,updatedanddrawninPlayState,rightafterCamera:

Page 574: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

classPlayState<GameState#...definitialize#[email protected]=@tank@radar=Radar.new(@object_pool,@tank)#...end#...defupdate#[email protected]@radar.update#...end#...defdraw#[email protected][email protected]

Page 575: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

end#...end

Timetoenjoytheresults.

Page 576: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Radarinaction

DynamicSoundVolumeAndPanning

Page 577: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Wehaveimprovedthevisuals,butsoundisstillterrible.Likesomesuperhero,youcanheareverythingthathappensinthemap,anditcandriveyouinsane.Wewillfixthatinamoment.

Theideaistomakeeverythingthathappensfurtherawayfromcameratargetsoundlessloud,untilthesoundfadesawaycompletely.Tomakeplayer’s

Page 578: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

experiencemoreimmersive,wewillalsotakeadvantageofstereospeakers-soundsshouldappeartobecomingfromtherightdirection.

Unfortunately,Gosu::Sample#play_pan

doesnotworkasonewouldexpectitto.Ifyouplaythesamplewithjustalittlepanning,itcompletelycutsofftheoppositechannel,meaningthatifyouplaya

Page 579: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

samplewithpanlevelof0.1(10%totheright),youwouldexpecttohearsomethinginleftspeakeraswell.Theactualbehavioristhatsoundplaysthroughtherightspeakerprettyloudly,andifyouincreasepanlevelto,say,0.7,youwillhearthesoundthroughrightspeakeragain,butitwillbewaymoresilent.

Toimplementrealisticstereosoundsthatcomethrough

Page 580: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

bothspeakerswhenpanned,weneedtoplaytwosampleswithoppositepanlevel.Aftersomeexperimenting,Idiscoveredthatfiddlingwithpanlevelmakesthingssoundweird,whileplayingwithvolumeproducessofter,moresubtleeffect.ThisiswhatIendeduphaving:09-polishing/misc/stereo_sample.rb1classStereoSample2@@all_instances=[]

Page 581: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

34defself.register_instances(instances

5@@all_instances<<instances6end78defself.cleanup9@@all_instances.eachdo|instances|10instances.eachdo|key,instance|11unlessinstance.playing?||instance.paused?12instances.delete(key)13end14end15end

Page 582: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

16end1718definitialize(window,sound_l,sound_r=sound_l)19@sound_l=Gosu::Sample.new(window,sound_l)20#Usesamesampleinmono->stereo21ifsound_l==sound_r22@sound_r=@sound_l23else24@sound_r=Gosu::Sample.new(window,sound_r)25end26@instances={}27self.class.register_instances(@instances

28end

Page 583: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

2930defpaused?(id=:default)31i=@instances["#{id}_l"]32i&&i.paused?33end3435defplaying?(id=:default)36i=@instances["#{id}_l"]37i&&i.playing?38end3940defstopped?(id=:default)41@instances["#{id}_l"].nil?42end4344defplay(id=:default,

Page 584: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

pan=0,45volume=1,speed=1,looping=false)46@instances["#{id}_l"]=@sound_l.play_pan(47-0.2,0,speed,looping)48@instances["#{id}_r"]=@sound_r.play_pan(490.2,0,speed,looping)50volume_and_pan(id,volume,pan)51end5253defpause(id=:default)54@instances["#{id}_l"].pause55@instances["#{id}_r"].pause56end

Page 585: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

5758defresume(id=:default)59@instances["#{id}_l"].resume60@instances["#{id}_r"][email protected]("#{id}_l")[email protected]("#{id}_r").stop66end6768defvolume_and_pan(id,volume,pan)69ifpan>070pan_l=1-pan*271pan_r=172else

Page 586: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

73pan_l=174pan_r=1+pan*275end76pan_l*=volume77pan_r*=volume78@instances["#{id}_l"].volume=[pan_l,0.05].max79@instances["#{id}_r"].volume=[pan_r,0.05].max80end81end

StereoSamplemanagesstereoplaybackofsampleinstances,andtoavoidmemoryleaks,ithascleanup

Page 587: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

thatscansallsampleinstancesandremovessamplesthathavefinishedplaying.Forthisremovaltowork,weneedtoplaceacalltoStereoSample.cleanupinsidePlayState#updatemethod.

Todeterminecorrectpanandvolume,wewillcreatesomehelpermethodsinUtilsmodule:

Page 588: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

moduleUtilsHEARING_DISTANCE=1000.0#...defself.volume(object,camera)return1ifobject==camera.targetdistance=Utils.distance_between(camera.target.x,camera.target.y,object.x,object.y)distance=[(HEARING_DISTANCE-distance),0].maxdistance/HEARING_DISTANCEend

defself.pan(object,camera)return0ifobject==camera.target

Page 589: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

pan=object.x-camera.target.xsig=pan>0?1:-1pan=(pan%HEARING_DISTANCE)/HEARING_DISTANCEifsig>0panelse-1+panendend

defself.volume_and_pan(object,camera)[volume(object,camera),pan(object,camera)]endend

Page 590: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Apparently,havingaccesstoCameraisnecessaryforcalculatingsoundvolumeandpan,sowewilladdattr_accessor:cameratoObjectPoolclassandassignitinPlayStateconstructor.Youmaywonderwhywedidn’tuseCamera#targetrightaway.Theansweristhatcameracanchangeit’starget.E.g.whenyourtankdies,newinstancewillbegeneratedwhenyourespawn,

Page 591: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

soifallotherobjectswouldstillhavethereferencetoyouroldtank,guesswhatyouwouldhear?

RemasteredTankSoundscomponentisprobablythemostelaborateexampleofhowStereoSampleshouldbeused:09-polishing/entities/components/tank_sounds.rb1classTankSounds<Component2definitialize(object,

Page 592: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

object_pool)3super(object)4@object_pool=object_pool5end67defupdate8id=object.object_id9ifobject.physics.moving?10move_volume=Utils.volume(11object,@object_pool.camera)12pan=Utils.pan(object,@object_pool.camera)13ifdriving_sound.paused?(id)14driving_sound.resume(id)

Page 593: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

15elsifdriving_sound.stopped?(id)16driving_sound.play(id,pan,0.5,1,true)17end18driving_sound.volume_and_pan(id,move_volume*0.5,pan)19else20ifdriving_sound.playing?(id)21driving_sound.pause(id)22end23end24end2526defcollide27vol,pan=Utils.volume_and_pan(

Page 594: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

28object,@object_pool.camera)29crash_sound.play(self.object_id,pan,vol,1,false)30end3132private3334defdriving_sound35@@driving_sound||=StereoSample.new(36$window,Utils.media_path('tank_driving.mp3'

37end3839defcrash_sound40@@crash_sound||=StereoSample.new(41$window,

Page 595: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Utils.media_path('metal_interaction2.wav'

42end43end

AndthisishowstaticExplosionSoundslookslike:09-polishing/entities/components/explosion_sounds.rb1classExplosionSounds2class<<self3defplay(object,camera)4volume,pan=Utils.volume_and_pan(object,camera)5sound.play(object.object_id,

Page 596: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

pan,volume)6end78private910defsound11@@sound||=StereoSample.new(12$window,Utils.media_path('explosion.mp3'

13end14end15end

Afterwiringeverythingsothatsoundcomponentshave

Page 597: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

accesstoObjectPool,therestisstraightforward.

GivingEnemiesIdentityWouldn’titbegreatifyoucouldtellyourselfapartfromtheenemies.Moreover,enemiescouldhavenames,soyouwouldknowwhichoneismoreaggressiveorhave,you

Page 598: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

know,personalissueswithsomeone.

Todothatweneedtoasktheplayertoinputanickname,andchoosesomefunnynamesforeachenemyAI.Hereisanicelistwewillgrab:http://www.paulandstorm.com/wha/clown-names/

Wefirstcompileeverythingintoatextfiledcalled

Page 599: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

names.txt,thatlookslikethis:media/names.txtStrippyBoffoBuffoDrips...

Nowweneedaclasstoparsethelistandgiveoutrandomnamesfromit.Wealsowanttolimitnamelengthto

Page 600: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

somethingthatdisplaysnicely.09-polishing/misc/names.rb1classNames2definitialize(file)3@names=File.read(file).split("\n").rejectdo|n|4n.size>[email protected]@names.delete(name)11name12end13end

Page 601: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Thenweneedtoplacethosenamessomewhere.Wecouldassignthemtotanks,butthinkahead-ifourplayerandAIenemieswillrespawn,weshouldgivenamestoinputs,becauseTankisreplaceable,driverisnot.Well,itis,butlet’snotgettoodeepintoit.

FornowwejustaddnameparametertoPlayerInputandAiInputinitializers,save

Page 602: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

itin@nameinstancevariable,andthenadddraw(viewport)methodtomakeitrenderbelowthetank:

#09-polishing/entities/components/player_input.rb

classPlayerInput<Component#DarkgreenNAME_COLOR=Gosu::Color.argb(0xee084408)

definitialize(name,camera)super(nil)@name=name@camera=cameraend#...

Page 603: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

defdraw(viewport)@name_image||=Gosu::Image.from_text($window,@name,Gosu.default_font_name,20)@name_image.draw(x-@name_image.width/2-1,y+object.graphics.height/2,100,1,1,Gosu::Color::WHITE)@name_image.draw(x-@name_image.width/2,y+object.graphics.height/2,100,1,1,NAME_COLOR)end#...

Page 604: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

end

#09-polishing/entities/components/ai_input.rb

classAiInput<Component#DarkredNAME_COLOR=Gosu::Color.argb(0xeeb10000)

definitialize(name,object_pool)super(nil)@object_pool=object_pool@name=name@last_update=Gosu.millisecondsend#...defdraw(viewport)@motion.draw(viewport)

Page 605: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@gun.draw(viewport)@name_image||=Gosu::Image.from_text($window,@name,Gosu.default_font_name,20)@name_image.draw(x-@name_image.width/2-1,y+object.graphics.height/2,100,1,1,Gosu::Color::WHITE)@name_image.draw(x-@name_image.width/2,y+object.graphics.height/2,100,1,1,NAME_COLOR)end

Page 606: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...end

WecanseethatgenericInputclasscanbeeasilyextracted,butlet’sfollowtheRuleofthreeandnotdoprematurerefactoring.

Instead,runthegameandenjoydyingfromabunchofmadclowns.

Page 607: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Identitymakesadifference

RespawningTanksAndRemovingDead

Page 608: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

OnesToimplementrespawningwecoulduseMap#find_spawn_pointeverytimewewantedtorespawn,butitmaygetslow,becauseitbruteforcesthemapforrandomspotsthatarenotwater.Wedon’twantourgametostartfreezingwhentanksarerespawning,sowewillchangehowtankspawningworks.Insteadof

Page 609: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

lookingforanewrespawnpointallthetime,wewillpre-generateseveralofthemforreuse.

classMap#...defspawn_points(max)@spawn_points=(0..max).mapdofind_spawn_pointend@spawn_points_pointer=0end

defspawn_point@spawn_points[(@spawn_points_pointer+=1)%@spawn_points.size]

Page 610: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

end#...end

Herewehavespawn_pointsmethodthatpreparesanumberofspawnpointsandstoresthemin@spawn_pointsinstancevariable,andspawn_pointmethodthatcyclesthroughall@spawn_pointsandreturnsthemonebyone.find_spawn_pointcannowbecomeprivate.

Page 611: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

WewilluseMap#spawn_pointswheninitializingPlayStateandpassObjectPooltoPlayerInput(AiInputalreadyhasit),sothatwewillbeabletocall@object_pool.map.spawn_point

whenneeded.

classPlayState<GameState#...definitialize#...@map=Map.new(@object_pool)

Page 612: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@map.spawn_points(15)@tank=Tank.new(@object_pool,PlayerInput.new('Player',@camera,@object_pool))#...10.timesdo|i|Tank.new(@object_pool,AiInput.new(@names.random,@object_pool))endend#...end

Whentankdies,wewantittostaydeadfor5secondsandthenrespawninoneofour

Page 613: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

predefinedspawnpoints.WewillachievethatbyaddingrespawnmethodandcallingitinPlayerInput#updateandAiInput#updateiftankisdead.

#09-polishing/entities/components/player_input.rb

classPlayerInput<Component#...defupdatereturnrespawnifobject.health.dead?#...end#...

Page 614: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

private

defrespawnifobject.health.should_respawn?object.health.restoreobject.x,object.y=@[email protected],@camera.y=x,yPlayerSounds.respawn(object,@camera)endend#...end

#09-polishing/entities/components/ai_input.rb

Page 615: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

classAiInput<Component#...defupdatereturnrespawnifobject.health.dead?#...end#...private

defrespawnifobject.health.should_respawn?object.health.restoreobject.x,object.y=@object_pool.map.spawn_pointPlayerSounds.respawn(object,@object_pool.camera)end

Page 616: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

endend

WeneedsomechangesinTankHealthclasstoo:

classTankHealth<HealthRESPAWN_DELAY=5000#...defshould_respawn?Gosu.milliseconds-@death_time>RESPAWN_DELAYend#...defafter_death@death_time=Gosu.milliseconds#...end

Page 617: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

end

classHealth<Component#...defrestore@health=@initial_health@health_updated=trueend#...end

Itshouldn’tbehardtoputeverythingtogetherandenjoytheneverendinggameplay.

Youmayhavenoticedthatwealsoaddedasoundthat

Page 618: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

willbeplayedwhenplayerrespawns.Anice“whoosh”.09-polishing/entities/components/player_sounds.rb1classPlayerSounds2class<<self3defrespawn(object,camera)4volume,pan=Utils.volume_and_pan(object,camera)5respawn_sound.play(object.object_idpan,volume*0.5)6end78private9

Page 619: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

10defrespawn_sound11@@respawn||=StereoSample.new(12$window,Utils.media_path('respawn.wav'))

13end14end15end

DisplayingExplosionDamageTrailsWhensomethingblowsup,youexpectittoleaveatrail,right?Inourcaseexplosions

Page 620: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

disappearasifnothinghaseverhappened,andwejustcan’tleaveitlikethis.Let’sintroduceDamagegameobjectthatwillberesponsiblefordisplayingexplosionresidueonsandandgrass:09-polishing/entities/damage.rb1classDamage<GameObject2MAX_INSTANCES=1003attr_accessor:x,:y4@@instances=[]56definitialize(object_pool,x,y)7super(object_pool)

Page 621: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

8DamageGraphics.new(self)9@x,@y=x,y10track(self)11end1213defeffect?14true15end1617private1819deftrack(instance)20if@@instances.size<MAX_INSTANCES21@@instances<<instance22else23out=@@instances.shift24out.mark_for_removal25@@instances<<

Page 622: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

instance26end27end28end

Damagetracksit’sinstancesandstartsremovingoldoneswhenMAX_INSTANCESarereached.Withoutthisoptimization,thegamewouldgetincreasinglyslowereverytimesomebodyshoots.

Wehavealsoaddedanewgameobjecttrait-effect?

Page 623: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

returnstrueonDamageandExplosion,falseonTank,Tree,BoxandBullet.ThatwaywecanfilterouteffectswhenqueryingObjectPool#nearbyforcollisionsorenemies.09-polishing/entities/object_pool.rb1classObjectPool2attr_accessor:objects,:map,:camera34definitialize5@objects=[]

Page 624: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

6end78defnearby(object,max_distance)9non_effects.selectdo|obj|10obj!=object&&11(obj.x-object.x).abs<max_distance&&12(obj.y-object.y).abs<max_distance&&13Utils.distance_between(14obj.x,obj.y,object.x,object.y)<max_distance15end16end1718defnon_effects19

Page 625: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@objects.reject(&:effect?)20end21end

Whenitcomestorenderinggraphics,tomakeanimpressionofrandomness,wewillcyclethroughseveraldifferentdamageimagesanddrawthemrotated:09-polishing/entities/components/damage_graphics.rb1classDamageGraphics<Component

Page 626: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

2definitialize(object_pool)3super4@image=images.sample5@angle=rand(0..360)6end78defdraw(viewport)[email protected]_rot(x,y,0,@angle)10end1112private1314defimages15@@images||=(1..4).mapdo|i|16Gosu::Image.new($window,17Utils.media_path("damage#

Page 627: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

{i}.png"),false)18end19end20end

ExplosionwillberesponsibleforcreatingDamageinstancesonsolidground,justbeforeexplosionanimationstarts:

classExplosion<GameObjectdefinitialize(object_pool,x,y)#...if@object_pool.map.can_move_to?

Page 628: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

(x,y)Damage.new(@object_pool,@x,@y)end#...end#...end

Andthisishowtheresultlookslike:

Page 629: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Damagedbattlefield

DebuggingBulletPhysics

Page 630: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Whenplayingthegame,thereisafeelingthatbulletsstartoutslowwhenfiredandgainspeedastimegoes.Let’sreviewBulletPhysics#updateandthinkwhythisishappening:

classBulletPhysics<Component#...defupdatefly_speed=Utils.adjust_speed(object.speed)

fly_distance=(Gosu.milliseconds-object.fired_at)*

Page 631: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

0.001*fly_speed/2object.x,object.y=point_at_distance(fly_distance)check_hitobject.explodeifarrived?end#...end

Flawhereisveryobvious.Gosu.milliseconds-

object.fired_atwillbeincreasinglybiggerastimegoes,thusincreasingfly_distance.Thefixisstraightforward-wewantto

Page 632: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

calculatefly_distanceusingtimepassedbetweencallstoBulletPhysics#update,likethis:

classBulletPhysics<Component#...defupdatefly_speed=Utils.adjust_speed(object.speed)

now=Gosu.milliseconds@last_update||=object.fired_atfly_distance=(now-@last_update)*0.001*fly_speedobject.x,object.y=point_at_distance(fly_distance)

Page 633: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@last_update=nowcheck_hitobject.explodeifarrived?end#...end

Butifyouwouldrunthegamenow,bulletswouldflysoslow,thatyouwouldfeellikeNeoinTheMatrix.Tofixthat,wewillhavetotellourtanktofirebulletsalittlefaster.

Page 634: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

classTank<GameObject#...defshoot(target_x,target_y)ifcan_shoot?@last_shot=Gosu.millisecondsBullet.new(object_pool,@x,@y,target_x,target_y).fire(self,1500)#Oldvaluewas100endend#...end

Nowbulletsflyliketheyaresupposedto.Icanonlywonderwhyhaven’tInoticed

Page 635: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

thisbugintheverybeginning.

MakingCameraLookAheadOneofthemostannoyingthingswithcurrentstateofprototypeisthatCameraisdraggingbehindinsteadofshowingwhatisinthedirectionyouaremoving.Tofixtheissue,weneedto

Page 636: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

changethewayhowCameramovesaround.FirstweneedtoknowwhereCamerawantstobe.WewilluseUtils.point_at_distancetochooseaspotaheadoftheTank.Then,Camera#updateneedstoberewritten,soCameracandynamicallyadjusttoit’sdesiredspot.Herearethechanges:

classCamera#...defdesired_spot

Page 637: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]?Utils.point_at_distance(@target.x,@target.y,@target.direction,@target.physics.speed.ceil*25)else[@target.x,@target.y]endend#...defupdatedes_x,des_y=desired_spotshift=Utils.adjust_speed(@target.physics.speed).floor+1if@x<des_xifdes_x-@x<shift@x=des_x

Page 638: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

else@x+=shiftendelsif@x>des_xif@x-des_x<shift@x=des_xelse@x-=shiftendendif@y<des_yifdes_y-@y<shift@y=des_yelse@y+=shiftendelsif@y>des_yif@y-des_y<shift@y=des_yelse@y-=shift

Page 639: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

endend#...end#...end

Itwouldn’twincodestyleawards,butitdoesthejob.Gameisnowmuchmoreplayable.

ReviewingTheChanges

Page 640: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Let’sgetbacktoourlistofimprovementstoseewhatwehavedone:

1. Enemytanksdonotrespawn.

2. Randommapsareboringandlackdetail,couldusemoretilesorrandomenvironmentobjects.

3. Bulletsarehardtoseeongreensurface.

4. Hardtotellwhereenemiesarecoming

Page 641: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

from,radarwouldhelp.5. Soundsplayatfull

volumeevenwhensomethinghappensacrossThewholemap.

6. Mytankshouldrespawnafterit’sdead.

7. Mapboundariesarevisiblewhenyoucometotheedge.

8. Bothmytankandenemiesdon’thaveanyidentity.Sometimeshard

Page 642: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

todistinguishwhoiswho.

9. Explosionsdon’tleaveatrace.

10. Deadtankskeeppilingupandclutteringthemap.

11. Camerashouldbescoutingaheadofyouwhenyoumove,notdraggingbehind.

12. Bulletsseemtoaccelerate.

Page 643: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Notbadforastart.Thisiswhatwestillneedtocoverinnextcoupleofchapters:

1. Enemytanksshootatmycurrentlocation,notatwhereIwillbewhenbullethitsme.

2. Enemytanksdon’tavoidcollisions.

3. Enemytankmovementpatternsneedpolishingandimprovement.

Page 644: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

4. Noideawhohasmostkills.HUDwithscoreandsomestatethatdisplaysscoredetailswould

5. Wouldbegreattohaverandompowerupslikehealth,extradamage.

6. Motionandfiringmechanicsseemclumsy.help.

7. Tankscouldleavetrails.

Page 645: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Iwilladd“OptimizeObjectPoolperformance”,becausegamestartsslowingdownwhentoomanyobjectsareaddedtothepool,andprofilingshowsthatArray#select,whichistheheartofObjectPool#nearby,isthemaincause.Speedisoneofmostimportantfeaturesofanygame,solet’snothesitatetoimproveit.

Page 646: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

DealingWithThousandsOfGameObjects

Gosuisblazingfastwhenitcomestodrawing,buttherearemorethingsgoingon.Namely,weuseObjectPool#nearbyquiteoftentoloopthrough

Page 647: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

thousandsofobjects60timespersecondtomeasuredistancesamongthem.Thisslowseverythingdownwhenobjectpoolgrows.

Todemonstratetheeffect,wewillgenerate1500trees,30tanks,~100boxesandleave1000damagetrailsfromexplosions.ItwasenoughtodropFPSbelow30:

Page 648: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Runningslowwiththousandsofgameobjects

SpatialPartitioning

Page 649: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Thereisasolutionforthisparticularproblemis“SpatialPartitioning”,andtheessenceofitisthatyouhavetouseatree-likedatastructurethatdividesspaceintoregions,placesobjectsthereandletsyouqueryitselfinlogarithmictime,omittingobjectsthatfalloutofqueryregion.SpatialPartitioningisexplainedwellinGameProgrammingPatterns.

Page 650: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Probablythemostappropriatedatastructureforour2Dgameisquadtree.ToquoteWikipedia,“quadtreesaremostoftenusedtopartitionatwo-dimensionalspacebyrecursivelysubdividingitintofourquadrantsorregions.”Hereishowitlookslike:

Page 651: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Visualrepresentationofquadtree

Page 652: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingAQuadtreeTherearesomeimplementationsofquadtreeavailableforRuby-rquad,rubyquadtreeandrubyquad,butitseemseasytoimplement,sowewillbuildonetailored(read:closelycoupled)toourgameusingthepseudocodefromWikipedia.

Page 653: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

AxisAlignedBoundingBoxOneofprerequisitesofquadtreeisAxisalignedboundingbox,sometimesreferredtoas“AABB”.Itissimplyaboxthatsurroundstheshapebuthasedgesthatareinparallelwiththeaxesofunderlyingcoordinatesystem.Theadvantageofthisboxisthatitgivesaroughestimatewheretheshapeisandisveryefficientwhenit

Page 654: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

comestoqueryingifapointisinsideoroutsideit.

Page 655: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Axisalignedboundingboxwithcenterpointandhalfdimension

Todefineaxisalignedboundingbox,weneedit’scenterpointandhalfdimensionvector,which

Page 656: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

pointsfromcenterpointtooneofthecornersofthebox,andtwomethods,onethattellsifAABBcontainsapoint,andonethattellsifAABBintersectswithanotherAABB.Thisishowourimplementationlookslike:10-partitioning/misc/axis_aligned_bounding_box.rb1classAxisAlignedBoundingBox2attr_reader:center,:half_dimension3definitialize(center,half_dimension)

Page 657: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

4@center=center5@half_dimension=half_dimension6@dhx=(@half_dimension[0]-@center[0]).abs7@dhy=(@half_dimension[1]-@center[1]).abs8end910defcontains?(point)11returnfalseunless(@center[0]+@dhx)>=point[0]12returnfalseunless(@center[0]-@dhx)<=point[0]13returnfalseunless(@center[1]+@dhy)>=point[1]14returnfalseunless(@center[1]-@dhy)<=point[1]15true

Page 658: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

16end1718defintersects?(other)19ocx,ocy=other.center20ohx,ohy=other.half_dimension21odhx=(ohx-ocx).abs22returnfalseunless(@center[0]+@dhx)>=(ocx-odhx)23returnfalseunless(@center[0]-@dhx)<=(ocx+odhx)24odhy=(ohy-ocy).abs25returnfalseunless(@center[1]+@dhy)>=(ocy-odhy)26returnfalseunless(@center[1]-@dhy)<=(ocy+odhy)27true

Page 659: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

28end2930defto_s31"c:#{@center},h:#{@half_dimension}"32end33end

Ifyoudigin10-partitioning/specs,youwillfindtestsforthisimplementationtoo.

ThemathusedinAxisAlignedBoundingBox#contains?

and

Page 660: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

AxisAlignedBoundingBox#intersects?

isfairlysimpleandhopefullyveryfast,becausethesemethodswillbecalledbillionsoftimesthroughoutthegame.

QuadTreeForGameObjectsToimplementthegloriousQuadTreeitself,weneedtoinitializeitwithboundary,thatisdefinedbyaninstance

Page 661: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ofAxisAlignedBoundingBoxandprovidemethodsforinserting,removingandqueryingthetree.PrivateQuadTree#subdividemethodwillbecalledwhenwetrytoinsertanobjectintoatreethathasmoreobjectsthanit’sNODE_CAPACITY.10-partitioning/misc/quad_tree.rb1classQuadTree2NODE_CAPACITY=123attr_accessor:ne,:nw,:se,:sw,:objects4

Page 662: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

5definitialize(boundary)6@boundary=boundary7@objects=[]8end910definsert(game_object)[email protected]?(12game_object.location)[email protected]<NODE_CAPACITY15@objects<<game_object16returntrue17end1819subdivideunless@[email protected](game_object)

Page 663: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected](game_object)[email protected](game_object)[email protected](game_object)2526#shouldneverhappen27raise"Failedtoinsert#{game_object}"28end2930defremove(game_object)[email protected]?(32game_object.location)[email protected](game_object)34returntrue35end36returnfalseunless@nw

Page 664: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected](game_object)[email protected](game_object)[email protected](game_object)[email protected](game_object)41false42end4344defquery_range(range)45result=[][email protected]?(range)[email protected]|o|51ifrange.contains?(o.location)

Page 665: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

52result<<o53end54end5556#Notsubdivided57returnresultunless@[email protected]_range(range)[email protected]_range(range)[email protected]_range(range)[email protected]_range(range)6364result65end6667private68

Page 666: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

69defsubdivide70cx,[email protected],[email protected]_dimension72hhx=(cx-hx).abs/2.073hhy=(cy-hy).abs/2.074@nw=QuadTree.new(75AxisAlignedBoundingBox.new(76[cx-hhx,cy-hhy],77[cx,cy]))78@ne=QuadTree.new(79AxisAlignedBoundingBox.new(80[cx+hhx,cy-hhy],81[cx,cy]))

Page 667: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

82@sw=QuadTree.new(83AxisAlignedBoundingBox.new(84[cx-hhx,cy+hhy],85[cx,cy]))86@se=QuadTree.new(87AxisAlignedBoundingBox.new(88[cx+hhx,cy+hhy],89[cx,cy]))90end91end

ThisisavanillaquadtreethatstoresinstancesofGameObjectanduses

Page 668: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

GameObject#locationforindexingobjectsinspace.Italsohasspecsthatyoucanfindincodesamples.

YoucanexperimentwithQuadTree#NODE_CAPACITY,butIfoundthatvaluesbetween8and16worksbest,soIsettledwith12.

IntegratingObjectPoolWith

Page 669: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

QuadTreeWehaveimplementedaQuadTree,butitisnotyetincorporatedintoourgame.Todothat,wewillhookitintoObjectPoolandtrytokeeptheoldinterfaceintact,sothatObjectPool#nearbywillstillworkasusual,butwillbeabletocopewithwaymoreobjectsthanbefore.10-partitioning/entities/object_pool.rb

Page 670: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1classObjectPool2attr_accessor:map,:camera,:[email protected](box)9@tree=QuadTree.new(box)10@objects=[]11end1213defadd(object)14@objects<<[email protected](object)16end1718deftree_remove(object)

Page 671: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected](object)20end2122deftree_insert(object)[email protected](object)[email protected](&:update)[email protected]!do|o|[email protected](o)31true32end33end34end3536defnearby(object,max_distance)37cx,cy=object.location38hx,hy=cx+

Page 672: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

max_distance,cy+max_distance39#Fast,[email protected]_range(41AxisAlignedBoundingBox.new([cx,cy],[hx,hy]))42#Siftthroughtoselectfine-grainedresults43results.selectdo|o|44o!=object&&45Utils.distance_between(46o.x,o.y,object.x,object.y)<=max_distance47end48end4950defquery_range(box)[email protected]_range(box)

Page 673: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

52end53end

Anoldfashionedarrayofallobjectsisstillused,becausewestillneedtoloopthrougheverythingandinvokeGameObject#update.ObjectPool#query_range

wasintroducedtoquicklygrabobjectsthathavetoberenderedonscreen,andObjectPool#nearbynowqueriestreeandmeasures

Page 674: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

distancesonlyonroughresultset.

Thisishowwewillrenderthingsfromnowon:

classPlayState<GameState#[email protected][email protected]_x=$window.width/2-cam_xoff_y=$window.height/[email protected],x2,y1,y2=viewportbox=

Page 675: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

AxisAlignedBoundingBox.new([x1+(x2-x1)/2,y1+(y2-y1)/2],[x1-Map::TILE_SIZE,y1-Map::TILE_SIZE])$window.translate(off_x,off_y)[email protected]$window.scale(zoom,zoom,cam_x,cam_y)[email protected](viewport)@object_pool.query_range(box).mapdo|o|o.draw(viewport)[email protected][email protected]

Page 676: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...end

MovingObjectsInQuadTreeThereisonemoreerrandwenowhavetotakecareof.Everythingworksfinewhenthingsarestatic,butwhentanksandbulletsmove,weneedtoupdatetheminourQuadTree.That’swhyObjectPoolhastree_remove

Page 677: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

andtree_insert,whicharecalledfromGameObject#move.Fromnowon,theonlywaytochangeobject’slocationwillbebyusingGameObject#move:

classGameObjectattr_reader:x,:y,:location,:componentsdefinitialize(object_pool,x,y)@x,@y=x,y@location=[x,y]@components=[]@object_pool=object_pool@object_pool.add(self)end

Page 678: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

defmove(new_x,new_y)returnifnew_x==@x&&new_y==@y@object_pool.tree_remove(self)@x=new_x@y=new_y@location=[new_x,new_y]@object_pool.tree_insert(self)end#...end

Atthispointwehavetogothroughallthegameobjectsandchangehowthey

Page 679: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

initializetheirbaseclassandupdatexandycoordinates,butwewon’tcoverthathere.Ifindoubt,refertocodeat10-partitioning.

Finally,FPSisbacktostable60andwecanfocusongameplayagain.

Page 680: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Spatialpartitioningsavestheday

Page 681: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingPowerups

Gamewouldbecomemorestrategiciftherewerewaystorepairyourdamagedtank,boostit’sspeedorincreaserateoffirebypickingupvariouspowerups.Thisshouldnotbetoodifficultto

Page 682: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

implement.Wewillusesomeoftheseimages:

Powerups

Fornow,therewillbefourkindsofpowerups:

Page 683: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1. Repairdamage.Wrenchbadgewillrestoredamagedtank’shealthbackto100whenpickedup.

2. Healthboost.Green+1badgewilladd25health,upto200total,ifyoukeeppickingthemup.

3. Fireboost.Doublebulletbadgewillincreasereloadspeedby25%,upto200%ifyoukeeppickingthemup.

Page 684: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

4. Speedboost.Airplanebadgewillincreasemovementspeedby10%,upto150%ifyoukeeppickingthemup

Thesepowerupswillbeplacedrandomlyaroundthemap,andwillautomaticallyrespawn30secondsafterpickup.

Page 685: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingBasePowerupBeforerushingforwardtoimplementthis,wehavetodosomeresearchandthinkhowtoelegantlyintegratethisintothewholegame.First,let’sagreethatPowerupisaGameObject.Itwillhavegraphics,soundsandit’scoordinates.Effectscanbyappliedbyharnessing

Page 686: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

GameObject#on_collision-whenTankcollideswithPowerup,itgetsit.11-powerups/entities/powerups/powerup.rb1classPowerup<GameObject2definitialize(object_pool,x,y)3super4PowerupGraphics.new(self,graphics)5end67defbox8[x-8,y-8,9x+8,y-8,

Page 687: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

10x+8,y+8,11x-8,y+8]12end1314defon_collision(object)15ifpickup(object)16PowerupSounds.play(object,object_pool.camera)17remove18end19end2021defpickup(object)22#overrideandimplementapplication23end2425defremove26object_pool.powerup_respawn_queue

Page 688: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

27respawn_delay,28self.class,x,y)29mark_for_removal30end3132defrespawn_delay333034end35end

IgnorePowerup#remove,wewillgettoitwhenimplementingPowerupRespawnQueue.The

Page 689: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

restshouldbestraightforward.

ImplementingPowerupGraphicsAllpowerupswillusethesamespritesheet,sotherecouldbeasinglePowerupGraphicsclassthatwillberenderinggivenspritetype.Wewillusegosu-texture-packergem,since

Page 690: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

spritesheetisconvenientlypackedalready.11-powerups/entities/components/powerup_graphics.rb1classPowerupGraphics<Component2definitialize(object,type)3super(object)4@type=type5end67defdraw(viewport)8image.draw(x-12,y-12,1)9Utils.mark_corners(object.box)if$debug

Page 691: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

10end1112private1314defimage15@image||=images.frame("#{@type}.png")16end1718defimages19@@images||=Gosu::TexturePacker.load_json(20$window,Utils.media_path('pickups.json'))

21end22end

Page 692: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingPowerupSoundsIt’sevensimplerwithsounds.Allpowerupswillemitamellow“bleep”whenpickedup,soPowerupSoundscanbecompletelystatic,likeExplosionSoundsorBulletSounds:11-powerups/entities/components/powerup_sounds.rb

Page 693: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1classPowerupSounds2class<<self3defplay(object,camera)4volume,pan=Utils.volume_and_pan(object,camera)5sound.play(object.object_id,pan,volume)6end78private910defsound11@@sound||=StereoSample.new(12$window,Utils.media_path('powerup.mp3'))

13end

Page 694: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

14end15end

ImplementingRepairDamagePowerupRepairingbrokentankisprobablythemostimportantpowerupofthemall,solet’simplementitfirst:11-powerups/entities/powerups/repair_powerup.rb1classRepairPowerup<Powerup

Page 695: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

2defpickup(object)3ifobject.class==Tank4ifobject.health.health<1005object.health.restore6end7true8end9end1011defgraphics12:repair13end14end

Thiswasincrediblysimple.Health#restorealready

Page 696: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

existedsincewehadtorespawnourtanks.Wecanonlyhopeotherpowerupsareassimpletoimplementasthisone.

ImplementingHealthBoostRepairingdamageisgreat,buthowaboutboostingsomeextrahealthforupcoming

Page 697: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

battles?Healthboosttotherescue:11-powerups/entities/powerups/health_powerup.rb1classHealthPowerup<Powerup2defpickup(object)3ifobject.class==Tank4object.health.increase(25)5true6end7end89defgraphics10:life_up11end12end

Page 698: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ThistimewehavetoimplementHealth#increase,butitisprettysimple:

classHealth<Component#...defincrease(amount)@health=[@health+25,@initial_health*2].min@health_updated=trueend#...end

Page 699: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

SinceTankhas@initial_healthequalto100,increasinghealthwon’tgoover200,whichisexactlywhatwewant.

ImplementingFireRateBoostHowaboutboostingtank’sfirerate?11-powerups/entities/powerups/fire_rate_powerup.rb

Page 700: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1classFireRatePowerup<Powerup2defpickup(object)3ifobject.class==Tank4ifobject.fire_rate_modifier<25object.fire_rate_modifier+=0.256end7true8end9end1011defgraphics12:straight_gun13end14end

Page 701: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Weneedtointroduce@fire_rate_modifierinTankclassanduseitwhencallingTank#can_shoot?:

classTank<GameObject#...attr_accessor:fire_rate_modifier#...defcan_shoot?Gosu.milliseconds-(@last_shot||0)>(SHOOT_DELAY/@fire_rate_modifier)end#...defreset_modifiers@fire_rate_modifier=1

Page 702: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

end#...end

Tank#reset_modifiershouldbecalledwhenrespawning,sincewewanttankstolosetheirpowerupswhentheydie.ItcanbedoneinTankHealth#after_death:

classTankHealth<Health#...defafter_deathobject.reset_modifiers#...

Page 703: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

endend

ImplementingTankSpeedBoostTankspeedboostisverysimilartofireratepowerup:11-powerups/entities/powerups/tank_speed_powerup.rb1classTankSpeedPowerup<Powerup2defpickup(object)3ifobject.class==Tank4if

Page 704: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

object.speed_modifier<1.55object.speed_modifier+=0.106end7true8end9end1011defgraphics12:wingman13end14end

Wehavetoadd@speed_modifiertoTankclassanduseitinTankPhysics#updatewhen

Page 705: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

calculatingmovementdistance.

#11-powerups/entities/tank.rbclassTank<GameObject#...attr_accessor:speed_modifier#...defreset_modifiers#...@speed_modifier=1end#...end

#11-powerups/entities/components/tank_physics.rb

classTankPhysics<Component#...

Page 706: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

defupdate#...new_x,new_y=x,yspeed=apply_movement_penalty(@speed)shift=Utils.adjust_speed(speed)*object.speed_modifier#...end#...end

Camera#updatehasalsorefertoTank#speed_modifier,otherwisetheoperatorwillfailtocatchupandcamerawillbelaggingbehind.

Page 707: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

classCamera#...defupdate#...shift=Utils.adjust_speed(@target.physics.speed).floor*@target.speed_modifier+1#...end#...end

SpawningPowerupsOnMap

Page 708: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Powerupsareimplemented,butnotyetspawned.Wewillspawn20-30randompowerupswhengeneratingthemap:

classMap#...definitialize(object_pool)#...generate_powerupsend#...defgenerate_powerupspups=0target_pups=rand(20..30)whilepups<target_pupsdox=rand(0..MAP_WIDTH*

Page 709: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

TILE_SIZE)y=rand(0..MAP_HEIGHT*TILE_SIZE)iftile_at(x,y)!=@waterrandom_powerup.new(@object_pool,x,y)pups+=1endendend

defrandom_powerup[HealthPowerup,RepairPowerup,FireRatePowerup,TankSpeedPowerup].sampleend#...end

Page 710: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Thecodeisverysimilartogeneratingboxes.It’sprobablynotthebestwaytodistributepowerupsonmap,butitwillhavetodofornow.

RespawningPowerupsAfterPickupWhenwepickupapowerup,wewantittoreappearinsamespot30secondslater.A

Page 711: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

thought“wecanstartanewThreadwithsleepandinitializethesamepowerupthere”soundsverybad,butIhaditforafewseconds.ThenPowerupRespawnQueuewasborn.

First,let’srecallhowPowerup#removemethodlookslike:

classPowerup<GameObject#...defremove

Page 712: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

object_pool.powerup_respawn_queue

respawn_delay,self.class,x,y)mark_for_removalend#...end

Powerupenqueuesitselfforrespawnwhenpickedup,providingit’sclassandcoordinates.PowerupRespawnQueueholdsthisdataandrespawns

Page 713: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

powerupsatrighttimewithhelpofObjectPool:11-powerups/entities/powerups/powerup_respawn_queue.rb1classPowerupRespawnQueue2RESPAWN_DELAY=10003definitialize4@respawn_queue={}5@last_respawn=Gosu.milliseconds6end78defenqueue(delay_seconds,type,x,y)9respawn_at=Gosu.milliseconds+delay_seconds*100010

Page 714: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@respawn_queue[respawn_at.to_i]=[type,x,y]11end1213defrespawn(object_pool)14now=Gosu.milliseconds15returnifnow-@last_respawn<RESPAWN_DELAY16@respawn_queue.keys.eachdo|k|17nextifk>now#notyet18type,x,y=@respawn_queue.delete(k)19type.new(object_pool,x,y)20end21@last_respawn=now22end23end

Page 715: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

PowerupRespawnQeueue#respawn

iscalledfromObjectPool#update_all,butisthrottledtorunoncepersecondforbetterperformance.

classObjectPool#...attr_accessor:powerup_respawn_queue#...defupdate_all#...@powerup_respawn_queue.respawn(self

end

Page 716: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...end

Thisisit,thegameshouldnowcontainrandomlyplacedpowerupsthatrespawn30secondsafterpickedup.Timetoenjoytheresult.

Page 717: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Playingwithpowerups

Wehaven’tdoneanychangestoAIthough,thatmeansenemieswillonlybepickingthosepowerupsbyaccident,

Page 718: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

sonowyouhaveasignificantadvantageandthegamehassuddenlybecametooeasytoplay.Don’tworry,wewillbefixingthatwhenoverhaulingtheAI.

Page 719: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingHeadsUpDisplay

Inordertoknowwhat’shappening,weneedsomesortofHUD.Wealreadyhavecrosshairandradar,buttheyarescatteredaroundincode.Nowwewanttodisplay

Page 720: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

activepowerupmodifiers,soyouwouldknowwhatisyourfirerateandspeed,andifit’sworthgettingonemorepowerupbeforegoingintothenextfight.

DesignConsiderationsWhilecreatingourHUDclass,wewillhavetostartbuildinggamestats,because

Page 721: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

wewanttodisplaynumberofkillsourtankmade.Statstopicwillbecoveredindepthlater,butfornowlet’[email protected],whichwewanttodrawintop-leftcornerofthescreen,alongwithplayerhealthandmodifiervalues.

HUDwillalsoberesponsiblefordrawingcrosshairand

Page 722: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

radar.

RenderingTextWithCustomFontPreviously,alltextwererenderedwithGosu.default_font_name,andwewantsomethingmorefancyandmorethematic,probablyadirtystencilbasedfontlikethisone:

Page 723: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ArmaliteRiflefont

Andonemorefancyfontwillmakeourgametitlelookgood.Toobadwedon’thaveatitleyet,but“TanksPrototype”writeninathematicwaystilllooksprettygood.

Page 724: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tohaveconvenientaccesstothesefonts,wewilladdahelpermethodsinUtils:

moduleUtils#...defself.title_fontmedia_path('top_secret.ttf')end

defself.main_fontmedia_path('armalite_rifle.ttf')

end#...end

Page 725: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

UseitinsteadofGosu.default_font_name:

size=20Gosu::Image.from_text($window,"Yourtext",Utils.main_font,size)

ImplementingHUDClassAfterwehaveputeverythingtogether,wewillgetHUDclass:12-stats/entities/hud.rb

Page 726: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1classHUD2attr_accessor:active3definitialize(object_pool,tank)4@object_pool=object_pool5@tank=tank6@radar=Radar.new(@object_pool,tank)7end89defplayer=(tank)10@[email protected][email protected]

Page 727: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]?||@tank.health.health!=@health20@[email protected]@health_image=Gosu::Image.from_text(22$window,"Health:#{@health}",Utils.main_font,20)23end24@[email protected]@stats_image.nil?||stats.changed_at<=Gosu.milliseconds30@stats_image=

Page 728: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Gosu::Image.from_text(31$window,"Kills:#{stats.kills}",Utils.main_font,20)32end33@[email protected]_rate_modifier>138if@[email protected]_rate_modifier39@[email protected]_rate_modifier40@fire_rate_image=Gosu::Image.from_text(41$window,"Firerate:#{@fire_rate.round(2)}X",42Utils.main_font,20)

Page 729: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

43end44else45@fire_rate_image=nil46end47@[email protected]_modifier>152if@[email protected]_modifier53@[email protected]_modifier54@speed_image=Gosu::Image.from_text(55$window,"Speed:#{@speed.round(2)}X",56Utils.main_font,20)57end

Page 730: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

58else59@speed_image=nil60end61@speed_image62end6364defdraw65if@active66@object_pool.camera.draw_crosshair

[email protected]=2070health_image.draw(20,offset,1000)71stats_image.draw(20,offset+=30,1000)72iffire_rate_image73fire_rate_image.draw(20,offset

Page 731: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

+=30,1000)74end75ifspeed_image76speed_image.draw(20,offset+=30,1000)77end78end79end

Touseit,weneedtohookintoPlayState:

classPlayState<GameState#...definitialize#...@hud=HUD.new(@object_pool,@tank)

Page 732: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

end

defupdate#[email protected]

defdraw#[email protected]#...end

[email protected],youshouldgetaneatviewshowinginteresting

Page 733: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

thingsintop-leftcornerofthescreen:

Page 734: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ShinynewHUD

Page 735: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImplementingGameStatistics

Gameslikeonewearebuildingareallaboutcompetition,andyoucannotcompeteifyoudon’tknowthescore.Letusintroduceaclassthatwillberesponsibleforkeepingtabsonvariousstatisticsofeverytank.

Page 736: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

12-stats/misc/stats.rb1classStats2attr_reader:name,:kills,:deaths,:shots,:changed_at3definitialize(name)4@name=name5@kills=@deaths=@shots=@damage=@damage_dealt=06changed7end89defadd_kill(amount=1)10@kills+=amount11changed12end1314defadd_death15@deaths+=116changed

Page 737: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

17end1819defadd_shot20@shots+=121changed22end2324defadd_damage(amount)25@damage+=amount26changed27end2829defdamage30@damage.round31end3233defadd_damage_dealt(amount)34@damage_dealt+=amount35changed36end

Page 738: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

3738defdamage_dealt39@damage_dealt.round40end4142defto_s43"[kills:#{@kills},"\44"deaths:#{@deaths},"\45"shots:#{@shots},"\46"damage:#{damage},"\47"damage_dealt:#{damage_dealt}]"48end4950private5152defchanged53@changed_at=Gosu.milliseconds

Page 739: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

54end55end

WhilebuildingtheHUD,weestablishedthatStatsshouldbelongtoTank#input,becauseitdefineswhoiscontrollingthetank.So,everyinstanceofPlayerInputandAiInputhastohaveit’sownStats:

#12-stats/entities/components/player_input.rb

Page 740: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

classPlayerInput<Component#...attr_reader:stats

definitialize(name,camera,object_pool)#...@stats=Stats.new(name)end#...defon_damage(amount)@stats.add_damage(amount)end#...end

#12-stats/entities/components/ai_input.rb

classAiInput<Component#...

Page 741: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

attr_reader:stats

definitialize(name,object_pool)#...@stats=Stats.new(name)end

defon_damage(amount)#[email protected]_damage(amount)endend

ThatitchtoextractabaseclassfromPlayerInputandAiInputisgettingstronger,

Page 742: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

butwewillhavetoresisttheurge,fornow.

TrackingKills,DeathsandDamageTobegintrackingkills,weneedtoknowwhomdoeseverybulletbelongto.Bulletalreadyhassourceattribute,whichcontainsthetankthatfiredit,therewillbenotroubletofindoutwho

Page 743: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

wastheshooterwhenbulletgetsadirecthit.Buthowaboutexplosions?Bulletsthathitthegroundnearbyatankdealsindirectdamagefromtheexplosion.

Solutionissimple,weneedtopassthesourceoftheBullettotheExplosionwhenit’sbeinginitialized.

classBullet<GameObject#...defexplode

Page 744: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Explosion.new(object_pool,@x,@y,@source)#...end#...end

MakingDamagePersonalNowthatwehavethesourceofeveryBulletandExplosiontheytrigger,wecanstartpassingthecauseofdamageto

Page 745: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Health#inflict_damageandincrementingtheappropriatestats.

#12-stats/entities/components/health.rb

classHealth<Component#...definflict_damage(amount,cause)if@health>0@health_updated=trueifobject.respond_to?(:input)object.input.stats.add_damage(amount

#Don'tcountdamageto

Page 746: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

treesandboxesifcause.respond_to?(:input)&&cause!=objectcause.input.stats.add_damage_dealt

endend@health=[@health-amount.to_i,0].maxafter_death(cause)ifdead?endend#...end

#12-stats/entities/components/tank_health.rb

classTankHealth<Health

Page 747: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...defafter_death(cause)#...object.input.stats.add_deathkill=object!=cause?1:-1cause.input.stats.add_kill(kill)

#...end#...end

TrackingDamageFromChain

Page 748: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ReactionsThereisonemorewaytocausedamage.Whenyoushootatree,boxorbarrel,itexplodes,probablytriggeringachainreactionofexplosionsaroundit.Ifthoseexplosionskillsomebody,itwouldonlybefairtoaccountthatkillforthetankthattriggeredthischainreaction.

Page 749: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tosolvethis,simplypassthecauseofdeathtotheExplosionthatgetstriggeredafterwards.

#12-stats/entities/components/health.rb

classHealth<Component#...defafter_death(cause)[email protected]#...Explosion.new(@object_pool,x,y,cause)#...end

Page 750: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...endendend

#12-stats/entities/components/tank_health.rb

classTankHealth<Health#...defafter_death(cause)#...Thread.newdo#...Explosion.new(@object_pool,x,y,cause)endendend

Page 751: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Noweverybitofdamagegetsaccountedfor.

DisplayingGameScoreHavingallthedataisuselessunlesswedisplayitsomehow.Forthis,let’srethinkourgamestates.NowwehaveMenuStateandPlayState.Bothofthemcanswitchoneintoanother.What

Page 752: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ifweintroducedaPauseState,whichwouldfreezethegameanddisplaythelistofalltanksalongwiththeirkills.ThenMenuStatewouldswitchtoPlayState,andfromPlayStateyouwouldbeabletogettoPauseState.

Let’sbeginbyimplementingScoreDisplay,thatwouldprintasortedlistoftankkillsalongwiththeirnames.

Page 753: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

12-stats/entities/score_display.rb1classScoreDisplay2definitialize(object_pool)3tanks=object_pool.objects.selectdo|o|4o.class==Tank5end6stats=tanks.map(&:input).map(&:stats)7stats.sort!do|stat1,stat2|8stat2.kills<=>stat1.kills9end10create_stats_image(stats)11end12

Page 754: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

13defcreate_stats_image(stats)14text=stats.mapdo|stat|15"#{stat.kills}:#{stat.name}"16end.join("\n")17@stats_image=Gosu::Image.from_text(18$window,text,Utils.main_font,30)19end2021defdraw22@stats_image.draw(23$window.width/2-@stats_image.width/2,24$window.height/4+30,251000)

Page 755: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

26end27end

WewillhavetoinitializeScoreDisplayeverytimewhenwewanttoshowtheupdatedscore.TimetocreatethePauseStatethatwouldshowthescore.12-stats/game_states/pause_state.rb1require'singleton'2classPauseState<GameState3includeSingleton4attr_accessor:play_state5

Page 756: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

6definitialize7@message=Gosu::Image.from_text(8$window,"GamePaused",9Utils.title_font,60)10end1112defenter13music.play(true)14music.volume=115@score_display=ScoreDisplay.new(@play_state.object_pool

16@mouse_coords=[$window.mouse_x,$window.mouse_y]17end1819defleave20music.volume=0

Page 757: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

21music.stop22$window.mouse_x,$window.mouse_y=@mouse_coords23end2425defmusic26@@music||=Gosu::Song.new(27$window,Utils.media_path('menu_music.mp3'

28end2930defdraw31@[email protected](33$window.width/[email protected]/2,34$window.height/[email protected],351000)

Page 758: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

36@score_display.draw37end3839defbutton_down(id)40$window.closeifid==Gosu::KbQ41ifid==Gosu::KbC&&@play_state42GameState.switch(@play_state)43end44ifid==Gosu::KbEscape45GameState.switch(@play_state)46end47end48end

Page 759: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

YouwillnoticethatPauseStateinvokesPlayState#draw,butwithoutPlayState#updatethiswillbeastillimage.Wemakesurewehidethecrosshairandrestorepreviousmouselocationwhenresumingplaystate.Thatwayplayerwouldnotbeabletocheatbypausingthegame,targetingthetankwhilenothingmovesandthenunpausingreadytodealdamage.OurHUDhad

Page 760: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

attr_accessor:active

exactlyforthisreason,butweneedtoswitchitonandoffinPlayState#enterandPlayState#leave.

classPlayState<GameState#...defbutton_down(id)#...ifid==Gosu::KbEscapepause=PauseState.instancepause.play_state=selfGameState.switch(pause)end#...end

Page 761: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#[email protected]=falseend

[email protected]=trueend#...end

Timeforatestdrive.

Page 762: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Pausingthegametoseethescore

Fornow,scoringmostkillsisrelativelysimple.Thisshouldchangewhenwewilltell

Page 763: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

enemyAItocollectpowerupswhenappropriate.

Page 764: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

BuildingAdvancedAI

TheAIwehaverightnowcankicksomeass,butitistoodumbforanyseasonedgamertocompetewith.Thisisthelistofcurrentflaws:

1. Itdoesnotnavigatewell,getsstuckamongtrees

Page 765: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

orsomewherenearwater.

2. Itisnotawareofpowerups.

3. Itcoulddobetterjobatshooting.

4. It’sfieldofvisionistoosmall,comparedtoplayer’s,whoisequippedwithradar.

Wewilltackletheseissuesincurrentchapter.

Page 766: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImprovingTankNavigationTanksshouldn’tbehavelikeRoombas,randomlydrivingaroundandbumpingintothings.Theycouldbenavigatinglikethis:

1. ConsultwithcurrentAIstateandfindorupdatedestinationpoint.

2. Ifdestinationhaschanged,calculate

Page 767: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

shortestpathtodestination.

3. Movealongthecalculatedpath.

4. Repeat.

Ifthislookseasy,letmeassureyou,itwouldprobablyrequirerewritingthemajorityofAIandMapcodewehaveatthispoint,anditisprettytrickytoimplementwithprocedurallygeneratedmaps,becausenormallyyouwould

Page 768: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

useamapeditortosetupwaypoints,navigationmeshorotherhintsforAIsoitdoesn’tgetstuck.Sometimesitisbettertohavesomethingworkingimperfectlyoveraperfectsolutionthatneverhappens,thuswewillusesimplethingsthatwillmakeasmuchimpactaspossiblewithoutrewritinghalfofthecode.

GeneratingFriendlierMaps

Page 769: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Oneofmainreasonswhytanksgetstuckisbadplacementofspawnpoints.Theydon’ttaketreesandboxesintoaccount,soenemytankcanspawninthemiddleofaforest,withnochanceofgettingoutwithoutblowingthingsup.AsimplefixwouldbetoconsultwithObjectPoolbeforeplacingaspawnpointonlywheretherearenoothergameobjects

Page 770: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

aroundin,say,150pixelradius:

classMap#...deffind_spawn_pointwhiletruex=rand(0..MAP_WIDTH*TILE_SIZE)y=rand(0..MAP_HEIGHT*TILE_SIZE)ifcan_move_to?(x,y)&&@object_pool.nearby_point(x,y,150).empty?return[x,y]endendend

Page 771: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...end

Howaboutpowerups?Theycanalsospawninthemiddleofaforest,andwhiletanksarenotseekingthemyet,wewillbeimplementingthisbehavior,andleadingtanksintowildernessoftreesisnotthebestideaever.Let’sfixittoo:

classMap#...

Page 772: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

defgenerate_powerupspups=0target_pups=rand(20..30)whilepups<target_pupsdox=rand(0..MAP_WIDTH*TILE_SIZE)y=rand(0..MAP_HEIGHT*TILE_SIZE)iftile_at(x,y)!=@water&&@object_pool.nearby_point(x,y,150).empty?random_powerup.new(@object_pool,x,y)pups+=1endendend

Page 773: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...end

Wecouldalsoreducetreecount,butthatwouldmakethemaplookworse,sowearegoingtokeepthisinourpocketasameanoflastresort.

ImplementingDemoStateToObserveAI

Page 774: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ProbablythebestwaytofigureoutifourAIisanygoodistotargetoneofAItankswithourgamecameraandseehowitplays.ItwillgiveusagreatvisualtestingtoolthatwillallowtweakingAIsettingsandseeingiftheyperformbetterorworse.ForthatwewillintroduceDemoStatewhereonlyAItankswillbepresentinthemap,andwewillbeabletoswitchcamerafromonetank

Page 775: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

toanother.

DemoStateisverysimilartoPlayState,themaindifferenceisthatthereisnoplayer.Wewillextractcreate_tanksmethodthatwillbeoverriddeninDemoState.

classPlayState<GameStateattr_accessor:update_interval,:object_pool,:tank

definitialize

Page 776: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...@camera=Camera.new@object_pool.camera=@cameracreate_tanks(4)end#...private

defcreate_tanks(amount)@map.spawn_points(amount*3)@tank=Tank.new(@object_pool,PlayerInput.new('Player',@camera,@object_pool))amount.timesdo|i|Tank.new(@object_pool,AiInput.new(@names.random,@object_pool))

Page 777: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]=@tank@hud=HUD.new(@object_pool,@tank)end#...end

Wewillalsowanttodisplayasmallerversionofscoreintop-rightcornerofthescreen,solet’saddsomeadjustmentstoScoreDisplay:

classScoreDisplaydefinitialize(object_pool,font_size=30)

Page 778: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@font_size=font_size#...end

defcreate_stats_image(stats)#...@stats_image=Gosu::Image.from_text($window,text,Utils.main_font,@font_size)end#...defdraw_top_right@stats_image.draw($window.width-@stats_image.width-20,20,1000)endend

Page 779: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

AndhereistheextendedDemoState:13-advanced-ai/game_states/demo_state.rb1classDemoState<PlayState2attr_accessor:tank34defenter5#PreventreactivatingHUD6end78defupdate9super10@score_display=ScoreDisplay.new(11object_pool,20)12end

Page 780: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

1314defdraw15super16@score_display.draw_top_right17end1819defbutton_down(id)20super21ifid==Gosu::[email protected]|t|[email protected]_to_tank(target_tank)26end27end2829private30

Page 781: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

31defcreate_tanks(amount)[email protected]_points(amount*3)33@tanks=[]34amount.timesdo|i|35@tanks<<Tank.new(@object_pool,AiInput.new([email protected],@object_pool))[email protected]@hud=HUD.new(@object_pool,target_tank)[email protected]=false41switch_to_tank(target_tank)42end43

Page 782: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

44defswitch_to_tank(tank)[email protected][email protected]=tank47self.tank=tank48end49end

TohaveapossibilitytoenterDemoState,weneedtochangeMenuStatealittle:

classMenuState<GameState#...defupdatetext="Q:Quit\nN:NewGame\nD:Demo"#...end

Page 783: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#...defbutton_down(id)#...ifid==Gosu::KbD@play_state=DemoState.newGameState.switch(@play_state)endendend

Now,mainmenuhastheoptiontoenterdemostate:

Page 784: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Overhauledmainmenu

Page 785: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ObservingAIindemostate

VisualAIDebugging

Page 786: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

AfterwatchingAIbehaviorindemomodeforawhile,Iwasterrified.Whenplayinggamenormally,youusuallyseetanksin“fighting”state,whichworksprettywell,butwhentanksgoroaming,it’sacompletedisaster.Theygetstuckeasily,theydon’tgotoofarfromtheoriginallocation,theywaittoomuch.

Somethingscouldbeimprovedjustbychanging

Page 787: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

wait_time,turn_timeanddrive_timetodifferentvalues,butwecertainlyhavetodobiggerchangesthanthat.

Ontheotherhand,“observeAIinaction,tweak,repeat”cycleprovedtobeveryeffective,Iwilldefinitelyusethistechniqueinallmyfuturegames.

Page 788: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tomakevisualdebuggingeasier,buildyourselfsometooling.Onewaytodoitistohaveglobal$debugvariablewhichyoucantogglebypressingsomebutton:

classPlayState<GameState#...defbutton_down(id)#...ifid==Gosu::KbF1$debug=!$debugend#...end#...end

Page 789: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Thenaddextradrawinginstructionstoyourobjectsandtheircomponents.Forexample,thiswillmakeTankdisplayit’scurrentTankMotionState

implementationclassbeneathit:

classTankMotionFSM#...defset_state(state)#...if$debug@image=

Page 790: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Gosu::Image.from_text($window,state.class.to_s,Gosu.default_font_name,18)endend#...defdraw(viewport)if$debug@image&&@image.draw(@[email protected]/2,@[email protected]/[email protected],100)endend#...end

Page 791: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Tomarktank’sdesiredgunangleasbluelineandactualgunangleasredline,youcandothis:

classAiGun#...defdraw(viewport)if$debugcolor=Gosu::Color::BLUEx,[email protected],@object.yt_x,t_y=Utils.point_at_distance(x,y,@desired_gun_angle,BulletPhysics::MAX_DIST)$window.draw_line(x,y,color,t_x,t_y,color,1001)

Page 792: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

color=Gosu::Color::REDt_x,t_y=Utils.point_at_distance(x,y,@object.gun_angle,BulletPhysics::MAX_DIST)$window.draw_line(x,y,color,t_x,t_y,color,1000)endend#...end

Finally,youcanautomaticallymarkcollisionboxcornersonyourgraphicscomponents.Let’stakeBoxGraphicsforexample:

Page 793: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#13-advanced-ai/misc/utils.rbmoduleUtils#...defself.mark_corners(box)i=0box.each_slice(2)do|x,y|color=DEBUG_COLORS[i]$window.draw_triangle(x-3,y-3,color,x,y,color,x+3,y-3,color,100)i=(i+1)%4endend#...end

#13-advanced-ai/entities/components/box_graphics.rb

Page 794: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

classBoxGraphics<Component#..defdraw(viewport)@box.draw_rot(x,y,0,object.angle)Utils.mark_corners(object.box)if$debugend#...end

Asadeveloper,youcanmakeyourselfseenearlyeverythingyouwant,makeuseofit.

Page 795: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

VisualdebuggingofAIbehavior

Althoughithurtstheframeratealittle,itisveryusefulwhenbuildingnotonlyAI,buttherestofthegame

Page 796: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

too.UsingthisvisualdebuggingtogetherwithDemomode,youcantweakalltheAIvaluestomakeitshootmoreoften,fightbetter,andbemoreagile.Wewon’tgothroughthisminortuning,butyoucanfindthechangesbyviewingchangesintroducedin13-advanced-ai.

Page 797: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

MakingAICollectPowerupsToevenouttheodds,wehavetomakeAIseekpowerupswhentheyarerequired.Thelogicbehinditcanbeimplementedusingacoupleofsimplesteps:

1. AIwouldknowwhatpowerupsarecurrentlyneeded.Thismayvaryfromstatetostate,i.e.

Page 798: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

speedandfireratepowerupsarenicetohavewhenroaming,butnotthatimportantwhenfleeingaftertakingheavydamage.Andwedon’twantAItowastetimeandcollectspeedpowerupswhenspeedmodifierisalreadymaxedout.

2. AiVisionwouldreturnclosestvisiblepowerup,

Page 799: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

filteredbyacceptablepoweruptypes.

3. SomeTankMotionStateimplementationwouldadjusttankdirectiontowardsclosestvisiblepowerupinchange_direction

method.

FindingPowerupsInSightToimplementchangesinAiVision,wewillintroduce

Page 800: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

closest_powerupmethod.Itwillqueryobjectsinsightandfilterthemoutbytheirclassanddistance.

classAiVision#...POWERUP_CACHE_TIMEOUT=50#...defclosest_powerup(*suitable)now=Gosu.milliseconds@closest_powerup=nilifnow-(@powerup_cache_updated_at||=0)>POWERUP_CACHE_TIMEOUT@closest_powerup=nil@powerup_cache_updated_at=now

Page 801: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

end@closest_powerup||=find_closest_powerup(*suitable)end

private

deffind_closest_powerup(*suitable)ifsuitable.empty?suitable=[FireRatePowerup,HealthPowerup,RepairPowerup,TankSpeedPowerup]end@in_sight.selectdo|o|suitable.include?

Page 802: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

(o.class)end.sortdo|a,b|x,[email protected],@viewer.yd1=Utils.distance_between(x,y,a.x,a.y)d2=Utils.distance_between(x,y,b.x,b.y)d1<=>d2end.firstend#...end

ItisverysimilartoAiVision#closest_tank,andpartsshouldprobablybe

Page 803: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

extractedtokeepthecodedry,butwewillnotbother.

SeekingPowerupsWhileRoamingRoamingiswhenmostpickingshouldhappen,becauseTankseesnoenemiesinsightandneedstoprepareforupcomingbattles.Let’sseehowcanweimplementthisbehaviorwhileleveragingthenewly

Page 804: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

madeAiVision#closest_powerup:

classTankRoamingState<TankMotionState#...defrequired_powerupsrequired=[][email protected]@object.fire_rate_modifier<2&&health>50required<<[email protected]_modifier<1.5&&health>50required<<TankSpeedPowerup

Page 805: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

endifhealth<100required<<RepairPowerupendifhealth<190required<<HealthPowerupendrequiredend

[email protected]_powerup(*required_powerups)ifclosest_powerup@seeking_powerup=trueangle=Utils.angle_between(@object.x,@object.y,closest_powerup.x,closest_powerup.y)

Page 806: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@object.physics.change_direction

angle-angle%45)else@seeking_powerup=false#...chooserandomdirectionend@changed_direction_at=Gosu.milliseconds@will_keep_direction_for=turn_timeend#...defturn_timeif@seeking_poweruprand(100..300)elserand(1000..3000)end

Page 807: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

endend

Itissimpleasthat,andourAItanksarenowgettingbuffedontheirsparetime.

SeekingHealthPowerupsAfterHeavyDamageToseekhealthwhendamaged,weneedtochangeTankFleeingState#change_direction

Page 808: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

classTankFleeingState<TankMotionState#[email protected]_powerup(RepairPowerup,HealthPowerup)ifclosest_powerupangle=Utils.angle_between(@object.x,@object.y,closest_powerup.x,closest_powerup.y)@object.physics.change_direction

angle-angle%45)else#...reversefromenemyend

Page 809: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@changed_direction_at=Gosu.milliseconds@will_keep_direction_for=turn_timeend#...end

ThissmallchangetellsAItopickuphealthwhilefleeing.TheinterestingpartisthatwhentankpicksupRepairPowerup,it’shealthgetsfullyrestoredandAIshouldswitchbacktoTankFightingState.This

Page 810: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

simplethingisamajorimprovementinAIbehavior.

EvadingCollisionsAndGettingUnstuckWhileobservingAInavigation,itwasnoticeablethattanksoftengotstuck,eveninsimplesituations,likedrivingintoatreeandhittingitrepeatedlyforadozenofseconds.Toreducethe

Page 811: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

numberofsuchoccasions,wewillintroduceTankNavigatingState,whichwouldhelpavoidcollisions,andTankStuckState,whichwouldberesponsiblefordrivingoutofdeadendsasquicklyaspossible.

Toimplementthesestates,weneedtohaveawaytotelliftankcangoforwardandawayofgettingadirectionwhichisnotblockedbyother

Page 812: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

objects.Let’saddacoupleofmethodstoAiVision:

classAiVision#...defcan_go_forward?in_front=Utils.point_at_distance(*@viewer.location,@viewer.direction,40)@object_pool.map.can_move_to?(*in_front)&&@object_pool.nearby_point(*in_front40,@viewer).reject{|o|o.is_a?Powerup}.empty?end

Page 813: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

defclosest_free_path(away_from=nil)paths=[]5.timesdo|i|ifpaths.any?returnfarthest_from(paths,away_from)endradius=55-i*5range_x=range_y=[-radius,0,radius]range_x.shuffle.eachdo|x|range_y.shuffle.eachdo|y|[email protected][email protected]+yif@object_pool.map.can_move_to?(x,y)&&

Page 814: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

@object_pool.nearby_point(x,y,radius,@viewer).reject{|o|o.is_a?Powerup}.empty?ifaway_frompaths<<[x,y]elsereturn[x,y]endendendendendfalseend

alias:closest_free_path_away_from:closest_free_path#...

Page 815: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

private

deffarthest_from(paths,away_from)paths.sortdo|p1,p2|Utils.distance_between(*p1,*away_from)<=>Utils.distance_between(*p2,*away_from)end.firstend#...end

AiVision#can_go_forward?

tellsiftankcanmoveahead,and

Page 816: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

AiVision#closest_free_path

findsapointwheretankcanmovewithoutobstacles.YoucanalsocallAiVision#closest_free_path_away_from

andprovidecoordinatesyouaretryingtogetawayfrom.

Wewilluseclosest_free_pathmethodsinnewlyimplementedtankmotionstates,andcan_go_forward?inTankMotionFSM,tomakea

Page 817: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

decisionwhentojumpintonavigatingorstuckstate.

Thosenewstatesarenothingfancy:13-advanced-ai/entities/components/ai/tank_navigating_state.rb1classTankNavigatingState<TankMotionState2definitialize(object,vision)3@object=object4@vision=vision5end67defupdate8change_directionif

Page 818: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

should_change_direction?9drive10end1112defchange_direction13closest_free_path=@vision.closest_free_path14ifclosest_free_path15@object.physics.change_direction

16Utils.angle_between([email protected],@object.y,*closest_free_path))18end19@changed_direction_at=Gosu.milliseconds20@will_keep_direction_for=turn_time21end22

Page 819: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

23defwait_time24rand(10..100)25end2627defdrive_time28rand(1000..2000)29end3031defturn_time32rand(300..1000)33end34end

TankNavigatingStatesimplychoosesarandomfreepath,changesdirectiontoitandkeepsdriving.

Page 820: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

13-advanced-ai/entities/components/ai/tank_stuck_state.rb1classTankNavigatingState<TankMotionState2definitialize(object,vision)3@object=object4@vision=vision5end67defupdate8change_directionifshould_change_direction?9drive10end1112defchange_direction13closest_free_path=@vision.closest_free_path14ifclosest_free_path

Page 821: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

[email protected]_direction

16Utils.angle_between([email protected],@object.y,*closest_free_path))18end19@changed_direction_at=Gosu.milliseconds20@will_keep_direction_for=turn_time21end2223defwait_time24rand(10..100)25end2627defdrive_time28rand(1000..2000)29end30

Page 822: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

31defturn_time32rand(300..1000)33end34end

TankStuckStateisnearlythesame,butitkeepsdrivingawayfrom@stuck_atpoint,whichissetbyTankMotionFSMupontransitiontothisstate.

classTankMotionFSMSTATE_CHANGE_DELAY=500LOCATION_CHECK_DELAY=5000

Page 823: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

definitialize(object,vision,gun)#...@stuck_state=TankStuckState.new(object,vision,gun)@navigating_state=TankNavigatingState.new(object,vision)set_state(@roaming_state)end#[email protected]_go_forward?unless@current_state==@stuck_stateset_state(@navigating_state)endend

Page 824: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

#Keepunstuckingitselfforawhilechange_delay=STATE_CHANGE_DELAYif@current_state==@stuck_statechange_delay*=5endnow=Gosu.millisecondsreturnunlessnow-@last_state_change>change_delayif@last_location_update.nil?@last_location_update=now@[email protected]@last_location_update>

Page 825: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

LOCATION_CHECK_DELAYputs"checkinlocation"unless@last_location.nil?||@current_state.waiting?ifUtils.distance_between(*@last_location*@object.location)<20set_state(@stuck_state)@[email protected]@last_location_update=now@[email protected]#...

Page 826: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

end#...end

Whatthisdoesisautomaticallychangestatetonavigatingwhentankisabouttohitanobstacle.Italsotrackstanklocation,andiftankhasn’tmoved20pixelsawayfromit’soriginaldirectionfor5seconds,itentersTankStuckState,whichdeliberatelytriesto

Page 827: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

navigateawayfromthestock_atspot.

AInavigationhasjustgotsignificantlybetter,anditdidn’ttakethatmanychanges.

Page 828: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

WrappingItUp

Ourjourneyintotheworldofgamedevelopmenthascometoanend.Wehavelearnedenoughtoproducedaplayablegame,yetonlyscratchedthesurface.Writingthisbookwasaveryenlighteningexperience,andhopefullyreadingitinspired

Page 829: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

orhelpedsomeonetogetastart.

LessonsLearnedBuildingthissmalltanksgameandlearningaboutgamedevelopmentwithRubycertainlyhadsomenastybumpsalongtheway,someofthemmademyheadhittheceiling.

RubyIsSlow

Page 830: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Thisshouldn’tbeashocker,becauseRubyisadynamic,interpretedlanguage,buthowexactlyslowitisatsomepointswasastaggeringdiscovery.ProbablythebestevidenceisthatdrawingmaptilesoffscreenusingnativeextensionswasactuallyfasterthandoingCamera#can_view?checksthatinvolvesimpleintegerarithmeticandrangechecks.

Page 831: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Ifyourgameisgoingtodealwithlargenumberofentities,Rubywillstartlettingyoudown.Dreamingaboutgoingpro?GoforC++,youwon’tmakeamistakehere.

Knowingthis,keepinmindthatRubyisawonderfullanguage,thathasit’sownstrengths.It’sgreatforprototypinganddynamicthings.Some5-10linesofRubycouldtranslateinto50-

Page 832: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

100linesofC++.Also,knowingmultiplelanguagesmakesyouabetterdeveloper.

PackagingRubyGamesSucksUnlessyouarereleasingyourgamefortechsavvyguyswhocangeminstallit,getreadytogothroughhell.Thereisnoniceandeasywaytocreateastandaloneexecutableapplicationfrom

Page 833: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Rubycodethatinvolvesnativeextensions.Andyouwillgothroughhellonceforeveryoperatingsystemyouwanttopublishyourgamefor.

That’snoteverything.WanttousethelatestRubyversion?CheckifyoucanmakeapackageforitinyourtargetOSbeforeyoustartcoding.Thinkingofusingsomethingthatrelieson

Page 834: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ImageMagick?Toobad,youprobablywon’tbeabletopackagethegameintoanativestandaloneapp,atleastonOSX.Ifyouareplanningonreleasingthegame,packageearlyandpackageoften,foreveryOS,andcheckiftherewillbenoproblemswithnativeextensions.

PlanNetworkedMultiplayerEarly

Page 835: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Ifyouaregoingtobuildagame,don’tmakeamistakeofthinking“I’lljustmakeitmultiplayerlater”,startattheverybeginning.ThiswasalessonIlearnedthehardway.TherehadtobeachapterinthisbookaboutturningTanksintomultiplayer,butitdidn’thappen,becauseitwouldrequireamajorrewriteofthecode.

Page 836: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

CreatingAWellPolishedGameRequiresExtraordinaryEffortHackinguparoughprototypeisextremelyfun.Yougettobuildanengine,wireeverythingtogether.Itdefinitelygivesasenseofachievement.Turningitintoagreatgame,however,isadifferentstory.Youcanspendhoursorevendaystweakinghowgamecontrols

Page 837: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

workandstillremainunsatisfied.Everytinydetailcanbepushedfurther.Preferqualityoverquantity,andrememberthatyouprobablycannotaffordbothandactuallyfinishitwithinnextcoupleofyears.

StartSmall,TakeBabyStepsYourfirstfewgamesshouldbesmallexperiments,

Page 838: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

prototypesordemos.Don’tattempttobuildagameyouwantedtobuildforeverwithyourfirstshot.TryreimplementingTetris,PacmanorBejeweledinstead.Youwillfindittobechallengingenough,andwhenyouwillfeelyouhavetheskillstodosomethingbigger,practicejustalittlemore.

Don’tReinventTheWheel

Page 839: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Beforedoinganything,research.YouwillprobablynotgetpointinpolycollisiondetectionbetterthanW.RandolphFranklindiditinhisresearch.Evenifyouthinkyoucandoitonyourown,learnwhatothersdiscoveredbeforeyou.Learnfromother’smistakes,notyourown.

Page 840: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

SpecialThanks

IwouldliketothankJulianRaschkeforcreatingandmaintainingGosuandforallthehelponIRC,GosuforumsandGitHub.ThisbookwouldnotexistwithoutyourenormouscontributiontoRubygamedevelopmentscene.

Page 841: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

ShoutoutgoestoShawnAnderson,creatorofGamebox.Thankyouformoralsupportandencouragement.StudyingGameboxsourcecodetaughtmemanythingsaboutGosuandgamedevelopment.

YoucanfindJulian,Shawnandmoregamedevelopmententhusiastsin#gosuonFreeNode.

Page 842: Developing Games With - DropPDF1.droppdf.com/files/tmMfD/developing-games-with-ruby-for-those-wh… · Developing Games With Ruby For those who write ... Getting Gosu to run on Mac

Andmostimportantly,thankyouforreadingthisbook!