Ho cercato in Internet un modo efficiente per creare una tilemap procedurale senza creare un GameObject per tile. Tutti i tutorial su TileMap che ho trovato creano tessere creando centinaia di GameObject. Quindi la gerarchia in Unity si sta espandendo in modo imprevisto.
Sono abbastanza sicuro che questo non sia il modo “giusto” per farlo. Soprattutto dopo aver visto i nuovi strumenti Unity 2D che supportano le tilemap. Unity lo ha fatto, puoi creare tessere in “un” oggetto di gioco, non per ciascuna tessera.
Quindi, come posso farlo nel modo giusto ed efficace?
Commenti
- Hai ‘ cross postato su due siti SE. Scegline uno.
- Cosa ‘ è il tuo problema specifico con la creazione di un gran numero di GameObjects? Se ‘ è solo un disordine gerarchico, ci sono modi semplici per risolverlo. Unity ‘ il raggruppamento in batch dovrebbe comunque combinare tessere simili in un unico batch, quindi ‘ è improbabile che sia una penalità di pareggio importante per farlo in questo modo. Ridurre al minimo i riquadri fuori schermo e Anche il tempo speso nelle funzioni di aggiornamento delle tessere è un problema risolvibile. Hai profilato il tuo gioco e identificato una specifica c collo di bottiglia che ‘ stai cercando di risolvere?
- @DMGregory Bene, se pensiamo alla mappa 100 * 100 sullo schermo (se supponiamo di aver ingrandito per vedere lintera map), creerà 10.000 oggetti di gioco nella scena. Significa anche 10.000 componenti trasformate non cesarie. Non ‘ so nemmeno se lunità può supportare 10.000 oggetti nella finestra della gerarchia. So che si blocca dopo duecento.
Rispondi
Ecco cosa sono a conoscenza:
Opzione 1. GameObject per tessera. Non è completamente orribile in alcuni casi. A seconda delle tue esigenze, potrebbe funzionare … abbastanza bene.
Opzione 2. Un singolo quad o piano che fa riferimento a una trama che crei in fase di esecuzione. essenzialmente utilizza la trama dellatlante delle tessere per “dipingere” la mappa come una nuova trama. A seconda delle dimensioni della mappa, ovviamente, potresti voler avere più quad / piani, ciascuno dei quali rappresenta porzioni della tua mappa.
Opzione 3. Crea la tua mesh. Questo sarebbe molto probabilmente il metodo che ti piacerà di più una volta implementato. Ti darà un sacco di flessibilità e probabilmente le massime prestazioni. Creeresti essenzialmente un quadruplo per tessera e imposterai ogni vertice UV per mappare alle tessere nel tuo atlante delle tessere.
Per lopzione 2, I ” Suggerisco di guardare questa serie di video di quill18creates: Serie di tutorial 3D TileMap di quill18creates
Per lopzione 3, questo è il mio codice, con modifiche, quindi potrebbe non essere perfetto:
//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; }
Commenti
- Le tue risposte mi hanno aiutato nel giorni. Ora, sto esaminando le mie vecchie domande e ‘ mi sono reso conto che ‘ non ho mai verificato questa risposta come accettata. Ci scusiamo per uneternità di approvazione in ritardo ^^ Grazie per la risposta.
Risposta
Come tu (penso ) alluso, la roadmap di Unity ha in programma un editor di tilemap. Non vedo lora, perché in questo momento “è un po complicato come procedere.
Nel frattempo, lapproccio migliore che ho “Ciò che vedo è creare la tua mappa in Tiled e quindi utilizzare X-UniTMX per importarla in Unity. Ovviamente questa non è una generazione procedurale; immagino che useresti la stessa tecnica usata da X-UniTMX per creare la mesh.
Risposta
Potresti semplicemente creare le tessere più in profondità nella gerarchia e chiudere quella cartella e non essere disturbato. Ciò che puoi fare è nascondere i tuoi oggetti di gioco dalla gerarchia `myTile.hideFlags = HideFlags. HideInHierarchy “non è sicuro di quante prestazioni si otterrebbero.
Mostrare trame 100×100 sullo schermo non è mai una buona idea disegnare trame è più pesante che disegnare poligoni comunque. Se devi rimpicciolire così tanto, stai meglio con trame più grandi. Lo stesso vale per lingrandimento, non dovresti disegnare le trame che non è necessario disegnare.
Quello che di solito faccio (non sono un tipo di Unity) è creare una classe per una mappa e utilizzare un array bidimensionale per contenere tutte le tue tessere. Questo array potrebbe essere semplicemente di int o una classe Tile con un paio di int che si riferiscono alle tue trame, tipo di tessera, oggetti, ecc. Quindi uno lo disegnerebbe come segue:
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); } }
Il metodo di disegno che uso sembra essere quello di disegnare una GUI ma potrebbe essere perfettamente adatto per il compito. Altrimenti devi scavare nel gestore di sprite e trovare un modo che funziona con questo metodo.
Potresti usare un dizionario per riferimento alle texture come int 1
nella tua classe di tile fa riferimento ad alcune texture e int 2
si riferisce a un altro.Nella riga in cui stai disegnando la tua texture useresti il dizionario per dare il giusto oggetto texture. In questo modo non dovrebbe creare un GameObject e quindi non creare tutto il sovraccarico non necessario.
Puoi fare lo stesso praticamente per tutto ciò che non necessita del livello di controllo di un GameObject. Attenzione però, in questo modo disegnerà ogni tessera della tua mappa, molto probabilmente non selezionerà automaticamente gli oggetti come penso che lunità faccia con gli oggetti del gioco. Ma disegnare ciò che deve essere sullo schermo è molto semplice. Conosci le dimensioni dello schermo / area di visualizzazione, la posizione della telecamera e le dimensioni delle tessere. Alcuni semplici calcoli dovrebbero disegnare esattamente ciò di cui hai bisogno.
Tuttavia, unity è un motore 3D. Supporta solo il 2D in modo 3D. Ma in pratica puoi fare la stessa cosa per quad / mesh con trame e una fotocamera ortografica. Disegnare solo le trame necessarie è piuttosto economico.
Rispondi
Come qualcuno che lavora su un progetto basato su voxel / blocchi , Non posso fare a meno di pensare di utilizzare lo stesso approccio, solo in 2D. Puoi costruire una mesh simile a una griglia proceduralmente e assegnare le giuste coordinate delle immagini delle tessere nel tuo atlante delle texture al canale UV. In 3D devi fare molto più lavoro rispetto a questo per avere prestazioni elevate, ma in 2D molto probabilmente è davvero sufficiente.
Risposta
Puoi sempre usare LeanPool . È una risorsa gratuita nel negozio di risorse. Fa il pool di oggetti per te. Quindi puoi eseguire un semplice sistema di eliminazione attorno alla vista delle telecamere che genera / de spawn gli oggetti di gioco delle tessere quando entrano / escono dalla vista delle telecamere. Non sono sicuro di quanto sarà grande la tua mappa delle tessere, ma Unity può gestire un bel po di oggetti di gioco. LeanPool ha scene di benchmark in Unity in cui puoi generare / de spawnare migliaia di oggetti con componenti box collision e penso che forse anche un componente di rendering su ciascuno di essi e lo fa molto molto rapidamente.
https://gamedevacademy.org/how-to-script-a-2d-tile-map-in-unity3d/
Ecco un link che ti mostrerà un esempio di utilizzo di LeanPool con una tilemap.