Einheitliche prozedurale TileMap-Generierung ohne Erstellen eines Spielobjekts pro Kachel

Ich habe im Internet nach einer effizienten Möglichkeit gesucht, eine prozedurale Kachelkarte zu erstellen, ohne ein GameObject pro Kachel zu erstellen. Alle TileMap-Tutorials, die ich gefunden habe, erstellen Kacheln, indem Sie Hunderte von GameObjects erstellen. Daher wird die Hierarchie in Unity unerwartet erweitert.

Ich bin mir ziemlich sicher, dass dies nicht der „richtige“ Weg ist, dies zu tun. Insbesondere nachdem ich die neuen Unity 2D-Tools gesehen habe, die Tilemaps unterstützen. Unity hat es so gemacht. Sie können Kacheln in „einem“ Spielobjekt erstellen, nicht für jede Kachel.

Wie mache ich das richtig und effizient?

Kommentare

  • Sie ‚ haben dies auf zwei SE-Sites gepostet. Wählen Sie eine aus.
  • Was ‚ ist Ihr spezielles Anliegen beim Erstellen einer großen Anzahl von GameObjects? Wenn ‚ nur Hierarchie-Unordnung ist, gibt es einfache Möglichkeiten, dies zu beheben. Einheit ‚ sollten ähnliche Kacheln ohnehin zu einer einzigen Charge kombiniert werden. Daher ist es unwahrscheinlich, dass ‚ auf diese Weise eine erhebliche Strafe für Draw Calls darstellt. Minimierung von Kacheln außerhalb des Bildschirms und Die für Kachelaktualisierungsfunktionen aufgewendete Zeit ist ebenfalls ein lösbares Problem. Haben Sie Ihr Spiel profiliert und eine bestimmte identifiziert? c Engpass Sie ‚ versuchen zu lösen?
  • @DMGregory Nun, wenn wir über 100 * 100 Karte im Bildschirm nachdenken (wenn wir annehmen, dass wir herausgezoomt haben, um das Ganze zu sehen Karte) werden 10.000 Spielobjekte in der Szene erstellt. Dies bedeutet auch 10.000 unnötige Transformationskomponenten. Ich ‚ weiß nicht einmal, ob Unity 10.000 Objekte im Hieararchy-Fenster unterstützen kann. Ich weiß, dass es nach ein paar hundert einfriert.

Antwort

Folgendes ist mir bekannt:

Option 1. GameObject pro Kachel. In bestimmten Fällen ist es nicht ganz schrecklich. Abhängig von Ihren Anforderungen könnte es gut genug funktionieren.

Option 2. Ein einzelnes Quad oder eine Ebene, die auf eine Textur verweist, die Sie zur Laufzeit erstellen Verwenden Sie im Wesentlichen Ihre Kachelatlas-Textur, um Ihre Karte als eine neue Textur zu „malen“. Abhängig von der Größe Ihrer Karte möchten Sie möglicherweise mehrere Quads / Ebenen haben, die jeweils Teile Ihrer Karte darstellen.

Option 3. Erstellen Sie Ihr eigenes Netz. Dies ist höchstwahrscheinlich die Methode, die Sie nach der Implementierung am liebsten mögen. Dies bietet Ihnen eine Menge Flexibilität und wahrscheinlich die höchste Leistung. Sie würden im Wesentlichen ein Quad pro Kachel erstellen und jeden Scheitelpunkt-UV so einstellen, dass er den Kacheln in Ihrem Kachelatlas zugeordnet wird.

Für Option 2, I “ Ich schlage vor, diese Videoserie von quill18creates anzusehen: 3D-TileMap-Lernserie von quill18creates

Für Option 3 ist dies mein Code mit Optimierungen. Daher ist es möglicherweise nicht 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; } 

Kommentare

  • Ihre Antworten haben mir in der Vergangenheit geholfen Tage. Jetzt schaue ich meine alten Fragen durch und habe ‚ festgestellt, dass ich ‚ diese Antwort nie als akzeptiert überprüft habe. Entschuldigung für eine ewige verspätete Genehmigung ^^ Danke für die Antwort.

Antwort

Wie Sie (glaube ich) ) angedeutet, Unitys Roadmap hat Pläne für einen Tilemap-Editor. Ich freue mich darauf, denn im Moment ist es ein wenig verwirrend, wie man vorgeht.

In der Zwischenzeit ist der beste Ansatz ich Ich sehe, dass Sie Ihre Karte in Tiled erstellen und dann mit X-UniTMX in Unity importieren müssen. Offensichtlich ist dies jedoch keine prozedurale Generierung. Ich würde mir vorstellen, dass Sie dieselbe Technik verwenden würden, die X-UniTMX zum Erstellen des Netzes verwendet.

