In deze zelfstudie laat ik je zien hoe je een tegelset kunt analyseren, deze kunt doorlopen en overeenkomsten kunt vinden. We gaan een spel maken waarin je lijnen met elkaar moet verbinden om volledig gesloten paden te vormen zonder open uiteinden. Om dingen te vereenvoudigen, gebruiken we bitmasking als onderdeel van ons algoritme door elke tegel (plus zijn rotatie) zijn eigen bitmaskerummer toe te wijzen. Maak je geen zorgen als je niet weet wat bitmasking is. Het is eigenlijk heel simpel!
gerelateerde berichtenIk zal het project in C # maken met behulp van Unity with the Futile framework, maar de code zal van toepassing zijn op vrijwel elk 2D-framework met weinig wijzigingen. Hier is de Github-repo met het volledige Unity-project. En hieronder is een speelbare demo van de game die we gaan maken:
Toen ik begon met het maken van Polymer, wilde ik iets anders dan een match-3-game maken. Mijn interne bijnaam was een "match-any" -game. Match-3 puzzelspellen zijn overal. Hoewel ze zeker leuk kunnen zijn, is een van de redenen waarom ze zo vaak voorkomen misschien omdat het algoritme om een overeenkomst van drie tegels te vinden vrij eenvoudig is.
Ik wilde in staat zijn om meerdere tegels aan elkaar te passen die rijen en kolommen in en uit zouden kunnen weven en zich een weg over het bord zouden banen. Niet alleen dat, maar ik wilde geen eenvoudig spel voor kleurafstemming. Ik wilde dat de overeenkomsten gebaseerd zijn op specifieke zijden van de tegels (een vorm kan bijvoorbeeld alleen links en rechts aan andere vormen worden gekoppeld, maar niet de boven- en onderkant.) Dit bleek veel complexer dan alleen maar een normaal match-3-algoritme.
Deze tutorial zal worden opgesplitst in drie secties: The Tile, The Match Group en The Game Board. In deze tutorial zal ik proberen zoveel mogelijk Futiel-specifieke code te vermijden. Als je de Futiel-specifieke dingen wilt zien, kijk dan naar de broncode. Ook zal ik niet elke methode en variabele in deze post laten zien. Alleen de belangrijkste. Dus als je denkt dat er iets ontbreekt, kijk dan eens naar de broncode.
Het woord 'bitmask' verwijst naar de manier waarop u een reeks waar / vals-waarden kunt opslaan in een enkele numerieke variabele. Omdat getallen worden weergegeven door enen en nullen wanneer ze in binair getal worden weergegeven, kun je door het aantal te wijzigen waarden in- of uitschakelen door te schakelen tussen een bit of een 0.
Zie dit artikel over bitwise operators en dit artikel over binaire getallen voor meer informatie.
Onze eerste klas heet LineTile. Laten we vóór het begin van de les elke soort tegels definiëren.
// De verschillende tegeltypen: public enum LineTileType Nub, Line, Corner, Threeway, Cross, MAX
Dit is hoe de stukken eruit zien:
Omdat we alleen rotaties van 90 graden toestaan, laten we dan een maken enum
voor rotatie.
// Ik gebruik dit in plaats van exacte graden, omdat de // -tegels slechts vier verschillende rotaties mogen hebben: public enum RotationType Rotation0, Rotation90, Rotation180, Rotation270, MAX
De volgende is een struct
riep TileIndex
, wat in principe hetzelfde is als een Vector2
, behalve met ints in plaats van met drijvers. Het wordt gebruikt om bij te houden waar een tegel zich op het spelbord bevindt.
public struct TileIndex public int xIndex; publieke int yIndex; openbare TileIndex (int xIndex, int yIndex) this.xIndex = xIndex; this.yIndex = yIndex;
Laten we tot slot de drie soorten verbindingen tussen twee tegels definiëren.
public enum TileConnectionType // Een mismatch. Ongeldig, // De tegels kunnen niet rechtstreeks worden verbonden, // maar niet vanwege een ongeëvenaarde rand. ValidWithOpenZijden, // De tegels verbinden direct. ValidWithSolidMatch
Definieer vervolgens binnen de klasse zelf een bitmasker aan elke kant van een generieke tegel.
// Hier zijn de bits die ik aan elke kant van de tegel heb toegekend: // ===== 1 ===== // | | // | | // 8 2 // | | // | | // ===== 4 ===== // 1 == 0001 in binair // 2 == 0010 in binair // 4 == 0100 in binair // 8 == 1000 in binair openbaar bestand int kBitmaskNone = 0; public const int kBitmaskTop = 1; public const int kBitmaskRight = 2; public const int kBitmaskBottom = 4; public const int kBitmaskLeft = 8;
Definieer vervolgens de instantievariabelen die elke tegel heeft.
// De sprite-weergave van de tegel: openbare FSPRite-sprite; // Het type van de tegel: public LineTileType lineTileType get; private set; // De rotatie van de tile: public RotationType rotationType get; private set; // De bitmasker die de tegel vertegenwoordigt met zijn rotatie: public int bitmask get; private set; // De locatie van de tile op het bord: public TileIndex tileIndex = new TileIndex ();
Maak voor de constructor de sprite en stel deze in op de juiste rotatie. Er is hier een code met een futiel-code, maar deze moet heel gemakkelijk te begrijpen zijn.
public LineTile (LineTileType lineTileType, RotationType rotationType) this.lineTileType = lineTileType; this.rotationType = rotationType; // Sprite instellen: switch (lineTileType) case LineTileType.Nub: sprite = nieuwe FSprite ("lineTileNub"); breken; case LineTileType.Line: sprite = new FSprite ("lineTileLine"); breken; case LineTileType.Corner: sprite = nieuwe FSprite ("lineTileCorner"); breken; case LineTileType.Threeway: sprite = nieuwe FSprite ("lineTileThreeway"); breken; case LineTileType.Cross: sprite = nieuwe FSprite ("lineTileCross"); breken; standaard: gooi nieuwe FutileException ("ongeldig lijntegeltype"); AddChild (sprite); // Sprite-rotatie instellen: switch (rotationType) case RotationType.Rotation0: sprite.rotation = 0; breken; case RotationType.Rotation90: sprite.rotation = 90; breken; geval RotationType.Rotation180: sprite.rotation = 180; breken; geval RotationType.Rotation270: sprite.rotation = 270; breken; standaard: gooi nieuwe FutileException ("ongeldig rotatietype");
Nu, een van de belangrijkste delen. We kennen elke tegel, in combinatie met zijn rotatie, een bitmasker toe die wordt bepaald aan de hand van welke zijden solide zijn en welke open zijn.
// Stel bitmask in door bitsgewijs OF uit te voeren met elke zijde die in de vorm is opgenomen. // Dus bijvoorbeeld, een tegel met alle vier zijden vast (bijvoorbeeld de kruistegel) zou // 1 | zijn 2 | 4 | 8 = 15, wat hetzelfde is als 0001 | 0010 | 0100 | 1000 = 1111 in binair getal. if (lineTileType == LineTileType.Nub) if (rotationType == RotationType.Rotation0) bitmask = kBitmaskTop; if (rotationType == RotationType.Rotation90) bitmask = kBitmaskRight; if (rotationType == RotationType.Rotation180) bitmask = kBitmaskBottom; if (rotationType == RotationType.Rotation270) bitmask = kBitmaskLeft; if (lineTileType == LineTileType.Line) if (rotationType == RotationType.Rotation0 || rotationType == RotationType.Rotation180) bitmask = kBitmaskTop | kBitmaskBottom; if (rotationType == RotationType.Rotation90 || rotationType == RotationType.Rotation270) bitmask = kBitmaskRight | kBitmaskLeft; if (lineTileType == LineTileType.Corner) if (rotationType == RotationType.Rotation0) bitmask = kBitmaskTop | kBitmaskRight; if (rotationType == RotationType.Rotation90) bitmask = kBitmaskRight | kBitmaskBottom; if (rotationType == RotationType.Rotation180) bitmask = kBitmaskBottom | kBitmaskLeft; if (rotationType == RotationType.Rotation270) bitmask = kBitmaskLeft | kBitmaskTop; if (lineTileType == LineTileType.Threeway) if (rotationType == RotationType.Rotation0) bitmask = kBitmaskTop | kBitmaskRight | kBitmaskBottom; if (rotationType == RotationType.Rotation90) bitmask = kBitmaskRight | kBitmaskBottom | kBitmaskLeft; if (rotationType == RotationType.Rotation180) bitmask = kBitmaskBottom | kBitmaskLeft | kBitmaskTop; if (rotationType == RotationType.Rotation270) bitmask = kBitmaskLeft | kBitmaskTop | kBitmaskRight; if (lineTileType == LineTileType.Cross) bitmask = kBitmaskTop | kBitmaskRight | kBitmaskBottom | kBitmaskLeft;
Onze tegels zijn klaar en we zijn klaar om ze samen te matchen!
Wedstrijdgroepen zijn alleen dat: groepen tegels die overeenkomen (of niet). U kunt op elke tegel in een overeenkomende groep beginnen en elke andere tegel bereiken via de verbindingen. Alle tegels zijn verbonden. Elk van de verschillende kleuren geeft een andere overeenkomende groep aan. De enige die is voltooid, is de blauwe in het midden - hij heeft geen ongeldige verbindingen.
De klasse van de wedstrijdgroep zelf is eigenlijk extreem eenvoudig. Het is eigenlijk gewoon een verzameling tegels met een paar hulpfuncties. Hier is het:
openbare klasse MatchGroup openbare lijsttegels; public bool isClosed = true; public MatchGroup () tiles = new List (); public void SetTileColor (Color color) foreach (LineTile tile in tiles) tile.sprite.color = color; public void Destroy () tiles.Clear ();
Dit is verreweg het meest gecompliceerde onderdeel van dit proces. We moeten het hele bord analyseren, het opsplitsen in zijn individuele matchgroepen en vervolgens bepalen welke, indien aanwezig, volledig gesloten zijn. Ik ga deze klas bellen BitmaskPuzzleGame
, aangezien het de hoofdklasse is die de spellogica omvat.
Voordat we echter in de implementatie treden, zullen we een paar dingen definiëren. De eerste is een eenvoudig enum
dat de pijlen worden toegewezen op basis van welke richting ze worden geconfronteerd:
// Om ons te helpen bepalen welke pijl werd ingedrukt: public enum Richting Boven, Rechts, Onder, Links
De volgende is een struct
dat wordt verzonden vanaf een pijl die wordt ingedrukt, zodat we kunnen bepalen waar het zich op het bord bevindt en in welke richting het wordt geconfronteerd:
// Wanneer een pijl wordt ingedrukt, zal deze deze gegevens bevatten om erachter te komen wat te doen met het bord: public struct ArrowData public direction direction; openbare int-index; public ArrowData (Direction direction, int index) this.direction = direction; this.index = index;
Definieer vervolgens in de klasse de instantievariabelen die we nodig hebben:
// Bevat alle tegels van de map: openbare LineTile [] [] tileMap; // Bevat alle groepen verbonden tegels: openbare lijstmatchGroups = nieuwe lijst (); // Wanneer een rij / kolom wordt verschoven, wordt deze ingesteld op true, zodat HandleUpdate weet te vernieuwen: private bool matchGroupsAreDirty = true; // Hoeveel tegels breed het bord is: private int tileMapWidth; // Hoeveel tegels het bord hoog is: private int tileMapHeight;
Hier is een functie die een tegel neemt en alle omliggende tegels teruggeeft (die boven, onder, links en rechts ervan):
// Helper-methode om alle tegels boven / onder / rechts / links van een specifieke tegel te krijgen: privélijstGetTilesSurroundingTile (LineTile tile) Lijst surroundingTiles = nieuwe lijst (); int xIndex = tile.tileIndex.xIndex; int yIndex = tile.tileIndex.yIndex; if (xIndex> 0) surroundingTiles.Add (tileMap [xIndex - 1] [yIndex]); if (xIndex < tileMapWidth - 1) surroundingTiles.Add(tileMap[xIndex + 1][yIndex]); if (yIndex > 0) surroundingTiles.Add (tileMap [xIndex] [yIndex - 1]); if (yIndex < tileMapHeight - 1) surroundingTiles.Add(tileMap[xIndex][yIndex + 1]); return surroundingTiles;
Nu twee methoden die alle tegels in een kolom of rij retourneren, zodat we ze kunnen verplaatsen:
// Helper-methode om alle tegels in een specifieke kolom te krijgen: private LineTile [] GetColumnTiles (int columnIndex) if (columnIndex < 0 || columnIndex >= tileMapWidth) gooi nieuwe FutileException ("ongeldige kolom:" + columnIndex); LineTile [] columnTiles = new LineTile [tileMapHeight]; voor (int j = 0; j < tileMapHeight; j++) columnTiles[j] = tileMap[columnIndex][j]; return columnTiles; // Helper method to get all the tiles in a specific row: private LineTile[] GetRowTiles(int rowIndex) if (rowIndex < 0 || rowIndex >= tileMapHeight) gooit nieuwe FutileException ("ongeldige kolom:" + rowIndex); LineTile [] rowTiles = new LineTile [tileMapWidth]; voor (int i = 0; i < tileMapWidth; i++) rowTiles[i] = tileMap[i][rowIndex]; return rowTiles;
Nu twee functies die een kolom of rij tegels in een specifieke richting daadwerkelijk verschuiven. Wanneer een tegel van een rand verschuift, loopt deze rond naar de andere kant. Een rechtsverschuiving op een rij met Nub, Cross, Line resulteert bijvoorbeeld in een rij lijn, Nub, Kruis.
// Verplaats de tegels in een kolom één naar boven of naar beneden (met inwikkeling). private void ShiftColumnInDirection (int columnIndex, Direction dir) LineTile [] currentColumnArrangement = GetColumnTiles (columnIndex); int nextIndex; // Verplaats de tegels zodat ze zich op de juiste plaatsen in de tileMap-array bevinden. if (dir == Direction.Up) for (int j = 0; j < tileMapHeight; j++) nextIndex = (j + 1) % tileMapHeight; tileMap[columnIndex][nextIndex] = currentColumnArrangement[j]; tileMap[columnIndex][nextIndex].tileIndex = new TileIndex(columnIndex, nextIndex); else if (dir == Direction.Down) for (int j = 0; j < tileMapHeight; j++) nextIndex = j - 1; if (nextIndex < 0) nextIndex += tileMapHeight; tileMap[columnIndex][nextIndex] = currentColumnArrangement[j]; tileMap[columnIndex][nextIndex].tileIndex = new TileIndex(columnIndex, nextIndex); else throw new FutileException("can't shift column in direction: " + dir.ToString()); // Once the tileMap array is set up, actually visually move the tiles to their correct spots. for (int j = 0; j < tileMapHeight; j++) tileMap[columnIndex][j].y = (j + 0.5f) * tileSize; matchGroupsAreDirty = true; // Shift the tiles in a row either right or left one (with wrapping). private void ShiftRowInDirection(int rowIndex, Direction dir) LineTile[] currentRowArrangement = GetRowTiles(rowIndex); int nextIndex; // Move the tiles so they are in the correct spots in the tileMap array. if (dir == Direction.Right) for (int i = 0; i < tileMapWidth; i++) nextIndex = (i + 1) % tileMapWidth; tileMap[nextIndex][rowIndex] = currentRowArrangement[i]; tileMap[nextIndex][rowIndex].tileIndex = new TileIndex(nextIndex, rowIndex); else if (dir == Direction.Left) for (int i = 0; i < tileMapWidth; i++) nextIndex = i - 1; if (nextIndex < 0) nextIndex += tileMapWidth; tileMap[nextIndex][rowIndex] = currentRowArrangement[i]; tileMap[nextIndex][rowIndex].tileIndex = new TileIndex(nextIndex, rowIndex); else throw new FutileException("can't shift row in direction: " + dir.ToString()); // Once the tileMap array is set up, actually visually move the tiles to their correct spots. for (int i = 0; i < tileMapWidth; i++) tileMap[i][rowIndex].x = (i + 0.5f) * tileSize; matchGroupsAreDirty = true;
Wanneer we op een pijl klikken (d.w.z. wanneer de pijlknop wordt losgelaten), moeten we bepalen welke rij of kolom moet worden verschoven en in welke richting.
// Verschuif een kolom omhoog / omlaag of een rij rechts / links wanneer een pijl wordt ingedrukt en losgelaten. public void ArrowButtonReleased (knop FButton) ArrowData arrowData = (ArrowData) button.data; if (arrowData.direction == Direction.Up || arrowData.direction == Direction.Down) ShiftColumnInDirection (arrowData.index, arrowData.direction); else if (arrowData.direction == Direction.Right || arrowData.direction == Direction.Left) ShiftRowInDirection (arrowData.index, arrowData.direction);
De volgende twee methoden zijn de belangrijkste in het spel. De eerste neemt twee tegels en bepaalt wat voor soort verbinding ze hebben. Het baseert de verbinding op de eerste tegelinvoer in de methode (genaamd baseTile
). Dit is een belangrijk onderscheid. De baseTile
zou kunnen hebben ValidWithOpenSide
verbinding met de otherTile
, maar als u ze in de omgekeerde volgorde invoert, kan deze terugkeren Ongeldig
.
// Er zijn drie soorten verbindingen die twee tegels kunnen hebben: // 1. ValidWithSolidMatch - dit betekent dat de tegels nauwkeurig worden gematcht met hun verbonden vaste zijden. // 2. ValidWithOpen Side-this betekent dat de baseTile een open zijde heeft die de andere tile raakt, dus het maakt niet uit wat de andere tile is. // 3. Ongeldig - dit betekent dat de solide zijde van de baseTile overeenkomt met de open kant van de andere tegel, wat resulteert in een mismatch. private TileConnectionType TileConnectionTypeBetweenTiles (LineTile baseTile, LineTile otherTile) int baseTileBitmaskSide = baseTile.bitmask; // Het bitmasker voor de specifieke basisTegelzijde die de andere tegel aanraakt. int otherTileBitmaskSide = otherTile.bitmask; // Het bitmasker voor de specifieke andere tegelkant die de basistegel aanraakt. // Afhankelijk van welke kant van de basistegel de andere tegel is geplaatst, bitsgewijs en elke zijde samen. met // de bitwise constante voor die individuele kant. Als het resultaat 0 is, is de zijkant open. Anders, // is de zijkant stevig. if (otherTile.tileIndex.yIndex < baseTile.tileIndex.yIndex) baseTileBitmaskSide &= LineTile.kBitmaskBottom; otherTileBitmaskSide &= LineTile.kBitmaskTop; else if (otherTile.tileIndex.yIndex > baseTile.tileIndex.yIndex) baseTileBitmaskSide & = LineTile.kBitmaskTop; otherTileBitmaskSide & = LineTile.kBitmaskBottom; else if (otherTile.tileIndex.xIndex < baseTile.tileIndex.xIndex) baseTileBitmaskSide &= LineTile.kBitmaskLeft; otherTileBitmaskSide &= LineTile.kBitmaskRight; else if (otherTile.tileIndex.xIndex > baseTile.tileIndex.xIndex) baseTileBitmaskSide & = LineTile.kBitmaskRight; otherTileBitmaskSide & = LineTile.kBitmaskLeft; if (baseTileBitmaskSide == 0) retourneer TileConnectionType.ValidWithOpenSide; // baseTile kant raakt otherTile open. else if (otherTileBitmaskSide! = 0) retourneer TileConnectionType.ValidWithSolidMatch; // baseTile-kant en andereTile-kant zijn solide en afgestemd. else return TileConnectionType.Invalid; // baseTile kant is solide maar andere kant van de tegel is open. Mismatch!
Tenslotte, UpdateMatches
. Dit is de belangrijkste methode van allemaal. Dit is degene die door het bord gaat, alle stukjes analyseert, bepaalt welke met elkaar verbinden, en welke matchgroepen volledig gesloten zijn. Alles wordt uitgelegd in de opmerkingen.
// Doorzoek het bord en analyseer alle tegels, zoek naar overeenkomsten: private void UpdateMatches () // Overeenkomstgroepen worden bijgewerkt, zodat ze niet langer vies zijn: matchGroupsAreDirty = false; // Omdat glijdende kolommen en rijen alles kunnen verpesten, moeten we de oude matchgroepen verwijderen en opnieuw beginnen. // Houd er rekening mee dat er waarschijnlijk een manier is om het algoritme te gebruiken, waarbij we niet alle matches moeten verwijderen en // opnieuw moeten beginnen (bijvoorbeeld, de matches bijwerken die door een dienst zijn onderbroken), maar dat kan later komen als // je de prestaties moet verbeteren. foreach (MatchGroup matchGroup in matchGroups) matchGroup.Destroy (); matchGroups.Clear (); // We gaan het bord analyseren vanaf de tegel linksonder. De huidige basistegel is de enige // waar we momenteel vanaf beginnen en het opbouwen van overeenkomende groepen uit. LineTile currentBaseTile = tileMap [0] [0]; LijsttileSurrounders; // Variabele die omringende tegels van verschillende basistegels bewaart. Lijst checkedTiles = nieuwe lijst (); // We bewaren basistegels hier nadat ze zijn geanalyseerd, zodat we ze niet opnieuw analyseren. MatchGroup currentMatchGroup; // De overeenkomende groep die de analyse bevat, bevat de huidige basistegel. // Loop continu door het bord en maak matchgroepen totdat er geen tegels meer zijn om matchgroepen van te maken. while (currentBaseTile! = null) // Maak een nieuwe overeenkomende groep, voeg de huidige basistegel toe als eerste tegel. currentMatchGroup = nieuwe MatchGroup (); currentMatchGroup.tiles.Add (currentBaseTile); // Doorloop de tegels beginnend op de huidige basistegel, analyseer hun verbindingen, vind een nieuwe basistegel, // en herhaal opnieuw, enzovoort totdat u geen mogelijke verbindingen meer vindt met een van de tegels in de overeenkomende groep bool stillWorkingOnMatchGroup = waar; while (stillWorkingOnMatchGroup) // Vul de lijst tileSurrounders in met alle tegels rondom de huidige basistegel: tileSurrounders = GetTilesSurroundingTile (currentBaseTile); // Ga door alle omliggende tegels en controleer of hun solide zijden zijn uitgelijnd met de massieve zijden van de basistegel: foreach (LineTile surroundingTile in tileSurrounders) TileConnectionType connectionType = TileConnectionTypeBetweenTiles (currentBaseTile, surroundingTile); // Voeg een surrounder toe aan de overeenkomende groep als er een degelijke overeenkomst is. // Als er een mismatch is, is de matchgroup geen perfecte "gesloten" matchgroep. // Als er een mismatch is vanwege een open zijde van de basistegel, maakt dat eigenlijk niets uit // omdat er geen solide zijde wordt afgekapt (dit wordt TileConnectionType.ValidWithOpenSide genoemd). if (connectionType == TileConnectionType.ValidWithSolidMatch) currentMatchGroup.tiles.Add (surroundingTile); else if (TileConnectionTypeBetweenTiles (currentBaseTile, surroundingTile) == TileConnectionType.Invalid) currentMatchGroup.isClosed = false; // Als de basistegel een gesloten / solide kant heeft die de rand van het bord raakt, kan de overeenkomstgroep niet worden gesloten. if (((currentBaseTile.bitmask & LineTile.kBitmaskTop)! = 0 && currentBaseTile.tileIndex.yIndex == tileMapHeight - 1) || ((currentBaseTile.bitmask & LineTile.kBitmaskRight)! = 0 && currentBaseTile.tileIndex.xIndex == tileMapWidth - 1) || ((currentBaseTile.bitmask & LineTile.kBitmaskBottom)! = 0 && currentBaseTile.tileIndex.yIndex == 0) || ((currentBaseTile.bitmask & LineTile.kBitmaskLeft)! = 0 && currentBaseTile.tileIndex.xIndex == 0)) currentMatchGroup.isClosed = false; // Voeg onze basistegel toe aan een array, zodat we dit later niet opnieuw controleren: if (! CheckedTiles.Contains (currentBaseTile)) checkedTiles.Add (currentBaseTile); // Zoek een nieuwe basistegel die we hebben toegevoegd aan de overeenkomende groep, maar die nog niet zijn geanalyseerd: for (int i = 0; i < currentMatchGroup.tiles.Count; i++) LineTile tile = currentMatchGroup.tiles[i]; // If the checkedTiles array has the tile in it already, check to see if we're on the last // tile in the match group. If we are, then there are no more base tile possibilities so we are // done with the match group. If checkedTiles DOESN'T have a tile in the array, it means // that tile is in the match group but hasn't been analyzed yet, so we need to set it as // the next base tile. if (checkedTiles.Contains(tile)) if (i == currentMatchGroup.tiles.Count - 1) stillWorkingOnMatchGroup = false; matchGroups.Add(currentMatchGroup); else currentBaseTile = tile; break; // We're done with a match group, so now we need to find a new un-analyzed tile that's // not in any match groups to start a new one from. So we'll set currentBaseTile to // null then see if we can find a new one: currentBaseTile = null; for (int i = 0; i < tileMapWidth; i++) for (int j = 0; j < tileMapHeight; j++) LineTile newTile = tileMap[i][j]; if (!TileIsAlreadyInMatchGroup(newTile)) currentBaseTile = newTile; break; if (currentBaseTile != null) break;
Het enige wat we nog hebben is het HandleUpdate
functie! Bij elk frame worden de overeenkomstgroepen bijgewerkt als ze moeten worden bijgewerkt (d.w.z.. matchGroupsAreDirty == true
) en hun kleuren instellen.
public void HandleUpdate () if (matchGroupsAreDirty) UpdateMatches ();
Dit is hoe het algoritme eruit zou zien als elke stap geanimeerd zou zijn:
En dat is het! Hoewel een deel van de code hierin specifiek is voor Futile, moet het vrij duidelijk zijn hoe deze moet worden uitgebreid naar een andere taal of engine. En om te herhalen, er ontbreken een heleboel niet-essentiële dingen in dit bericht. Kijk naar de broncode om te zien hoe het allemaal samenwerkt!