Advertisement
  1. Code
  2. Coding Fundamentals
  3. Game Development

Een Inleiding tot het Maken van een Tegelkaart Engine

Scroll to top
Read Time: 19 min

() translation by (you can also view the original English article)

In deze tutorial, zal ik helpen je niveaus voor elk spel genre maken en ontwerpen niveaus veel gemakkelijker. You Gonna leren hoe te maken van je eerste tegel kaart motor voor gebruik in om het even welk van je toekomstige projecten. Ik zal Haxe gebruiken met OpenFL, maar je moet zitten kundig voor volgen in elke taal.

Hier is wat we zullen behandelen:

  • Wat is een-game dakpan?
  • Vinden of maken van uw eigen stenen.
  • Het schrijven van de code om tegels op het scherm weer te geven.
  • Het bewerken van Tegel lay outs voor verschillende niveaus.

Misschien krijg je een goede start op een nieuw spel idee, ook!


Wat Is een Game Dakpan?

Natuurlijk, Wikipedia heeft een diepgaande definitie van wat een op tegels gebaseerd spel is, maar om de basiszin te krijgen, zijn er maar een paar dingen die je moet weten:

  1. Een tegel is een kleine afbeelding, meestal vierkant of isometrische, die als een puzzel stuk van kunst fungeert voor het bouwen van grotere afbeeldingen.
  2. Een kaart is een groepering van tegels samen maken een (hopelijk) visueel aantrekkelijk "sectie" (zoals een niveau of gebied).
  3. Op-tegels gebaseerd verwijst naar de methode voor het bouwen van levels in een game. De code zal lay out tegels in specifieke locaties ter dekking van het beoogde gebied.

Als je nog meer fundamentele, zal ik het als volgt:

Een tegel-based spel legt tegels om te creëren van elk niveau.

Verwijzing naar de tegel voorkomende - rechthoekige en isometrische - zullen we gebruiken rechthoekige tegels in dit artikel voor hun eenvoud. Als je besluit om uit te proberen isometrische niveaus een dag, is er extra wiskunde betrokken te laten werken. (Als je hier klaar bent, kijk op deze grote tutorial over het maken van isometrische werelden.)

Er zijn sommige vrij koele voordelen die je krijgt van het met behulp van een tegel engine. Het meest herkenbaar perk is dat je hoeft te maken van de enorme beelden met de hand voor elk individueel niveau. Dit zal bezuinigen op de ontwikkeltijd en bezuinigen op de bestandsgrootte. Na 50 1280x768px beelden voor een spel vs van 50 niveau met één afbeelding met 100 tegels maakt een enorm verschil.

Een ander neveneffect is dat het vinden van dingen op uw kaart met behulp van code een beetje makkelijker wordt. In plaats van dingen zoals botsing op basis van een exacte pixel te controleren, kunt je een snelle en gemakkelijke formule om te bepalen welke tegel je toegang moet hebben. (Ik ga over dat een beetje later.)


Vinden of Maken van Je Eigen Tegels

Het eerste ding zal je bij het bouwen van je tegel engine is een set van tegels. Je hebt twee opties: gebruikmaken van andermans tegels of je eigen zorg.

Als je besluit te gebruiken tegels die al zijn gemaakt, kunt je vrij kunstaanbod helemaal over het web. Downside aan dit is dat de kunst was niet speciaal voor je spel gemaakt. Aan de andere kant, als je gewoon prototyping of proberen te leren van een nieuw concept, zal gratis tegels doen de truc.

Waar Vindt u Je Tegels

Er zijn nogal wat middelen daar voor vrije en open source kunst. Hier zijn een paar plaatsen om te beginnen je zoekopdracht:

  1. OpenGameArt.org
  2. Let's Make Games
  3. Pixel Prospector

Deze drie links moet geven je meer dan genoeg plaatsen te vinden sommige fatsoenlijke tegels voor je prototypes. Voordat je gekke grijpen opwaarts welbeschouwd je gaat, zorg ervoor dat je begrijpt wat alles is onder licentie en welke beperkingen ze voorzien. Met veel licenties kunt je de kunst vrij en voor commercieel gebruik gebruiken, maar hiervoor is mogelijk attributie vereist.

