Gitterbaseret Sti Findning | hyperPad Documentation

Loading...

Logo

I denne tutorial vil vi lave en stisøgningssimulation baseret på et 2-dimensionelt arraygitter. Dette vil give os den grundlæggende idé i at skabe stisøgningsaktiviteter til vores spil. Vi vil visualisere gitteret ved hjælp af tomme firkantede objekter som fliser og et rundt objekt som vores avatar, der kan bevæge sig på det gitterområde med vores kommando.

Video_2019-07-30__2_32_01_PM.gif

I. Opsætning af objekterne

Vi vil kun bruge fire objekter i vores projekt. Vores grønne avatar, en blå flise, en hvid blokade, og gitteretiketten til opsætning og visualisering af vores gitter.

Photo_2019-07-29__1_50_10_PM.png

Avatar

Vores avatar er et tomt objekt, der har en x- og y-skala på 50%. Sæt dens kollisionsform til en rund form, så den ligner den i billedet nedenfor. Dette objekt vil have tre foruddefinerede attributter: på flise, tidligere flise og målflice. Sæt disse attributters standardværdier til nul, så de ikke får en null-værdi, når vi prøver at hente dem senere.

Photo_2019-07-29__1_53_38_PM.png

Fliseobjekt

Opret et andet tomt objekt, der vil blive brugt til at visualisere fliserne i vores gitter. Dens skala er også 50% og har kun én foruddefineret attribut: på flise. Sæt også denne værdi til nul.

Photo_2019-07-29__1_53_51_PM.png

Blokadeobjekt

Opret et andet tomt objekt, der vil fungere som blokader i vores gitter. Dette er et hvidt tomt objekt med en skala på 40%. Vores avatar vil ikke kunne krydse til en flise, der har en blokade ovenpå.

Grid Label

Dette er bare en etikette, der vil have adfærd, der vil tillade opsætningen og visualiseringen af vores gitter. Den har foruddefinerede attributter: start x med en værdi på 4 og start y med en værdi på 3. Disse værdier er offsetværdier, der vil blive brugt som referencer ved spawnen af vores fliser for at placere vores gitter pænt i midten.

Photo_2019-07-29__1_56_01_PM.png

Avatar/Tile Foruddefinerede attributter:

Vi definerer en flise her som et 2-størrelse array, som vil have en x- og y-værdi baseret på vores gitter.

  • på flise - dette er fliseværdien, som vores objekt i øjeblikket er på i vores gitter
  • tidligere flise - en flise, der tidligere blev krydset af vores avatar
  • målflice - flisen, som vores avatar vil gå til

II. Opsætning af gitteret

Inde i gitteretiketten er hvor vi vil definere vores 2D-array og spawnen af vores gitter. Der er 2 hovedpunkter i dette objekt: opsætning af arrayet og visualisering af arrayet. Lad os først gøre opsætningsbundtet.

Photo_2019-07-29__3_05_10_PM.png

Opsæt array - bundle

Først er at oprette et tomt array ved navn 'Grid'. Dette array vil indeholde vores 2-dimensionale array. Vi vil have en bokscontainer ved navn 'x row count', der har en værdi på 24 og et andet tomt array ved navn 'y row', hvilket har 18 tomme værdier.

Photo_2019-07-29__1_55_28_PM.png

Den første adfærd i vores bundle er en løkke med et repetitionsantal af 'x row count'. For hvert trin i denne løkke vil vi tilføje et tomt y row til 'Grid array'. Dette vil skabe et array inden i et array med dimensioner på 24x18.

Bemærk, at vi har tilsluttet en inaktiv kommentar i starten af vores bundle for at negere den automatiske udførelse af denne rodadfærd. En rodadfærd er en adfærd, der ikke udløses baseret på nogen begivenhed og er placeret åbent i interface.

Visualisering af gitteret - bundle

Den vigtigste ting, vi vil gøre her, er at bevæge os på hver værdi af vores 'Grid array' og spawne et fliseobjekt. Vi vil også tilføje en betingelse i vores løkke, der vil tillade spawnen af en hvid blokade oven på fliseobjektet.

