noobtuts - unity 2d snake tutorial
DESCRIPTION
Tutorial SnakeTRANSCRIPT
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 1/21
Tutorials Articles Premium About
Unity2DSnakeTutorial
Foreword
ThisTutorialwillexplainhowtomakeasimple2DSnakeGameinUnity.Snakeisanarcadegamethatwascreatedbackinthe1970s.Andlikemostarcadegamesitsstillawholelotoffunandeasytodevelop,whichmakesitagreatgameforaTutorial.
Requirements
KnowledgeOurTutorialdoesnotrequireanyspecialskillsexceptsomeknowledgeabouttheUnitybasicslikeGameObjectsandTransforms.Evenifyoudontknowthoseconceptsyet,theTutorialshouldstillbedoable.
FeelfreetoreadoureasierUnityTutorialslikeUnity2DPongGametogetusedtothisamazinggameengine.
UnityVersionOurSnakeTutorialwilluseUnity5.0.0f4.Newerversionsshouldwork
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 2/21
neaswell,olderversionsmayormaynotwork.ThefreeversionofUnity5nowcomeswithalltheenginefeatures,whichmakesittherecommendedversion.
ProjectSetup
Letsgettoit.WewillstartUnityandselectNewProject:
Wewillnameitsnake,selectanylocationlikeC:\,select2DandclickCreateProject:
IfweselecttheMainCameraintheHierarchythenwecansettheBackgroundColortoblack,adjusttheSizeandthePositionlikeshown
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 3/21
inthefollowingimage:
Note:Sizeispreymuchthezoomfactor.
AddingBorders
Wewilluseonehorizontalandoneverticalwhitelineimageforourborders:
border_horizontal.pngborder_vertical.pngNote:rightclickeachlink,selectSaveAs...andsavetheimagesintheprojectsAssetsfolder.
OncewehavetheminourProjectsAssetsfolder,wecanselecttheminUnitysProjectArea:
AfterwardswecanchangetheirImportSeingsintheInspectortomakethemappearintherightsizewiththerightlooks:
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 4/21
Note:PixelsPerUnitistheratiobetweenonepixelintheimageandoneunitintheworld.TheSnakewillhaveasizeof1x1pixel,whichshouldbe1unitinthegameworld.ThisiswhywewilluseaPixelsPerUnitvalueof1forallourtextures.
Nowwecandrageachborderimageintothescenetwiceandpositionthemsotheyformonerectangularborder:
Note:thehorizontalborderimageisusedforthetopandboomborders.Theverticalborderimageisusedfortheleftandrightborders.
LetsrenametheborderstoBorderTop,BorderBoom,BorderLeftandBorderRight.WewillselectoneafteranotherintheHierarchyandtheneitherpressF2orrightclickitandselectRename.Hereistheresult:
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 5/21
Rightnowthebordersarejustimagesinthegame.Theymaylooklikeborders,buttheyarenotpartofthephysicalworldjustyet.IfwewanttheSnaketocollidewiththeborders,thenwehavetoaddColliderstothem.WecandosobyrstselectingallthebordersintheHierarchy:
Rightnowthebordersarejustimages,theyarentreallyborders.Thesnakecouldwalkrightthroughthembecausetheyarenotpartofthephysicsworldyet.LetstakealookattheInspectorandselectAddComponent>Physics2D>BoxCollider2D.Andsincewehaveallbordersselectedrightnow,thiswilladdaBoxCollider2Dtoeachofthem:
Andthatsallthereistoit.Wejustcreatedthebordersforourgame
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 6/21
withoutwritingasinglelineofcode,thankstothispowerfulgameengine.
CreatingtheFoodPrefab
Wedontwantoursnaketogethungry,soletsrandomlyspawnsomefoodinthegame.Asusualwewillstartwithafoodimage,inourcaseacoloredpixel:
food.pngNote:rightclickonthelink,selectSaveAs...andsaveitintheprojectsAssetsfolder.
WewillusethefollowingImportSeingsforthefoodimage:
Alright,letsdragthefoodimageintotheScenetocreateaGameObject:
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 7/21
TheSnakeshouldreceivesomekindofinformationwheneveritcollideswithfood.Thismeansthatthefoodhastobepartofthephysicsworld,whichcanbedonewithaCollider.
AGameObjectwithoutaColliderisjustavisualthing,itsnotpartofthephysicsworld.AGameObjectwithaColliderispartofthephysicsworld,justlikeawall.Itwillcauseotherthingstocollidewithit,anditwilltriggertheOnCollisionEnter2Devent.AGameObjectwithaColliderthathasIsTriggercheckedwillnotcauseotherthingstocollidewithit,butitwillstilltriggertheOnTriggerEnter2Devent.
TheSnakeshouldgetnotiedwhenitwalksthroughfood,butitsnotsupposedtocollidewithitlikeifthefoodwasawall.SoletsselectthefoodintheHierarchyandthenchooseAddComponent>Physics2D>BoxCollider2DintheInspectorandenableIsTrigger:
Okay,nowwedontwantthefoodtobeintheScenefromthebeginning.InsteadwewantaPrefabsothatwecanInstantiateitwheneverweneedit.InordertocreateaPrefab,allwehavetodoisrenamethefoodtoFoodPrefabandthendragitfromtheSceneintotheProjectArea:
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 8/21
NowwecandeletetheFoodPrefabGameObjectfromtheHierarchy,becausewedontwantittobeinthegameworldjustyet.
SpawningFood
Letsspawnnewfoodatsomerandompositioneveryfewseconds.ThiskindofbehaviorcanbeimplementedwithaScript,soletscreateaSpawnFoodScript.TheScriptshouldbeintheSceneallthetime,sowewillkeepitsimpleandaddittotheMainCamera(becauseitwillbeintheSceneallthetime,too).LetsselecttheMainCameraintheHierarchyandthenclickonAddComponent>NewScript,nameitSpawnFoodandselectCSharpforthelanguage:
AfterwardswewilldoubleclickitintheProjectAreatoopenit:
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 9/21
usingUnityEngine;usingSystem.Collections;
publicclassSpawnFood:MonoBehaviour{
//UsethisforinitializationvoidStart(){}//UpdateiscalledonceperframevoidUpdate(){}}
WewontneedtheUpdatefunction,soletsremoveit:usingUnityEngine;usingSystem.Collections;
publicclassSpawnFood:MonoBehaviour{
//UsethisforinitializationvoidStart(){}}
OurScriptneedstoknowwherethefoodPrefabis.WewilladdapublicvariableoftypeGameObject:usingUnityEngine;usingSystem.Collections;
publicclassSpawnFood:MonoBehaviour{//FoodPrefabpublicGameObjectfoodPrefab;//UsethisforinitializationvoidStart(){}}
Thefoodshouldbespawnedwithintheborders,notoutside.SowewillalsoneedavariableforeachoftheborderssothatourScriptknowstheirpositions:usingUnityEngine;usingSystem.Collections;
publicclassSpawnFood:MonoBehaviour{//FoodPrefabpublicGameObjectfoodPrefab;
//BorderspublicTransformborderTop;publicTransformborderBottom;publicTransformborderLeft;publicTransformborderRight;
//UsethisforinitializationvoidStart(){
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 10/21
}}
Note:theyarealreadyoftypeTransformsowedonthavetowriteborderTop.transform.positionallthetime.InsteadwewillbeabletoaccesstheirpositionslikeborderTop.position.
LetscreatetheSpawnfunctionthatspawnsonepieceoffoodwithintheborders.Atrstwewillchoosethexpositionsomewhererandomlybetweentheleftandrightborder.Thenwewillchoosetheypositionrandomlybetweenthetopandboomborder.AfterwardswewillinstantiatethefoodPrefabatthatposition://SpawnonepieceoffoodvoidSpawn(){//xpositionbetweenleft&rightborderintx=(int)Random.Range(borderLeft.position.x,borderRight.position.x);
//ypositionbetweentop&bottomborderinty=(int)Random.Range(borderBottom.position.y,borderTop.position.y);
//Instantiatethefoodat(x,y)Instantiate(foodPrefab,newVector2(x,y),Quaternion.identity);//defaultrotation}
Note:xandyareroundedvia(int)tomakesurethatthefoodisalwaysspawnedatapositionlike(1,2)butneveratsomethinglike(1.234,2.74565).
NowletsmakesurethatourScriptcallstheSpawnfunctioneveryfewseconds.WecandosobyusingInvokeRepeating://UsethisforinitializationvoidStart(){//Spawnfoodevery4seconds,startingin3InvokeRepeating("Spawn",3,4);}
Hereisourfullscript:usingUnityEngine;usingSystem.Collections;
publicclassSpawnFood:MonoBehaviour{//FoodPrefabpublicGameObjectfoodPrefab;
//BorderspublicTransformborderTop;publicTransformborderBottom;publicTransformborderLeft;publicTransformborderRight;
//UsethisforinitializationvoidStart(){//Spawnfoodevery4seconds,startingin3InvokeRepeating("Spawn",3,4);
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 11/21
}
//SpawnonepieceoffoodvoidSpawn(){//xpositionbetweenleft&rightborderintx=(int)Random.Range(borderLeft.position.x,borderRight.position.x);
//ypositionbetweentop&bottomborderinty=(int)Random.Range(borderBottom.position.y,borderTop.position.y);
//Instantiatethefoodat(x,y)Instantiate(foodPrefab,newVector2(x,y),Quaternion.identity);//defaultrotation}}
IfwesavetheScriptandselecttheMainCamerathenwecanseethatallourpublicvariablesarenowshownintheInspector.TheyarestillNone,soletsdragtheFoodPrefabfromtheProjectAreaintotheFoodPrefabvariableandtheBordersfromtheHierarchyintotheircorrespondingslots:
Note:wecandragsomethingintoaScriptsvariablebyliterallydraggingitwiththemousefromtheHierarchyorProjectAreaintothoseslotthingsthatcanbeseenintheabovepicture.
Alright,nowitstimetopressPlayandwaitafewseconds.Weshouldbeabletoseesomenewfoodspawninbetweentheborders:
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 12/21
CreatingtheSnake
Letsnishthemainpartoftheourgame:theSnake.Asusualwewillstartbydrawingthesnakeimage,whichisjusta1x1pixeltexture:
snake.pngNote:rightclickonthelink,selectSaveAs...andsaveitintheprojectsAssetsfolder.
WewillusethefollowingImportSeingsforit:
NowwecandragthesnakeimageintothemiddleoftheScene:
SofaritsjusttheSnakeshead,soletsrenameittoHeadtokeepthingsclean:
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 13/21
Thesnakeshouldbepartofthephysicsworld,whichmeansthatweneedtoaddaCollidertoitagain,soletsselectAddComponent>Physics2D>BoxCollider2D:
Note:theColliderhasthesize(0.7,0.7)insteadof(1,1)sothatitdoesntcollidewithotherpartsofthesnakethatarerightnexttoit.WesimplywanttogiveUnitysomespace.
Nowthesnakeisalsosupposedtomovearound.Asaruleofthumb,everythinginthephysicsworldthatissupposedtomove,needsaRigidbody.ARigidbodytakescareofthingslikegravity,velocityandmovementforces.WecanaddonebyselectingAddComponent>Physics2D>Rigidbody2D.Wewillusethefollowingseingsforit:
Notes:TheRigidbodysGravityScaleis0becausewedontwantthesnaketofalltowardstheboomofthescreenallthetime.TheIsKinematicoptiondisablesthephysicalbehavioroftheRigidbody,soitdoesntreacttogravityorcollisions.Weonlyneedtoknowifthesnakecollidedwithsomething.WedontneedUnitysphysicstopushthingsaroundincaseofcollisions.Moreinfo:Rigidbody2DUnityDocs.
Thenalsnakewillconsistofmanylileelements.TherewillalwaysbetheHeadatthefrontandthentherewillbeseveralTailelementslikehere:
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 14/21
ooooox
TheonlydierencebetweentheTailelementsandtheHeadisthattheheaddoesallthethinking.WewilladdaScripttoitlater.
LetsdragthesnakeHeadfromtheHierarchyintotheProjectAreatocreateaPrefabandthennameitTailPrefabsowecanloaditwheneverthesnakegrows:
Note:someUnityversionswillautomaticallyrenameGameObjectintheHierarchytoo,somakesurethattheoneintheHierarchyisstillnamedHead.
Alright,letsselectthesnakeHeadintheHierarchyagainandclickonAddComponent>NewScript,nameitSnakeandselectCSharpasthelanguage:
WecanopentheScriptbydoubleclickingitintheProjectArea:usingUnityEngine;usingSystem.Collections;
publicclassSnake:MonoBehaviour{
//UsethisforinitializationvoidStart(){}//UpdateiscalledonceperframevoidUpdate(){}}
LetsmodifythetopoftheScripttoincludesomeListfunctionalitythatwewillneedlateron:usingUnityEngine;usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.Linq;
publicclassSnake:MonoBehaviour{
//UsethisforinitializationvoidStart(){
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 15/21
}//UpdateiscalledonceperframevoidUpdate(){}}
TheSnakeshouldalwaysmoveexactlyoneunitintowhateverdirectionitwantstomove.NowifwewouldallowittomoveineveryUpdatecall,thenitwouldbereallyfast.Insteadwewillonlyallowmovementevery300millisecondsbyusingUnitysInvokeRepeatingfunction.ItslikewecreateourownUpdatemethodthatonlygetscalledevery300msinsteadofeveryframe:usingUnityEngine;usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.Linq;
publicclassSnake:MonoBehaviour{
//UsethisforinitializationvoidStart(){//MovetheSnakeevery300msInvokeRepeating("Move",0.3f,0.3f);}//UpdateiscalledonceperframevoidUpdate(){}voidMove(){//DoMovementStuff..}}
TheSnakeshouldalwaysbemovingintosomedirection,itshouldneverstandstill.SoletsdeneadirectionvariableanduseittomovethesnakeintheMovefunction:usingUnityEngine;usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.Linq;
publicclassSnake:MonoBehaviour{//CurrentMovementDirection//(bydefaultitmovestotheright)Vector2dir=Vector2.right;
//UsethisforinitializationvoidStart(){//MovetheSnakeevery300msInvokeRepeating("Move",0.3f,0.3f);}//UpdateiscalledonceperframevoidUpdate(){}
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 16/21
voidMove(){//Moveheadintonewdirectiontransform.Translate(dir);}}
Note:transform.Translatemeansaddthisvectortomyposition.
ThedirectionvariableisoftypeVector2,whichmeansthatithasanxandyvalue.ThefollowingimageshowsdierentdirectionsforaVector2:
IfwepressplaythenwecanalreadyseetheSnakemovetotheright:
Theusershouldbeabletochangethemovementdirectionbypressingoneofthearrowkeys.NowwecouldjustcheckforkeypressesinourMovefunction,butthatwouldmakethegamefeellaggybecausethenwewouldonlydetectkeypressesevery300ms.InsteadwewillusetheUpdatefunctiontodetectkeypressesallthetime://UpdateiscalledonceperFramevoidUpdate(){//MoveinanewDirection?if(Input.GetKey(KeyCode.RightArrow))
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 17/21
dir=Vector2.right;elseif(Input.GetKey(KeyCode.DownArrow))dir=Vector2.up;//'up'means'down'elseif(Input.GetKey(KeyCode.LeftArrow))dir=Vector2.right;//'right'means'left'elseif(Input.GetKey(KeyCode.UpArrow))dir=Vector2.up;}
Note:ifyouarenotsurewhyweusedUpdateandMoveinsteadofjustUpdateorjustMove,feelfreetoputthecodefromMoveintoUpdateorthecodefromUpdateintoMove,thenyouwillseethatthesnakemovesrapidlyfastorthatthekeypressesaredetectedonlyrarely.
IfwepressplaythenwecannowmovetheSnakewiththearrowkeys:
TheSnakesTail
LetsthinkabouthowtheSnakestailwillwork.Firstofall,letsassumewehaveasnakewithoneheadandthreetailelements:ooox
Nowassoonastheheadmovestotheright,theobviousthingwouldbetomoveeverytailelementtowhereitsprevioustailelementwas,likethis:step1:ooox//snakedidn'tmoveyetstep2:ooox//headmovedtotherightstep3:ooox//firsttailfollowsstep4:ooox//secondtailfollowsstep5:ooox//thirdtailfollows
Thiswouldwork,butitwouldalsobesomecomplicatedcode.Letsuseaneatliletricktomakeourliveseasier.Insteadofmovingonetailelementafteranother,wewillsimplymovethelasttailelementintothegaplikehere:step1:ooox//snakedidn'tmoveyetstep2:ooox//headmovedtotherightstep3:ooox//lasttailelementmovedintothegap
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 18/21
Nowthatsoundslikeaneasyalgorithm.Ineverymovementcall,allwehavetodoismovethelasttailelementtowheretheheadwasbefore.
Atrstwewillneedsomekindofdatastructuretokeeptrackofallthetailelementsthatwewilladdlateron://KeepTrackofTailListtail=newList();
Note:itsreallyimportanttoaddusingSystem.Collections.Generic;andusingSystem.Linq;tothetopinorderforliststowork.
Letsgettothecodethattakesthelasttailelement,removesitfromthebackandputsitintothegapmentionedabove:voidMove(){//Savecurrentposition(gapwillbehere)Vector2v=transform.position;
//Moveheadintonewdirection(nowthereisagap)transform.Translate(dir);
//DowehaveaTail?if(tail.Count>0){//MovelastTailElementtowheretheHeadwastail.Last().position=v;
//Addtofrontoflist,removefromthebacktail.Insert(0,tail.Last());tail.RemoveAt(tail.Count1);}}
Note:Translatesimplymeansaddthisvectortomyposition.Afterwardswecheckifthereisanythinginthetaillist,inwhichcasewechangethelasttailelementspositiontothegapposition(wheretheheadwasbefore).Wealsohavetokeepourlistorder,hencetheInsertandRemoveAtcallsattheend.Theymakesurethatthelasttailelementisnowtherstelementinthelist,too.
AndthatwastheonlyslightlycomplicatedpartofourUnity2DSnakeTutorial.Nowwearealmostdone.
FeedingtheSnake
WewillusetheOnTriggerEnter2Dfunctiontoreceivecollisioninformation(whichwillhappenwheneverthesnakewalksintofoodorintoaborder).
Wheneveritrunsintofood,wewillusetheexactsamemechanicsthatweusedforourmovementabove,exceptthatthistimeinsteadofremovingthelasttailelementandmovingitintothegap,wewillonlyInstantiateanewelementintothegap:ooox//gapoooox//gapfilledwithnewelement
ItsimportanttounderstandthatwewillnotmaketheSnakelonger
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 19/21
immediatelyafteriteatssomething.Justlikewithourarrowkeypresses,wewillwaituntilitactuallymoves.ThereforewewillneedanewvariablethatwewillsettotruewhenevertheSnakeatesomething://Didthesnakeeatsomething?boolate=false;
WewillalsoneedapublicvariablethatletsusassigntheTailPrefablateron://Didthesnakeeatsomething?boolate=false;
//TailPrefabpublicGameObjecttailPrefab;
Note:thetwovariablesaredenedatthetopofourSnakescript.
NowletsgettotheOnTriggerEnter2Dfunction.Thisonewillbestraightforwardagain.WewillndoutiftheSnakecollidedwithfood,inwhichcasewesettheatevariabletotrueanddestroythefood.Ifitdidntcollidewithfood,theniteithercollidedwithitselforwithaborder:voidOnTriggerEnter2D(Collider2Dcoll){//Food?if(coll.name.StartsWith("FoodPrefab")){//GetlongerinnextMovecallate=true;//RemovetheFoodDestroy(coll.gameObject);}//CollidedwithTailorBorderelse{//ToDo'Youlose'screen}}
Note:weusecoll.name.StartsWithbecausethefoodiscalledFoodPrefab(Clone)afterinstantiatingit.ThemoreelegantwaytondoutifcollisfoodornotwouldbebyusingaTag,butforthesakeofsimplicitywewillusestringcomparisoninthisTutorial.
Alright,letsmodifyourMovefunctionsoitmakestheSnakelongerwheneverateistrue:voidMove(){//Savecurrentposition(gapwillbehere)Vector2v=transform.position;
//Moveheadintonewdirection(nowthereisagap)transform.Translate(dir);
//Atesomething?TheninsertnewElementintogapif(ate){//LoadPrefabintotheworldGameObjectg=(GameObject)Instantiate(tailPrefab,v,Quaternion.identity);
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 20/21
//Keeptrackofitinourtaillisttail.Insert(0,g.transform);
//Resettheflagate=false;}//DowehaveaTail?elseif(tail.Count>0){//MovelastTailElementtowheretheHeadwastail.Last().position=v;
//Addtofrontoflist,removefromthebacktail.Insert(0,tail.Last());tail.RemoveAt(tail.Count1);}}
Note:allwedidwascheckifateistrue,thenInstantiatethetailprefabatthepositionvwiththedefaultrotation(Quaternion.identity).Afterwardsweaddittothetaillistandresettheateag.Therestofthecodewasalreadythere.
NowwecanselectthesnakeHeadintheHierarchy,takealookattheInspectoranddragtheTailPrefabfromtheProjectAreaintotheScript:
IfwepressPlaythenwecannowplayaniceroundofSnake:
Summary
SnakeisoneawesomegameforaUnityTutorial.ThereisalotofvalueinunderstandinghowtodopixelexactgameslikethisandhowtoaddmovementwithInvokeRepeating.Yetagainwesawhowamazinglyeasy2DgamesarewithUnitys2Dfeaturesthatwereintroducednotverylongago.
-
12/06/2015 noobtutsUnity2DSnakeTutorial
http://noobtuts.com/unity/2dsnakegame 21/21
Nowitsuptothereadertomakethegamefun!Therearetonsofimprovementstobemadelikeawin/losescreen,abeerlookingsnaketexture,multiplelevels,powerups,increasingspeed,highscores,multiplayerandsoon.
DownloadSourceCode&ProjectFiles
TheUnity2DSnakeTutorialsourcecode&projectlescanbedownloadedbyPremiummembers.
AllTutorials.AllSourceCodes&ProjectFiles.OnetimePayment.GetPremiumtoday!
20122015noobtuts.com