Voor deze tutorial gebruikte ik sommige tegels uit een bundel The Open Spel Kunst voor platformers. Je kunt mijn verkleinde versies of de originelen.

Hoe Maak je Je Eigen Tegels

Als je de sprong van het maken van kunst voor uw games nog niet hebben genomen, is het wellicht een beetje intimiderend. Gelukkig zijn er enkele verbazingwekkende en eenvoudige stukjes software die je in de dikke van het zodat je met het beoefenen beginnen kunt.

Veel ontwikkelaars beginnen met pixel kunst voor hun games en hier zijn een paar geweldige hulpmiddelen voor dat.:

  1. Aseprite
  2. Pyxel Bewerken
  3. Afbeeldingen Gale
  4. Pixen voor de Mac-gebruikers

Dit zijn enkele van de meest populaire programma's voor het maken van pixelart. Als je wilt dat iets een beetje meer krachtige, is GIMP een uitstekende optie. U kunt ook doen sommige vector kunst met Inkscape en volg enkele geweldige tutorials over op 2D Game Art voor programmeurs.

Zodra je de software die je experimenteren beginnen kunt met het maken van uw eigen tegels grijpen. Aangezien deze zelfstudie bedoeld is om je te laten zien hoe je uw tegelkaart kunt maken motor Ik zal niet te veel ingaan op het maken van de tegels zelf, maar er is één ding om altijd in gedachten te houden:

Zorg ervoor dat je tegels naadloos in elkaar passen en toevoegen om ze te houden interessante afwisseling.

Als je tegels duidelijke lijnen tussen hen wanneer samen tonen, uitzien niet je spel erg leuk. Zorg ervoor dat je enige tijd in het creëren van een leuke "puzzel" van tegels door waardoor ze naadloos en toevoeging van afwisseling.


De Code schrijven voor het Weergeven van Tegels

Nu hebben we al dat spul van kunst uit de weg, kunnen we duiken in de code om te zetten van je nieuw verworven (of gemaakt) tegels op scherm.

Hoe een Enkele Tegel op het Scherm wordt Weergegeven

Laten we beginnen met de zeer fundamentele taak één tegel op het scherm weer te geven. Zorg ervoor dat je tegels allemaal dezelfde grootte zijn en opgeslagen in afzonderlijke afbeeldingsbestanden (we zullen praten meer over sprite sheets later).

Als je eenmaal de tegels in je map assets van je project, kunt je schrijven van een zeer eenvoudige Tegel klasse. Hier is een voorbeeld in Haxe:

1
import flash.display.Sprite;
2
import flash.display.Bitmap;
3
import openfl.Assets;
4
5
class Tile extends Sprite {
6
7
    private var image:Bitmap;
8
9
    public function new() {
10
        super();
11
12
        image = new Bitmap(Assets.getBitmapData("assets/grassLeftBlock.png"));
13
        addChild(image);
14
    }
15
}

Omdat alles wat we nu doen is het zetten van één tegel op het scherm, het enige dat de klasse doet is import de tile afbeeldingen uit de map assets en als een kind toevoegen aan het object. Deze klasse zal waarschijnlijk variëren sterk gebaseerd op de programmeertaal die je gebruikt, maar je moet zitten kundig voor gemakkelijk het vinden van een handleiding over hoe je een afbeelding op het scherm weergeven.

Nu we een Tile klasse hebben, moeten we een instantie van een Tile maken en deze aan onze hoofdklasse toevoegen:

1
import flash.display.Sprite;
2
import flash.events.Event;
3
import flash.Lib;
4
5
class Main extends Sprite {
6
7
    public function new() {
8
        super();
9
10
        var tile = new Tile();
11
        addChild(tile);
12
    }
13
14
    public static function main() {
15
        Lib.current.addChild(new Main());
16
    }
17
}

De Main klasse maakt een nieuwe Tegel als de constructor (de new() functie, dat wanneer het spel begint wordt genoemd) wordt genoemd, en voegt het toe aan het weergaveoverzicht.

