Bouw een op rasters gebaseerd puzzelspel zoals Minesweeper in Unity Setup

Puzzelgames vinden vaak plaats op een raster met tegels met gedrag en eigenschappen, en reageren op regels en ingangen. In deze serie laat ik je zien hoe je een eenvoudige, eenvoudige versie van het klassieke spel Minesweeper kunt bouwen, het perfecte voorbeeld om mee te beginnen voor het maken van je eigen puzzelspellen.

Of je nu een memoryspel voor kinderen maakt of een complexe strategietitel, het implementeren van de basisbouwstenen van Minesweeper is een geweldige plek om te beginnen. In het eerste deel van deze drieledige instructiereeks bouwen we een speelveld dat u vervolgens kunt gebruiken om uw eigen versie van het spel te maken. 

Je hebt Unity hiervoor nodig, en een basisbegrip ervan. (Bekijk Build Arkanoid With Unity als je nieuw bent.) De broncode kan worden gedownload, maar is niet noodzakelijk om deze tutorial te voltooien.

De regels van de mijnenveger

Mijnenveger is een puzzelspel waarin je alle mijnen in een veld moet lokaliseren. De veldgrootte varieert per moeilijkheidsgraad en kan variëren van 9x9 tegels (eenvoudig) tot 16x30 tegels (hard) of aangepaste afmetingen.

Door op een tegel te klikken, "ontdek" je hem. Als het een mijn is, verlies je; als het leeg is en ten minste één mijn in een van de aangrenzende tegels staat, verschijnt er een nummer dat het aantal mijnen in de naburige tegels aangeeft. Als er geen mijnen in de aangrenzende tegels zijn, worden alle aangrenzende tegels ook onbedekt.

Een tegel kan worden gemarkeerd door er met de rechtermuisknop op te klikken en er een vlag op te plaatsen. Zodra alle tegels met mijnen correct zijn gemarkeerd, is het spel gewonnen.

Probeer het hier:

Elementen die we nodig hebben

Uit de bovenstaande regels kunnen we de verschillende elementen extraheren die onze eenvoudige versie van mijnenveger nodig heeft. Dit zijn

  • Een raster met tegels
  • Tegels die een mijn kunnen bevatten
  • Tegels die kunnen worden geïntervenieerd via muisklikken
  • Tegels die rekening houden met aangrenzende tegels bij het reageren op muisklikken

Een basistegel bouwen

Maak een nieuw Unity-project. Maak een kubus en geef hem een ​​naam Tegel. Sleep het naar de projectmap om er een prefab van te maken. We gebruiken deze niet-functionele tegel om het speelveld op te bouwen en later functionaliteit aan toe te voegen.

De Grid Generator bouwen

Maak een nieuw leeg object en noem het rooster, en maak er ook een prefab van. Dit is de generator van het speelveld en alle tegels erin.

Maak een nieuw JS-bestand, noem het rooster ook, en voeg het toe aan de rooster voorwerp. 

Voeg de volgende regels toe aan het Grid-script, zodat we kunnen beginnen met het maken van een veld:

public var tilePrefab: GameObject; public var numberOfTiles: int = 10; public var distanceTetweenTiles: float = 1.0; functie Start () CreateTiles ();  functie CreateTiles () 

Sleep vervolgens de prefab Tile naar de Tegel Prefab slot van de rooster voorwerp. Het zou er zo uit moeten zien:

De numberOfTiles variabele stelt u in staat om het aantal tegels in te stellen dat moet worden gemaakt. DistanceBetweenTiles definieert de afstand tussen hen, zodat we de afstand naar wens kunnen aanpassen.

Op dit moment doet de netwerkgenerator niets. Voeg deze code toe om het meerdere tegels te laten maken CreateTiles () functie:

var xOffset: float = 0,0; for (var tilesCreated: int = 0; tilesCreated < numberOfTiles; tilesCreated += 1)  xOffset += distanceBetweenTiles; Instantiate(tilePrefab, Vector3(transform.position.x + xOffset, transform.position.y, transform.position.z), transform.rotation); 

