Generowanie proceduralnych TileMap w Unity bez tworzenia obiektu gry dla każdego kafelka

Przeszukiwałem internet, aby znaleźć skuteczny sposób na utworzenie proceduralnej mapy kafelkowej bez tworzenia GameObject na kafelek. Wszystkie samouczki TileMap, które znalazłem, tworzą kafelki, tworząc setki obiektów GameObject. W ten sposób hierarchia w Unity rozszerza się nieoczekiwanie.

Jestem prawie pewien, że to nie jest „właściwy” sposób, aby to zrobić. Zwłaszcza po obejrzeniu nowych narzędzi Unity 2D, które obsługują mapy tilemaps. Dzięki Unity tak było, możesz tworzyć kafelki w „jednym” obiekcie gry, a nie dla każdego kafelka.

Więc jak mam to zrobić we właściwy i efektywny sposób?

Komentarze

  • ' przesłałeś to na dwie SE. Wybierz jedną.
  • Co ' czy Twoim szczególnym problemem jest tworzenie dużej liczby obiektów GameObject? Jeśli ' to tylko bałagan w hierarchii, istnieją proste sposoby, aby to naprawić. Unity ' batching powinien i tak łączyć podobne kafelki w jedną partię, więc ' raczej nie będzie stanowić dużej kary za remis przy zrobieniu tego w ten sposób. Minimalizacja kafelków poza ekranem i Czas spędzony na funkcjach aktualizacji kafelków to również problemy do rozwiązania. Czy profilowałeś swoją grę i zidentyfikowałeś specyfikację? c wąskie gardło, które ' próbujesz rozwiązać?
  • @DMGregory Cóż, jeśli pomyślimy o mapie 100 * 100 na ekranie (jeśli założymy, że pomniejszyliśmy, aby zobaczyć całą map), stworzy 10.000 obiektów gry w scenie. Oznacza to również 10.000 nieregularnych składników transformacji. Nie ' nawet nie wiem, czy jedność może obsługiwać 10.000 obiektów w oknie hierarchii. Wiem, że zawiesza się po kilkuset.

Odpowiedź

Oto, o czym wiem:

Opcja 1. GameObject na kafelek. W niektórych przypadkach nie jest to całkowicie okropne. W zależności od potrzeb może działać .. wystarczająco dobrze.

Opcja 2. Pojedynczy quad lub płaszczyzna odwołująca się do tekstury tworzonej w czasie wykonywania. zasadniczo użyj tekstury atlasu kafelków, aby „pomalować” mapę jako jedną nową teksturę. Oczywiście w zależności od rozmiaru mapy możesz chcieć mieć wiele quadów / płaszczyzn, z których każdy reprezentuje fragmenty mapy.

Opcja 3. Stwórz własną siatkę.Jest to prawdopodobnie metoda, którą polubisz najbardziej po wdrożeniu. Zapewni to mnóstwo elastyczności i prawdopodobnie najwyższą wydajność. Zasadniczo utworzyłbyś quad na kafelek i ustawiłby każdy wierzchołek UV tak, aby był mapowany na kafelki w twoim atlasie kafelków.

W przypadku Opcji 2, I ” d sugeruj obejrzenie tej serii filmów autorstwa quill18creates: Seria samouczków 3D TileMap autorstwa quill18creates

W przypadku Opcji 3 to jest mój kod, z poprawkami, więc może nie być idealne:

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

Komentarze

  • Twoje odpowiedzi pomogły mi wrócić do dni. Teraz przeglądam swoje stare pytania i ' zdałem sobie sprawę, że ' nigdy nie sprawdziłem tej odpowiedzi jako zaakceptowanej. Przepraszam za spóźnioną o wieczność akceptację ^^ Dzięki za odpowiedź.

Odpowiedź

Tak jak ty (myślę ) nawiązał do, mapa drogowa Unity zawiera plany dotyczące edytora map tilem. Nie mogę się doczekać, ponieważ w tej chwili jest to trochę mylące, jak postępować.

