Dybdsortering kan forklares med enkle uttrykk som en måte å finne ut hvilket element som er nærmere kameraet, og som er lengre unna, og derved bestemme rekkefølgen de må ordnes for for å formidle riktig dybde i scenen.
I denne veiledningen vil vi grave dypere inn i dybdesortering for isometriske nivåer som vi prøver å legge til flyttbare plattformer. Dette er ikke en nybegynneropplæring om isometrisk teori og handler ikke om koden. Fokus er å forstå logikken og teorien i stedet for å dissektere koden. Valg av verktøy for opplæringen er Unity, og derfor er dybdsortering i hovedsak endring av sortingOrder
av sprites involvert. For andre rammer kan det være en endring av z-ordren eller sekvensen av tegningsordre.
For å komme i gang med isometrisk teori, vennligst se denne opplæringsserien. Koden og scenestrukturen følger min tidligere isometriske opplæring. Vennligst referer til disse hvis du finner opplæringen vanskelig å følge da jeg bare vil fokusere på logikk i denne opplæringen.
Hvis ditt isometriske nivå ikke har noen bevegelige elementer, eller bare noen få tegn går over nivået, er dybdsorteringen enkel. I slike tilfeller vil tegnene som okkuperer isometriske fliser være mindre enn flisene selv og kan enkelt bare bruke samme tegningsorden / dybde som flisen de opptar.
La oss referere til slike ubevegelige nivåer som statiske nivåer. Det er noen måter der slike nivåer kan tegnes slik at den riktige dybden blir formidlet. Vanligvis vil nivådataene være et todimensjonalt array hvor radene og kolonnene vil korrespondere med rader og kolonner av nivået.
Vurder følgende isometriske nivå med bare to rader og syv kolonner.
Tallene på flisene indikerer deres sortingOrder
eller dybde- eller z-ordre, dvs. ordren der de må tegnes. I denne metoden tegner vi alle kolonnene i første rad, begynner med den første kolonnen med a sortingOrder
av 1.
Når alle kolonnene er tegnet i første rad, har nærmeste kolonne til kameraet a sortingOrder
av 7, og vi fortsetter til neste rad. Så et element i den andre raden vil ha en høyere sortingOrder
enn noe element i første rad.
Dette er akkurat slik flisene må ordnes for å formidle den riktige dybden som et sprite med en høyere sortingOrder
vil bli overlaid over noen andre sprites med lavere sortingOrder
.
Når det gjelder koden, handler dette bare om å løpe gjennom rader og kolonner av nivået array og tilordne sortingOrder
sekvensielt i en økende rekkefølge. Det ville ikke bryte, selv om vi bytter rader og kolonner, som det kan sees på bildet nedenfor.
Her tegner vi en komplett kolonne først før du går videre til neste rad. Dybdeoppfattelsen forblir intakt. Så logikken for et statisk nivå er å tegne enten en komplett rad eller komplett kolonne og deretter fortsette til neste mens tildeling sortingOrder
sekvensielt i en økende rekkefølge.
Hvis vi vurderer nivået som en bygning, drar vi for øyeblikket i første etasje. Hvis vi trenger å legge til en ny etasje i bygningen vår, er alt vi trenger å vente til vi tegner hele første etasje først og følger samme metode for neste etasje.
For riktig dybde ventet vi til hele raden var ferdig før vi flyttet til neste rad, og på samme måte venter vi til alle radene er ferdige før vi flytter til neste etasje. Så for et nivå med bare en enkelt rad og to etasjer, ville det se ut som bildet nedenfor.
I hovedsak vil alle fliser på høyere etasje ha høyere sortingOrder
enn noen fliser i underetasjen. Når det gjelder koden for å legge til høyere etasjer, trenger vi bare å kompensere y
verdien av skjermkoordinatene til flisene, avhengig av hvilken gulv den opptar.
float floorHeight = fliser Størrelse / 2,2f; float currentFloorHeight = floorHeight * floorLevel; // tmpPos = GetScreenPointFromLevelIndices (jeg, j); tmpPos.y + = currentFloorHeight; tile.transform.position = tmpPos;
De floorHeight
verdien indikerer den oppfattede høyden til det isometriske blokkflisen, mens floorLevel
angir hvilket gulv flisene okkuperer.
Dybde sortering på et statisk isometrisk nivå var ikke komplisert, ikke sant? Fortsett, la oss bestemme oss for å følge radens første metode, hvor vi tildeler sortingOrder
til første rad helt og fortsett til neste. La oss vurdere vår første flyttefliser eller plattform som beveger seg på en enkelt akse, x-aksen.
Når jeg sier at bevegelsen er på x-aksen, må du innse at vi snakker om det kartesiske koordinatsystemet og ikke det isometriske koordinatsystemet. La oss vurdere et nivå med bare en etasje i tre rader og syv kolonner. La oss også vurdere at den andre raden bare har en enkelt flis, som er vår flyttefliser. Nivået vil se ut som bildet nedenfor.
Den mørke flisen er vår bevegelige flis, og sortingOrder
det ville bli tildelt vil være 8 som den første raden har 7 fliser. Hvis flisen beveger seg på den kartesiske x-aksen, vil den bevege seg langs grøften mellom de to radene. På alle stillingene som det kan oppta langs den banen, vil flisene i rad 1 ha en mindre sortingOrder
.
På samme måte vil alle fliser i rad 2 ha høyere sortingOrder
, uavhengig av posisjonen til den mørke flisen langs banen. Så som vi følger en rad første metode for tildeling sortingOrder
, vi trenger ikke å gjøre noe for bevegelse på x-aksen. Nå var det enkelt.
Problemer begynner å oppstå når vi begynner å vurdere y-aksen. La oss vurdere et nivå der vår mørke flis beveger seg langs en rektangulær grøft, som vist nedenfor. Du kan se det samme i MovingSortingProblem
Enhetsscene i kilden.
Ved hjelp av vår første tilnærming, kan vi gi en sortingOrder
for vår flyttefliser basert på raden den for tiden bruker. Når flisen er mellom to rader, vil den bli tildelt a sortingOrder
basert på raden den beveger seg fra. I så fall kan det ikke følge sekvensielt sortingOrder
i raden inn i hvilken den beveger seg. Dette bryter i hovedsak vår dybdesorteringsmetode.
For å løse dette må vi dele vårt nivå i forskjellige blokker, blant hvilke er problemblokken, som bryter under vår rad første tilnærming, og resten er blokker som kan følge raden første tilnærming uten å bryte. Vurder bildet nedenfor for å få bedre forståelse.
Den 2x2 fliseblokk representert av det blå området er vår problemblokk. Alle de andre blokkene kan fortsatt følge radens første tilnærming. Vær ikke forvirret av bildet, da det viser et nivå som allerede er riktig sortert ved hjelp av vår blokke tilnærming. Den blå blokken består av de to kolonnefliser i rader mellom hvilke våre mørke fliser nå beveger seg og flisene umiddelbart til venstre for dem.
For å løse dybdeproblemet for problemblokken, kan vi bruke kolonnens første tilnærming for denne blokken alene. Så for de grønne, rosa og gule blokkene bruker vi først rad, og for den blå blokken bruker vi kolonne første tilnærming.
Legg merke til at vi fortsatt må sekvensielt tilordne sortingOrder
. Først den grønne blokken, den rosa blokken til venstre, den blå blokken, kommer nå den rosa blokken til høyre, og til slutt den gule blokken. Vi bryter ordren bare for å bytte til kolonne første tilnærming mens den blå blokken.
Alternativt kan vi også vurdere 2x2-blokken til høyre for den bevegelige flisekolonnen. (Det interessante er at du ikke engang trenger å bytte tilnærminger som å bryte inn blokker selv har allerede løst vårt problem i dette tilfellet.) Løsningen kan ses i aksjon i BlockSort
scene.
Dette oversetter til kode som nedenfor.
privat tomrom DepthSort () Vector2 movingTilePos = GetLevelIndicesFromScreenPoint (movingGO.transform.position); int blockColStart = (int) movingTilePos.y; int blockRowStart = (int) movingTilePos.x; int dybde = 1; // sorteringsrader før blokk for (int i = 0; i < blockRowStart; i++) for (int j = 0; j < cols; j++) depth=AssignDepth(i,j,depth); //sort columns in same row before the block for (int i = blockRowStart; i < blockRowStart+2; i++) for (int j = 0; j < blockColStart; j++) depth=AssignDepth(i,j,depth); //sort block for (int i = blockRowStart; i < blockRowStart+2; i++) for (int j = blockColStart; j < blockColStart+2; j++) if(movingTilePos.x==i&&movingTilePos.y==j) SpriteRenderer sr=movingGO.GetComponent(); sr.sortingOrder = depth; // tilordne ny dybde dybde ++; // trinn dybde annet deep = AssignDepth (i, j, dybde); // sorter kolonner i samme rad etter blokken for (int i = blockRowStart; i < blockRowStart+2; i++) for (int j = blockColStart+2; j < cols; j++) depth=AssignDepth(i,j,depth); //sort rows after block for (int i = blockRowStart+2; i < rows; i++) for (int j = 0; j < cols; j++) depth=AssignDepth(i,j,depth);
En bevegelse i z-aksen er en falsk bevegelse på et isometrisk nivå. Det er i hovedsak bare bevegelse på skjermens y-akse. For et isometrisk nivå i et etasje er det ikke noe mer å gjøre for å legge til bevegelse på z-aksen hvis du allerede har gjort blokk sorteringsmetoden beskrevet ovenfor. Du kan se dette i aksjon i SingleLayerWave
Unity scene, hvor jeg har lagt til en ekstra bølge bevegelse på z-aksen sammen med lateral trench bevegelse.
Å legge til en ekstra etasje til ditt nivå er bare et spørsmål om å kompensere skjermens y-koordinat, som forklart før. Hvis flisen ikke beveger seg på z-aksen, er det ikke nødvendig å gjøre noe spesielt for dybdsortering. Vi kan blokkere sortering av første etasje med bevegelse og deretter bruke rad første sortering til hver påfølgende gulv. Du kan se dette i aksjon i BlockSortWithHeight
Enhets scene.
Et meget lignende dybdeproblem oppstår når flisene begynner å bevege seg mellom gulvene. Det kan bare tilfredsstille sekvensiell rekkefølge av en etasje ved hjelp av vår tilnærming og ville bryte dybdesorteringen av den andre etasjen. Vi må utvide eller modifisere vår blokk sortering til tre dimensjoner for å håndtere dette dybdeproblemet med gulv.
Problemet vil i hovedsak bare være de to etasjene mellom hvilke flisene for tiden beveger seg. For alle andre etasjer kan vi holde fast ved vår nåværende sorteringsmetode. Spesielle behov gjelder kun disse to etasjene, blant annet kan vi først bestemme underetasjen som under hvor tileZOffset
er mengden bevegelse på z-aksen for flytteflisen vår.
flyte whichFloor = (tileZOffset / floorHeight); flyte ned = Mathf.Floor (whichFloor);
Dette betyr at Nedre
og lavere + 1
er gulvene som trenger en spesiell tilnærming. Trikset er å tildele sortingOrder
for begge disse gulvene sammen, som vist i koden nedenfor. Dette løser sekvensen slik at dybdeproblemene blir sortert ut.
hvis (gulv == lavere) // vi må sortere nedre etasje og gulvet rett over det sammen på en gang dybde = (gulv * (rader * kols)) + 1; int nextFloor = gulv + 1; if (nextFloor> = totalFloors) nextFloor = gulvet; // sorteringsrader før blokk for (int i = 0; i < blockRowStart; i++) for (int j = 0; j < cols; j++) depth=AssignDepth(i,j,depth,floor); depth=AssignDepth(i,j,depth,nextFloor); //sort columns in same row before the block for (int i = blockRowStart; i < blockRowStart+2; i++) for (int j = 0; j < blockColStart; j++) depth=AssignDepth(i,j,depth,floor); depth=AssignDepth(i,j,depth,nextFloor); //sort block for (int i = blockRowStart; i < blockRowStart+2; i++) for (int j = blockColStart; j < blockColStart+2; j++) if(movingTilePos.x==i&&movingTilePos.y==j) SpriteRenderer sr=movingGO.GetComponent(); sr.sortingOrder = depth; // tilordne ny dybde dybde ++; // trinn dybde else depth = AssignDepth (jeg, j, dybde, gulv); dybde = AssignDepth (i, j, dybde, nextFloor); // sorter kolonner i samme rad etter blokken for (int i = blockRowStart; i < blockRowStart+2; i++) for (int j = blockColStart+2; j < cols; j++) depth=AssignDepth(i,j,depth,floor); depth=AssignDepth(i,j,depth,nextFloor); //sort rows after block for (int i = blockRowStart+2; i < rows; i++) for (int j = 0; j < cols; j++) depth=AssignDepth(i,j,depth,floor); depth=AssignDepth(i,j,depth,nextFloor);
I hovedsak vurderer vi to etasjer som en etasje og gjør en blokk sortering på den ene etasjen. Sjekk ut koden og handlingen i scenen BlockSortWithHeightMovement
. Med denne tilnærmingen er flisen vår nå fri til å bevege seg på noen av de to aksene uten å bryte dybden av scenen, som vist nedenfor.
Tanken med denne opplæringen var å klargjøre logikken i dybdesorteringsmetodene, og jeg håper du har forstått dette. Det er tydelig at vi vurderer relativt enkle nivåer med bare en flytteflise.
Det er ingen bakker enten som blant annet løyper ville ha gjort dette til en mye lengre opplæring. Men når du har forstått sorteringslogikken, kan du prøve å forlenge den todimensjonale hellingslogikken til isometrisk visning.
Enhet har en aktiv økonomi. Det er mange andre produkter som hjelper deg med å bygge opp prosjektet ditt. Plattformens natur gjør det også til et flott alternativ som du kan forbedre dine ferdigheter. Uansett kan du se hva vi har tilgjengelig på Envato Market.