Jag har letat efter internet för att hitta ett effektivt sätt att skapa en procedurell tilemap utan att skapa ett GameObject per kakel. Alla TileMap-handledning jag har hittat skapar brickor genom att skapa hundratals GameObjects. Således utvidgas hierarkin i Unity oväntat.
Jag är ganska säker på att detta inte är det ”rätta” sättet att göra det. Speciellt efter att ha sett de nya Unity 2D-verktygen som stöder tilemaps. Unity gjorde det så, du kan skapa brickor i ”ett” spelobjekt, inte för varje sida.
Så hur gör jag det på rätt och effektivt sätt?
Kommentarer
- Du ’ har korsat detta till två SE-webbplatser. Välj en.
- Vad ’ är ditt specifika intresse för att skapa ett stort antal GameObjects? Om det ’ bara är hierarkisk röran finns det enkla sätt att fixa det. Enhet ’ s batching ska i alla fall kombinera liknande brickor till en enda sats, så det är osannolikt att ’ är en stor utmaning för att göra det på detta sätt. tid som spenderas i brickuppdateringsfunktioner är båda lösbara problem också. Har du profilerat ditt spel och identifierat en specifikation? c flaskhals du ’ försöker du lösa?
- @DMGregory Tja om vi tänker på 100 * 100 kartan på skärmen (om vi antar att vi har zoomat ut för att se hela karta) kommer det att göra 10.000 spelobjekt i scenen. Det betyder också 10.000 onödig transformeringskomponent. Jag vet inte ’ om ens enhet kan stödja 10.000 objekt i hieararchy-fönstret. Jag vet att det fryser efter några hundra.
Svar
Här är det jag känner till:
Alternativ 1. GameObject per sida. I vissa fall är det inte helt hemskt. Beroende på dina behov kan det fungera .. tillräckligt bra.
Alternativ 2. En enda fyrhjuling eller plan som refererar till en struktur du skapar vid körning. använd i huvudsak din kakelatlasstruktur för att ”måla” din karta som en ny konsistens. Beroende på storleken på din karta kan du naturligtvis vilja ha flera fyrhjulingar / plan som var och en representerar delar av din karta.
Alternativ 3. Skapa ditt eget nät. Detta skulle mer än troligen vara den metod som du gillar mest när du har implementerat. Det kommer att ge dig massor av flexibilitet och förmodligen den högsta prestandan. Du skulle i huvudsak skapa en fyrhjuling per sida och ställa in varje topp-UV för att mappa till brickorna i din kakelatlas.
För alternativ 2, jag ” föreslår att du tittar på den här videoserien av quill18creates: 3D TileMap tutorials av quill18creates
För alternativ 3 är det här min kod, med tweaks, så det kanske inte är perfekt:
//For this, your GameObject this script is attached to would have a //Transform Component, a Mesh Filter Component, and a Mesh Renderer //component. You will also need to assign your texture atlas / material //to it. void Start() { meshFilter = GetComponent<MeshFilter>(); BuildMesh(); } public void BuildMesh() { int numTiles = mapSizeX * mapSizeY; int numTriangles = numTiles * 6; int numVerts = numTiles * 4; Vector3[] vertices = new Vector3[numVerts]; UVArray = new Vector2[numVerts]; int x, y, iVertCount = 0; for (x = 0; x < mapSizeX; x++) { for (y = 0; y < mapSizeY; y++) { vertices[iVertCount + 0] = new Vector3(x, y, 0); vertices[iVertCount + 1] = new Vector3(x + 1, y, 0); vertices[iVertCount + 2] = new Vector3(x + 1, y + 1, 0); vertices[iVertCount + 3] = new Vector3(x, y + 1, 0); iVertCount += 4; } } int[] triangles = new int[numTriangles]; int iIndexCount = 0; iVertCount = 0; for (int i = 0; i < numTiles; i++) { triangles[iIndexCount + 0] += (iVertCount + 0); triangles[iIndexCount + 1] += (iVertCount + 1); triangles[iIndexCount + 2] += (iVertCount + 2); triangles[iIndexCount + 3] += (iVertCount + 0); triangles[iIndexCount + 4] += (iVertCount + 2); triangles[iIndexCount + 5] += (iVertCount + 3); iVertCount += 4; iIndexCount += 6; } mesh = new Mesh(); //mesh.MarkDynamic(); if you intend to change the vertices a lot, this will help. mesh.vertices = vertices; mesh.triangles = triangles; meshFilter.mesh = mesh; UpdateMesh(); //I put this in a separate method for my own purposes. } //Note, the example UV entries I have are assuming a tile atlas //with 16 total tiles in a 4x4 grid. public void UpdateMesh() { int iVertCount = 0; for (int x = 0; x < mapSizeX; x++) { for (int y = 0; y < mapSizeY; y++) { UVArray[iVertCount + 0] = new Vector2(0, 0); //Top left of tile in atlas UVArray[iVertCount + 1] = new Vector2(.25f, 0); //Top right of tile in atlas UVArray[iVertCount + 2] = new Vector2(.25f, .25f); //Bottom right of tile in atlas UVArray[iVertCount + 3] = new Vector2(0, .25f); //Bottom left of tile in atlas iVertCount += 4; } } meshFilter.mesh.uv = UVArray; }
Kommentarer
- Dina svar hjälpte mig tillbaka i dagar. Nu tittar jag igenom mina gamla frågor och jag ’ har insett att jag ’ aldrig har kontrollerat detta svar som godkänt. Ledsen för ett evigt sent godkännande ^^ Tack för svaret.
Svar
Som du (tror jag ) antydde att Unitys färdplan har planer på en tilemap-redigerare. Jag ser fram emot det, för just nu är det lite förvirrande hur man går vidare.
Under tiden är det bästa tillvägagångssättet jag ”jag ser är att göra din karta i Tiled och sedan använda X-UniTMX för att importera den till Unity. Uppenbarligen är det dock inte procedurgenerering; jag skulle föreställa mig att du skulle använda samma teknik som X-UniTMX använder för att skapa nätet.
Svar
Du kan bara få brickorna att skapas djupare i hierarkin och stänga den mappen och bry dig inte. Vad du också kan göra är att dölja dina spelobjekt från hierarkin `myTile.hideFlags = HideFlags. HideInHierarchy ”inte säker på hur mycket prestanda skulle uppnås.
Att visa 100×100 texturer på skärmen är aldrig en bra idé att rita texturer är tyngre än att rita polygoner ändå. Om du behöver zooma ut så långt är du bättre med större strukturer. Samma sak gäller att zooma in, du ska inte rita texturerna som inte behöver ritas.
Det jag brukar göra (jag är inte en Unity-kille) är att skapa en klass för en karta och använda en tvådimensionell matris för att hålla alla dina brickor. Denna matris kan helt enkelt vara av ints eller en Tile-klass med ett par ints som hänvisar till dina texturer, kakeltyp, objekt, etc. Sedan skulle man rita den enligt följande:
for (int y = 0; y < mapHeight; y++) { for(int x = 0; x < mapHeight; x++) { Graphics.DrawTexture(new Rect(x * tileWidth, y * tileHeight, tileWidth, tileHeigt), tileTexture); } }
Ritningsmetoden som jag använder verkar vara för att rita ett GUI men kan passa perfekt för uppgiften. Annars måste du gräva i sprite manager och hitta ett sätt som fungerar med den här metoden.
Du kan använda en ordlista för texturreferens som int 1
i din klinkerklass hänvisar till viss struktur och int 2
hänvisar till en annan.På linjen du ritar din textur skulle du använda din ordlista för att ge rätt texturobjekt. På det här sättet ska det inte skapa ett GameObject och därmed inte skapa alla onödiga omkostnader.
Du kan göra detsamma för i stort sett allt som inte behöver kontrollnivån för ett GameObject. Tänk dock, på det här sättet kommer det att rita alla brickor på din karta det troligen inte automatiskt avlägsna objekten som jag tror att enhet gör med spelobjekt. Men att bara rita vad som behöver vara på skärmen är väldigt enkelt. Du känner till skärm- / visningsstorlek, kameraposition och brickstorlek. Någon enkel matte borde rita exakt vad som behövs.
Ändå är enhet en 3D-motor. Den stöder bara 2D på ett 3D-sätt. Men du kan i princip göra samma sak för fyrhjulingar / maskor med texturer och en ortografisk kamera. Att bara rita de maskor som behövs är ganska billigt.
Svar
Som någon som arbetar med voxel / blockbaserat projekt , Jag kan inte låta bli att tänka på att bara använda samma tillvägagångssätt, bara i 2D. Du kan bygga ett rutnätsnät procedurellt och tilldela rätt koordinater för tegelvisuella bilder i din texturatlas till UV-kanal. än att ha hög prestanda, men i 2D är det troligtvis tillräckligt.
Svar
Du kan alltid använda LeanPool . Det är en gratis tillgång i tillgångsbutiken. Det samlar objekt för dig. Då kan du göra ett enkelt avlägsnande system runt kamerans vy som spawns / de spawns tile-objekt när de går in / ut ur kamerans vy. Jag är inte säker på hur stor din tilemap kommer att bli men Unity kan hantera en hel del spelobjekt. LeanPool har riktmärkesscener i Unity där du kan leka / de spawna tusen objekt med boxkollisionskomponenter och jag tror möjligen en renderingsdel också på var och en och det gör det väldigt snabbt.
https://gamedevacademy.org/how-to-script-a-2d-tile-map-in-unity3d/
Här är en länk som visar dig ett exempel på att använda LeanPool med en tilemap.