W międzyczasie najlepsze podejście, jakie Widzę, że tworzymy mapę w kafelkach, a następnie używam X-UniTMX do importowania jej do Unity. Oczywiście nie jest to jednak generowanie proceduralne; wyobrażam sobie, że użyłbyś tej samej techniki, której używa X-UniTMX do tworzenia siatki.

Odpowiedź

Możesz po prostu utworzyć kafelki głębiej w hierarchii i zamknąć ten folder i nie przejmować się. Możesz również ukryć obiekty gry przed hierarchią `myTile.hideFlags = HideFlags. HideInHierarchy „nie jestem pewien, jak wiele osiągnięto by wydajność.

Wyświetlanie tekstur 100×100 na ekranie nigdy nie jest dobrym pomysłem rysowanie tekstur jest cięższe niż rysowanie wielokątów. Jeśli chcesz tak daleko oddalić, lepiej będzie, jeśli masz większe tekstury. To samo dotyczy powiększania, nie powinieneś rysować tekstur, których nie trzeba rysować.

To, co zwykle robię (nie jestem facetem z Unity), to tworzenie klasy dla mapy i używanie 2-wymiarowa tablica do przechowywania wszystkich twoich kafelków. Ta tablica może składać się po prostu z ints lub klasy Tile z kilkoma intami, które odnoszą się do twoich tekstur, typu kafelka, obiektów itp. Następnie można to narysować w następujący sposób:

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

Metoda rysowania, której używam, wydaje się być przeznaczona do rysowania GUI, ale może być idealnie odpowiednia do tego zadania. W przeciwnym razie musisz zagłębić się w menadżera duszków i znaleźć sposób który działa z tą metodą.

Możesz użyć słownika do odwołań do tekstur, takiego jak int 1 w klasie kafelków, aby odwołać się do jakiejś tekstury, a int 2 odnosi się do innego.W linii, na której rysujesz teksturę, możesz użyć słownika, aby podać właściwy obiekt tekstury. W ten sposób nie powinno tworzyć GameObject, a tym samym nie tworzyć wszystkich niepotrzebnych narzutów.

Możesz zrobić to samo dla prawie wszystkiego, co nie wymaga poziomu kontroli GameObject. Pamiętaj jednak, że w ten sposób narysuje każdy kafelek twojej mapy, ale najprawdopodobniej nie usunie automatycznie obiektów, tak jak myślę, że jedność robi z obiektami gry. Ale samo narysowanie tego, co ma być na ekranie, jest bardzo łatwe. Znasz rozmiar ekranu / widocznego obszaru, położenie kamery i rozmiar pola. Prosta matematyka powinna narysować dokładnie to, co jest potrzebne.

Mimo to, jedność to silnik 3D. Obsługuje tylko 2D w 3D. Ale w zasadzie możesz zrobić to samo dla kwadratów / siatek z teksturami i aparat ortograficzny. Samo narysowanie potrzebnych siatek jest dość tanie.

Odpowiedź

Jako osoba pracująca nad projektem opartym na wokselach / blokach , Nie mogę nic na to poradzić, ale myślę o zastosowaniu tego samego podejścia, tylko w 2D. Możesz proceduralnie zbudować siatkę podobną do siatki i przypisać właściwe współrzędne elementów wizualnych w atlasie tekstur do kanału UV. W 3D musisz wykonać znacznie więcej pracy niż to, aby mieć wysoką wydajność, ale w 2D bardzo prawdopodobne jest, że to naprawdę wystarczy.

Odpowiedź

Zawsze możesz użyć LeanPool . Jest to darmowy zasób w magazynie aktywów. Wykonuje dla Ciebie pule obiektów. Następnie możesz wykonać prosty system cull wokół widoku kamer, który odradza / odradza obiekty gry kafelkowej, gdy wchodzą / wychodzą z widoku kamery. Nie jestem pewien, jak duża będzie twoja mapa tilemap, ale Unity może obsłużyć całkiem sporo obiektów gry. LeanPool ma sceny wzorcowe w Unity, w których możesz spawnować / de spawnować tysiące obiektów z komponentami kolizji skrzynek i myślę, że prawdopodobnie również komponent renderujący na każdym z nich i robi to bardzo szybko.

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

Oto link, który pokaże przykład użycia LeanPool z mapą tilemapy.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *