Post on 13-Apr-2015
transcript
2DGameplayTutorialProviding2DGameplaywithUnity2
Author:GraveckInteractive
LastRevision:19FEB2008
Contents
1. IntroductionWhy2DistheBee'sKnees 4Prerequisites 6
2. SettingTheSceneGettinginthe2DMindSet 7ACloserLook 9SettingtheLevelAttributes 10ObjectProfile:LevelAttributes 12ObjectProfile:DeathZone 13SettingUpthePlatforms 13ObjectProfile:Platform(Prefabs) 15ObjectProfile:PreAssembledPlatform 16IntroducingLerpz,OurLovelyCharacter 17PlacingLerpz 18DirectingtheCamera 19ObjectProfile:Character(Lerpz) 20LightingourScene 22SpicinguptheCharacter 24TheCamera 26ObjectProfile:MainCamera 27ContinuingourLevel 28ScriptProfile:CameraTargetAttributes 28HandlingRigidbodies 29ObjectProfile:Crate 30Exercise 31MovingPlatforms 32ObjectProfile:MovingPlatform 33TheSpaceship 34ObjectProfile:Spaceship 35WellDone! 36
3. DelvingDeeper:ScriptingExamplesStudyingtheScripts 38MovingPlatformParticleEffects 38
TheCameraScrollingScript 40StreamlineYourWorkflow 41SpaceshipScriptPart1:DefiningHelperClasses 43SpaceshipScriptPart2:ControllingtheSpaceship 44SpaceshipScriptPart3:SpecialEffects 47Finished! 47
4. What'sNext?YourTurn 48
Introduction
Why2DistheBee'sKneesItisnosecretthatUnitycanhelpyoucreategreatthreedimensionalgameswithease.Itsrawpowerandflexibilityallowsevenbeginnerstocreateimpressivegameswithoutmuchdifficulty.Unityisundoubtedlyagreat3Dgameenginesowhyonearthwouldyouwanttocreatea2Dgamewithit?
Forcertaingametypes,thatextra"D"in3Dcanbeahindrance.Somegamessimplyworkbetterwithtwodimensionalgameplaymechanics.Thinkofthosesimpleandfun2Dsidescrollinggamesyouhaveplayedinthepast,ormaybeyouhaveasimplepuzzlegameideathatwouldworkbestconstrainedtotwodimensionsthelistkeepsgoingbutthebottomlineismanygamescanbenefitbytheuseofonlytwodimensions.
Twodimensionalgamesarealsocommonlyeasierforthecasualgamertounderstand,whichissomethingtoconsiderifyou'reasmallgamedeveloper(seethearticle"CasualGamesasaBusiness").
Luckily,Unityisextremelyflexibleandcaneasilyhandle2Dgameplay!ItsworldclassAgeiaPhysXishighlyadaptableandcanbeconstrainedinmanywaysincludingtwodimensions.
Inthistutorialwedefinea2DGameasagamewheregraphicsarestillin3D,butrestrictedmotioncausesthephysicsandgameplayonlytooccurinasingle2Dplane.Thisletsususe3Dmodelsforourcontentandmakeslifeeasierforartistsanddevelopersalike.Onecouldsaythatwe'reusingthebestofbothworlds:theeaseof2D
Sometimes2Dgameplaycallsandyoucan'tresistitsalluringcharm!Unitycanhandleit.
Thistutorialshowsthestepsyouneedtocreateabasic2Dstyleplatformgame.
gameplayandthebeautyof3Dgraphicswiththeaddedattractionthatexistingdevelopersalreadyhaveagood3Dassetproductionpipelineinplace.
Thistutorialwillguideyouinbuildinga2Dplatformgame.Wehavedesignedthistutorialwithbeginner/intermediatelevelusersinmind;weonlyaskthatyouhaveabaselineknowledgeofUnity.Wehavealsoincludedsomeadvancedconceptsthatmaybeofinteresttomoreseasonedusers.
Webeginbygettingyouintothe2Dmindset.Thenwewillwalkyouthroughbuildinga2Dworldinwhichyourcharacterwillmovearound.Afteraddingafewcoolobstaclesandscenery,we'lllastlyaddarocketshipfortheplayertofly.
Wehopeyouenjoythistutorialasmuchaswehadfuncreatingit!
Thetutorial’sdemolevelinaction.
5
PrerequisitesHerearethetoolsandknowledgeyoushouldhavebeforeyoubeginthistutorial:
• Unity2
Althoughyoucanbenefitfromthistutorialifyou'reaUnity1.xuser,therearesomefeaturesweusewithinthistutorialthatareonlyfoundinUnity2.0andabove.
• BasicScripting.
Weassumethatyoualreadyhaveagraspofbasicscriptingprinciples.
• FamiliaritywiththeUnityuserinterface.
YoushouldalsobefamiliarwithUnity’skeyinterfaceelements,suchastheInspector,thevariousViews,andbasicdraganddroptechniques.IfyouareunfamiliarwithUnity,pleasetakealookatour“IntroductiontoUnity”videos.You’llfindtheseinourwebsite’sResourcesarea.
• 3DModelingTools(Recommended).
Althoughnotrequiredsincewesupplythemodels,itisrecommendedthatyouhavetoolstoexaminethe3Dassets.SuchtoolsincludeAutodeskMaya8,3DStudioMax,Cinema4D,andCheetah3D.(NOTE:BlendercanexportFBXfiles,butcannotcurrentlyimportthisformat.)
• 2DGraphicsTools(Recommended)
Again,itisnotrequiredbutwerecommendedthatyouhavetoolstoexaminethe2Dassetswesupply.SuchtoolsmayincludeAdobePhotoshop,CorelPainter,oroneofthebudgetalternativessuchasPixelmator.
Also,besuretodownloadtheprojectfilemeanttoaccompanythistutorial.You’llfindthefilesinourResourcessection:http://unity3d.com/support/resources/
6
SettingTheScene
ThissectionofthetutorialwillmostlydealwithhowtosetupGameObjectsinthesceneview,addingComponents,andhowtomanipulatethemintheInspector.
Weprovideyouwitharelativelyemptysceneandyourmissionistobuildontothatscenetomakeupamorecompletelevel.Bottomlineis,weareprovidingthetoolsyouneedandyouneedtousethemtoconstructalevel.Lateroninthistutorialwedelveabitdeeperandexplainhowsomeofthespecificscriptswork.
Gettinginthe2DMindSetNowweneedtogetinthepropermindsetandcreatesomecommonconventionsthatwillremainconsistentthroughoutourproject.Firstweneedtodefineourplaneofmotion.Inotherwords,weneedtorestrictmotiontoonlytwoofthethreedimensions,traditionallynamedX,Y,andZ.Todothiswemustspecificallydecidewhichaxis ofmotionwillhavenomovement.
TIP WhenintheSceneViewyoucanrememberwhichcolorcorrelatestowhichaxiswiththesimplemnemonicdevice"RGB=XYZ"
TheusualconventionisfortheXaxistocorrespondtohorizontalmovementrelativetotheobserver,whiletheYaxiscorrespondstoverticalmovement.TheZaxisthereforecorrespondstomovementstowardsandawayfromtheobserverforourpurposes,thismeanstheZaxiscorrespondstomotiontowardsandawayfromourcamera.
Throughoutthetutoriallet’skeepthefollowinginmind:
7
It’stimetoprepareforourjourney.
InthissectionwestartputtingourscenetogetherandlookathowUnitycanbemadetohandle2Dgames.
• DefiningourPlaneofMotion.
WearegoingtostickwithcommonconventionandhaveourmotionbeintheXYplane,meaningthatnomovementwilloccurintheZaxis.VerticalmovementwillbeintheYaxisandhorizontalmovementwillbeintheXaxis.
• RestrictedRotation.
Wealsoneedtorestrictourrotation.Asageneralrule,theonlyrotationthatwewillallowisrotationaroundtheZaxis.RemembertheZaxispassesthroughthecamera;thereforerotationaroundtheZaxiswillresultinclockwiseandcounterclockwiserotationastheMainCameraseesit.Thereisoneexceptiontothisrestrictedrotation,however.Thecharacterisallowedrotationabouttheyaxissohecanturnfromsidetoside.
A2Dgameneedsjusttwoaxes:XandY.
Withallthisinmind,it'sfinallytimetoopenourprojectandscene.Ifyouhaven'talreadydoneso,pleasedownloadtheprojectfilesnow.
SelectFile>OpenProjectandlocatethe2DTutorialprojectthatyouhavedownloaded.
Onceyouhaveopenedtheproject,findthescene2DPlatformerintheProjectPaneandopenit.
PlaytheScene.
8
The2DPlatformerScene.
ControlsUsethecursorkeystomoveLerpz.HolddowntheCtrlkeytomakehimrunandusethespacebartojump.
TheGUIbuttonsatthetoptogglebetweencontrollingthecharacterandthespaceship.Everythinginthisscenehasalreadybeenlaidoutforyou.Feelfreetoexploreandexamineeverythingyoucan.Themorefamiliaryouarewithhowwesetupourlevel,theeasieritwillbetocreateyourown.
ACloserLookHerearetwothingsyoucaninvestigatetobetterunderstandhowtosetupa2Dgamebeforeyoudoityourself:
ObjectPositionsIfyoubringupanelementintheInspector,you’llseethatallobjectsareplacedatzerointheZaxis,keepingtotheconventionwedefinedabove.
Whenmodelingyour3Dassets,itmaymakeyourlifeeasiertomodeltheminyourmodelingapplicationwiththesameorientationasinUnity.Althoughnotcrucial,thisavoidstheinconvenienceofhavingtorotatethemafteryouimportthem.
PlatformTilingIfyouinvestigatetheplatformsinthissceneyou'llnoticethattheyaremadeupofsmaller,tileablepieces,withendcapsforthebeginningsandendsofplatforms.ThiscansavehoursofmodelingtimesoplatformscanbebuiltwithinUnityandeasilychanged.Everythingfromthesizetothetexturesaremodeledwithtilinginmind.
9
NOTE Tilingwasaverycommontechniqueintheearlydaysofcomputergames.Ithadtheveryusefuladvantageofreducingtheamountofgraphicalassetsrequired,keepingtheproject’soverallsizedown.Inthedayswhencomputermemorywasmeasuredinkilobytes,thiswasanimportantfactor.Today,tilingremainsausefultechniqueasitreducesbothassetproductiontimeanddownloadsize.
SettingtheLevelAttributesAfterplayingourprebuiltlevel,it'stimetobeginourown.
CreateanewscenebygoingtoFile>New.Younowhaveacompletelyemptyscenethatisreadytorock.Beforeyoubegin,makesurethatyourinterfaceissetuphowyouprefer.BesurethattheSceneView,ProjectPane,HierarchyPane,andInspectorareallpresent.
FirstthingtodoistodefineourSkybox:
GotoEdit>RenderSettingsinthemenu.IntheInspector,youshouldseeanemptyslotforaSkybox.
IntheProjectPane,expandthefolderStandardAssets>Skyboxes.
DragMartianStratosphereintotheSkyboxMaterialslotintheInspectorfortheRenderSettings.
TheRenderSettings
Nowweshouldhaveaniftyskyboxthatwewillseeinthebackgroundatalltimesinourgame.
10
TheGameView,showingtheSkybox.
Next,weneedtoaddsomethingwhichwillmanagesomeimportantattributes.
LookintheProjectPaneandfindthePrefabnamedLevelAttributeswithintheLevelPrefabsfolder.
DragthePrefabintotheHierarchyPanesoitisloadedinyourscene.
EnsurethatitsPositionisat(0,0,0).Thiswillmakelifeeasierinthelongrunforthechildobject"DeathZone."
TheLevelAttributesPrefabintheSceneView.Weseetwonewobjectshere:thesmallrectanglerisingupwardsdefinesthelevel’sboundaries.Thelongoblonglyingflatisthe“DeathZone”(displayingtheskull).
11
IntheSceneViewyoushouldnowbeabletoseeagreenrectanglethatrepresentsthesizeofyourlevel.Ifyoucannotseethegreenrectangle,adjustyourviewingpositionsothatyoucanclearlyseeit.
Adjustthesettingsaccordingtohowbigyouwantyourleveltobe.
Asareferencepoint,thecompletedlevelthatwesuppliedwas44.25unitswideby60unitstall.MakesurethateverythingislocatedatzerointheZaxis.Thesizeofyourlevelcaneasilybechangedlatersodon’tworryaboutgettingitabsolutelyright.
Finally...
SAVEyourscene!
Sowhat’sgoingonhere?LetstakeamuchcloserlookattheLevelAttributesandDeathZoneGameObjects...
ObjectProfile:LevelAttributesTheLevelAttributesobjectstartedasanemptyGameObjectatposition(0,0,0).ThescriptLevelAttributeshasbeenappliedtoit.
Functions• OnDrawGizmos()
Displaysthelevel’sdimensions.Thelevel’ssizeisdenotedbythegreenborderedrectangledrawninthesceneview.
• Start()
CreatesphysicsCollidersatstartupthatactasbordersaroundtheworldtopreventthecharacterfromleavingthelevelboundaries.
Script:LevelAttributesThisscriptdefinesthelevel’skeyattributesbasedonthevaluesyousetintheInspector:
• Bounds
‣ X:Thexcoordinatethatyourlevelwillstartat.
‣ Y:Theycoordinatethatyourlevelwillstartat.
‣ Width:ThewidthofyourlevelstartingattheXcoordinateabove.
‣ Height:TheheightofyourlevelstartingattheYcoordinateabove.
12
• FallOutBuffer:Thiscreatesabufferzoneatthebottomofyourlevel.ItspurposeistogiveyourcharactersomeroomtofallwithoutthecamerafollowinguntilithitsthebottomCollider.
• ColliderThickness:ThethicknessoftheCollidersthatcreateyourborders.
FurtherAnalysisIfyouselecttheLevelAttributesGameObjectafterpressingplay,thenlookatthegreenboundaryrectangleinthesceneview,youwillnoticeColliders(representedbylightgreenboxes)attheedges.ThesearetheautomaticallygeneratedphysicsColliderscreatedbytheLevelAttributesscript.
ObjectProfile:DeathZoneTheDeathZoneobjectstartedasanemptyGameObjectatposition(0,0,0).ItisachildobjectofLevelAttributes.ItdoesnotneedtobeachildofLevelAttributes,butfororganizationalpurposesworkswellthere.Thescript"DeathTrigger"hasbeenappliedtoit.
FunctionProvidesaColliderdefinedasaTriggerwhichcausesthecharactertorespawnifhe/shefallsontoit.Thisisusefulforpitsthattheplayercanfallinto.
Script:DeathTriggerThisscriptdrawsthelittleskullandcrossbonesthatyouseeinthesceneviewbytakingadvantageofGizmoicons.Althoughit'snotnecessary,itisuseful.(“SettingUpthePlatforms”hasmoreinformationonGizmos.)
SettingUpthePlatformsNowit'stimetocreatethefoundationofourlevel:theplatforms.
IntheProjectPaneyouwillseeaprefabcalled"PreAssembledPlatform."DragitintotheScene.
Ensuretheplatformislocatedatzeroalongthezaxis.
Positiontheplatforminaplaceyou'rehappywith.
13
PlacingthePreAssembledPlatformPrefab.
Thisplatformwaspreassembledforyou,butyouwillhavetomaketherestyourself.
LookintheHierarchyPaneandyou'llseethatthePreAssembledPlatformhasseveralchildobjects.Thesechildrenobjectsarewhatmakeuptheplatform.Ifyouinvestigatetheplatformsyou'llnoticethattheyaremadeupofsmaller,tileablepieces,withendcapsforthebeginningsandends:
LookinginsidethePreAssembledPlatformPrefab.
Usingtheseplatformtiles,createmoreplatformsforyourcharactertorunwild!
Keepthesepointersinmind:
• Alwaysmakesurethezpositionisatzero.
• Lookatthepreassembledplatformforreference.
14
• Wehighlyrecommendthatyouparentgroupsofplatformtilestogether,forreasonsdescribedinObjectProfile:PreAssembledPlatform,below.
Todothis,createanemptyGameObjectbygoingtoGameObject>CreateEmptyandnameitappropriately.MakesuretheGameObjectislocatedatzeroalongtheZaxis.AlsomakesurethattheXandYcoordinatesarewhereyouwanttheplatformtobelocated.ThenyoucandragtheplatformtilesinsidetheemptyGameObjectyoujustcreated.Last,applythescriptCombineChildrensoyoumimicthefunctionofthePreAssembledPlatformGameObjectdescribedabove.
• Thetilescanbepreciselypositionedeasilybecausetheirlengthsarenicewholenumbervalues.
• Theplatformsmuststayinsideofthegreenlevelboundaryyousetupintheprevioussection!Ifyourplatformsareoutsidethisareatheywillbeunreachable.Youcanalwayschangethesizeoftheboundaries.
• Savefrequently!
Youcanalwayscreatemoreplatformslater,butyouatleastwantanareathatthecharactercanrunaround.
ObjectProfile:Platform(Prefabs)IntheProjectPaneyoucanfindtheseprefabsinsideLevelPrefabs/Platforms.
FunctionsThesearethetileablepiecesthatmakeupthelargerplatforms.You'llfindfivedifferentpieceswithinthePlatformTilesfolder:
• PlatformLevel:Alevelpieceofplatformthatis6unitslong.
• PlatformSlopeUp:Apieceofplatformthatslopesupmovingfromlefttoright.Itis3unitslong.
• PlatformSlopeDown:Apieceofplatformthatslopesdownmovingfromlefttoright.Itis3unitslong.
• PlatformEndCapLeft:Thisbelongsattheleftedgeofanarrayofplatformstocapitoff.
• PlatformEndCapRight:Thisbelongsattherightedgeofanarrayofplatformstocapitoff.
15
Thelengthofthesepieces,(withtheexceptionoftheendcapssinceitisnotnecessary,)arenicewholenumberssotheycanbepreciselytiledbyeditingthenumbersintheInspector.
Components• BoxCollider
Withoutthis,thecharacterandspaceshipwouldfallrightthroughtheplatform!Thisisneededtophysicallyinteractwiththecharacter.TheBoxCollidersizehasbeenadjustedtofittheplatformtile,otherwiseallsettingsaredefault.Sincetheplatformdoesnotmoveatall,wedonothavetoapplyaRigidbodycomponent.
• Pipeline,MeshFilter,andMaterial:Theseassignthepropermeshandtexturesoitrendersinthescene.
Script:CollisionSoundEffectThefootscriptattachedtoourplayerchecksGameObjectitcomesintocontactwithforthepresenceofthisscriptandplaysthesoundeffectitholds(ifyouhavesetone).Inthiswayourplayercharacter’sfootstepscanbemadetosounddifferentondifferentsurfacese.g.ametallicsoundonmetalplatforms;awoodenfootstepsoundonwoodensurfaces,andsoon.
Script:CollisionParticleEffectThisscript,liketheoneabove,providesasimilarserviceforparticleeffects.Theplayer’sfootscriptlookstoseeifwe’vesetaparticleeffectGameObjectandstartsitifso.Thisishowthecharacterraisesthecloudsofdustasherunsaroundtheexamplelevel.
TIP Ifyou'recurious,examinethetexture(whichisthesameforeachtile)toseehowitloops.
ObjectProfile:PreAssembledPlatformIt'stheparentobjectthatcontainsplatformtilesthatcreateasinglelargeplatform.
Function:ThisGameObjectservestwopurposes.
• Asacontainerusedtoorganizetheleveland
• Toaidperformanceseethescriptdescribedbelow.
Itisrecommendedthatyoustructureyourentirelevelusingthismethod.Inotherwords,foreachgroupofplatformtilesthatmakeupalargeplatform,createaparentobjectforthemwiththeCombineChildrenscriptapplied.
16
Script:CombineChildrenIntheInspectoryoucanseethisscriptwithitsselfexplanatoryoptions.Whatthisdoes istakeallofthechildrenGameObjectsi.e.theplatformtilesandcombinetheirmeshessoinsteadofrendering6differentobjects,only1objectisrendered.Thisenhancesperformance,especiallywhenyoureachalargenumberofplatforms.
TIP ThisscriptactuallycomesintheStandardAssetspackage,whichisshippedwithUnity.
IntroducingLerpz,OurLovelyCharacter
Lerpz,ourzanycharacter,isgettinganxiousforaction!
Letsgetourspawnpointsetupfirst.Thespawnpointiswherethecharacterwillappearwhenyoustartthegame.It'sprettysimpletodo,justfollowthesesteps:
CreateanewemptyGameObjectbygoingtoGameObject>CreateEmpty.Renameitto“CharacterSpawnPoint”.
17
ApplythescripttitledSpawnPointtotheGameObjectyoujustcreated.Thisscriptcreatesthatlittle2DiconofLerpzinsidetheSceneViewsoyoucanseewherethespawnpointis.(ThislittledrawingiscalledaGizmo.TheDeathZonealsohasoneofthesetodisplaytheskullandcrossbonesicon.)
PositionthespawnpointwhereyouwantLerpztoappear.Makesureitisatz=0withaplatformunderfoot,soheactuallyhasaplacetostandwhenheappears.
WhatexactlyisaGizmo?Gizmosareshapes,iconsandothervisualaidsthatappearintheSceneViewsuchaslines,lamps,cameras,andaudiosourcestoassistinvisualdebuggingorlayout.Gizmosdrawnexclusivelyinthis2DtutorialaretheDeathZone,andCharacterSpawnPoint.
Allittakesisaverysimplescript.Here'sanexampleofthescriptSpawnPointthatisappliedtotheCharacterSpawnPoint:
function OnDrawGizmos(){ Gizmos.DrawIcon(transform.position, "Player Icon.tif");
}
GizmoiconsmustbeplacedintheAssets/Gizmosfolder.
TheLevelAttributesscriptalsotakesadvantageofGizmos:ThegreenborderyouseerepresentingthelevelboundariesisaGizmo.ForacompletereferenceonGizmos,youcanrefertothedocumentation(http://unity3d.com/Documentation/ScriptReference/Gizmos.html).
PlacingLerpzThenextstepistoaddLerpzhimselftoourScene:
DragthePrefab"Character(Lerpz)"inourLevelPrefabsdirectoryintotheScene.Sincewehaveaspawnpointsetup,youcanplacehimanywhereyou'dlike,justaslongashe'ssomewhereintheScene.
Ifit’snotalreadyvisible,bringupourCharacterintheInspectorandopenupthePlatformControllerScriptComponent.NotetheSpawnPointslot:
18
Character(Lerpz)withnoSpawnPointset.
DragourearlierCharacterSpawnPointobjectintothisslot,soitlookslikethis:
Character(Lerpz)withtheSpawnPointset.
ThenextstepistogettheMainCameratofollowLerpzaround...
DirectingtheCameraAtthemoment,ourmaincamerawillsimplysitwhereitisandpointatwhateverit’saimedat.MuchlikeinamovieorTVproduction,weneedtodirectthecameratellithowtomove,whentodosoandwhatitshouldbeaimedat.Weachievethiswithtwoscripts:
DroptheCameraScrollingscript(fromScripts>2D>Camera)ontotheMainCameraGameObject.
DroptheCameraFocusscript(fromthesamelocation)ontotheMainCamera.
Thenextstepistogivethescriptstheinformationtheyneedtowork:
SelecttheMainCameraintheHierarchyPaneandopenuptheCameraFocusscriptComponentintheInspector.
OpentheTargetsgroupandchangeSizeto1.Element0shouldappearbelowit.
DragourCharacter(Lerpz)GameObjectontotheElement0slot.
OpentheTargetButtonNamesgroupandchangeSizeto1.(Again,Element0shouldappear.)
Type“Player”intoElement0’sslot.
19
Theresultshouldlookliketheimagebelow:
SettinguptheCameraFocusscriptcomponent.
Weshouldnowhaveaworkingcameraandcharacterrunningandjumpingoverourplatforms.
ItwasveryeasytogetthecharacterinthelevelusingPrefabs,butoncloserinspectionLerpzisanythingbutsimple:
ObjectProfile:Character(Lerpz)Lerpzisthemaincharacterofourgame.Hecanwalk,run,jump,andfall.Hemovesaroundourlevelwreakinghavocwhereverhegoes.
Components• Animation
Thiscomponentstoresalistofanimationsforthecharacterthatcanbeaccessedbyscripting.PlatformPlayerAnimation(listedbelow)makesuseofthiscomponentbyaccessingdifferentanimations.
• CharacterControllerThetraditionalsidescrollingcharactercontrolsaregenerallynotphysicallyrealistic.Thecharactercomestoahaltimmediatelyandturnsonadime,makingitdifficultandimpracticaltouseRigidbodyphysics.Asaresult,weuseanalternatemethodtomovethecharacteraroundbyusingtheCharacterController.Seemoredetailonthiscomponentinthedocumentation.(http://unity3d.com/Documentation/Components/classCharacterController.html)
ScriptApplied:PlatformerControllerThisscriptisacustomscriptmadeforthis2Dtutorial.Thisscript,incooperationwiththeCharacterControllercomponent,isusedtodefineitsphysicalmechanicswithinourworld.Mostoftheadjustablesettingsareselfexplanatoryandwewillnotgointomuchdetail,butafewrequiresomefurtherdiscussion:
20
• SpeedSmoothingHowquicklydoesthecharacterchangespeeds?Forexample,howquicklycanthecharactergofromnotmovingtorunning.Highermeansfaster.
• RotationSmoothingHowfastthecharactervisuallychangesdirections.Itdoesnotaffectthemotion.
• CanControlThissimplystateswhethertheplayercancontrolthecharacter.Thiscanbeturnedoffbyanotherscriptifatanytimeyouwantusertoloseorgaincharactercontrol.Anexampleofthisbeingtogglediswhenyoutogglebetweenthespaceshipandtheplayer.
• SpawnPointYoumustdefinethespawnpointbydraggingaTransformobjectintotheslot.Thenthecharacterwillspawnatthatpoint.
Script:PlatformerPlayerAnimationThisscripttakestheanimationslistedintheAnimationComponentandplaysthemattheappropriatetimes.Forexampleitdetectswhenaplayerisonthegroundandmovingatacertainspeed,andthenplaystheappropriateanimationsuchas"run."
Script:PlatformerPushBodiesSincethecharacterisnotaRigidbody,itdoesnotautomaticallyphysicallyinteractwitheverythingaroundit.ThisscriptallowsthecharactertoapplyforcestoRigidbodiessuchasthecrateswithinthelevel.
ThesettingPushPoweristhestrengthofthepushappliedbythecharacter.
ThePushLayerssettingdetermineswhatlayersthecharactercanactuallypush.Sometimes,youmaynotwantaspecificRigidbodytobepushedbythecharacterbutstillinteractphysicallywiththeworldaroundit,soyoucancreatealayerforthatobjectmakesurethatthecharactercannotpushthatlayerwiththissetting.
Script:CameraTargetAttributeThisdefinessomecamerabehaviors,andisalsoappliedtotheSpaceship.Thisscriptismorethoroughlydiscussedinthenextsection.
FurtherAnalysisWehavejustscratchedthesurfaceofexplainingthecharacter.Tofullybenefityou,itwouldbewisetoexamineandexperimentwithallofthescriptsattachedtothecharactertoseehowtheywork.Wehavesuppliedcommentsinthecodetohelpguideyoualong.
TakeafewmomentstoplayaroundwithLerpz'ssettings.Adjustthedifferentsettingstoseewhattheydo,andifthingsgettoocrazyyoucanalwaysdeletehimfromthesceneandaddanewoneusingthePrefab!
21
LightingourSceneAtthisstagewehaveourcharacterrunningaroundourScene,butit’sallverydark.Weneedsomelightstomakeeverythingeasierontheeye!
We’lladdtwoDirectionalLights:
CreateanEmptyGameObject.Nameit“MainLights”.(We’llusethistoorganizeourlightsandkeeptheminoneplace.)
CreateaDirectionalLight.(GameObject>CreateOther>DirectionalLight).
Renameit“Downlight”.
DragthelightintoourMainLightsobject.
RotateourDownlightobjecttopointabout60degreesdownwards.
Setitasshownbelow(Intensityisalsochangedfromthedefault,to0.5):
Thelightbluedownlight’ssettings.
Nowwe’llrepeattheprocessagain,butforouruplighter.Thiswilllighttheundersidesoftheplatforms:
CreateaDirectionalLight.(GameObject>CreateOther>DirectionalLight).
Renameit“Uplight”.
DragthelightintoourMainLightsobject.
RotateourUplighttopointabout60degreesupwards.
Setitasshownbelow(Intensityisagainchangedfromthedefault,to0.5):
22
Color Red Green Blue OpacityLight 184 233 255 100
Thepurpleuplight’ssettings.
Thenextstepispurelyforourownconvenience:
SelectourMainLightsparentobjectanddragitbackwards,awayfromtheplatforms(seescreenshotbelow).Precisionisn’timportanthere:thisisjusttokeepthelightsoutofthewaywhileweworkasthey’reDirectionalLights,theirdistancefromtheplatformshasnoeffect.
Ourcompletedlightingrigshouldlooksomethinglikethis,(althoughyourlevel’splatformswillprobablybeverydifferent):
Ourlights,positionedawayfromourCameraandlevel,sowecanseethemmoreclearly.The“MainLights”objectishighlightedhere,showingboththechildlights.
TIP Thelightcolorschoseninthisexamplearehardlysubtle,buttheyclearlyshowhoweachlightaffectsthescenery.Feelfreetochangethecolors!
23
Color Red Green Blue OpacityLight 238 71 255 100
SpicinguptheCharacterLerpzhasacoupleofsimplevisualtouches:aworkingjetpackanddustcloudskickedupwhenhewalks.Let’slookattheseinmoredetail:
JetPackParticleEffectsIfyouwatchthecharacter'sjetpackitonlyfireswhenhejumpsandismovingupwards.Additionalscriptingisneededtoaccomplishthis.Wealsoneedtomakesomeparticleeffects.
IntheHierarchyPane,expandtheCharacter,thenexpandrootJointandlastlyexpandtorso.HereyouwillseewheretheRocketJetGameObjectsarelocated.
ThecodetostartthejetsisinsidethePlatformerControllerscriptwithintheUp-
date()function.
TIP Unity’sParticleSystemfeaturesarecoveredindepthinourResourcesarea.CheckoutForest“Yoggy”Johnson’svideoonthesubject,aswellasour3DPlatformerTutorial.
FootstepsinthedustAsLerpzwalks,wehearhisfootstepsandseehimkickingupplentyofdust.(Clearlyit’sbeensometimesincetheseplatformsweregivenagoodclean!)
IfyouexpandthemanylevelsofLerpz'slegsintheHierarchyPane,you'llnoticethateachfoothasaFootEffectGameObjectattachedtoit.ThiscontainsthreeComponentsandascript:
• RigidBodyThiscomponentisrequiredifwewantUnitytodetectcollisions.
• AudioSourceEssentiallyaplaceholderforafootstepsound.Whenourscriptdetectsthatourfoothasstruckanotherobject,itchecksifthatobjecthasaCollisionSoundEffectscript.Ifitdoes,itgrabsthatsoundeffect,dropsitintothisAudioSourcecomponentandplaysit,addingasubtle,randomvariationtothepitcheachtimeforvariety.
• SphereColliderUnity’sphysicsengineusesthistodeterminewhenthefoothastouchedsomething.Thisissetasatrigger.WhenthisCollidertouchesthecolliderinaplatformobject,thefootscriptreactsaccordinglybyscanningtheobjectwe’vestruckforCollisionSoundEffect(seeabove)andCollisionParticleEffectscripts,playingtherelevanteffectsaccordingly.
Thefootscriptdoesnothingotherthanthetasksmentionedaboveandisthereforeveryshortandsimple:
24
var baseFootAudioVolume = 1.0;
var soundEffectPitchRandomness = 0.05;
Thesetwovariablesdefinethevolumeofthefootstepsoundeffect,aswellashowmuchvariationisappliedtoitspitch.(Thisvariationisusedtopreventthefootstepsoundingtooartificial.)
ThefirstfunctionwedefineisOnTriggerEnter().Thisiscalledwheneverthe
SphereCollidertouchesanotherCollider,suchasthatattachedtoaplatformelement:
function OnTriggerEnter (other : Collider) { var collisionParticleEffect : CollisionParticleEffect = other.GetComponent(CollisionParticleEffect); if (collisionParticleEffect) {
Instantiate(collisionParticleEffect.effect, transform.position, transform.rotation); }
TheabovecodelooksforaCollisionParticleEffectscriptintheobjectwe’vecollidedwith.Ifitfindsone,itfetchestheparticlesystemPrefabwe’vestoredinthereandinstantiatesitatthefoot’sposition.Thisishowweproducethelittlecloudsofdust.
Thenextsectionofcodedoessomethingverysimilarforthefootstepsoundeffect:
var collisionSoundEffect : CollisionSoundEffect =
other.GetComponent(CollisionSoundEffect);
if (collisionSoundEffect) { audio.clip = collisionSoundEffect.audioClip; audio.volume = collisionSoundEffect.volumeModifier * baseFootAudioVolume;
audio.pitch = Random.Range(1.0 - soundEffectPitchRandomness, 1.0 + soundEffectPitchRandomness); audio.Play(); }}
Thiscodelooksforafootstepsampleintheobjectwe’vecollidedwith.Ifitfindsone,itgrabsit,copiesitintotheFootEffectGameObject’sownAudioSourcecomponent,addsabitofrandomvariationtoitspitch,thenplaysit.
TheonlyotherfunctioninthisscriptisReset(),whichsimplyensurestwokeyprop
ertiesaresettothecorrectdefaultvalues.Thisfunctioniscalledautomaticallyby
25
UnitywhenthescriptisfirstaddedtoaGameObject,anditcanalsobecalledmanuallybyclickingonthecogwheelicontotherightofthescriptcomponent’snameintheInspector.
function Reset() {
rigidbody.isKinematic = true; collider.isTrigger = true;}
@script RequireComponent(AudioSource, SphereCollider, Rigidbody)
TheverylastlineinthecodeisaUnitydirectivewhichensuresthethreecomponentslistedarepresentinourGameObject.Thissaveshavingtoremembertoaddthemmanually.
TheCameraIt’snowtimetolookatoperatingtheCamera.Weneedittofollowourplayeraroundthelevel.
SavethesceneyouhavebuiltsofarandreopentheScenenamed2DPlatformerthatcamepremadewiththistutorial.
PlaytheSceneforamomentandobservethecameramovement.
• Youshouldseethatnotonlydoesthecamerafollowthecharacter,butthecharacter's positionshiftsashewalksfurtherinasingledirection.Thissubtlemovementallowstheplayertomoreeasilyviewwhat'sahead.ThisisatechniquewhichcanbeseeningamesasoldasWilliams’classicarcadegame,“Defender”.
• Inadditiontothisbasicmovement,wealsoaddeda"Springiness"propertytoourcamera’sscript:Whenthecharacterjumps,itispreferablenottohavethecamerafollowtheentirejumpingmotionbecauseitmakesforsomejerkycameramovement.Tosolvethisproblem,weprovideasettingthatallowsthecameratolagalittlesoitdoesn'tfolloweverysinglemotion.
• Thethirdandfinalpointtonoteisthecamera’sbehaviorattheboundariesoftheworld.Noticehowthecameradoesnotmovepasttheboundaries.
Havingawellplacedcameraisalmostalwaysdifficultnomatterwhattypeofgameyouaremaking,andthereforecanoftengetcomplicated.Thecameramotionweprovideinthistutorialmaynotbeperfectineveryway,butitisagoodplacetostart.
26
ObjectProfile:MainCameraThisprovidestheplayer’sviewofourSceneandisanimportantpartofourgame.
Components• Camera
ThisisthecorecomponentforaUnitycamera.ItisacomplexcomponentwhichreliesonthefollowingComponents,(whichUnitywillnormallyaddautomatically):
‣ GUILayerThisallows2DGUIstoberendered.
‣ FlareLayerThisallowslensflareeffectstoberendered.Thesearebeyondthescopeofthistutorial.
‣ AudioListenerThisisbasicallyamicrophoneattachedtothecamera.Traditionally,themicrophoneisattachedtothecamerabecauseitallowsformorerealisticstereosoundasitrepresentstheplayer’spointofview.Withoutthiscomponent,wewouldnothearanyaudiowhileplayingourgame.
Script:CameraScrollingThisisthescriptthatmakesthecameramovehowwewant.Thereisn'tmuchtoadjusthereexceptfor:
• DistanceThisisthedistanceinthezdirectionthatthecameraisfromthetargetobject.
• SpringinessAswestatedearlier,whenthecharacterjumpsitispreferablenottohavethecamerafollowtheentirejumpingmotionbecauseitmakesforjerkymotion.Thissettingdefineshowresponsiveourcamerawillbetothetarget'smotion.
Script:CameraFocusThisscriptallowsustoeasilyswitchbetweendifferenttargetsforthecamera.Inourcase,thetargetswillbeLerpzandtheSpaceship.
NOTE ThisscriptalsotakesadvantageofthenewGUIfeaturesinUnity2.0.Inthepremadescenewehavesetupforyou,thisscriptiswhatallowsyoutotogglebetweentheLerpzandtheSpaceship.
Let’stakealookattheadjustablesettings:
• TargetsYoucansetasmanytargetsasyoulike.Ourpreassembledscenehastwo.YouneedtodragaTransformobjectfromtheHierarchyintotheslot.
27
• TargetButtonNamesThisshouldhaveasmanynamesastherearetargets.ThesearethenamesthatappearonthebuttonsoftheGUIdisplaypanel.
FurtherAnalysisWewilltakeacloserlookatthecamerascriptsinthenextsectionofthistutorial.
ContinuingourLevelNowthatwehaveanideawhatcomponentsandscriptsweneed,it’stimetogetthecameraworkinginournewScene...
Reopenyourscene,ifit’snotalreadyopen.
ExperimentwiththeSpringinessandDistancesettingsintheCameraScrollingscript.Setthemaccordingtoyourpreference.
Thereisanothercamerarelatedscriptwhichisnotappliedtothecameraitself.Weneedtoexaminethistoo.ItistheCameraTargetAttributesscript.
ThisscriptisappliedtotheCharacter,andlaterwillbeappliedtotheSpaceship.
ScriptProfile:CameraTargetAttributesProvidesafewadditionalcameramovementpropertiesthataren'tappliedontothecameraitself.
AppliedTo: Character(Lerpz)andSpaceship
KeyProperties
HeightOffsetWhenat0,thetargetwillbesittingverticallyinthecenterofthescreen.Ifitissettoapositivenumber,thatmeansthecamerawillshiftupwards,resultinginaverticallyoffcentertarget.
DistanceModifierThedistanceofthecamerafromthetargetisdefinedintheCameraScrollingscript,butthissettingaddsontothatvalue.Inthepreassembledscenetherockethasahigherdistancemodifier,sothecamerapullsbackalittlewhenyouchoosetocontrolit.
VelocityLookAheadThisdefineshowquicklythecamerashiftsto"lookahead"whenacharacterismoving.
28
MaxLookAheadThisdistanceiswherethe"lookingahead"willstopsothecharacterdoesn'tleavethescreen.Xrepresentsthehorizontaldistance,Yrepresentstheverticaldistance.
Beforeyoumoveon,playaroundwiththeLerpz'sCameraTargetAttributessettingstounderstandwhatthisscriptdoes.
OrthographicProjectionEventhoughweareworkingwith2Dmechanics,thegraphicsarestill3Dandeverythingstillhasabitofperspectivetoit.Foryoutraditionalistsoutthere,justfollowthesestepssoit'sstrictlysidevieworthographicwithnoperspective:
IntheHierarchy,selectyourMainCamera,andchecktheboxintheInspectorthatsays"Isorthographic."
IntheGameViewyoushouldseeastrictorthographicviewofyourlevelwithoutperspective.Butthere'saproblemnow,theSkyboxhasdisappearedbecauseitdoesn'tworkfororthographicviews.Noneedtoworry,afewquickadjustmentsandwe'rebackinbusiness!
AdjustasettingoftheMainCameraintheInspector.Bydefault,thesettingClearFlagsissettoSkyboxbutwewantittobesettoDepthOnly.
Nowweneedtoaddanewcameratorenderthebackdrop.
GotoGameObject>CreateOther>Camera.
ThisnewcamerawillbesettoonlyrendertheSkyboxandnothingelse.
ChangetheDepthsettingto"2",whichsetsittorenderbeforetheMainCameraandthereforewillappearinthebackground.
NowtheCullingMasksettingneedstobechangedtoNothing,otherwiseyourlevelmayberenderedmorethanonce.
YoucanalsoadjusttheFieldofViewsothatyoucanseeasmuchoraslittleoftheskyboxasyoudesire.
Nowyouhaveasidescrollerthathasamoretraditionalfeelwithoutperspective!
HandlingRigidbodiesRigidbodiesarethegatewayforapplyingphysicstoyourobjects.(IfyouareunfamiliarwiththeconceptofaRigidbody,pleaseviewthedocumentation.)
OurjobistotelltheRigidbodieshowtobehaveinthisrestrictive2Dplaneofmotion.TheplatformswillnevermovesotheRigidbodycomponentisnotnecessary,butthe
29
rocketshipandthecratesneedtomoveandphysicallyinteractwiththeirsurroundings.ThissectionexplainshowtorestrictmotionoftheseRigidbodies.
IfyouweretoexamineboththecrateandtherocketintheInspectorViewofourpreassembledscene,youwouldnoticetwomajorthingsthatarespecifictoour2Dgame:
• Theyarebothlocatedat0alongtheZaxis.ThisisimportantbecauseeveryobjectneedstobeatthesameplacealongtheZaxis.
• Theyalsohaveacomponentcalled"ConfigurableJoint."ThisisanewcomponentinUnity2.0whichofferscountlesspossibilities,butforourpurposesitisusedforrestrictingmotion.
NoticethatZMotionislocked,whichdisallowsmotionintheZaxis.AngularXMotionandAngularYMotionarealsolocked,preventinganyforbiddenrotationsconformingwithwhatwedecidedinthepreviouschapter.TheConfigureInWorldSpacecheckboxisalsoselected.Allothersettingsareleftattheirdefaultvalues.
Letstakeacloserlookatthecrate.(TheSpaceshiphasadditionalcomponentsadded,andwewilllookatthatlater.)
ObjectProfile:CrateIntheProjectPaneyoucanfindthisprefabinsideofthedirectoryLevelPrefabs.Thecrateisnotmeanttobestationary,butratherinteractwiththecharacterandtheworldaroundit.
Components• BoxCollider
WithouttheBoxCollider,theobjectwouldnotbeabletophysicallyinteractwithitsenvironment.Allofthesettingsherearethedefaultsettings.
• RigidbodyThisalsoallowsthecratetophysicallyinteractwithitsenvironment.Thesettingsherearealsothedefaultvalues,butyoucanadjustthemtomakeitmoremassive,toignoregravity,ortobeimmovable.
• ConfigurableJointThisisthecomponentthatrestrictsourmovementtoour2Dplane.Allsettingsaredefaultexceptforthefollowingfour:
‣ ZMotion:Locked
‣ AngularXMotion:Locked
30
‣ AngularYMotion:Locked
‣ ConfigureinWorldSpace:Checked
• Pipeline,MeshFilter,andMaterialTheseassignthepropermeshandtexturesoitrendersinthescene.
Script:CollisionSoundEffectThisscriptassignsasoundforwhenanobjectcollideswithit.Thecollidingobjectmustactivatethesoundthroughscripting.
Thehumblecrate.Soversatile!Soeasytomodel!Wherewouldthegamesindustrybewithoutthem?
ExerciseAddasmanycratestoyoursceneasyouwant.Youcanorientthemhoweveryouwantaslongasthey'relocatedatzeroalongthezaxis.
Afteryouhaveaddedcrates,stepitupbycreatingyourownRigidbodytobeloadedinthescene.
Trycreatingaspherethatthecharactercanrollwhenitispushed.Applythesamecomponentsandsettingstothesphere,butmakesureyouaddaSphereColliderinsteadofaBoxCollider.
Don'tforgettosaveyourscene!
31
MovingPlatformsAcommoningredientinasidescrolling2Dgameisamovingplatform.Tocreateamovingplatformwe’regoingtopositiontwowaypointsintheScenethatthemovingplatformwilloscillatebetween.
DroptheMovingPlatformPrefabintoyourscene.
DropaPlatformWayPointPrefabintoyoursceneandpositionitwhereyouwanttheMovingPlatformtostartfrom.
DuplicatethePlatformWayPointandpositionitwhereyouwanttheMovingPlatformtomoveto.
IntheMovingPlatform’sInspectorthereisascriptnamedPlatformMoverwithtwoslots,TargetAandTargetB.DropyourtwoPlatformWayPointGameObjectsfromtheHierarchyintotheirrespectiveslotsintheInspector.
ThereisalsoasettingforSpeedwhichcontrolshowfasttheMovingPlatformwillmovebetweenthetwoPlatformWayPoints.
Nowifyouhitplay,theplatformshouldbemovinghowyou'dexpect.Ifitisn'tbehavingcorrectly,adjustyourtwoPlatformWayPointsandtheSpeedvariableuntilyouachievethedesiredresult.
TIP Youcanaddasmanymovingplatformsasyou'dlike.EachmovingplatformshouldhaveitsownsetoftwoPlatformWayPointstomovebetween.
32
ObjectProfile:MovingPlatformDescription:Themovingplatformthatthecharactercanstandon.Themovingplatforminthepreassembled2DTutorialscenemovesvertically,buttheycanbemadetomovewhicheverdirectionyoudesire.
Components• BoxCollider
WithouttheBoxCollider,thecharacterandotherobjectswouldfallrightthroughit!
• RigidbodyThisalsoallowsthecratetophysicallyinteractwiththecharacterandotherobjects.Afewsettingsdeviatefromthedefault."UseGravity"settingisoff.The"IsKinematic"settingison.The"IsKinematic"settingpreventsthecharacterorotherRigidbodiesfrommovingtheplatformsomewherebesidesitspredefinedpath.
• ConfigurableJointLiketheRigidbodiesdescribedintheprevioussection,thiscomponentrestrictsourmovement.EverythingisthesameexceptnowALLrotationisforbidden:
‣ ZMotion:Locked
‣ AngularXMotion:Locked
‣ AngularYMotion:Locked
‣ AngularZMotion:Locked
‣ ConfigureinWorldSpace:Checked
33
• Pipeline,MeshFilter,andMaterialTheseassignthepropermeshandtexturesoitrendersinthescene.
Script:MovingPlatformEffectsThisscriptisusedtoactivatetheparticleeffectsonthebottomoftheplatform.TheHorizontalSpeedtoEnableEmitterspropertydefineshowfasttheplatformneedstomovehorizontallyforthejetstofire.Itautomaticallyfiresforanyverticalmovement.We’lltakeamoreindepthlookatthisscriptlater.
TheSpaceshipBynowyoushouldhavealmosteverythingsetup.Lerpz,thecharacter,shouldbemovingaroundandnavigatingovercratesandmovableplatforms.ThelastthingyouhavetosetupistheSpaceship.AddingaspaceshipinthistutorialwillshowyouhowtoaddforcestoaRigidbodyandmakeitmove.
ThereareonlytwothingsyouneedtodotogettheSpaceshipfullyfunctional:
FirstdragtheSpaceshipPrefabintotheScene.
Positionitwhereyouwantinyourlevel.
NowweneedtoadjustafewsettingsintheMainCamerasothatthecamerawillswitchbetweentheSpaceshipandLerpz.It'stimetorevisittheCameraFocusscript:
ChangethenumberofTargetsto2withElement0asCharacter(Lerpz)andElement1asSpaceship.ThiseasilyachievedbydraggingtherespectiveGameObjectsontothe“Element”slots.
YoualsoneedtochangethesizeofTargetButtonNamesto2,withElements0and1namedPlayerandSpaceshiprespectively.Youcanseethefinalsettingsinthefollowingscreenshot.
Nowyou'regoodtogo!
34
TheupdatedCameraFocusscriptsettings.
Youshouldbynowhaveacompleteandworkinglevel!Ifanythingisn'tworkingproperly,readbackandseeifyoumissedanything.Alsorememberthatyoucanalwaysopenthescene2DTutorialandusethatasareference.
Don'tforgettosave!
ObjectProfile:SpaceshipTheSpaceshipprefabcanbefoundinthedirectorLevelPrefabs.It'stheSpaceshipyouflyaroundthelevelwith.
Components• MeshCollider
Allowstheobjecttophysicallyinteractwithitssurroundings.ItisimportantthatConvexischecked.AconvexMeshColliderisabletomoveinrealtime,otherwiseitistoocomputationallyexpensivetorun.ToseethedefinitionofaConvexMesh,youcanviewthedocumentation(http://unity3d.com/Documentation/Components/classMeshCollider.html).
• RigidbodyThisalsoallowstheSpaceshiptophysicallyinteractwithitsenvironment.ThesettingsusedarethedefaultsettingswhenyouapplyaRigidbodytoanobject.
• ConfigurableJointThestandardsettingsthatweapplytootherRigidbodiesinthesceneasseenonourcrate:
‣ ZMotion:Locked
35
‣ AngularXMotion:Locked
‣ AngularYMotion:Locked
‣ ConfigureinWorldSpace:Checked
• Pipeline,MeshFilter,MeshRenderer,andMaterial:Theseassignthepropermeshandtexturesoitrendersinthescene.
Script:SpaceshipSofartheSpaceshipisnotmuchdifferentfromthecrate,butthisscriptiswhatsetsitapartfromaninanimatephysicsobject.
TheSpaceshipscriptdefineshowitmoveswiththeinputfromthekeyboard.Theadjustablesettingsonthescriptare:
• ForwardDirection
• PositionalMovement
• RotationalMovement.
ForbothPositionalandRotationalMovement,you'llseethatthereisamaxspeedand,bydefault,ifthatspeedisexceededthedragdrasticallyincreases,makingitmuchmoredifficulttoaccelerate.
ThesettingCanControlistoggledwiththecamerascriptCameraFocus,soyouneednotworryaboutthatsetting.
WellDone!Congratulations!Youarefinishedwithbuildingyour2Dlevel.Thiswasnoeasytaskthroughoutthetutorialsofaryouhavebeenintroducedtoahandfuloffundamentalconcepts...andsomemoreadvancedconcepts.Here'swhatyoushouldhaveaccomplishedsofar:
• Learnedhowtorestrictmovementtoa2Dplane;
• Builtyourlevelwithtileableplatforms;
• Setyourlevelboundaries;
• BeenintroducedtoGizmos;
• ExploredthefundamentalsofsettingupaCharacter;
• Exploredthecomplexitiesofsettingupyourcamera;
36
• Seenhowtomakeastrictorthographiccameraview;
• LearnedhowtoplaceandmakeRigidbodies;
• Usedwaypointsystemtocreatemovingplatforms;
• SetuptheSpaceship.
Takeamomentforadeepbreathandenjoyplayingyourlevel.Then,ifyou'reambitiousyoucandiveintothenextchapter.
37
DelvingDeeper:ScriptingExamples
StudyingtheScriptsTherearealotofscriptswithinthisproject,andwewillonlycoverafewofthemoreimportantones.Fortheoneswedonotcoverinthetutorialtext,youwillseethatthescriptsarethoroughlycommentedsoyoucanwalkthroughthembyyourself.Thesescriptscoverbothbasicandadvancedconcepts,sowhetheryou'renewtoUnityoraseasoneduseryouwillbenefitfromreadingthem.
MovingPlatformParticleEffectsIfyouwatchthemovingplatform,you'llnoticethattheparticleeffectonlyoccurswhenitismovingupwards.ThiseffectwasaccomplishedwiththescriptMovingPlatformEffects.
Inanutshell,thisscriptcomparesthepreviouspositionwiththecurrentpositionandifit'smovingupwardstheparticleemittersturnon.NotetheusageoftheLateUp-
date()functioninsteadofUpdate()thisistostoptheparticleemitterfromreactingoneframelate.
// We will turn on our special effects when the platform is raising, but if it is moving side// to side, how fast does it have to be moving to cause our special effects to turn on?var horizontalSpeedToEnableEmitters = 1.0;
// A true/false (boolean) variable to keep track of whether or not our special effects are
// currently turned on.private var areEmittersOn : boolean;
38
Nowwe’velearnedhowtheprojectisorganizedandhowtousethetoolsprovided,it’stimetopeerunderthehoodandseehowthesetoolswork.
// A reference to our other Moving Platform script that is handling all our movement.
// We'll need it to query the current platform velocity for our special effects.private var movingPlatform : MovingPlatform;
// We are going to use these later to calculate the current velocity.private var oldPosition : Vector3;
private var currentVelocity : Vector3;
function Start() { // Grabs the initial position of the platform. oldPosition = transform.position;
}
function Update() { // Remember if our emitters were on, then we'll see if they are currently on. wereEmittersOn = areEmittersOn;
// The emitters are on if the vertical (y) velocity is greater than 0 (positive), or if the // horizontal velocity in either direction (positive or negative speed) is greater than // our horizontalSpeedToEnableEmitters threshold. areEmittersOn = (currentVelocity.y > 0) || (Mathf.Abs(currentVelocity.x) >
horizontalSpeedToEnableEmitters); // We only have to update the particle emitters if the state of them has changed. // This saves needless computation. if (wereEmittersOn != areEmittersOn) {
// Get every child ParticleEmitter in the moving platform. for (var emitter in GetComponentsInChildren(ParticleEmitter)) { //Simply set them to emit or not emit depending on the value of areEmittersOn emitter.emit = areEmittersOn;
} }}
function LateUpdate () { currentVelocity = transform.position - oldPosition; oldPosition = transform.position;}
// This line tells Unity to nicely place this script in a submenu of the Component menu.@script AddComponentMenu("2D Platformer/Moving Platform/Moving Platform Effects")
39
TheCameraScrollingScriptNowletsexaminehowwegetthecameratofollowthecharacter.Toaccomplishthisweusescripting.Asimpleyetfunctionalcamerascriptcouldbeappliedtothemaincamera,readthecharacter'sXandYcoordinates,andusethosevaluesforitsownpositionwhilekeepingacertaindistanceawayintheZaxis.Thisworksperfectlywell,butifyoucloselyexaminepopularsidescrollinggamesyou'llnoticethatit'sneverquitethatsimple:thereareahandfulofsubtletouchestobemadeinordertogeteffectivecamerascrolling.
AllofthismovementisdefinedinCameraScrollingfoundinScripts>2D>Camera.Openthescriptandexamineit.Usethecommentswesuppliedtounderstandhowitworks.Herewewillbrieflydescribewhateachfunctiondoes:
• SetTarget()
Lookatthetopofthescriptandyou'llnoticeaprivatevariablecalledtarget.TheSetTarget()functionisusedbyotherscriptstochangetheprivatevariabletarget.Morespecifically,theCameraFocusscriptusesthisfunctionwhenyouclickonthebuttonsatthetopofthescreentochoosewhethertocontrolLerpzorhisspaceship.
Whynotallowsettingofthevariabledirectly?Simple:thiswaywecanensurethatthevariableisalwayssetbycallingourSetTarget()functions,makingiteasierto
checkthatthevaluewe’resettingittoisavalidoneforourpurposes.
NotealsothatwedefinetheSetTarget()functionmorethanonce.Eachdefinitionacceptsadifferentnumberofarguments(otherwiseUnitywillcomplain).WecanusethesemultipledefinitionsasaneasywaytodefaultthesecondargumenttoFALSEandalsotomakeourscriptseasiertofollow.(Thisprogrammingtechniqueismostcommonlyreferredtoas“Overloading”.)
• GetTarget()
Thisisasimpleaccessorfunction,(sometimescalleda"getter").Itisapubliclycallablefunctionthatreturnsaprivatevariable.Noticehowtarget,definedatthetopofthescript,ismarked"private"?Wecannotaccessitdirectlyfromanotherscript,butanotherscriptcanaccessthisfunction.
Functionslikethisenforceaconceptcalled“encapsulation”.InUnity,thismeansourscriptiscompletelyselfcontained.Otherscriptsdon’tneedtoknowhowitworksinternallyandthishelpsusreducebugs,aswellasmakingourscriptseasiertoreuseinotherprojects.
• LateUpdate()
We'reusingLateUpdate()insteadofUpdate()toensurethatthecameraisn't
40
laggingaframebehindofthemotion.ThisfunctionusesthefunctionGetGoalPo-
sition()tointerpolatebetweenthecurrentcamerapositionandthegoalposition.
• GetGoalPosition()
Thisfunctioncalculateswherethecamerashouldbewhenthenextframeisdrawn.
(Thispartofourscriptseemsfairlylongwinded,butmuchofitdealswithhowthecamerabehavesattheboundariesofthelevel,whichinvolvesperformingsimilar,butnotidentical,testsforeachedge.)
StreamlineYourWorkflowAnimportantconcepttokeepinmindforanyprojectishowtooptimizeyourworkflow.
Onewaytooptimizeyourworkflowisincludedwithinthistutorial.ByharnessingtheflexibilityofUnity,youcancreatescriptsthatautomatecertainproceduresforyou.Morespecifically,inthistutorialyou'llnoticeamenuatthetopofthescreentitled"2D"thatcontainstwoitemsthatautomatetheprocesswejustdescribed.
GiveoneofthesemenuitemsatrybydraggingacrateprefabintotheSceneView.
SelectthecrateintheSceneView,goto2D>MoveOnto2DPlane.Ifitwasn'talready,you'llnoticethatthecrate'sZpositionhaschangedtozero.
TheothermenuitemisnotnecessaryforthecratesincethatprefabalreadyhastheRigidbody(andotherrequiredcomponents)attached.
Creatingcustommenucommandscanbesurprisinglysimple!Belowweexplainthescriptusedtocreatethesemenuitems.Thescriptbelow,titledTwoDHelpercanbefoundintheProjectPanewithintheEditorfolder.
NOTE ScriptsthataddcustommenuitemsmustbelocatedintheEditorfolder.
Firstup,wehavethe2Dmenu’sMoveOnto2DPlanefunction.
Thismenuitemhastwofunctions:MoveOnto2DPlane()itself,whichperformsthe
functionwewant;andValidateMoveOnto2DPlane(),whichtellstheUnityEdi
torwhentoenablethemenuitem.(Notallmenucommandswillneedthelatterfunction.)
@MenuItem ("2D/Move Onto 2D Plane ^2")static function MoveOnto2DPlane () { for (var transform in Selection.transforms) {
transform.position.z = 0; }
41
}
@MenuItem ("2D/Move Onto 2D Plane ^2", true)static function ValidateMoveOnto2DPlane () { return (Selection.activeTransform != null);}
ThevalidationfunctionmerelychecksthatwehaveaGameObjectselected.(WeactuallycheckifthecurrentlyselectedobjecthasaTransformasallGameObjectshaveoneoftheseComponents.)
Thesecondmenuitemperformsthesamemoveto2DplaneactionbycallingMoveOnto2DPlane()first,thengoesaheadandaddstheRigidBodyandConfigur
ableJointComponentsweneedforaGameObjecttoworkinour2Dgame.ItevenensurestheConfigurableJointComponent’szMotion,angularXMotionandangularYMotionpropertiesaresetto“Locked”forus.
NOTE BothourmenucommandswillloopthroughwhateverGameObjectwe’veselectedandapplythesameinstructionsonanychildGameObjectsitcontains.
@MenuItem ("2D/Make Selection 2D Rigidbody")static function MakeSelection2DRigidbody () {
MoveOnto2DPlane(); for (var transform in Selection.transforms) { var Rigidbody : Rigidbody = transform.GetComponent(Rigidbody);
if (!Rigidbody) transform.gameObject.AddComponent(Rigidbody); var configurableJoint : ConfigurableJoint = transform.GetComponent(ConfigurableJoint);
if (!configurableJoint) configurableJoint = transform.gameObject.AddComponent(ConfigurableJoint);
//configurableJoint.configuredInWorldSpace = true; configurableJoint.xMotion = ConfigurableJointMotion.Free; configurableJoint.yMotion = ConfigurableJointMotion.Free; configurableJoint.zMotion = ConfigurableJointMotion.Locked; configurableJoint.angularXMotion = ConfigurableJointMotion.Locked;
configurableJoint.angularYMotion = ConfigurableJointMotion.Locked; configurableJoint.angularZMotion = ConfigurableJointMotion.Free;
42
} }
@MenuItem ("2D/Make Selection 2D Rigidbody", true)static function ValidateMakeSelection2DRigidbody () { return (Selection.activeTransform != null);}
SpaceshipScriptPart1:DefiningHelperClassesThenextscriptwewillbeexaminingiscalledSpaceshipandcanbefoundintheProjectPaneinScripts>2D>Spaceship.Forthesakeofsavingspacetheentirescriptwillnotbelistedinthistext,butcanbeexaminedonyourownbyusingthecommentsweprovidethroughout.
Whilethespaceshipisselectedinthehierarchy,lookintheInspectorattheSpaceshipcomponent.
NoticethePositionalMovementsettingsandRotationalMovementsettingsareidentical.TheybothhaveMaxSpeed,NegativeAcceleration,DragWhileCoasting,etc.
Sincethesesettingsareidentical,thisisaperfectopportunitytocreateahelperclass.
Ifusedcorrectly,ahelperclasscanbeusedtocreatemuchcleanerandreusablecode.Youwillseelaterwhereandhowweusethisclass,butfornowwewilljustdefineit.
(AnotheradvantagetodefiningahelperclasssuchasthisisitspropertieswillbegroupedtogetherbytheInspector,makingforamuchcleanerinterface.)
...class MovementSettings { var maxSpeed : float;
var positiveAcceleration : float; var negativeAcceleration : float; var dragWhileCoasting : float; var dragWhileBeyondMaxSpeed : float; var dragWhileAcceleratingNormally : float;
//A function that determines which drag variable to use. function ComputeDrag(input : float, velocity : Vector3) { var drag = 0.0;
//Is the input not zero (the 0.01 allows for some error since we're working with floats) //If the input is zero, use dragWhileCoasting if (Mathf.Abs(input) > 0.01) { //Are we greater or less than our max speed? and assign the appropriate
drag
43
if (velocity.magnitude > maxSpeed) drag = dragWhileBeyondMaxSpeed;
else drag = dragWhileAcceleratingNormally; } else drag = dragWhileCoasting;
return drag; }}
ThefunctionComputeDrag()definedintheMovementSettingsclassabovewillbe
usedlaterinthescript.Computingthedragisthesameforbothangularandpositionalmovement,soputtingitinthehelperclassmeanswedon'thavetowritethesamecodetwicewhendeterminingwhichdragtouse.
Nextwewilldefineonemorehelperclasstouselaterforaddingparticleeffectstothespaceship.Thisoneisabitshorterandsweeter.
//...continued from Spaceship
//Generally always need this next line for your helper classes.
@script System.Serializableclass SpecialEffects { var positiveThrustEffect : GameObject; var negativeThrustEffect : GameObject; var positiveTurnEffect : GameObject;
var negativeTurnEffect : GameObject; var collisionVolume = 0.01;}
SpaceshipScriptPart2:ControllingtheSpaceshipThenextchunkofcodeshownbelowissimplydefiningourvariablesthatwillshowupintheInspector.
We'reputtingourMovementSettingshelperclassintogooduse.WedefinebothpositionalSettingsandrotationalSettingsasaMovementSettingsclasstype.
//...continued from Spaceship //What is our forward direction? Our spaceship moves in the positive y direction.
var forwardDirection : Vector3 = Vector3(0.0, 1.0, 0.0);
//We create two instances using our MovementSettings helper class.
44
//One will be for translational (position) movement, the other for rotational.var positionalMovement : MovementSettings;
var rotationalMovement : MovementSettings;
//We create an instance using our SpecialEffects helper class.var specialEffects : SpecialEffects;
Nowwefinallygettotheheartofthescript.Abovewehavedefinedeverythingthatweneed,andnowweputthoseitemstouse.
//...continued from Spaceship
//FixedUpdate() is advantageous over Update() for working with Rigidbody physics.function FixedUpdate() { // Retrieve input. Note the use of GetAxisRaw(), which in this case helps responsiveness of the controls.
// GetAxisRaw() bypasses Unity's builtin control smoothing. thrust = Input.GetAxisRaw("Vertical"); turn = Input.GetAxisRaw("Horizontal");
//Use the MovementSettings class to determine which drag constant should be used
for the positional movement. //Remember the MovementSettings class is a helper class we defined ourselves. See the top of this script. Rigidbody.drag = positionalMovement.ComputeDrag(thrust, Rigidbody.velocity); //Then determine which drag constant should be used for the angular movement.
Rigidbody.angularDrag = rotationalMovement.ComputeDrag(turn, Rigidbody.angularVelocity);
//Determines which direction the positional and rotational motion is occurring, and then modifies thrust/turn with //the given accelerations.
//If you are not familiar with the ?: conditional, it is basically shorthand for an "if...else" statement pair. See //http://www.javascriptkit.com/jsref/conditionals.shtml thrust *= (thrust > 0.0) ? positionalMovement.positiveAcceleration : positionalMovement.negativeAcceleration;
turn *= (turn > 0.0) ? rotationalMovement.positiveAcceleration : rotationalMovement.negativeAcceleration;
// Add torque and force to the Rigidbody. Torque will rotate the body and force will move it.
// Always modify your forces by Time.deltaTime in FixedUpdate(), so if you ever need to change your Time.fixedTime // setting, your setup won't break. Rigidbody.AddRelativeTorque(Vector3(0.0, 0.0, -1.0) * turn * Time.deltaTime, ForceMode.VelocityChange);
Rigidbody.AddRelativeForce(forwardDirection * thrust * Time.deltaTime, ForceMode.VelocityChange);
45
}
// The Reset() function is called by Unity when you first add a script, and when you choose Reset on the// gear popup menu for the script.
Next,wedefinesomedefaultvaluesthatappearifyouchooseResetintheInspector.
//...continued from Spaceship
// The Reset() function is called by Unity when you first add a script, and when you choose Reset on the// gear popup menu for the script.function Reset() { // Set some nice default values for our MovementSettings.
// Of course, it is always best to tweak these for your specific game.
positionalMovement.maxSpeed = 3.0; positionalMovement.dragWhileCoasting = 3.0; positionalMovement.dragWhileBeyondMaxSpeed = 4.0;
positionalMovement.dragWhileAcceleratingNormally = 0.01; positionalMovement.positiveAcceleration = 50.0; // By default, we don't have reverse thrusters. positionalMovement.negativeAcceleration = 0.0;
rotationalMovement.maxSpeed = 2.0; rotationalMovement.dragWhileCoasting = 32.0; rotationalMovement.dragWhileBeyondMaxSpeed = 16.0; rotationalMovement.dragWhileAcceleratingNormally = 0.1; // For rotation, acceleration is usually the same in both directions.
// It could make for interesting unique gameplay if it were significantly // different, however! rotationalMovement.positiveAcceleration = 50.0; rotationalMovement.negativeAcceleration = 50.0;}
Last,wetellUnitywhichcomponentsareneededwhenthisscriptisattached.Thisisactuallyfoundattheverybottomofthescript.Itisnotrequiredtobeatthebottom,butforthesakeofconsistencyyouwillnoticethateverytimeRequireCompo-
nent()isusedinourscriptsitisatthebottom.
//...continued from Spaceship
// In order for this script to work, the object its applied to must have a Rigidbody and AudioSource component.
46
// This tells Unity to always have the components when this script is attached.@script RequireComponent(Rigidbody, AudioSource)
SpaceshipScriptPart3:SpecialEffectsWiththescriptabove,wehaveafullyfunctionalspaceshipthatiscontrolledbytheplayer.However,togiveitalittlemoremojowewanttoaddsomespecialeffects.
TheremainingsectionsoftheSpaceshipscriptdealwiththespecialeffects.
Briefly,alltheparticleeffectsaretakencareofwithintheUpdate()function.Itends upbeingpartitionednicelysinceallofthephysicsandcontrolsaretakencareofwithintheFixedUpdate()function.
ThesoundeffectsareexecutedwiththeOnCollisionEnter()function.
Readthroughthescripttounderstandhowitworks,usingthecommentsweincludedtoassistyou.
NOTE Thespaceshipcurrentlyhasonlyoneparticleeffectthatoccurswhenforwardthrustisoccurring,butthescriptallowsforparticleeffectsinalldirections.Thisisagoodexampleofreusablecodeforvariousdifferentpurposes.
Asanexercise,wesuggestaddingmoreparticleeffectsforthrustintheotherdirections.
Finished!Ifyouhavereachedtheendofthissectionyoushouldbeproud.Youdidn'treallyaddmuchtoyourlevelinthissection,butyoudidexpandyourknowledgebase.Youcanusesomeofthetoolsandconceptsyoulearnedhereandapplythemtocountlessotherprojects.Evenifyoudidn'tcompletelygraspallofthescripts,that'sokayjuststorethisprojectawayandkeepthesescriptsinmindtouseasaresourcelateron.
Now,propyourfeetonthedeskandenjoyanicetallglassofbeerlemonadeyou'veearnedit.
(Disclaimer:UnityTechnologiesandGraveckInteractivedonotcondonedrinkingonthejoboranyotherinappropriateorillegalalcoholicconsumption.)
47
What'sNext?
YourTurnInthistutorialwehavelookedintothebasicsofbuilding2Dgamesusing3Dtools.Nowit’stimetotakeoffthoselittlestabilizingwheelsfromthebicycleofwisdomandrideoffonourown!Herearesomesuggestions...
Improvethegame’sUIAtthemoment,theonlywaytoswitchbetweenLerpzandtheSpaceshipisbyclickingonabuttonwiththemouse.Thisbreaksthecontinuityofthegameworldbyrequiringtheuseofacompletelydifferentinputdevice.Therearetwopossiblesolutionstothis:
Usethekeyboardinstead.
ReplacetheGUIwithakeyboardcommandtotogglebetweenLerpzandtheSpaceship.(AddingandchangingcontrolsinUnityiscoveredintheUserGuide.)
AllowLerpztoentertheSpaceship.
HavethecontrolautomaticallyswitchtotheSpaceshipwhenLerpztouchesit.ThetrickypartistomakeitlookasifLerpzhassteppedinsideyou’llneedtohidetheCharacter(Lerpz)modelwhiletheSpaceshipisbeingcontrolled.
You’llalsoneedtoaddawaytoexittheSpaceshipperhapsbyhavingLerpzreappearwhenitlands,orbyaddinganewkeyboardcommand.
48
Hereareafewchallengeswegiveyoutomakethis2Dplatformgamemorecomplete.
AddsomeblingWhatsidescrollingplatformerwouldbecompletewithoutsomesortofcoin,ring,orothersortofbling.
Here'sastartingpointifyouneedit:
Createanobject(acylinderperhaps)thathasRigidbodyandCollidercomponents.
Don'tforgettoapplytheusual2Drestrictions.
Onemethodofcompletingthistaskwouldbetohavetheblingbeatrigger.Whenthecharacterhitsthetrigger,amessageissentfromthecharactertotheobjectthatinturntriggersforces/torquetomakeitspinandflyoffthescreen.
Ifyou'rereallyambitiousyoucouldhaveittriggersoundandparticleeffects.
AddmorepizzazztothespaceshipCurrently,thespaceshiphasoneparticleeffectfortheforwardthrust.Tryaddingparticleeffectsforturningthespaceship.Thiswillbegoodpracticeworkingwithparticleeffects.Don'tjustreusethesameflameeffectexperimentandchangeitupalittle!Additionally,youcouldhavethespaceshipthrustbackwards.Thisentiretaskrequiresnoadditionalscripting!
HavetheDeathZonerespawntheSpaceshipLookthroughthescriptstoexplorehowthecharacterisrespawnedandapplythesamemethodtotheSpaceshipthroughscripting.
TurnitintoagameLerpzdoesn’treallyhaveagoalatthemoment.Thistutorialwasdesignedtoeducateandhasn’tdippedintogamedesignissues.Considerthetutorialasastartingpointandtrymakingacompletegamewithit!Addsomeenemiestofight,puzzlestotosolveandalltheothertrappingsofaplatformer.
49