Photo_2019-07-29__3_56_37_PM.png

Først er at få arraytællingen af vores 'y række array', 'start x' attributværdien for dette objekt og 'start y'.

Opret en løkke, der har en gentagelse af 'x row count', og for hvert trin i denne løkke vil vi tilføje indeksværdien i den løkke og 'start x' attributværdien. Dette resulterer i en absolut x-position, som vi vil bruge til at placere vores spawne fliser senere. Næste er 'y row løkke', som har en gentagelse af 'y row count'. For hvert trin i denne løkke vil vi tilføje indeksværdien fra den løkke og 'start y' attributværdien, hvilket nu resulterer i den absolutte y-position.

Photo_2019-07-29__4_03_51_PM.png

Efter at have tilføjet værdierne under 'y row løkke' er målet at spawne det blå objekt. Sæt #of alive objects til 999, fordi vi vil have mange af dem til vores gitter, og også med en varighed på 0. Flyt derefter det spawne objekt til et x-punkt med en værdi fra x-løkken 'tilføje værdier', og y-punktet med værdi fra y-løkken 'tilføje værdier'.

Næste trin er at tilføje et array med 2 tomme værdier kaldet 'On tile', som vi kun vil bruge som et arraypladsholder. Efter at have flyttet fliseobjektet er det at ændre 'On tile' arrayet ved at erstatte dens værdi ved indeks 0 med værdien af 'x row loop'. Derefter tilføj en anden arraymodifikation, der erstatter værdien ved indeks 1 med 'y row index'. Dette er x- og y-koordinaterne i vores gitter, som objektet vil have som en 'on tile'-attribut.

Nu skal attributten for det spawne objekt sættes med en dynamisk nøgle, 'on tile', og med en værdi af 'On tile - array'.

Photo_2019-07-29__4_41_55_PM.png

Under y row løkken findes stadig tilstanden for at spawne den hvide blokade. Vi vil have en 2 ud af 5 chance for at udføre dette bundle, hvilket vil tilføje til tilfældigheden af vores gitter. Så vil vi markere en værdi på 1 til x- og y-koordinaten i vores 'Grid'-array, der fortæller os, at den koordinat har en spawnet blokade.

Først er at få et tilfældigt nummer fra 1 til 5. Hvis det nummer er mindre end eller lig med 2, vil vi spawne blokaden. Sæt dens #Alive-objekter til 999 og flyt det objekt til det samme punkt som den blå flise, vi tidligere spawne, og også med en varighed på 0.

Næste trin er at gemme informationen om, at denne koordinat var besat af en blokade, hvis den blev spawnet. Vi gør dette ved at markere den koordinat med værdien 1. Først er at få værdien ved indeks 'x row loop' i 'Grid'-arrayet. Denne værdi vil give os et array af en 'y row'. Vi vil ændre denne 'y row' ved at erstatte dens værdi ved indeks 'y row loop' med værdien 1, som er den markerede værdi. Fordi denne værdiændring kun gælder for den værdi, og ikke for 'Grid' i sig selv, skal vi stadig ændre 'Grid'-arrayet. Erstat værdien ved indeks 'x row loop' i 'Grid'-arrayet med værdien 'modify y row - array'.

Når det spilles, skal det resultere i denne form.

Photo_2019-07-29__4_45_18_PM.png

III. På fliseklik

For at kunne interagere med gitteret selv, har vi brug for et bundle-tilstand, når vi trykker på en blå flise. Det første klik resulterer i, at vores avatar vises i vores gitter, og enhver efterfølgende klik efter den begivenhed vil starte dens stisøgning.

Inde i det blå objekt findes en adfærdspakke, der har 3 hovedpunkter: at nulstille den tidligere flise af vores avatar, sætte dens på flise/sætte dens målflice og derefter lave en farveanimation for at visualisere trykbegivenheden på skærmen.

Photo_2019-07-29__5_00_44_PM.png