Wanneer het spel wordt uitgevoerd, de main() functie zal ook worden genoemd, en een nieuwe Main object wordt toegevoegd aan het werkgebied. Je hebt nu je tegel verschijnen op de top links van het scherm. Tot nu toe, zo goed.

Tip: Als niets van dat steek - Maak je geen zorgen! Het is gewoon standaard boilerplate Haxe code. Het belangrijkste om te begrijpen is dat dit een Tile object maakt en dit aan het scherm toevoegt.

Het gebruik van Arrays om Lay Out een hele Scherm van Tegels

De volgende stap is het vinden van een manier om te vullen het hele scherm met tegels. Een van de gemakkelijkste manieren om dit te doen is te vullen met een array met gehele getallen die elk een tegel ID vertegenwoordigen. Je kunt vervolgens doorlopen aan de array om te beslissen welke tegel om weer te geven en waar weer te geven.

Hebt je de mogelijkheid met behulp van een typische array of met behulp van een 2- dimensionale array. In het geval je niet bekend bent met 2D-arrays, is het eigenlijk één array dat gevuld is met meerdere arrays. Meeste talen zal dit duiden als nameOfArray [x] [y] waar x en y zijn indexen voor toegang tot een enkel element.

Sinds de x en y worden ook gebruikt voor schermcoördinaten, kan het zinvol zijn om te gebruiken x en y als coördinaten voor onze tegels. De truc met 2D matrices is te begrijpen hoe de gehele getallen worden georganiseerd. Het is wellicht om te keren de y en x bij het doorlopen van de arrays (voorbeeld hieronder).

1
private var exampleArr = [ [0, 0, 0, 0, 0],
2
                           [0, 0, 0, 0, 0],
3
                           [0, 0, 0, 0, 0],
4
                           [0, 0, 0, 0, 0],
5
                           [0, 0, 0, 0, 0] ];

Merk op dat in deze implementatie is het "0de" element in de matrix zelf een matrix, met vijf gehele getallen. Dit zou betekenen dat je toegang elk element met y tot eerst, dan x. Als je toegang probeert te exampleArr [1] [0], je zou toegang krijgt tot de zesde tegel.

Als je niet helemaal begrijp hoe de 2D arrays werken nu, maak je geen zorgen. Voor deze tutorial zal ik een normale matrix gebruiken om de dingen simpel te houden en om dingen gemakkelijker te visualiseren:

1
private var exampleArr = [ 0, 0, 0, 0, 0,
2
                           0, 0, 0, 0, 0,
3
                           0, 0, 0, 0, 0,
4
                           0, 0, 0, 0, 0,
5
                           0, 0, 0, 0, 0 ];

Het bovenstaande voorbeeld ziet je hoe een normale matrix een beetje eenvoudiger kan worden. We kunnen visualiseren precies waar de tegel worden en alles wat we moeten doen is een eenvoudige formule gebruiken (maak je geen zorgen, er komen!) om de tegel die we willen.

Nu laten we schrijven sommige code aan onze array maken en vul deze met enen. De nummer één zullen de ID waarmee onze eerste tegel.

Eerst moeten we een variabele binnenkant van onze Main klasse te houden onze matrix te maken:

1
private var map:Array<Int>;

Dit oogt een beetje vreemd, dus ik break it down voor je.

Naam van de variabele is kaart en ik heb gezien het een zeer specifiek type: Array. Het <Int>gedeelte gewoon vertelt ons programma dat de array zal alleen gehele getallen. Matrices kunnen houden zowat elk type dat je wilt, dus als je iets anders gebruikt om te identificeren je tegels, voel je vrij om de parameter hier wijzigen.

Vervolgens moeten we wat code toevoegen aan onze Main class's constructor (onthoud, dit is de nieuwe () functie) zodat we een exemplaar van onze kaart kunnen maken:

1
map = new Array<Int>();

Deze regel maakt een lege matrix die we binnenkort met onze degenen vullen kunt om het uit te testen. Ten eerste, laten we definiëren sommige waarden die ons met onze wiskunde helpen zal:

1
public static var TILE_WIDTH = 60;
2
public static var TILE_HEIGHT = 60;
3
public static var SCREEN_WIDTH = 600;
4
public static var SCREEN_HEIGHT = 360;

