You are on page 1of 21

12/06/2015

noobtutsUnity2DSnakeTutorial

Tutorials

Articles

Premium

About

Unity2DSnakeTutorial

Foreword
ThisTutorialwillexplainhowtomakeasimple2DSnakeGamein
Unity.Snakeisanarcadegamethatwascreatedbackinthe1970s.And
likemostarcadegamesitsstillawholelotoffunandeasytodevelop,
whichmakesitagreatgameforaTutorial.

Requirements
Knowledge
OurTutorialdoesnotrequireanyspecialskillsexceptsomeknowledge
abouttheUnitybasicslikeGameObjectsandTransforms.Evenifyou
dontknowthoseconceptsyet,theTutorialshouldstillbedoable.
FeelfreetoreadoureasierUnityTutorialslikeUnity2DPongGameto
getusedtothisamazinggameengine.
UnityVersion
OurSnakeTutorialwilluseUnity5.0.0f4.Newerversionsshouldwork
http://noobtuts.com/unity/2dsnakegame

1/21

12/06/2015

noobtutsUnity2DSnakeTutorial

neaswell,olderversionsmayormaynotwork.Thefreeversionof
Unity5nowcomeswithalltheenginefeatures,whichmakesitthe
recommendedversion.

ProjectSetup
Letsgettoit.WewillstartUnityandselectNewProject:

Wewillnameitsnake,selectanylocationlikeC:\,select2Dandclick
CreateProject:

IfweselecttheMainCameraintheHierarchythenwecansetthe
BackgroundColortoblack,adjusttheSizeandthePositionlikeshown
http://noobtuts.com/unity/2dsnakegame

2/21

12/06/2015

noobtutsUnity2DSnakeTutorial

inthefollowingimage:

Note:Sizeispre ymuchthezoomfactor.

AddingBorders
Wewilluseonehorizontalandoneverticalwhitelineimageforour
borders:
border_horizontal.png
border_vertical.png
Note:rightclickeachlink,selectSaveAs...andsavetheimagesinthe
projectsAssetsfolder.
OncewehavetheminourProjectsAssetsfolder,wecanselectthemin
UnitysProjectArea:

AfterwardswecanchangetheirImportSe ingsintheInspectorto
makethemappearintherightsizewiththerightlooks:

http://noobtuts.com/unity/2dsnakegame

3/21

12/06/2015

noobtutsUnity2DSnakeTutorial

Note:PixelsPerUnitistheratiobetweenonepixelintheimageandoneunit
intheworld.TheSnakewillhaveasizeof1x1pixel,whichshouldbe1unitin
thegameworld.ThisiswhywewilluseaPixelsPerUnitvalueof1forallour
textures.
Nowwecandrageachborderimageintothescenetwiceandposition
themsotheyformonerectangularborder:

Note:thehorizontalborderimageisusedforthetopandbo omborders.The
verticalborderimageisusedfortheleftandrightborders.
LetsrenametheborderstoBorderTop,BorderBo om,BorderLeftand
BorderRight.WewillselectoneafteranotherintheHierarchyandthen
eitherpressF2orrightclickitandselectRename.Hereistheresult:

http://noobtuts.com/unity/2dsnakegame

4/21

12/06/2015

noobtutsUnity2DSnakeTutorial

Rightnowthebordersarejustimagesinthegame.Theymaylooklike
borders,buttheyarenotpartofthephysicalworldjustyet.Ifwewant
theSnaketocollidewiththeborders,thenwehavetoaddCollidersto
them.WecandosobyrstselectingallthebordersintheHierarchy:

Rightnowthebordersarejustimages,theyarentreallyborders.The
snakecouldwalkrightthroughthembecausetheyarenotpartofthe
physicsworldyet.LetstakealookattheInspectorandselectAdd
Component>Physics2D>BoxCollider2D.Andsincewehaveall
bordersselectedrightnow,thiswilladdaBoxCollider2Dtoeachof
them:

Andthatsallthereistoit.Wejustcreatedthebordersforourgame
http://noobtuts.com/unity/2dsnakegame

5/21

12/06/2015

noobtutsUnity2DSnakeTutorial

withoutwritingasinglelineofcode,thankstothispowerfulgame
engine.

CreatingtheFoodPrefab
Wedontwantoursnaketogethungry,soletsrandomlyspawnsome
foodinthegame.Asusualwewillstartwithafoodimage,inourcasea
coloredpixel:
food.png
Note:rightclickonthelink,selectSaveAs...andsaveitintheprojects
Assetsfolder.
WewillusethefollowingImportSe ingsforthefoodimage:

Alright,letsdragthefoodimageintotheScenetocreateaGameObject:

http://noobtuts.com/unity/2dsnakegame

6/21

12/06/2015

noobtutsUnity2DSnakeTutorial

TheSnakeshouldreceivesomekindofinformationwheneveritcollides
withfood.Thismeansthatthefoodhastobepartofthephysicsworld,
whichcanbedonewithaCollider.
AGameObjectwithoutaColliderisjustavisualthing,itsnotpartofthe
physicsworld.AGameObjectwithaColliderispartofthephysics
world,justlikeawall.Itwillcauseotherthingstocollidewithit,andit
willtriggertheOnCollisionEnter2Devent.AGameObjectwitha
ColliderthathasIsTriggercheckedwillnotcauseotherthingsto
collidewithit,butitwillstilltriggertheOnTriggerEnter2Devent.
TheSnakeshouldgetnotiedwhenitwalksthroughfood,butitsnot
supposedtocollidewithitlikeifthefoodwasawall.Soletsselectthe
foodintheHierarchyandthenchooseAddComponent>Physics2D
>BoxCollider2DintheInspectorandenableIsTrigger:

Okay,nowwedontwantthefoodtobeintheScenefromthe
beginning.InsteadwewantaPrefabsothatwecanInstantiateit
wheneverweneedit.InordertocreateaPrefab,allwehavetodois
renamethefoodtoFoodPrefabandthendragitfromtheSceneintothe
ProjectArea:

http://noobtuts.com/unity/2dsnakegame

7/21

12/06/2015

noobtutsUnity2DSnakeTutorial

NowwecandeletetheFoodPrefabGameObjectfromtheHierarchy,
becausewedontwantittobeinthegameworldjustyet.

SpawningFood
Letsspawnnewfoodatsomerandompositioneveryfewseconds.This
kindofbehaviorcanbeimplementedwithaScript,soletscreatea
SpawnFoodScript.TheScriptshouldbeintheSceneallthetime,sowe
willkeepitsimpleandaddittotheMainCamera(becauseitwillbeinthe
Sceneallthetime,too).LetsselecttheMainCameraintheHierarchyand
thenclickonAddComponent>NewScript,nameitSpawnFoodand
selectCSharpforthelanguage:

AfterwardswewilldoubleclickitintheProjectAreatoopenit:
http://noobtuts.com/unity/2dsnakegame

8/21

12/06/2015

noobtutsUnity2DSnakeTutorial