Først er at få 'on tile'-attributten af fliseobjektet. Sæt 'previous tile'-attributten for vores avatar til 0. Vores avatar vil blive indstillet til at undgå at gå tilbage til en 'previous tile', derfor nulstiller vi 'previous tile' ved hvert fliseklik.

Næste trin er at få 'on tile'-attributten af vores avatar. Den første hvis-betingelse er, om 'on tile'-værdien er lig med nul. Dette betyder, at hvis avatar endnu ikke er dukket op, vil dette resultere i sandt. Hvis det er sandt, skal vi sætte dens 'on tile'-attribut med værdi af fliseobjektets 'on tile'-attribut. Derefter flytte vores avatars position ved at få positionen af fliseobjektet og pege dens x- og y-værdier til det punkt med en varighed på 0.

Hvis 'on tile'-værdien ikke er lig med nul, sætter vi 'target tile'-attributten for vores avatar med fliseobjektets 'on tile'-attributværdi. Dette betyder, at vores avatar allerede er i vores gitter, og så kan vi udføre adfærdspakken, 'find stien'. Vi har stadig ikke denne adfærd endnu, men vi vil ordne dette igen efter at have gjort den senere del af denne tutorial for 'find stien'-bundtet.

Nu hvor vi har sat vores avatar korrekt i vores gitter, skal vi blot visualisere denne trykbegivenhed. Først har vi en rodadfærd 'get color' for at få dens oprindelige farve. Derefter, efter trykbegivenheden, sætter vi farven på fliseobjektet til sort med en varighed af 0, derefter sættes dens farve tilbage til dens oprindelige værdi med en varighed på 0,2.

At trykke på en blå flise skal resultere i dette.

Photo_2019-07-30__1_04_42_PM.png

IV. Udfør Find Path Bundle

For denne sidste del af vores tutorial vil vi gøre algoritmen, der gør det muligt for os at finde den nærmeste flise, som vores avatar kan tage for at nå sit mål. Dette bundle vil blive udført gentagne gange for hver flisestep, som vores avatar bevæger sig på vores gitter.

Vi vil opsætte algoritmen inde i vores avatarobjekt og som vil have tre hovedpunkter: finde de tilstødende fliser, finde den nærmeste tilstødende flise og bevægelsen til den tilstødende flise.

Photo_2019-07-29__5_39_25_PM.png

Finder de tilstødende fliser

I denne del vil vi indsamle alle de tilstødende fliser, som vores avatar vil kunne bevæge sig til. Vi vil kontrollere dens fire retningsbestemte tilstødende fliser og se, om disse fliser har en blokade ovenpå eller hvis de tidligere er blevet betrædt.

Photo_2019-07-29__5_40_24_PM.png

Først er at tilføje vores 'Adjacent tiles' array. Et 'Direction' array med 2 tomme værdier og de fire retningsbestemte arrays, der har 2 værdier for hver: N (0,1), S (0,-1), E (1,0), W (-1,0).

Den første adfærd i vores bundle er at rydde vores tilstødende fliser. Fordi vi vil udføre dette bundle gentagne gange, er vi nødt til at få vores indsamlede 'tilstødende fliser' nulstillet hver gang. De næste fire adfærd er ændringer til 'Direction'-arrayet. Vi sætter arrayet af 'Direction'-arrayet fire gange med de fire retningsbestemte arrays og eksekverer derefter bundtet nedenfor. Vi gør dette for at oprette en løkke med forskellige 'Direction'-arrayværdier hver gang.

Photo_2019-07-29__6_04_42_PM.png

Nu hvor vi har retningen, skal vi blot kombinere deres x- og y-værdier med 'on tile'-attributten af vores avatar. Så vil vi være i stand til at få vores målværdi i 'Grid'-arrayet for at vide, om den flise var markeret med en blokade.

'Direction x' er værdien af 'Direction'-arrayet ved indeks 0, 'get on tile' x er værdien af 'get on tile' ved indeks 0. Target x er de additive værdier af 'direction x' og 'get on tile x'. Det samme gælder for y-værdierne, men med et målindeks på 1.