Ik heb deze waarden gemaakt openbare statische omdat dit ons toegang geeft vanaf waar dan ook in ons programma (via Main.Tile_WIDTH enzovoort). Ook, zou je gemerkt hebben dat delen van SCREEN_WIDTH door TILE_WIDTH geeft ons 10 en verdelen SCREEN_HEIGHT door TILE_HEIGHT ons geeft 6. Deze twee nummers worden gebruikt om te beslissen hoeveel gehele getallen op te slaan in onze matrix.

1
        var w = Std.int(SCREEN_WIDTH / TILE_WIDTH);
2
        var h = Std.int(SCREEN_HEIGHT / TILE_HEIGHT);
3
4
        for (i in 0...w * h) {
5
            map[i] = 1
6
        }

In dit blok code toewijzen we 10 en 6 w en h, zoals ik hierboven vermeld. Dan we moeten om te springen in een for lus maken een matrix die gehele getallen van 10 * 6 past. Dit zal goed zijn voor genoeg tegels te vullen het hele scherm.

tileMapDiagram1tileMapDiagram1tileMapDiagram1

Nu hebben we onze fundamentele kaart gebouwd, maar hoe gaan we om te vertellen van de tegels in hun juiste plaats te krijgen? Daarvoor moeten we teruggaan naar de tegel klasse en een functie dat ons toelaten zal om tegels rond bewegen op wil maken:

1
    public function setLoc(x:Int, y:Int) {
2
        image.x = x * Main.TILE_WIDTH;
3
        image.y = y * Main.TILE_HEIGHT;
4
    }

Wanneer we de setLoc() functie aanroepen, we passeren in de x en y coördinaten volgens onze kaart klasse (formule binnenkort, dat beloof ik!). De functie die waarden neemt en vertaalt ze in pixelcoördinaten door te vermenigvuldigen met hen TILE_WIDTH en TILE_HEIGHT, respectievelijk.

Het enige wat overblijft om te doen om onze tiles op het scherm is te vertellen onze Main klasse te maken van de tegels en leg ze in op basis van hun locaties in de kaart. We gaan terug naar de Main en uit te voeren die:

1
        for (i in 0...map.length) {
2
            var tile = new Tile();
3
            var x = i % w;
4
            var y = Math.floor(i / w);
5
            tile.setLoc(x, y);
6
            addChild(tile);
7
        }

O ja! Dat klopt, dat we hebben nu een scherm vol van tegels. Laten we breken wat er boven gebeurt.

De Formule

De formule die ik steeds noemt is eindelijk hier.

We berekenen x door het nemen van de absolute waarde (%) van i en w (oftewel 10, onthouden).

De elasticiteitsmodulus is gewoon de rest na integer divisie: \ (14 \div 3 = 4 \text {rest} 2\) dus \ (14 \text {modulus} 3 = 2\).

We gebruiken dit omdat we willen dat onze waarde voor x om te resetten terug naar 0 aan het begin van elke rij, zodat we de respectieve tegel op de uiterst links trekken:

tile_grid_colstile_grid_colstile_grid_cols

Wat betreft de y, nemen we de vloer() van i / w (dat wil zeggen we dat resultaat naar beneden afronden) want we alleen y willen te verhogen zodra we hebben bereikt het einde van elke rij en één niveau omlaag verplaatst:

tile_grid_rowstile_grid_rowstile_grid_rows
Tip: De meeste talen niet nodig u Bel Math.floor() bij het verdelen van de gehele getallen; HaXe pakt gewoon integer divisie anders. Als je een taal die integer divisie doet gebruikt, je annuleerteken uitsluitend toepassing ik / w (ervan uitgaande dat ze zijn beide gehele getallen).

Tot slot wilde ik een beetje vermelden over scrollen niveaus. Meestal je zal niet het creëren van niveaus die past perfect binnen de viewport. Je kaarten zullen waarschijnlijk veel groter dan het scherm en je niet wilt gaan met het tekenen van afbeeldingen die de speler niet kan zien. Met enkele snelle en gemakkelijke wiskunde, moet je zitten kundig voor berekenen welke tegels moeten op scherm en die tegels om te voorkomen dat de tekening.

Bijvoorbeeld: je schermgrootte is 500 x 500, je tegels zijn 100 x 100 en de grootte van je wereld is 1000 x 1000. Je zou gewoon moeten doen een snelle controle alvorens tegels om erachter te komen welke tegels op het scherm zijn. Met behulp van de locatie van uw viewport - laten we zeggen 400 x 500 - je zou alleen moeten tegels trekken van 4 tot en met 9 rijen en kolommen 5 tot en met 10. Je kunt deze nummers krijgen door de locatie te delen door de blokgrootte en vervolgens deze waarden compenseren met de grootte van het scherm gedeeld door de blokgrootte. Eenvoudig.

Hierbij lijkt niet veel maar aangezien alle tegels hetzelfde zijn, maar de Stichting er bijna is. De enige dingen die te doen zijn onze kaart zo ontwerpen dat ze line up en maken iets moois te maken van verschillende soorten tegels.


Tegel lay outs bewerken voor Verschillende Niveaus

Oke, hebben we nu een kaart die vol is van degenen die betrekking heeft op het scherm. Bij dit punt moet je meer dan één type van de tegel, wat betekent dat we veranderen onze tegel constructor moeten om te verklaren dat:

1
public function new(id:Int) {
2
        super();
3
4
        switch(id) {
5
            case 1:
6
                image = new Bitmap(Assets.getBitmapData("assets/grassLeftBlock.png"));
7
            case 2:
8
                image = new Bitmap(Assets.getBitmapData("assets/grassCenterBlock.png"));
9
            case 3:
10
                image = new Bitmap(Assets.getBitmapData("assets/grassRightBlock.png"));
11
            case 4:
12
                image = new Bitmap(Assets.getBitmapData("assets/goldBlock.png"));
13
            case 5:
14
                image = new Bitmap(Assets.getBitmapData("assets/globe.png"));
15
            case 6:
16
                image = new Bitmap(Assets.getBitmapData("assets/mushroom.png"));
17
        }
18
        addChild(image);
19
    }

Omdat ik zes verschillende tegels voor mijn kaart gebruikt, moest ik een switch statement dat betrekking heeft op de nummers één tot en met zes. Je zult merken dat de constructor nu een integer als parameter neemt zodat we wat voor soort tegel weten te maken.

Nu, moeten we teruggaan naar onze Main constructor en repareren van de oprichting van de tegel in onze for lus:

1
        for (i in 0...map.length) {
2
            var tile = new Tile(map[i]);
3
            var x = i % w;
4
            var y = Math.floor(i / w);
5
            tile.setLoc(x, y);
6
            addChild(tile);
7
        }

Alles wat we moesten doen was het passeren van de kaart [i] aan de constructor van de tegel om het weer aan het werk te maken. Als je probeert uit te voeren zonder het passeren van integer naar tegel, geeft het je enkele fouten.

Bijna alles is aanwezig, maar nu moeten we een manier om het ontwerpen van kaarten in plaats van ze gewoon vullen met willekeurige tegels. Eerst verwijdert de for lus in de Main constructor waarin elk element een. Dan we onze eigen kaart met de hand creëren kunnen:

1
        map = [ 0, 4, 0, 0, 0, 0, 0, 5, 0, 0,
2
                0, 0, 0, 0, 0, 1, 2, 2, 3, 0,
3
                0, 0, 0, 6, 0, 0, 0, 0, 0, 0,
4
                1, 2, 2, 3, 0, 0, 0, 0, 0, 0,
5
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6
                0, 0, 0, 0, 0, 0, 1, 2, 2, 3 ];

Als je de array opmaken zoals ik hierboven heb, kunt je gemakkelijk zien hoe onze tegels zal worden georganiseerd. Je kunt ook gewoon de matrix invoeren als één lange regel van getallen, maar de voormalige is leuk omdat je over 10 en 6 naar beneden zien kunt.

