Articles

Unity: miten luoda 2D Tilemap ohjelmallisesti

video tutorial klikkaa tästä

Jos haluat luoda erilaisia Tilemapeja erikokoisia katso tämän opetusohjelman toinen osa

Tilemap komponentti otettiin käyttöön Unity 2017.2: ssa ja helpotti merkittävästi 2D-pelin kehitysprosessia. Version 2018.3 myötä otettiin käyttöön isometrinen Tilemap, joka tarjoaa suuren tuen 2.5 D-peleille. Viime aikoina minulla oli mahdollisuus työskennellä tämän komponentin tiiviisti ja haastoi tehtävän luoda laatat ohjelmallisesti. Viimeisessä pelissäni minulla on paljon tasoja ja kaikissa niissä on sama Tilemap-pohjainen lauta. Mutta aluksella itsessään on tason ainutlaatuinen setup. Ilmeisesti, koska ammatillinen kehittäjä en halunnut luoda 60 pelin kohtauksia ja maalata kaikki tasot käsin, vaan on mekanismi täyttää aluksella asianmukaiset elementit riippuen annetusta panoksesta. Jos olet utelias, miten lopputulos näyttää tässä on linkki peliin.

lähdekoodi löytyy GitHubista, katso linkki tämän opetusohjelman lopusta.

käytän viimeisintä saatavilla olevaa Unity 2019.2.0.1 f. Jotta voisit työskennellä tämän opetusohjelman kanssa, sinulla pitäisi olla vähintään versio 2018.3. Käytämme isometristä ruudukkoa, mutta kuvattu tekniikka soveltuu mihin tahansa tyyppiin.

ennen kuin aloitan, suosittelen vahvasti lukemaan tämän loistavan isometrisen 2D-ympäristöjen läpi Tilemap-blogimerkinnällä saadakseni perustiedot isometrisestä Tilemapista.

koska työskentelemme 2D-ympäristössä, sinun tulisi perustaa uusi 2D-projekti (katso 2dand3dmodesettings)

tavoitteen saavuttamiseksi tarvitaan 3 pääkomponenttia: pelilauta, jossa peli tapahtuu, paikka, jossa pidetään tasokuvaus ja jokin koodi, joka yhdistää toisiinsa.

Osa 1. Levyn luominen

aloitetaan tuomalla tarvittavat kuvavarat. Käytän samoja kuvia kuin pelissäni.:

Used to create a base tilemap level

Used as a path

Used to mark the start and end points of a path

pidämme kuvat laatat-kansiossa, yksinkertaisesti vetämällä ja pudottamalla ne sinne.

Tiles setup

Huom! Sinulla pitäisi olla oikea ”Pixel Per Unit” – kokojoukko jokaista laattakuvaa kohti (lisätietoja on Isometrisissä 2D-ympäristöissä Tilemapilla). Näiden kuvien arvo on 1096.

Image setup

on hyvä käytäntö erottaa näyttämöllä olevat eri kerrokset omiksi pelikohteiksi, joilla on kuvailevat nimet. Kuvittele tyypillinen pelinäyttö, joka saattaa sisältää pelialueen, käyttöliittymän, mainosten sijoittelut ja niin edelleen.

tätä lähestymistapaa noudattaen luodaan uusi tyhjä pelikohde, jonka nimi on GameZone, johon laudan ja kaikki pelielementit voisi sijoittaa.

nyt on aika luoda varsinaisia laattoja aiemmin tuomistamme kuvista

paina ikkunaa -> 2D -> Laattapaletti

laattapaletti

laattapaletti avautuu. Klikkaa ”Luo uusi paletti” ja luo paletti:

New Palette

Drag and drop tile images one by one to create an actual tiles.

Tiles setup

With those tiles we can finally create the game board which will be filled with elements programmatically on a level startup later.

Etsi GameZone Hierarkianäkymässä hiiren oikealla painikkeella → 2D-objekti → isometrinen Tilakartta. Uusi pelikohde Grid luodaan.

laudan koko tulee olemaan 11×11 laattaa ja voimme aloittaa maalaamisen. Valitse laatikko harja työkalu (4.Elementti vasemmalta) ”laatta paletti” näkymä, valitse ”puhdas” laatta. Maalaa se näkymässä.

Board

kun olet tehnyt maalauksen, sinun tulee pakata käsin tilemapin rajoja. Tätä varten on valittava Tilemap Hierarkianäkymässä, painettava Tilemap-komponentin asetuspainiketta (gear) ja valittava ”Compress Tilemap Bounds”

Compress Tilemap Bounds