'Target y row' er arrayværdien af 'Grid'-arrayet ved indeks 'Target x'. Og så vil 'Target index in y row' være værdien af 'Target y row'-arrayet ved indekset af 'Target y'. Det er koordinatet i vores gitter, der vil kunne fortælle os, om det var markeret med en blokade.

Photo_2019-07-29__6_17_41_PM.png

Hvis værdien i 'Target index in y row' er 1, så var den målflise markeret som blokeret. Men hvis værdien ikke er lig med 1, kan vi fortsætte i vores bundle.

Fordi vores Target x og y bestod vores betingelse, har vi tilføjet et nyt tomt tile-array kaldet 'New adjacent tile'. Dette vil gemme værdierne af Target x og y som et flisearray. Vi vil sætte værdien af Target x til indeks 0 af 'New adjacent tile' og Target y til dens indeks 1.

Nu skal vi få 'previous tile' attributten af vores avatar. Hvis 'previous tile' ikke er lig med 'new adjacent tile', vil det betyde, at den nye flise ikke tidligere er blevet betrædt. Så kan vi sikkert tilføje 'New Adjacent tile' til 'Adjacent tiles'-arrayet ved at tilføje det. Vi vil sætte værdien af 'previous tile' senere, efter at vi har fået vores avatar til at bevæge sig til en anden flise.

"Du kan udvide dette bundle ved at lave et 8-retningers arrays, som tillader din avatar at bevæge sig til diagonale retninger."

Finder den nærmeste tilstødende flise

Nu hvor vi har indsamlet vores pålidelige tilstødende fliser, skal vi blot få den tilstødende flise, der er tættest på vores avatars målflice. Vi vil udføre beregningen ved at bruge en afstandsformel forsynet af x- og y-værdierne af vores målflice og de tilstødende fliser.

Der er to nøglepunkter i dette bundle: initialiseringen af variabler til beregning og beregningen af fliseafstande inde i en løkke.

a. Initialisering af variabler

Først er at få arraytællingen af vores tilstødende fliser. Derefter får vi 'target tile'-attributten af vores avatar og får dens x- og y-værdier. Vi vil tilføje 2 nye bokscontainere: 'Min distance' og 'Target tile index'. Vi sætter den indledende værdi af 'Min distance' til 9999, og værdien af 'Target tile index' til 0. Min afstand er sat til et højt antal, fordi vi har brug for den mindste afstand fra starten. Target tile index er vores referenceindeks i 'Adjacent tiles'-arrayet, der har den mindste afstand til vores 'target tile'.

Vores hovedmål her er at finde indekset for flisen inde i vores 'Adjacent tiles'-array, som er tættest på vores 'target tile'.

Photo_2019-07-29__6_47_43_PM.png

b. Beregning af fliseafstande

I dette bundle vil vi udføre beregningen inden i en løkke, som vi vil gøre for hver tilstødende flise. Løkken gentages med 'adjacent tiles count', og vi vil få fliseværdien af 'Adjacent tiles'-arrayet ved at bruge indekset af den løkke.

Få x- og y-værdierne af den tilstødende flise, og så får vi afstanden mellem vores 'target tile' og den 'tilstødende flise' ved hjælp af denne formel:

afstand = sqrt((x2 - x1)^2+(y2 - y1)^2)
x1 = Target x
x2 = Adjacent x
y1 = Target y
y2 = Adjacent y

Vi trækker først deres x- og y-værdier fra hinanden, multiplerer dem med sig selv for at få deres eksponentværdier, tilføjer disse værdier og tager derefter kvadratroden af de tilføjede værdier for at få afstandsværdien.

Photo_2019-07-29__6_46_04_PM.png

Hvis værdien af 'Distance' er mindre end værdien af 'Min distance' bokscontaineren, sætter vi derefter værdien af 'target tile index' til den nuværende indeks i løkken, som er indekset for vores hentede flise inde i 'Adjacent tiles'-arrayet. Vi sætter også 'Min distance' bokscontainerens værdi med 'Distance' værdien, så vi kan sammenligne den med den næste flise i vores løkke.