Wanneer je probeert het programma nu uitvoeren, moet je enkele null pointer uitzonderingen krijgen. Het probleem is dat we zijn met behulp van nullen in onze kaart en onze tegel klasse niet wat weet te doen met een nul. Eerst, zullen wij de constructor verhelpen door te in een selectievakje toe te voegen, voordat we het beeld kind toevoegen:

1
        if (image != null) addChild(image);

Deze snelle controle zorgt ervoor dat we geen null kinderen zijn niet toevoegt aan de tegel objecten die we maken. De laatste wijziging voor deze klasse is de setLoc() functie. Op dit ogenblik wij willen verzameling deen y waarden voor een variabele die nog niet is geïnitialiseerd.

Laten we een andere snelle controle toevoegen

1
    public function setLoc(x:Int, y:Int) {
2
        if (image != null) {
3
            image.x = x * Main.TILE_WIDTH;
4
            image.y = y * Main.TILE_HEIGHT;
5
        }
6
    }

Met deze twee eenvoudige correcties in plaats, en de tegels die ik hierboven, moet je zitten kundig voor start het spel, en zien een eenvoudige platformgame niveau. Aangezien we 0 als een "niet-tegel verliet" kan laten we het transparante (leeg). Als je spice up van het niveau wilt, kun je een achtergrond in voordat je lay out de tegels; Ik voegde enkel een licht blauwe kleurovergang te laten uitzien als een hemel op de achtergrond.

tileMapDiagram2tileMapDiagram2tileMapDiagram2

Dat is vrij veel alles wat die je nodig hebt om in te stellen op een eenvoudige manier om het bewerken van je niveaus. Proberen om een beetje experimenteren met de array en zien wat ontwerpen je kunt verzinnen voor andere niveaus.

Terts-Verschijnende partij Software voor het Ontwerpen van Niveaus

Zodra je de basis hebt, kun je overwegen om een ​​aantal andere tools te gebruiken om snel levels te ontwerpen en te zien hoe ze eruit zien voordat je ze in het spel gooit. Een optie is om je eigen niveau editor te maken. Het alternatief is om te grijpen sommige software thats beschikbaar kostenloos te gebruiken. De twee populaire tools zijn Betegeld Map Editor en Ogmo Editor. Beiden maken niveau veel gemakkelijker bewerken met meerdere exportopties.


Je Hebt net een op Tegels-Gebaseerde motor Gemaakt!

Nu weet je wat een spel op tegels is, hoe je wat tegels kunt gebruiken voor je levels, en hoe je je handen vies kunt maken en de code voor je engine kunt schrijven, en je kunt zelfs wat basisniveaubewerking doen met een eenvoudige array . Vergeet niet dat dit slechts het begin is; There's a lot van experimenteren kan je doen om een nog betere motor.

Ook heb ik voorzien de bronbestanden om uit te checken. Hier is wat het uiteindelijke SWF-bestand als kijkt:

Download hier het SWF bestand.

.. .en hier, nogmaals, is de matrix die het wordt gegenereerd op basis van:

1
        map = [ 0, 4, 0, 0, 0, 0, 0, 5, 0, 0,
2
                0, 0, 0, 0, 0, 1, 2, 2, 3, 0,
3
                0, 0, 0, 6, 0, 0, 0, 0, 0, 0,
4
                1, 2, 2, 3, 0, 0, 0, 0, 0, 0,
5
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6
                0, 0, 0, 0, 0, 0, 1, 2, 2, 3 ];

Don't Stop hier!

Je volgende taak is om te doen wat onderzoek en uitproberen wat nieuwe dingen om te verbeteren wat je hier gemaakt. Sprite sheets zijn een geweldige manier om de prestaties te verbeteren en maken het leven een beetje makkelijker. De truc is om sommige stabiele code voor het lezen van een sprite blad zodat uw spel niet hoeft te lezen elk beeld individueel aangelegd.

Je moet ook je kunst vaardigheden oefenen door het maken van een paar tilesets van je eigen. Op die manier kunt je de juiste techniek voor je toekomstige games.

Zoals altijd, enkele opmerkingen hieronder laat over hoe je motor voor je werkt - en misschien zelfs enkele demo's, zodat wij je volgende Tegelspel kunt uitproberen.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.