usingUnityEngine;
usingSystem.Collections;
publicclassSpawnFood:MonoBehaviour{
//Usethisforinitialization
voidStart(){

//Updateiscalledonceperframe
voidUpdate(){

}
}

WewontneedtheUpdatefunction,soletsremoveit:
usingUnityEngine;
usingSystem.Collections;
publicclassSpawnFood:MonoBehaviour{
//Usethisforinitialization
voidStart(){

}
}

OurScriptneedstoknowwherethefoodPrefabis.Wewilladdapublic
variableoftypeGameObject:
usingUnityEngine;
usingSystem.Collections;
publicclassSpawnFood:MonoBehaviour{
//FoodPrefab
publicGameObjectfoodPrefab;

//Usethisforinitialization
voidStart(){

}
}

Thefoodshouldbespawnedwithintheborders,notoutside.Sowewill
alsoneedavariableforeachoftheborderssothatourScriptknows
theirpositions:
usingUnityEngine;
usingSystem.Collections;
publicclassSpawnFood:MonoBehaviour{
//FoodPrefab
publicGameObjectfoodPrefab;
//Borders
publicTransformborderTop;
publicTransformborderBottom;
publicTransformborderLeft;
publicTransformborderRight;
//Usethisforinitialization
voidStart(){
http://noobtuts.com/unity/2dsnakegame

9/21

12/06/2015

noobtutsUnity2DSnakeTutorial

}
}

Note:theyarealreadyoftypeTransformsowedonthavetowrite
borderTop.transform.positionallthetime.Insteadwewillbeabletoaccess
theirpositionslikeborderTop.position.
LetscreatetheSpawnfunctionthatspawnsonepieceoffoodwithinthe
borders.Atrstwewillchoosethexpositionsomewhererandomly
betweentheleftandrightborder.Thenwewillchoosetheyposition
randomlybetweenthetopandbo omborder.Afterwardswewill
instantiatethefoodPrefabatthatposition:
//Spawnonepieceoffood
voidSpawn(){
//xpositionbetweenleft&rightborder
intx=(int)Random.Range(borderLeft.position.x,
borderRight.position.x);
//ypositionbetweentop&bottomborder
inty=(int)Random.Range(borderBottom.position.y,
borderTop.position.y);
//Instantiatethefoodat(x,y)
Instantiate(foodPrefab,
newVector2(x,y),
Quaternion.identity);//defaultrotation
}

Note:xandyareroundedvia(int)tomakesurethatthefoodisalways
spawnedatapositionlike(1,2)butneveratsomethinglike(1.234,2.74565).
NowletsmakesurethatourScriptcallstheSpawnfunctioneveryfew
seconds.WecandosobyusingInvokeRepeating:
//Usethisforinitialization
voidStart(){
//Spawnfoodevery4seconds,startingin3
InvokeRepeating("Spawn",3,4);
}

Hereisourfullscript:
usingUnityEngine;
usingSystem.Collections;
publicclassSpawnFood:MonoBehaviour{
//FoodPrefab
publicGameObjectfoodPrefab;
//Borders
publicTransformborderTop;
publicTransformborderBottom;
publicTransformborderLeft;
publicTransformborderRight;
//Usethisforinitialization
voidStart(){
//Spawnfoodevery4seconds,startingin3
InvokeRepeating("Spawn",3,4);
http://noobtuts.com/unity/2dsnakegame

10/21

12/06/2015

noobtutsUnity2DSnakeTutorial

}
//Spawnonepieceoffood
voidSpawn(){
//xpositionbetweenleft&rightborder
intx=(int)Random.Range(borderLeft.position.x,
borderRight.position.x);
//ypositionbetweentop&bottomborder
inty=(int)Random.Range(borderBottom.position.y,
borderTop.position.y);
//Instantiatethefoodat(x,y)
Instantiate(foodPrefab,
newVector2(x,y),
Quaternion.identity);//defaultrotation
}
}

IfwesavetheScriptandselecttheMainCamerathenwecanseethatall
ourpublicvariablesarenowshownintheInspector.Theyarestill
None,soletsdragtheFoodPrefabfromtheProjectAreaintotheFood
PrefabvariableandtheBordersfromtheHierarchyintotheir
correspondingslots:

Note:wecandragsomethingintoaScriptsvariablebyliterallydraggingit
withthemousefromtheHierarchyorProjectAreaintothoseslotthingsthat
canbeseenintheabovepicture.
Alright,nowitstimetopressPlayandwaitafewseconds.Weshould
beabletoseesomenewfoodspawninbetweentheborders:

http://noobtuts.com/unity/2dsnakegame

11/21

12/06/2015

noobtutsUnity2DSnakeTutorial

CreatingtheSnake
Letsnishthemainpartoftheourgame:theSnake.Asusualwewill
startbydrawingthesnakeimage,whichisjusta1x1pixeltexture:
snake.png
Note:rightclickonthelink,selectSaveAs...andsaveitintheprojects
Assetsfolder.
WewillusethefollowingImportSe ingsforit:

NowwecandragthesnakeimageintothemiddleoftheScene:

SofaritsjusttheSnakeshead,soletsrenameittoHeadtokeepthings
clean:

http://noobtuts.com/unity/2dsnakegame

12/21

12/06/2015

noobtutsUnity2DSnakeTutorial

Thesnakeshouldbepartofthephysicsworld,whichmeansthatwe
needtoaddaCollidertoitagain,soletsselectAddComponent
>Physics2D>BoxCollider2D:

Note:theColliderhasthesize(0.7,0.7)insteadof(1,1)sothatitdoesnt
collidewithotherpartsofthesnakethatarerightnexttoit.Wesimplywantto
giveUnitysomespace.
Nowthesnakeisalsosupposedtomovearound.Asaruleofthumb,
everythinginthephysicsworldthatissupposedtomove,needsa
Rigidbody.ARigidbodytakescareofthingslikegravity,velocityand
movementforces.WecanaddonebyselectingAddComponent
>Physics2D>Rigidbody2D.Wewillusethefollowingse ingsforit:

Notes:
TheRigidbodysGravityScaleis0becausewedontwantthesnake
tofalltowardsthebo omofthescreenallthetime.
TheIsKinematicoptiondisablesthephysicalbehaviorofthe
Rigidbody,soitdoesntreacttogravityorcollisions.Weonlyneed
toknowifthesnakecollidedwithsomething.WedontneedUnitys
physicstopushthingsaroundincaseofcollisions.Moreinfo:
Rigidbody2DUnityDocs.
Thenalsnakewillconsistofmanyli leelements.Therewillalwaysbe
theHeadatthefrontandthentherewillbeseveralTailelementslike
here:
http://noobtuts.com/unity/2dsnakegame

13/21

12/06/2015

noobtutsUnity2DSnakeTutorial

ooooox

TheonlydierencebetweentheTailelementsandtheHeadisthatthe
headdoesallthethinking.WewilladdaScripttoitlater.
LetsdragthesnakeHeadfromtheHierarchyintotheProjectAreato
createaPrefabandthennameitTailPrefabsowecanloaditwhenever
thesnakegrows:

Note:someUnityversionswillautomaticallyrenameGameObjectinthe
Hierarchytoo,somakesurethattheoneintheHierarchyisstillnamedHead.
Alright,letsselectthesnakeHeadintheHierarchyagainandclickon
AddComponent>NewScript,nameitSnakeandselectCSharpasthe
language:

WecanopentheScriptbydoubleclickingitintheProjectArea:
usingUnityEngine;
usingSystem.Collections;
publicclassSnake:MonoBehaviour{
//Usethisforinitialization
voidStart(){

//Updateiscalledonceperframe
voidUpdate(){

}
}

LetsmodifythetopoftheScripttoincludesomeListfunctionalitythat
wewillneedlateron:
usingUnityEngine;
usingSystem.Collections;
usingSystem.Collections.Generic;
usingSystem.Linq;
publicclassSnake:MonoBehaviour{
//Usethisforinitialization
voidStart(){

http://noobtuts.com/unity/2dsnakegame

14/21

12/06/2015

noobtutsUnity2DSnakeTutorial

//Updateiscalledonceperframe
voidUpdate(){

}
}

TheSnakeshouldalwaysmoveexactlyoneunitintowhateverdirection
itwantstomove.NowifwewouldallowittomoveineveryUpdate
call,thenitwouldbereallyfast.Insteadwewillonlyallowmovement
every300millisecondsbyusingUnitysInvokeRepeatingfunction.Its
likewecreateourownUpdatemethodthatonlygetscalledevery300
msinsteadofeveryframe:
usingUnityEngine;
usingSystem.Collections;
usingSystem.Collections.Generic;
usingSystem.Linq;
publicclassSnake:MonoBehaviour{
//Usethisforinitialization
voidStart(){
//MovetheSnakeevery300ms
InvokeRepeating("Move",0.3f,0.3f);
}

//Updateiscalledonceperframe
voidUpdate(){

voidMove(){
//DoMovementStuff..
}
}

TheSnakeshouldalwaysbemovingintosomedirection,itshould
neverstandstill.Soletsdeneadirectionvariableanduseittomove
thesnakeintheMovefunction:
usingUnityEngine;
usingSystem.Collections;
usingSystem.Collections.Generic;
usingSystem.Linq;
publicclassSnake:MonoBehaviour{
//CurrentMovementDirection
//(bydefaultitmovestotheright)
Vector2dir=Vector2.right;
//Usethisforinitialization
voidStart(){
//MovetheSnakeevery300ms
InvokeRepeating("Move",0.3f,0.3f);
}

//Updateiscalledonceperframe
voidUpdate(){

http://noobtuts.com/unity/2dsnakegame

15/21

12/06/2015

noobtutsUnity2DSnakeTutorial

voidMove(){
//Moveheadintonewdirection
transform.Translate(dir);
}
}

Note:transform.Translatemeansaddthisvectortomyposition.
ThedirectionvariableisoftypeVector2,whichmeansthatithasanx
andyvalue.Thefollowingimageshowsdierentdirectionsfora
Vector2:

IfwepressplaythenwecanalreadyseetheSnakemovetotheright:

Theusershouldbeabletochangethemovementdirectionbypressing
oneofthearrowkeys.Nowwecouldjustcheckforkeypressesinour
Movefunction,butthatwouldmakethegamefeellaggybecausethen
wewouldonlydetectkeypressesevery300ms.Insteadwewillusethe
Updatefunctiontodetectkeypressesallthetime:
//UpdateiscalledonceperFrame
voidUpdate(){
//MoveinanewDirection?
if(Input.GetKey(KeyCode.RightArrow))
http://noobtuts.com/unity/2dsnakegame

16/21

12/06/2015

noobtutsUnity2DSnakeTutorial

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:ifyouarenotsurewhyweusedUpdateandMoveinsteadofjust
UpdateorjustMove,feelfreetoputthecodefromMoveintoUpdateorthe
codefromUpdateintoMove,thenyouwillseethatthesnakemovesrapidly
fastorthatthekeypressesaredetectedonlyrarely.
IfwepressplaythenwecannowmovetheSnakewiththearrowkeys:

TheSnakesTail
LetsthinkabouthowtheSnakestailwillwork.Firstofall,letsassume
wehaveasnakewithoneheadandthreetailelements:
ooox

Nowassoonastheheadmovestotheright,theobviousthingwouldbe
tomoveeverytailelementtowhereitsprevioustailelementwas,like
this:
step1:ooox//snakedidn'tmoveyet
step2:ooox//headmovedtotheright
step3:ooox//firsttailfollows
step4:ooox//secondtailfollows
step5:ooox//thirdtailfollows

Thiswouldwork,butitwouldalsobesomecomplicatedcode.Letsuse
aneatli letricktomakeourliveseasier.Insteadofmovingonetail
elementafteranother,wewillsimplymovethelasttailelementintothe
gaplikehere:
step1:ooox//snakedidn'tmoveyet
step2:ooox//headmovedtotheright
step3:ooox//lasttailelementmovedintothegap
http://noobtuts.com/unity/2dsnakegame

17/21

12/06/2015

noobtutsUnity2DSnakeTutorial

Nowthatsoundslikeaneasyalgorithm.Ineverymovementcall,allwe
havetodoismovethelasttailelementtowheretheheadwasbefore.
Atrstwewillneedsomekindofdatastructuretokeeptrackofallthe
tailelementsthatwewilladdlateron:
//KeepTrackofTail
List<Transform>tail=newList<Transform>();

Note:itsreallyimportanttoaddusingSystem.Collections.Generic;and
usingSystem.Linq;tothetopinorderforliststowork.
Letsgettothecodethattakesthelasttailelement,removesitfromthe
backandputsitintothegapmentionedabove:
voidMove(){
//Savecurrentposition(gapwillbehere)
Vector2v=transform.position;
//Moveheadintonewdirection(nowthereisagap)
transform.Translate(dir);
//DowehaveaTail?
if(tail.Count>0){
//MovelastTailElementtowheretheHeadwas
tail.Last().position=v;
//Addtofrontoflist,removefromtheback
tail.Insert(0,tail.Last());
tail.RemoveAt(tail.Count1);
}
}

Note:Translatesimplymeansaddthisvectortomyposition.Afterwardswe
checkifthereisanythinginthetaillist,inwhichcasewechangethelasttail
elementspositiontothegapposition(wheretheheadwasbefore).Wealsohave
tokeepourlistorder,hencetheInsertandRemoveAtcallsattheend.They
makesurethatthelasttailelementisnowtherstelementinthelist,too.
AndthatwastheonlyslightlycomplicatedpartofourUnity2DSnake
Tutorial.Nowwearealmostdone.

FeedingtheSnake
WewillusetheOnTriggerEnter2Dfunctiontoreceivecollision
information(whichwillhappenwheneverthesnakewalksintofoodorintoa
border).
Wheneveritrunsintofood,wewillusetheexactsamemechanicsthat
weusedforourmovementabove,exceptthatthistimeinsteadof
removingthelasttailelementandmovingitintothegap,wewillonly
Instantiateanewelementintothegap:
ooox//gap
oooox//gapfilledwithnewelement

ItsimportanttounderstandthatwewillnotmaketheSnakelonger
http://noobtuts.com/unity/2dsnakegame

18/21

12/06/2015

noobtutsUnity2DSnakeTutorial

immediatelyafteriteatssomething.Justlikewithourarrowkey
presses,wewillwaituntilitactuallymoves.Thereforewewillneeda
newvariablethatwewillsettotruewhenevertheSnakeatesomething:
//Didthesnakeeatsomething?
boolate=false;

WewillalsoneedapublicvariablethatletsusassigntheTailPrefab
lateron:
//Didthesnakeeatsomething?
boolate=false;
//TailPrefab
publicGameObjecttailPrefab;

Note:thetwovariablesaredenedatthetopofourSnakescript.
NowletsgettotheOnTriggerEnter2Dfunction.Thisonewillbe
straightforwardagain.WewillndoutiftheSnakecollidedwithfood,
inwhichcasewesettheatevariabletotrueanddestroythefood.Ifit
didntcollidewithfood,theniteithercollidedwithitselforwitha
border:
voidOnTriggerEnter2D(Collider2Dcoll){
//Food?
if(coll.name.StartsWith("FoodPrefab")){
//GetlongerinnextMovecall
ate=true;

//RemovetheFood
Destroy(coll.gameObject);
}
//CollidedwithTailorBorder
else{
//ToDo'Youlose'screen
}
}

Note:weusecoll.name.StartsWithbecausethefoodiscalled
FoodPrefab(Clone)afterinstantiatingit.Themoreelegantwaytondoutif
collisfoodornotwouldbebyusingaTag,butforthesakeofsimplicitywe
willusestringcomparisoninthisTutorial.
Alright,letsmodifyourMovefunctionsoitmakestheSnakelonger
wheneverateistrue:
voidMove(){
//Savecurrentposition(gapwillbehere)
Vector2v=transform.position;
//Moveheadintonewdirection(nowthereisagap)
transform.Translate(dir);
//Atesomething?TheninsertnewElementintogap
if(ate){
//LoadPrefabintotheworld
GameObjectg=(GameObject)Instantiate(tailPrefab,
v,
Quaternion.identity);
http://noobtuts.com/unity/2dsnakegame

19/21

12/06/2015

noobtutsUnity2DSnakeTutorial

//Keeptrackofitinourtaillist
tail.Insert(0,g.transform);
//Resettheflag
ate=false;
}
//DowehaveaTail?
elseif(tail.Count>0){
//MovelastTailElementtowheretheHeadwas
tail.Last().position=v;
//Addtofrontoflist,removefromtheback
tail.Insert(0,tail.Last());
tail.RemoveAt(tail.Count1);
}
}

Note:allwedidwascheckifateistrue,thenInstantiatethetailprefabatthe
positionvwiththedefaultrotation(Quaternion.identity).Afterwardsweadd
ittothetaillistandresettheateag.Therestofthecodewasalreadythere.
NowwecanselectthesnakeHeadintheHierarchy,takealookatthe
InspectoranddragtheTailPrefabfromtheProjectAreaintotheScript:

IfwepressPlaythenwecannowplayaniceroundofSnake:

Summary
SnakeisoneawesomegameforaUnityTutorial.Thereisalotofvalue
inunderstandinghowtodopixelexactgameslikethisandhowtoadd
movementwithInvokeRepeating.Yetagainwesawhowamazingly
easy2DgamesarewithUnitys2Dfeaturesthatwereintroducednot
verylongago.
http://noobtuts.com/unity/2dsnakegame

20/21

12/06/2015

noobtutsUnity2DSnakeTutorial

Nowitsuptothereadertomakethegamefun!Therearetonsof
improvementstobemadelikeawin/losescreen,abe erlookingsnake
texture,multiplelevels,powerups,increasingspeed,highscores,
multiplayerandsoon.

DownloadSourceCode&ProjectFiles
TheUnity2DSnakeTutorialsourcecode&projectlescanbe
downloadedbyPremiummembers.
AllTutorials.AllSourceCodes&ProjectFiles.OnetimePayment.
GetPremiumtoday!

20122015noobtuts.com

http://noobtuts.com/unity/2dsnakegame

21/21

You might also like