hyvin tehty, pelilauta on valmis käyttöön! Palaamme siihen osassa 3.

Osa 2. Tason tiedot

koska haluamme käyttää samaa kohtausta ja samaa pelilautaa uudelleen, tason tiedot tulisi säilyttää jossain. Yksinkertainen ratkaisu tähän on yksinkertainen JSON-tiedosto, joka kuvaa, miten kukin taso olisi rakennettava.

on tärkeää ymmärtää, mitä yritämme saavuttaa, siksi minun on sanottava muutama sana mekaniikasta. Pelissä on esineitä, jotka liikkuvat polun rinnalla alusta loppuun (melko lailla kuten Zumassa) ja pelaajan tavoitteena on tuhota ne kaikki. Tässä opetusohjelmassa luomme tämän polun, joka on ainutlaatuinen kullekin tasolle.

okei, takaisin projektiin.

on olemassa useita tapoja, miten käyttää ulkoista dataa suoritusajassa komentosarjasta. Tässä käytämme Resurssikansioita

Let ’ s create a new folder — Files — and a sub-folder Resources. Se on paikka, jossa haluamme säilyttää tiedot, joten luo uusi tiedosto-tasot.JSON ja laita se tuonne.

opetustarkoituksiin meillä on vain kaksi kenttää kuvaamaan kutakin tasoa:

  • numero — int tason tunnistamiseksi
  • polku — laattapohjainen polku, jonka haluamme luoda ohjelmallisesti. Array arvoja, joissa ensimmäinen arvo on alkupiste ja viimeinen arvo on päätepiste.

tätä tiedostoa aion käyttää. Älä murehdi niitä arvoja polulla, tulemme siihen myöhemmin.

{
"levels":
},
{
"number": 2,
"path":
},
{
"number": 3,
"path":
}
]
}

luodaan toinen kansio — skriptit — ja nyt koodaus vihdoin alkaa.

haluamme päästä käsiksi koodin tiedoston tietoihin, joten tarvitsemme sille malliluokan. On aika luoda aivan ensimmäinen skripti – LevelsData. Sitä ei ole tarkoitettu ykseyden instantioimaksi, joten MonoBehaviour ja StartUpdate menetelmät tulisi poistaa. Yllä olevasta tiedostosta voimme nähdä, että juurielementti on array tasoista, joissa jokaisella tasolla tulee olla yksi int kenttäluku ja yksi int array kenttäpolku. Myös, älä unohda laittaa huomautus.


public class LevelsData
{
public LevelData levels;
public class LevelData
{
public int number;
public int path;
}
}

kiva, nyt on tiedosto ja malli. Seuraava askel on muuttaa toinen toisekseen. Luodaan toinen skripti – GameZone — ja liitetään se GameZone objekti paikalle. Tätä komentosarjaa käytetään myöhemmin koko pelilaudan setupointiin.

seuraa yhden vastuun periaatetta luodaanpa vielä toinen skripti — LevelsDataLoader — joka tekee kaiken muutoksen. Liitä se myös GameZone objektiin.

public class LevelsDataLoader : MonoBehaviour
{
private const string LevelsPath = "Levels";
public Dictionary<int, LevelsData.LevelData> ReadLevelsData()
{
var jsonFile = Resources.Load(LevelsPath, typeof(TextAsset)) as TextAsset;
if (jsonFile == null)
{
throw new ApplicationException("Levels file is not accessible");
}
var loadedData = JsonUtility.FromJson<LevelsData>(jsonFile.text);
return loadedData.levels.ToDictionary(level => level.number, level => level);
}
}

Tämä luokka lataa tiedon ja palauttaa sen sanakirjana, jossa avain on tasoluku ja tieto itse tasotieto.

nyt pitäisi päästä käsiksi GameZone script.

public class GameZone : MonoBehaviour
{
private Dictionary<int, LevelsData.LevelData> _levelsData;
private LevelsDataLoader _dataLoader;private void Awake()
{
_dataLoader = GetComponent<LevelsDataLoader>();
}private void Start()
{
_levelsData = _dataLoader.ReadLevelsData();Debug.Log(_levelsData.Count + " levels have been stored in the dictionary!");
}
}

vaihda takaisin Unityyn, paina toistopainiketta ja tarkista konsoli — sinun pitäisi nähdä viesti ”3 tasoa on tallennettu sanakirjaan!”

Osa 3. Kun yhdistät taulun ja tiedot

Onnittelut, olet saavuttanut tämän opetusohjelman viimeisen ja kiinnostavimman osan. Miten liitämme taulun ja datan? Jatka lukemista saadaksesi sen selville!