Als je de huidige scène uitvoert, zou het een regel van onze tegels moeten maken, zoals deze:

De functie maakt kopieën van het prefab prefab - zoveel als we hebben opgegeven - en plaatst ze op een rij, een afstand van distanceBetweenTiles deel. Probeer een aantal verschillende waarden uit om een ​​goede spatiëring te vinden.

Maar voor Mijnenveger hebben we een raster nodig, geen lijn. Voeg om dit te bereiken deze variabele toe aan het begin van de rooster code:

openbare var tilesPerRow: int = 4;

... en pas het aan CreateTiles () functie om er zo uit te zien:

functie CreateTiles () var xOffset: float = 0.0; var zOffset: float = 0,0; for (var tilesCreated: int = 0; tilesCreated < numberOfTiles; tilesCreated += 1)  xOffset += distanceBetweenTiles; if(tilesCreated % tilesPerRow == 0)  zOffset += distanceBetweenTiles; xOffset = 0;  Instantiate(tilePrefab, Vector3(transform.position.x + xOffset, transform.position.y, transform.position.z + zOffset), transform.rotation);  

Als je het uitvoert, moet je eindigen met verschillende regels met tegels:

Als u de  tilesPerRow verander correct (zoals 24 tegels in 6 rijen), moet de generator een mooi rechthoekig speelveld creëren. Als uw programmeervaardigheden voldoende geavanceerd zijn, kunt u proberen uit te zoeken hoe u het proces verder kunt automatiseren. (De versie van Mijnenveger die we bouwen, werkt ook met onregelmatig gevormde velden.)

De tegels in mijnen draaien

Nu we een standaard Mijnenveger-veld kunnen maken, kunnen we eraan werken om er echte mijnen aan toe te voegen.

Maak een nieuw JS-bestand, noem het Tegel, en voeg het toe aan het prefab Tile. Voeg vervolgens de volgende variabele eraan toe:

public var isMined: boolean = false;

Dit zal ons vertellen of de tegel een mijn erin heeft. 

Vervolgens moeten we de eigenlijke mijnen in het net plaatsen. Wijzig daarvoor de GameObject type van de tegel prefab van de nieuwe Tegel klas die we net hebben gemaakt.
Verander de tilePrefab variabele zodat het er zo uitziet:

public var tilePrefab: Tegel;

En wijs vervolgens het Tile-object opnieuw toe aan die variabele. Nu kan het automatisch toegang krijgen tot de variabelen die we daar vanaf het begin hebben ingevoerd.

Het toewijzen van mijnen is een beetje lastiger. We doen dit vanuit de Grid-generator. 

Eerst drie arrays om onze tegels op de Grid-code te houden:

static var tilesAll: Tile []; static var tilesMined: Array; static var tilesUnmined: Array;

We moeten ze ook initialiseren. Zet de volgende regels aan het begin van de CreateTiles () functie:

tilesAll = new Tile [numberOfTiles]; tilesMined = new Array (); tilesUnmined = new Array ();

Wijzig vervolgens de instantiate-opdracht in de CreateTiles () functie om er zo uit te zien:

var newTile = Instantiate (tilePrefab, Vector3 (transform.position.x + xOffset, transform.position.y, transform.position.z + zOffset), transform.rotation); tilesAll [tilesCreated] = newTile;

Voeg nu deze opdracht toe aan het einde van de CreateTiles () functie om het te starten AssignMines () werkwijze:

AssignMines ();

De CreateTiles () functie zou er als volgt uit moeten zien:

function CreateTiles () tilesAll = new Tile [numberOfTiles]; tilesMined = new Array (); tilesUnmined = new Array (); var xOffset: float = 0,0; var zOffset: float = 0,0; for (var tilesCreated: int = 0; tilesCreated < numberOfTiles; tilesCreated += 1)  xOffset += distanceBetweenTiles; if(tilesCreated % tilesPerRow == 0)  zOffset += distanceBetweenTiles; xOffset = 0;  var newTile = Instantiate(tilePrefab, Vector3(transform.position.x + xOffset, transform.position.y, transform.position.z + zOffset), transform.rotation); tilesAll[tilesCreated] = newTile;  AssignMines(); 

