I candrawshapes, so I'm goingtodraw a boundaryhereandyoucanseeit's it's sortof a tilemaparrayonthenicethingisnowwhen I holdontherightmousebuttonandturnthelightoff, wecouldseethattheboundariescastshadowswell, thecashshadows, buttheyalsoindicatethelocationsthatcan't beseenfromwherethemousecursoris.
Sothisisalso a lineofsight.
Hebehavesquitenicely a lotin a fewmorefeaturesandseehowitbehavesandallofthefeaturescasttheirownshadows.
Formyvideos, though, I don't reallywantthefilestructureitprovides.
Thefirstthing I wanttodoisgetridofthe P c h dot h fileonthePCHdotCPPfile.
So I selectthemandpressdelete.
I don't wantthem I'm notgoingtouseprecompiledheaders.
Thisalso, thatmeans I havetogetridoftheIncludePCHdot h fromthemain.
What's thematter?
I'm goingtogetridofallofthesecommentstoWeneedtotellitthatwedon't wanttouseprecompiledheadersinourProjectSigmatoprojectpropertiesandmakesurewe'vegotdebugselected, appearandexpandthe C in C plusplusoption.
Now I knowit's verycontroversial, butthenextthing I wanttodoisactuallyincludetheSTDnamespace, andtheonlyreason I dothisisbecauseit's easiertomakevideosthatappearclearer.
Bestpracticeisnottodothis.
We'recreating a pixelgameengineapplication, soatthispoint, youNepalineedtogototheoneloancoded, gethopeanddownloadtheheadoffile, andhereitisOhElsiepixelgameenginedot h.
GrabthisfileonCopyitintothefolderthatyoucreatedwhenyoucreated a newsolution.
And I wanttoconstruct a pixelgameenginewithresolutionprettyhighnow 6 40 by 4 80 whereeachpixelistwobytwoscreenpixels, andifthat's successful, thenstarttheengine.
Atthispoint, youmaywanttodo a test, compileandrunjusttomakesureeverything's setupcorrectly, weshouldsee a blackscreenoffthedimensionswe'vejustspecifiedverynice.
Nowthisis a bitof a twoforonevideobecausetoimplementshadowcastingorlineofsight, wereallyneedtoalgorithms.
I liketheconvenienceofbeingabletodrawtheworld's intiles.
Youcouldhave a selectionofblocksandplacethemwhereveryouwant, buttheshadowcastingalgorithmitselfreliesheavilyongeometry.
Andifwehadtodogeometryforalloftheblocks, everysingleframe, well, I feelthat's notveryefficient.
Sothefirststageofthealgorithmistoconvertourtilemapofblocksinto a polygonmapofedges.
Here I'vedrawnoutonourpoetrysection, offlevelorworldthatbasedon a tilemapsoyoucanseewhere I'veplacedtheblockswhere I haven't placedtheblocksinthebackground.
There's lotsofadvantagestousing a tilemap, butwedon't wanttousethegeometryofeverysingleblockedgetocastshadowsbecauseatanygivenmomentthere's a lotofedges.
Relatetothenorth, south, eastandwestedges, andaswesawatthestart, a cellmayshareanedgewithothercells.
Thisimpliesthatanygivencellcan't actuallyownanedge, andsaiditmustuseonethatstoredelsewereSo I'm goingtoalsoincludefourinterviewswhichrepresentstheonly D off a givenedgeonthenorth, south, eastorWestSidefromsomeedgepoolthatwillcreateelsework.
Sowe'regoingtoapplyteststothiscellonthefirsttestthatwilltryfromtheperspectiveofthiscellisDo I have a westernneighbor?
Well, inthissituation, clearly I don't have a westernneighbor, so I definitelyhave a westernedge.
Butwheredo I getthisedgefrom?
Well, theonlyotherplaceanedgecouldcomefromisfrom a northernneighborthatalsohas a westernedgeandineffectwilltakethatedgeandgrowitdownwards.
Inthissituation, wedon't have a northernneighbor, sowe'regoingtocreate a newedgeandsowilladdtoouredgepooledge, eh?
Andinourcellstructurewilllinkouredge.
I d tothelocationoftheedgeintheedgePoolwillnowsystematicallychecktheothersidesofthetile.
Firstly, we'llchecktheeasternedge.
Soif I haven't Easternneighbor, whichinthiscase I do, thenclearlythatisn't anedgenecessarybetweenus.
Wedon't needtodoanythingfurther.
Nowweneedtocheckournorthernneighbor.
Well, I don't have a northernneighborinthiscase, so I doneedanedge, butworkand I getonefromWell, I caneithergetonefrommywesternneighboror I needtocreateoneofmyown.
Andsince I don't have a westernneighbor, I'm goingtohavetocreateoneofmyown.
Sowe'llcreate a newedgecalled B andwillgivetheideaofthatedgetothecellAlsodrawingthe a hedgethere.
Asyoucanprobablytellalreadyit's a similarsituationforthissouthernedge, too.
We'regoingtoneedtocreateoneforthiscell.
See, nowwe'retraversingfromtoplefttobottom.
Right.
Sothisisthenextcellthatwecheckon.
Werunthroughexactlythesameroutine.
Do I have a westernneighbor?
Willtheydoso?
I don't need a westernedge.
Do I haveaneasternneighbor?
Well, again, I do.
I don't needaneasternedge.
Do I have a northernneighbor?
No, I don't.
So I doneedanedge.
Butthistime, ratherthancreatingoneformyself.
What I canseeisthatmyWesternneighborcurrentlyalreadyhas a northernedge.
Itdoesn't haveanyneighbors, sotheconsequenceofthisisgoingtoaddfournewedgestotheedgepool, a westernedgeoneasternedge, thenorthernedgeonthesouthernedge.
Heif G and H andsettheedge.
ID's for 56 andseven.
Sotheworstcasescenariois a mapmadeupoflotsofindividualblocks.
Carryontesting, but I'm notgoingtogoinasmuchdetailnow.
Thenextblocktestedisthisonethatdoesexistwell.
Thisoneneeds a newWesternedge, whichis I nowwe'reupto, butitcanborrowfromitsnorthernneighbor.
It's easternedge, and I'lljustcarrythealgorithmalongnowfortherestoftheshape.
Oncewe'vegonethrough, allofthetileswereinterestedinwillhaveanedgepoolthatcontainsonlytheboundingedgesofftheshapes, andtheedgesaredefinedby a startonanendcoordinate.
It's verypossiblethatedgeswillshare a coordinate, butneedlesstosay, we'veconvertedourtilemapinto a setofedges, notstrictly a polygon, becausewe'renotdefined.
Andi, thisissomethingwe'veseenmany, manytimesnow I equals a y coordinatetimesthewidthofthearrayplus X, whichconvertsourtwo d X and Y cornetsinto a onedecornetinthearray.
Sowhogotthescreenwiththemassacresurround, Andif I clickwherever I click, I placetheblueblock, andif I select a blueblockandclickit, itgetsridofit.
Werebasicallytoggling.
Doestheblockexistatthatlocationornot?
Nowwecanworryaboutturningthetilemapinto a poolofedgesonthecontainer.
Goesuseforthisis a vectorcalledbackedgesonbecause I knowthatdoingthistypeofconversionisgoingtobeincrediblyusefulforfuturevideos.
I'm goingtocreate a functionthatexplicitlydoesthis.
Itconverts a binarytilemapintowhat I'm callingthepolymap.
It's goingtopopulatethisfactorwithalloftheedgeinformationgiven a particularregionof a tilemap, sotheparametersofthisfunctionare a starting X and Y coordinatethewidthandheightoftherectangleofftilesofwhich I wishtoinspectandturnintoedgesarealsogoingtopassintheblock.
Andthat's simplybecause I don't wanttohaveanyoutofboundsmemoryerrorswhen I'm checkingalongtheedgesoffthetwo D array, I couldgetawaywiththatforthisdemonstration.
Butgoingforward, I'llprobablywanttotightenthatup a littlebittoaccommodategenuinearrayboundaries.
Ifitdoesexist, willchecktoseedoesn't have a westernneighborbecauseifitdoesn't have a westernneighborthanitneeds a westernedge, oneoftheplaceswecanget a westernedgefromisournorthernneighborbyextendingitdownwards.
Solet's seeifournorthernneighbordoesthathave a westernedge, ifitdoes, willextendit, andwecanextenditbylookingatournorthernneighbors.
Westernedge.
I d.
Onusingthat I d toindexintoouredgepoolsowecanfindwhichedgeisonthewesternsideofournorthernneighbor.
Andweknowthatwe'regoingtogrowdownwards.
Sowewanttoextendtheendcoordinateofthatedgebyoneblockwitdown, whichiswhatthislinedoessoinourpoolofedgeswerelookingatournorthernneighborswesternedge I d togettotheedgethatisrelevanttous.
We'retakingtheend y coordinatebecausewe'regoingtoextendinthe y axisdownwardson.
I d ofourcurrentsellswesternedgetobethesameasonnorthernneighbors, Westernedge.
Andsincetheinchexists.
We'llsetthattotrue.
Now, if I didn't have a northernneighbor, I stillneedanedgefromsomewhere.
So I'llneedtocreateonetocreate a newedgeobjecton.
Wecanusetheposition.
WeareinthearrayontheblockwidthvariabletoworkoutwhereweareinrealspaceSowecansetthisstartcoordinateofouredge X Andwhyhere, usingwth e arraycoordinatesmultipliedbytheblockwithAndi, weknowatthemomentthatouredgeisgoingtobeatleastoneblocktall.
Andsincewe'vecreated a newedge, aswedidappear, weneedtoknowsettothe I d.
Onwhethertheedgeexistsornot.
Forthiscell, well, it's a newedge I d on.
We'veusedthelocationofitinthevectortospecifythat I d.
Andsothatisallofthecoderequiredtoworkoutwhetherweshouldcreate a newwesternedgeorborrowfromournorthernneighborsWenowneedverysimilarcodefortheotherfouredges, and I'm notgoingtotalkthroughitall.
Soeventhough I appreciatethatseemslike a reallylargeamountofcodetoputitinonego, I hopeyoucanappreciatethatisactuallyverysimilartotheonethatwe'vejustdone.
Youcanprobablytellthat I'm going a littlebitfasterthanusualonthisvideo.
That's onlybecausetherearetwopartsofthealgorithmthat I wanttoinclude, but I don't wantthevideotobecomeanhourlong.
Andhere I amcallingit, and I'm givingittheregionofinterestthat I wishforittoconvert, whichinthiscaseisthewholearrayon.
I specifytheblockwithcoordinatessotheedgescanbedonetotherightscaleonespeciallythepitchtobethewitoftheworld.
It's actuallythesameasthevalueamusinghere, because, coincidentally, thewholeworldisrepresentedbythesinglescreen I cansee.
I thinkit'llbequitenicetovisualizetheedges, tohelpuswithsomedebuggingandtomakesurethateverythingisworkingaccordingly.
Soafterwe'vedrawntheblocksongoingtocreate a littleautofourlooptoiteratedthroughalloftheedgesinourvectorofedgeson, I'llusethedrilllinefunctiontodraw a whitelinefromthestartingcoordinates.
Theendingcoordinatesofftheedge, buttomaketheendsoftheedge a littlebitmorevisible, I'm goingtodraw a redfilledincirclethat's eachend, I said.
Youonlyneedtoregeneratethepolymapifthetilemapchanges, andinsomesituationsitcouldbe a completelyoffline, prettycompilationstepofhowyourleveldataisstopped.
If I hadinonemorepoint, whichisthesource, what I'm actuallyconstructedis a fanofftriangles.
That's onetrianglenexttriangle, andthesetrianglesconstruct a polygon, whichcoverstheareathatisdefinitelyvisiblefromthesourceTheproblemis, it's a bitof a strangepullago, becauseif I shadedinthispolygonwithlight, wecanseethere's somebiggapswhicharedefinitelyvisible.
Butthey'vebeenignoredbythealgorithm.
Whatcanwedoaboutthesebiggapsthat, well, there's a littlehackthatwecanapply.
Insteadofcastingonerayfromthesourceto a Vertex, wecastthree.
Raiseonegoesdirectlytoit, andwehaveoneeithersidedisplacedby a tinyfractureandangle.
There's goingtobe a setofpointsthatrepresentsthevisiblespacefrom a sourcelocationdefinedby O X and A Y over a givenradius.
But I'm goingtouse a littlebitofmodernseatohelpmeouthere.
I'm goingtostorethepointsofthispolygonas a vectoroftopplesofffloats, andyou'llnoticetherearethreefloatsthefirstfloatisgoingtorepresenttheanglefromthesourceofftheVertexthatweretargetingwiththerayandthesecondtofloatsarethe X and Y locationoffthatVertex.
Thiscouldtheoreticallyhappeninanysortoforder, whichmeanswhen I cometodrawthesetriangleslateron, I can't doitsensibly, effectivelyneedtodroolthesepointsinsomerotationalorder.
Since I needtheangleoftheray, I'm goingtostartbyfirstcalculatingtheradiantoftheraynow, dependingonwhetherwe'reatthestartortheend.
So I'veusedtheTurner, a operatorhere, toselectbetweenthestartpointoftheendpointon.
I'm subtractingfromthatthesourcelocation O X.
I knowwhygivingmetwovariablesaretheaccentarty.
Why?
Whichrepresentstherayvector.
Now I'm notbotheredwhatourangleisrelativetoaslongasit's consistent, so I'm justgoingtocreateanothervariablebaseangleandusedtheAtentofunctionusingtheRDXandarethe Y values.
Sothisgivesusanangleoffourrayvector, andweknowthatforeachray, actually, we'regoingtocastthreeadditionalraisewith a slightdeviationbetweenthetwo.
So I create a temporalvariablecalledangle, whichisgoingtobetheanglewewillshoottherateat.
Now, however, theonethingweguaranteedisthatourstrategyismoreoptimalthancastingraiseoutinalldirectionsandseeingwhathappensatleastnowraisearegoingdidintelligentlytoatleastsomefeatureswithintheworld.
Andthisiswherethereallychewypartofthealgorithmcomesbecauseforeverysingleraywenowneedtocheckforintersectionbetweentherayonalloftheedgesinthescene, thealgorithmhasnowcomedownto a simplelinesegmentintosectiontestsowecantaketolinesegmentsandwewanttoworkoutthepointatwhichtheyintersect.
Onewaytothinkaboutthisistotake a knownpointoneachline, representthelinesegmentas a vector.
Thereforetheopposingpointbecomesexistingpoint.
Plusthatvectoron, wecanaddinhere a parameterdoyouwantand t too, becauseif t oneisequaltoonewereatthisendoftheline.
Andif t oneisequaltozero, we'reatthisendoffthelineandsowillfindwe'reintoSectionPointisbylookingatthe T values.
It's notgoingtolieontopofit, so I'llcheckforthatbyjustlookingafterthevaluesoffthevectorcomponentsonmakingsurethatthey'resufficientlydifferent.
Forexample, ifbothhad a d Y zero, thenboththerayontheedgecouldbehorizontal.
There's a chancetheycouldoverlap, andthereisn't a singlesolutionpointthatrepresentsthepointofintersection.
Nowwecancalculatethe T oneand T twovaluesusingthelinesegmentIntersectionPointalgorithm, andinthisinstance, T oneisthedistancealongtherayand T twoisthedistancealongtheedge.
Andsoif t oneispositive, thatmeanswe'retravelingalongtherayinthecorrectdirection.
Andif t twoliesbetweenzeroandone, thenwe'vedefinitelyhit a linesegment.
Eventhoughwe'vedetectedintersectionsalongmanyedges, wewanttorejectmostofthemononlyretaintheonethatisclosesttothesourceand R T.
Onevaluerepresentsthatinformation.
Wedon't needtodoPythagorastheoremheretocalculatethedistancebecause T oneindicatesthelengthalongtheray.
Andsoforeachraythat I cast, I'm goingtostoresometemporaryvariablesthatrepresentstheminimum t onedistance, and I'm alsogoingtostorethe X and y oftheintersectionpointatthatdistance, I'llsetittoinfinityforeachRaytostuff.
Butifthe t onethatrepresentstheintersectionpointoftherayofjusttestedislessthanourcurrentclosestintosectionpoint, I'm goingtoreplaceit, and I'm alsogoingtocalculatethenewintersection, pointandangle.
Ofcourse.
Now, forallofmyrace, once I'vecalculatedweretherayends, I'm goingtoaddthatlocationtomyvectorofvisiblePolidentpoints.
OurcalculatevisibilityPolygonhasnotquitefinishedyetbecauserightnowwe'vegot a vectorfullofpointsinanyparticularorder, andso I needtosortthembasedupontheangle.
Fortunately, thestandardlivewecanprovide a nice, simpleroutinetodothisforest.
Solet's addin a fewobstacles, ofcourse, willexpectthenumberofracetoincreaseorcasting 100 92 Rays.
Butnowwe'reonlydrawingabout 50 rays.
I thinkthisisquite a significantoptimizationtomakelotsoffeatures.
840 Ray's castonweredrawingwell, about 25% ofthem.
I'm goingtofillinthetrianglesagainnowandsowecanseewe'vegotquite a robustlineofsightorshadowcastingalgorithmimplemented.
Now, atthestartofthisvideo, I madeitlook a littlebitmorespecialbecause I used a spriteoff a lightsauceonmodulated, whereitiswhiteherewiththatsprite.
Sothisis a bitofpixelgameenginetrickery.
Now, inphotoshop, I havecreated a spritethatrepresents a lightsourceemanatingoutfrom a centralpointit's a PNGfile.
I'm goingtoloadtheSpriteintothepixelgameengine, and I'lldothatinonusercreate.
I'm notgoingtodosomething a littlebitnovelforthischannel.
I'm goingtodosomeoffscreenrenderingwenttocreatetwoadditionalspritescalledBuffettLightRayandBufferlikeTexonthesearegoingtobesurfacestowhich I'm goingtodosomepostprocessing, but I needtocreatetheseinonusercreates.
You'llsee I'm notloading a file.
I'm justgivingthem a dimension.
They'rebasicallygoingtobeanimagebuffertoe, which I'lldrawthingsandthenmodifythepixelgame.
Andifthat's thecase, I wanttodroolinthecurrentscreenlocation.
X and Y thepixelofmylightcastSpriteinthecorrespondinglocation.
Let's take a lookso I canseemySpritehasnowbeendrawnwherevermymousecursorisputinsomeblocksandthelightlooks a littlebitmorerealisticwillnoticethattheperformancehastaken a littlebitof a hit.
Here.
We'vegonedowntoabout 18 framespersecond, andthisissomethingtodowithhowthepixelgameenginevalidatesallofthepixelsin D bookmode.
Ifwenowchangefromdebugmodetoreleasemodeandrunthesamecode, wecanseetheframerateis a farmoreacceptable 102 100 francsforsecondonmymachine.
Putinsomeobstacles.
Verynice.
Theuseofoffscreenbuffersis a littlebitangryintothethingswe'vebeendoingonthischannel, butit's a verycommonpracticeinallmannerofcomputergraphicsonthefactthatwenowworkwithpixelsinsteadofchara