Efter enden af løkken har vi sammenlignet hver en af vores tilstødende fliser, og vi har fået indeksværdien af den tilstødende flise, der er tættest på vores 'target tile'.

Bevægelse til den tilstødende flise

I dette sidste bundle af vores tutorial vil vi flytte vores avatar til den nærmeste tilstødende flise og gentage hele 'Find Path' bundle, hvis vi ikke allerede er flyttet til vores 'target tile'.

Photo_2019-07-30__1_23_31_PM.png

Det første er at tjekke, om vores 'Adjacent tiles count' er større end 0. Dette er for at sikre, at vi kun bevæger os, hvis vi har hentet mindst én pålidelig tilstødende flise.

Derefter 'Get the nearest tile' ved at bruge vores 'Target tile index' værdi fra det foregående bundle til at få arrayværdien af 'Adjacent tiles'-arrayet.

For at få det præcise punkt, hvor vores avatar bevæger sig til, skal vi have x- og y-fliseværdierne af den flise og også få 'start x' og 'start y'-attributværdierne af vores 'Grid'-etiket. Vi tilføjer derefter x-værdien af vores 'nærmeste flise' og 'start x'-værdien, samt det samme med y-værdierne. Disse tilføjede værdier er vores mål x- og y-punkter, hvor vores avatar vil flytte til.

Før vi bevæger os til det punkt, sætter vi vores avatars 'previous tile' med dens nuværende 'on tile'-attributværdi. Vi kan få denne 'on tile'-værdi fra de tidligere bundter. Vi bevæger derefter vores avatar til vores målpunkter med en varighed på 0,2.

Efter afslutningen af 'Move to point'-adfærden sætter vi nu 'on tile'-attributværdien af vores avatar med 'Get nearest tile'-arrayværdien. Hvis 'Get nearest tile'-arrayværdien ikke er lig med vores 'target tile', vil vi derefter udføre 'Find Path' bundle, og derved gentage hele bundtet igen. 'Target tile'-attributværdien kan hentes fra det tidligere bundle.

Ved at trykke på en hvilken som helst blå flise, og efter at vores avatar vises i gitteret, vil 'Find Path' bundtet blive udført. Dette vil udløse bevægelsen af avatar fra flise til flise.

Konklusion

I denne tutorial har vi lært at lave en objektsstisøgningsaktivitet ved hjælp af et array, som vi kaldte 'Grid', som bruges til at opbevare information om, hvorvidt den flise var optaget eller ej. Du kan udvide denne idé ved at bruge objekts-id'er som informationslagring i stedet for blot et tal for vores 'Grid'-array. Dette vil give os mere pålidelig information, som vi kan bruge, når vi laver stisøgning. For eksempel kan vi få attributterne af det objekts-id for at vide, om det er i live eller ej, og om det vil tillade os at træde på dets flise eller ej.

Denne tutorial har kun tjent den grundlæggende idé bag stisøgning. En ulempe ved dette er, at det ikke skaber den korteste mulige sti til en målflice, og kun tjekker dens nuværende tilstødende flise. Dette kan resultere i en bevægelsesløkke, der ikke når nogen steder.

Men dette kan løses ved at udvide vores stisøgningsalgoritme. Vi kan gøre dette ved at gentage på vores hentede tilstødende fliser for også at få deres tilstødende fliser, indtil vi finder vores målflise. Hver fundet nærmeste tilstødende flise vil blive tilføjet til en liste. For at forhindre en uendelig løkke, skal du tilføje en betingelse, så hvis den tilstødende flise allerede er blevet kontrolleret, ikke bliver den tilføjet til vores liste. Derudover skal du tilføje en maksimal grænse for iterationsantallet for at forhindre en uendelig løkke, der skyldes målflicen, hvis den er for langt væk eller ikke kan findes. Når den iteration finder målflisen, forlader vi derefter den iteration og begynder at bevæge avatar fra flise til flise ved hjælp af fliselisten.