Antwort

Sie könnten einfach die Kacheln tiefer in der Hierarchie erstellen lassen und diesen Ordner schließen, ohne sich darum zu kümmern. Sie können Ihre Spielobjekte auch vor der Hierarchie „myTile.hideFlags = HideFlags“ verstecken. HideInHierarchy „nicht sicher, wie viel Leistung erzielt werden würde.

Das Anzeigen von 100×100-Texturen auf dem Bildschirm ist niemals eine gute Idee. Das Zeichnen von Texturen ist ohnehin schwerer als das Zeichnen von Polygonen. Wenn Sie so weit herauszoomen müssen, sind Sie mit größeren Texturen besser dran. Gleiches gilt für das Vergrößern. Sie sollten keine Texturen zeichnen, die nicht gezeichnet werden müssen.

Was ich normalerweise mache (ich bin kein Unity-Typ), ist das Erstellen einer Klasse für eine Karte und deren Verwendung Ein zweidimensionales Array zum Speichern aller Kacheln. Dieses Array kann einfach aus Ints oder einer Kachelklasse mit einigen Ints bestehen, die sich auf Ihre Texturen, Kacheltypen, Objekte usw. beziehen. Dann würde man es wie folgt zeichnen:

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); } } 

Die von mir verwendete Zeichenmethode scheint zum Zeichnen einer GUI zu sein, ist jedoch möglicherweise perfekt für die Aufgabe geeignet. Andernfalls müssen Sie sich in den Sprite-Manager vertiefen und einen Weg finden Dies funktioniert mit dieser Methode.

Sie können ein Wörterbuch als Texturreferenz verwenden, z. B. int 1 in Ihrer Kachelklasse bezieht sich auf eine Textur und bezieht sich auf einen anderen.In der Linie, in der Sie Ihre Textur zeichnen, würden Sie Ihr Wörterbuch verwenden, um das richtige Texturobjekt zu erhalten. Auf diese Weise sollte kein GameObject erstellt werden und somit nicht der gesamte unnötige Overhead.

Sie können dasselbe für so ziemlich alles tun, für das nicht die Steuerungsebene eines GameObject erforderlich ist. Beachten Sie jedoch, dass auf diese Weise jedes Plättchen Ihrer Karte gezeichnet wird und die Objekte höchstwahrscheinlich nicht automatisch ausgesondert werden, wie es meiner Meinung nach die Einheit mit Spielobjekten tut. Aber nur zu zeichnen, was auf dem Bildschirm angezeigt werden muss, ist sehr einfach. Sie kennen die Bildschirm- / Ansichtsfenstergröße, die Kameraposition und die Kachelgröße. Einige einfache Berechnungen sollten genau das zeichnen, was benötigt wird.

Dennoch ist Unity eine 3D-Engine. Sie unterstützt 2D nur auf 3D-Weise. Grundsätzlich können Sie jedoch dasselbe für Quads / Meshes mit Texturen und tun eine orthografische Kamera. Nur die benötigten Netze zu zeichnen, ist ziemlich billig.

Antwort

Als jemand, der an einem voxel- / blockbasierten Projekt arbeitet Ich kann nicht anders, als darüber nachzudenken, nur denselben Ansatz zu verwenden, nur in 2D. Sie können prozedural ein gitterartiges Netz erstellen und dem UV-Kanal die richtigen Koordinaten der Kachelvisualisierungen in Ihrem Texturatlas zuweisen. In 3D müssen Sie viel mehr Arbeit leisten als dies, um eine hohe Leistung zu erzielen, aber in 2D ist es sehr wahrscheinlich genug.

Antwort

Sie können immer LeanPool verwenden . Es ist ein kostenloses Asset im Asset Store. Es führt Objektpooling für Sie durch. Dann können Sie ein einfaches Cull-System um die Kameraansicht herum erstellen, das beim Betreten / Verlassen der Kameraansicht Kachelspielobjekte erzeugt / de erzeugt. Ich bin mir nicht sicher, wie groß Ihre Tilemap sein wird, aber Unity kann eine ganze Reihe von Spielobjekten bewältigen. LeanPool hat Benchmark-Szenen in Unity, in denen Sie tausend Objekte mit Box-Kollisionskomponenten spawnen / spawnen können, und ich denke, möglicherweise auch eine Render-Komponente für jede einzelne, und das sehr, sehr schnell.

https://gamedevacademy.org/how-to-script-a-2d-tile-map-in-unity3d/

Hier ist ein Link, der Sie anzeigt Ein Beispiel für die Verwendung von LeanPool mit einer Tilemap.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.