ensinnäkin sijoitetaan horizontal ja start_stop opetusohjelman ensimmäisessä osassa luodut laatat Resurssikansioon laattojen kansion alle. Lisää sitten uusi skripti— TilesResourcesLoader – staattinen apuluokka, jolla voit ladata laatat kyseisestä kansiosta suorituksen aikana.

public static class TilesResourcesLoader
{
private const string PathHorizontal = "horizontal";
private const string StartStop = "start_stop"; public static Tile GetPathHorizontalTile()
{
return GetTileByName(PathHorizontal);
} public static Tile GetStartStopTile()
{
return GetTileByName(StartStop);
} private static Tile GetTileByName(string name)
{
return (Tile) Resources.Load(name, typeof(Tile));
}
}

viimeisenä vaiheena pitäisi laittaa nuo laatat taululle kohtauksen käynnistyessä. Palataan GameZone skriptiin. Ensinnäkin meidän täytyy simuloida tason valinta, oikeassa pelissä se tapahtuu yleensä aina, kun käyttäjä painaa tason painiketta. Lisätään yksinkertaisuuden vuoksi julkinen kenttätaso GameZone ja muutetaan se arvoksi 1 aloitusta varten. Näytän ensin lopullisen käsikirjoituksen:

public class GameZone : MonoBehaviour
{
public int Level; private const int FieldLineSize = 11;
private const int FieldTotalTiles = FieldLineSize * FieldLineSize;
private Dictionary<int, LevelsData.LevelData> _levelsData; private void Start()
{
_levelsData = GetComponent<LevelsDataLoader>().ReadLevelsData();
SetupTiles();
} private void SetupTiles()
{
var baseLevel = GetComponentsInChildren<Tilemap>(); var localTilesPositions = new List<Vector3Int>(FieldTotalTiles);
foreach (var pos in baseLevel.cellBounds.allPositionsWithin)
{
Vector3Int localPlace = new Vector3Int(pos.x, pos.y, pos.z);
localTilesPositions.Add(localPlace);
} SetupPath(localTilesPositions, baseLevel);
} private void SetupPath(List<Vector3Int> localTilesPositions, Tilemap baseLevel)
{
var path = _levelsData.path;
var pathHorizontalTile = TilesResourcesLoader.GetPathHorizontalTile();
var first = path.First();
var last = path.Last();
foreach (var localPosition in localTilesPositions.GetRange(first, Math.Abs(first - last)))
{
baseLevel.SetTile(localPosition, pathHorizontalTile);
} var startStopTile = TilesResourcesLoader.GetStartStopTile();
baseLevel.SetTile(localTilesPositions, startStopTile);
baseLevel.SetTile(localTilesPositions, startStopTile);
}
}

Vau, onpa paljon toimintaa! Anna kun selitän.

SetupTiles menetelmässä pitäisi ensin saada itse tilemerkki, koska sen muuttamiseksi pitää tietää laattojen paikat. Tämän saavuttamiseksi käytämme tilemap.cellBounds.allPositionsWithin — menetelmää, joka palauttaa kaikki laattojen asennot alkaen ensimmäisestä-annetussa konfiguraatiossa se on alaspäin eniten laatta.

katso seuraava kuva, jossa jokainen numero edustaa localTilesPositions – listan indeksiä.

numeroitu tilemap

Muistatko arvot, joita käytämme polullaLevels.json? Kuten ehkä arvata jo nämä arvot ovat indeksit laatat array. Kaikki mitä sinun tarvitsee tehdä nyt on cheatsheet kuva auttaa rakentamaan tasoja. Se on yksi Olen käyttänyt kehityksen aikana:

my ugly numered tilemap

tässä esimerkissä asetamme vaakasuoran viivan polulle, katsoSetupPathmenetelmä. Keskeinen osa on seuraava silmukka:

foreach (var localPosition in localTilesPositions.GetRange(first, Math.Abs(first - last)))
{
baseLevel.SetTile(localPosition, pathHorizontalTile);
}

tässä iteroidaan localTilesPositions, jotta löydetään ne, joilla haluttu laatta asetetaan vaakatasoon tässä tapauksessa.

Huom! GetRange menetelmällä on kaksi muuttujaa — indeksi ja lukumäärä.

polkujen alku-ja loppupisteiden merkitsemiseen käytetään start_stop – laattaa.

tässä on kovan työmme tulos:

lopputulos

yritä nyt muuttaaGameZonescript 1: stä 2: een tai 3: een ja näet, että polku on ladattu oikein annetulle tasolle.

jälkeenpäin