Dieptesortering kan in eenvoudige bewoordingen worden uitgelegd als een manier om uit te zoeken welk element dichter bij de camera staat en wat verder weg is, waardoor de volgorde wordt bepaald waarin ze moeten worden gerangschikt om de juiste diepte in de scène over te brengen.
In deze zelfstudie gaan we dieper in op dieptesortering voor isometrische niveaus terwijl we proberen bewegende platforms toe te voegen. Dit is geen beginnershandleiding over isometrische theorie en gaat niet over de code. De focus ligt op het begrijpen van de logica en theorie in plaats van de code te ontleden. De tool bij uitstek voor de tutorial is Unity, en daarom is het sorteren van de diepte in wezen het veranderen van de sortingOrder
van de betrokken sprites. Voor andere raamwerken kan het een wijziging van de z-volgorde of de volgorde van de tekenvolgorde zijn.
Raadpleeg deze tutorialserie om aan de slag te gaan met de isometrische theorie. De code en scènestructuur volgen mijn vorige isometrische zelfstudie. Raadpleeg deze als u vindt dat de handleiding moeilijk te volgen is, omdat ik me in deze zelfstudie alleen op de logica richt.
Als uw isometrische niveau geen bewegende elementen heeft of als er slechts een paar tekens over het niveau lopen, is de dieptesortering eenvoudig. In dergelijke gevallen zijn de tekens die de isometrische tegels innemen kleiner dan de tegels zelf en kunnen ze eenvoudig dezelfde tekenvolgorde / diepte gebruiken als de tegel die ze innemen.
Laten we naar onbeweeglijke niveaus verwijzen als statische niveaus. Er zijn een paar manieren waarop dergelijke niveaus kunnen worden getekend, zodat de juiste diepte wordt overgebracht. Doorgaans zullen de niveaudata een tweedimensionale array zijn waarbij de rijen en kolommen overeenkomen met de rijen en kolommen van het niveau.
Beschouw het volgende isometrische niveau met slechts twee rijen en zeven kolommen.
De cijfers op de tegels geven hun aan sortingOrder
of diepte- of z-volgorde, d.w.z. de volgorde waarin ze moeten worden getekend. In deze methode tekenen we alle kolommen in de eerste rij, te beginnen met de eerste kolom met een sortingOrder
van 1.
Nadat alle kolommen in de eerste rij zijn getekend, heeft de dichtstbijzijnde kolom naar de camera een sortingOrder
van 7, en we gaan naar de volgende rij. Dus elk element in de tweede rij zal hoger zijn sortingOrder
dan elk element van de eerste rij.
Dit is precies hoe de tegels moeten worden gerangschikt om de juiste diepte als een sprite met een hogere uit te drukken sortingOrder
wordt over andere sprites gelegd met een lagere sortingOrder
.
Wat betreft de code, dit is gewoon een kwestie van het doorlopen van de rijen en kolommen van de niveau-array en toewijzen sortingOrder
opeenvolgend in een toenemende volgorde. Het zou niet breken, zelfs als we rijen en kolommen ruilen, zoals te zien is in de onderstaande afbeelding.
Hier tekenen we eerst een volledige kolom voordat we naar de volgende rij gaan. De dieptewaarneming blijft intact. Dus de logica voor een statisch niveau is om ofwel een volledige rij ofwel een volledige kolom te tekenen en dan door te gaan naar de volgende tijdens het toewijzen sortingOrder
opeenvolgend in een toenemende volgorde.
Als we het niveau als een gebouw beschouwen, tekenen we momenteel de begane grond. Als we een nieuwe vloer aan ons gebouw moeten toevoegen, hoeven we alleen maar te wachten tot we eerst de hele begane grond hebben getekend en dezelfde methode voor de volgende verdieping hebben gevolgd.
Voor de juiste diepte wachtten we tot de volledige rij voltooid was voordat we naar de volgende rij gingen, en op dezelfde manier wachten we tot alle rijen voltooid zijn voordat we naar de volgende verdieping gaan. Dus voor een niveau met slechts één rij en twee verdiepingen zou het eruitzien als de afbeelding hieronder.
In essentie zal elke tegel op de hogere verdieping hoger zijn sortingOrder
dan elke tegel op de benedenverdieping. Wat betreft de code voor het toevoegen van hogere verdiepingen, hoeven we alleen maar de Y
waarde van de schermcoördinaten voor de tegel, afhankelijk van welke verdieping deze inneemt.
float floorHeight = tileSize / 2.2f; vlotterstroom FloorHeight = floorHeight * floorLevel; // tmpPos = GetScreenPointFromLevelIndices (i, j); tmpPos.y + = currentFloorHeight; tile.transform.position = tmpPos;
De floorHeight
waarde geeft de waargenomen hoogte van het isometrische bloktegelbeeld aan, terwijl etage
geeft aan op welke verdieping de tegel zich bevindt.
Dieptesortering op statisch isometrisch niveau was niet ingewikkeld, toch? Ga verder en laat ons beslissen om de rij eerste methode te volgen, waar we toewijzen sortingOrder
helemaal naar de eerste rij en ga dan verder met de volgende. Laten we eens kijken naar onze eerste bewegende tegel of platform die op één as beweegt, de x-as.
Als ik zeg dat de beweging op de x-as staat, moet je je realiseren dat we het hebben over het cartesiaanse coördinatensysteem en niet het isometrische coördinatensysteem. Laten we een niveau overwegen met alleen een begane grond van drie rijen en zeven kolommen. Laten we ook bedenken dat de tweede rij slechts één tegel heeft, wat onze bewegende tegel is. Het niveau ziet eruit als de onderstaande afbeelding.
De donkere tegel is onze bewegende tegel en de sortingOrder
het zou krijgen toegewezen zal worden 8 als de eerste rij 7 tegels heeft. Als de tegel op de cartesiaanse x-as beweegt, dan beweegt deze over de sleuf tussen de twee rijen. Op alle posities die het langs dat pad kan innemen, zullen de tegels in rij 1 een mindere positie innemen sortingOrder
.
Evenzo zullen alle tegels in rij 2 een hoger cijfer hebben sortingOrder
, ongeacht de positie van de donkere tegel langs dat pad. Dus als we een rij eerst methode van toewijzen volgen sortingOrder
, we hoeven niets te doen voor beweging op de x-as. Dat was makkelijk.
Er ontstaan problemen wanneer we de y-as gaan overwegen. Laten we een niveau bekijken waarin onze donkere tegel langs een rechthoekige greppel beweegt, zoals hieronder wordt weergegeven. Je kunt hetzelfde zien in de MovingSortingProblem
Eenheidsscène in de bron.
Met behulp van onze eerste rij benadering, kunnen we een sortingOrder
voor onze bewegende tegel op basis van de rij die hij momenteel inneemt. Als de steen tussen twee rijen staat, krijgt hij een a toegewezen sortingOrder
op basis van de rij waar hij uitkomt. In dat geval kan het de reeks niet volgen sortingOrder
in de rij waarin het beweegt. Dit breekt in essentie onze aanpak van de dieptesortering.
Om dit op te lossen, moeten we ons niveau onderverdelen in verschillende blokken, waaronder het probleemblok, dat onder onze eerste rij doorbreekt, en de rest zijn blokken die de eerste rij kunnen volgen zonder te breken. Beschouw de afbeelding hieronder voor een beter begrip.
Het tegelblok van 2x2, vertegenwoordigd door het blauwe gebied, is ons probleemblok. Alle andere blokken kunnen nog steeds de eerstvolgende rij volgen. Wees alsjeblieft niet in verwarring door de afbeelding, want deze toont een niveau dat al goed is gesorteerd met behulp van onze blokaanpak. Het blauwe blok bestaat uit de twee kolomtegels in de rijen waartussen onze donkere tegel zich momenteel verplaatst en de tegels onmiddellijk links ervan.
Om het diepteprobleem voor het probleemblok op te lossen, kunnen we alleen de eerste kolomaanpak voor dit blok gebruiken. Dus voor de groene, roze en gele blokken gebruiken we eerst de rij en voor het blauwe blok gebruiken we de eerste kolombenadering.
Merk op dat we nog steeds achter elkaar moeten toewijzen sortingOrder
. Eerst het groene blok, dan het roze blok naar links, dan het blauwe blok, nu komt het roze blok naar rechts en tenslotte het gele blok. We breken de volgorde alleen om over te schakelen naar de eerste kolom naderen bij het blauwe blok.
Als alternatief kunnen we ook het blok 2x2 aan de rechterkant van de kolom met bewegende tegels bekijken. (Het interessante is dat je niet eens van aanpak hoeft te wisselen omdat het inbreken van blokken zelf ons probleem in dit geval al heeft opgelost.) De oplossing is zichtbaar in de actie in de BlockSort
tafereel.
Dit vertaalt zich naar code zoals hieronder.
private void DepthSort () Vector2 movingTilePos = GetLevelIndicesFromScreenPoint (movingGO.transform.position); int blockColStart = (int) movingTilePos.y; int blockRowStart = (int) movingTilePos.x; int diepte = 1; // sorteer rijen voor blok voor (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; // nieuwe diepte diepte ++; // increment depth else depth = AssignDepth (i, j, depth); // sorteer kolommen in dezelfde rij na het blok voor (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);
Een beweging in de z-as is een nepbeweging op isometrisch niveau. Het is in wezen gewoon beweging op de y-as van het scherm. Voor een isometrisch niveau op één verdieping hoeft u niets meer te doen om beweging op de z-as toe te voegen als u de hierboven beschreven bloksorteermethode al hebt uitgevoerd. Je kunt dit in actie zien in de SingleLayerWave
Unity-scène, waarbij ik een extra golfbeweging op de z-as heb toegevoegd, samen met de beweging van de laterale greppel.
Het toevoegen van een extra verdieping aan uw niveau is slechts een kwestie van het compenseren van de scherm-y-coördinaat, zoals eerder uitgelegd. Als de tegel niet op de z-as beweegt, hoeft er niets speciaals te worden gedaan voor het sorteren van de diepte. We kunnen de begane grond blokkeren met beweging en vervolgens rij eerste sortering toepassen op elke volgende verdieping. Je kunt dit in actie zien in de BlockSortWithHeight
Unity-scène.
Een zeer vergelijkbaar diepteprobleem ontstaat wanneer de tegel tussen verdiepingen begint te bewegen. Het kan alleen voldoen aan de volgorde van een verdieping met behulp van onze aanpak en zou de dieptesortering van de andere verdieping doorbreken. We moeten onze bloksortering uitbreiden tot drie dimensies om met dit diepteprobleem met vloeren om te gaan.
Het probleem zal in wezen alleen de twee verdiepingen zijn waartussen de tegel zich momenteel verplaatst. Voor alle andere verdiepingen kunnen we ons houden aan onze huidige sorteerbenadering. Speciale behoeften gelden alleen voor deze twee verdiepingen, waaronder we eerst de benedenverdieping kunnen bepalen zoals hieronder tileZOffset
is de hoeveelheid beweging op de z-as voor onze bewegende tegel.
float whichFloor = (tileZOffset / floorHeight); zweven lager = Mathf.Floor (whichFloor);
Dit betekent dat lager
en lagere + 1
zijn de vloeren die een speciale aanpak nodig hebben. De kunst is om toe te wijzen sortingOrder
voor beide verdiepingen samen, zoals weergegeven in de onderstaande code. Hiermee wordt de reeks opgelost, zodat de diepteproblemen worden opgelost.
if (floor == lower) // we moeten de onderste verdieping en de verdieping er net boven samen in één go diepte sorteren = (floor * (rijen * cols)) + 1; int nextFloor = verdieping + 1; if (nextFloor> = totalFloors) nextFloor = vloer; // sorteer rijen voor blok voor (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; // nieuwe diepte diepte ++; // increment depth else depth = AssignDepth (i, j, depth, floor); diepte = AssignDepth (i, j, diepte nextFloor); // sorteer kolommen in dezelfde rij na het blok voor (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);
In essentie overwegen we twee verdiepingen als een enkele verdieping en doen we een bloksoort op die ene verdieping. Bekijk de code en actie in de scène BlockSortWithHeightMovement
. Met deze benadering is onze tile nu vrij om op een van de twee assen te bewegen zonder de diepte van de scène te onderbreken, zoals hieronder wordt getoond.
Het idee van deze tutorial was om de logica van de dieptesorteringsbenaderingen te verduidelijken en ik hoop dat je dit redelijk begrepen hebt. Het is duidelijk dat we relatief eenvoudige niveaus overwegen met slechts één bewegende steen.
Er zijn geen hellingen, ook niet als hellingen dit een veel langere zelfstudie zouden hebben gemaakt. Maar als u eenmaal de sorteerlogica hebt begrepen, kunt u proberen de tweedimensionale hellingslogica uit te breiden naar de isometrische weergave.
Eenheid heeft een actieve economie. Er zijn veel andere producten die u helpen uw project uit te bouwen. De aard van het platform maakt het ook een geweldige optie van waaruit je je vaardigheden kunt verbeteren. Hoe het ook zij, u kunt zien wat we beschikbaar hebben op de Envato-markt.