Voeg ook de functie toe AssignMines (), zodat we het echt kunnen gebruiken:

function AssignMines () tilesUnmined = tilesAll; for (var minesAssigned: int = 0; minesAssigned < numberOfMines; minesAssigned += 1)  var currentTile: Tile = tilesUnmined[Random.Range(0, tilesUnmined.length)]; tilesMined.Push(currentTile); tilesUnmined.Remove(currentTile); currentTile.GetComponent(Tile).isMined = true;  

Dit is wat er gebeurt: wanneer een nieuwe tegel wordt gemaakt in de CreateTiles-functie is toegevoegd aan de tilesAll-matrix. Alle tegels daarin worden vervolgens gekopieerd naar de tilesUnmined-matrix. Uit deze reeks hebben we willekeurig één tegel gekozen om een ​​mijn aan toe te voegen. We voegen een mijn toe door de isMined-verander in waar, verwijder het van de tilesUnmined-array en voeg het toe aan de tilesMined-array (die we later zullen gebruiken). Uiteindelijk hebben we willekeurig het opgegeven aantal mijnen op het speelveld geplaatst.

Op dit moment is een gedolven tegel niet zichtbaar anders dan een unmined tegel. Het doel van het spel is om dat alsnog uit te zoeken!

In deze build kun je testen hoe het hoort te werken. Voor demonstratiedoeleinden worden gedolven tegels als rood weergegeven.

En voilá: je hebt nu een Mijnenveger-veld met een aangepast formaat!

De tegels visueler interessant maken

Op dit moment zijn de tegels standaard Unity-kubussen. Laten we ze echt maken tegels.

In de bronbestanden vindt u een 3D-bestand genaamd puzzleObjects.fbx. Kopieer het naar uw activamap, zodat we het in onze game kunnen gebruiken. Zorg ervoor dat het bestand is geïmporteerd met het formaat ingesteld op 1, zodat het past bij de instellingen die we tot nu toe hebben gebruikt. 

De importinstellingen van het bestand zouden er als volgt uit moeten zien:

Ga vervolgens naar de instellingen van de prefab tile en verwissel de cube mesh voor de tileImproved maas.

Terwijl we hier zijn, druk je op Reset op de Box Collider onderdeel van de tegel. Dit zorgt ervoor dat de spuitmachine weer dicht op de tegel past.

Geef als laatste de tegel een nieuw materiaal, zodat deze niet de standaard witte uitstraling heeft.

Vergeet niet om alle wijzigingen in de tegel-prefab ook toe te passen, zodat nieuwe worden gemaakt wanneer we een nieuwe game starten. Als je het uitprobeert, moet het spel het raster maken met deze nieuwe tegels in plaats van de oude kubussen.

Een nummerweergave aan de tegels toevoegen

We hebben een manier nodig om een ​​nummer weer te geven zodat een tegel ons laat zien hoeveel mijnen er naast liggen. Een eenvoudige manier om dit te bereiken is door een 3D Tekst, wat met eenheid komt.

Maak er een door op te klikken GameObject> Maak anders> 3D-tekst, en voeg het toe aan de tegel. Het zou er zo uit moeten zien:

Laten we dat verbeteren. Draai de tekst zodat deze naar boven wijst. Stel de reeks in waarnaar deze momenteel wordt weergegeven 0, zodat we weten welke maat de tekst zal zijn. Pas ook de Lettertypegrootte en Lettergrootte, zodat het er niet wazig uitziet.

Super goed! Nu moeten we toegang hebben tot de 3D-tekst in code. Voeg de volgende variabele toe aan de Tegel code:

public var displayText: TextMesh;

Sleep de 3D-tekst naar de open sleuf, zodat we deze later via code kunnen openen.

Vergeet niet om alles toe te passen op de prefab tegels en probeer het uit. De nieuwe en geïmporteerde tegels moeten nu worden gemaakt.

Conclusie

We hebben een functionele basis voor een uit puzzelspel gemaakt, maar kunnen deze nog niet echt spelen. We voegen die functionaliteit toe in het tweede deel van deze serie.