Snake, de groeiende slang...

In het spel Snake bestuur je een hongerige slang. Bij elk stukje eten wat de slang op eet, groeit het lichaam van de slang. In elk level moet je een bepaald aantal stukjes eten voordat je doorgaat naar een volgend level. Hoe sneller je het voedsel pakt, des te meer punten je er voor krijgt. Het gevaar in het spel komt van muren en het groeiende lichaam van de slang. Je mag met de kop van de slang namelijk niet tegen je eigen lichaam aankomen.

Snake is een variant op het spel Blockade uit 1976. In de jaren 70 heeft het spel verschillende namen gehad, zoals Surround, Chase en Worm. Snake is écht populair geworden bij het grote publiek rond 1998, toen het standaard werd meegeleverd op de telefoons van Nokia.

In dit hoofdstuk maak je zelf de besturing van de slang.

Leerdoelen: wat kun je na deze oefening?

Na het maken van Snake kun je variabelen gebruiken om de positie van een object in een room te veranderen. Je kunt in eigen woorden uitleggen wat het verschil is tussen een persistent object en een gewoon object. Daarnaast kun je uitleggen hoe het Create-event gebruikt wordt om recursie toe te passen. Ook kun je de getallen noemen die in Game Maker horen bij de richtingen links, rechts, boven en onder. Tot slot kun je in eigen woorden uitleggen hoe vaak de acties in een Step-event worden uitgevoerd.

Eerste versie testen

Download nu het zip-bestand (snake.zip) met daarin alle bestanden die je nodig hebt om Snake te maken. Er is al een heel veel voor je gemaakt, maar het spelletje is nog niet speelbaar. Je gaat zodadelijk namelijk zelf de besturing van de slang maken. Wat werkt er dan al wel? Open nu eerst snake1.gmk.

De controller: obj_controller

In obj_controller zijn al allerlei variabelen ingesteld. Zie afbeelding 1. Je begint met 0 punten, 3 levens en in level 1. Er is een een variabele time. Deze houdt bij hoe snel je het voedsel pakt. De variabele to_catch bepaalt hoeveel stukjes je in elk level moet eten. In dit geval dus 10 per level. Tot slot is er de variabele needed die bij houdt hoeveel stukjes je nog moet eten. Als needed (nodig) gelijk is aan 0, dan ga je door naar het volgende level.

Er zijn al heel wat variabelen ingesteld.Afbeelding 1. Er zijn al heel wat variabelen ingesteld.

Persistent betekent blijvend. Het Create-event wordt overigens maar één keer uitgevoerd. Namelijk, in de kamer waar het object wordt aangemaakt.

Verder zie je dat er een vinkje staat bij Persistent. Dit zorgt ervoor dat het object voor altijd blijft bestaan wanneer het eenmaal in een room heeft gestaan. Met andere woorden: obj_controller staat alleen in de eerste room, maar werkt ook nog steeds in room 2, 3, 4, enzovoorts.

Voedsel willekeurig in de kamer

Het plaatsen van een willekeurig stukje voedsel in de kamer is behoorlijk ingewikkeld. Uiteraard moet het stukje binnen de grenzen van de kamer worden geplaatst, maar tegelijkertijd mag het ook niet op het lichaam van de slang geplaatst worden. Aangezien de slang beweegt, moeten we dus goed controleren waar het stukje voedsel gemaakt mag worden. Zie afbeelding 2.

Het Create-event van obj_point (voedsel). Zie je de recursie?Afbeelding 2. Het Create-event van obj_point (voedsel). Zie je de recursie?

Als de kamer heel vol staat, bijvoorbeeld omdat de slang al heel lang is, dan kan het best zo zijn dat er 20 keer gegokt moet worden. Omdat de computer dit allemaal heel snel berekent merk je daar gelukkig niets van.

De variabelen newx en newy worden met een formule bepaald. In deze formule zie je onder andere de functie random(). Met deze functie kun je een willekeurig getal kiezen. In dit geval worden er coördinaten gegokt. Vervolgens wordt er gekeken of deze coördinaten vrij zijn. Als dat zo is, dan wordt het stukje voedsel geplaatst. Is de plaats niet vrij? Dan roepen we opnieuw het Create-event aan en gokken we dus opnieuw. Dit is een vorm van recursie, want het object wordt opnieuw gemaakt.

Het lichaam volgt automatisch de kop van de slang

Je kunt de slang nog niet besturen, maar het groeien van de slang is al geprogrammeerd. Elk lichaamsdeel van de slang volgt het lichaamsdeel waar het aan vast zit. Het eerste lichaamsdeel volgt de kop. Zie afbeelding 3. Hierin is de kop weergegeven met een rood blokje. De lichaamsdelen zijn groen.

Elk lichaamsdeel heeft een uniek nummer, een ID.Afbeelding 3. Elk lichaamsdeel heeft een uniek nummer, een ID.

Eigenlijk maken we hier gebruik van een Linked List (gelinkte lijst).

Stel dat de kop in de afbeelding hierboven botst met voedsel. Wat gebeurt er dan?

  1. Er is een globale variabele global.last met het id van het laatst aangemaakte lichaamsdeel. In dit geval global.last = 9.
  2. Er wordt een nieuw lichaamsdeel gemaakt, met variabelen id = 10, follow = global.last.
  3. De globale variabele global.last wordt op 10 gezet. Dus global.last = 10.

Als je wilt weten hoe dit precies is geprogrammeerd, bekijk dan eens obj_snake_body. Er worden in totaal maar 4 variabelen en 4 acties voor gebruikt, dus veel werk is het eigenlijk niet.

Zelf bouwen

Dan is het nu tijd om zelf te gaan programmeren. Je gaat alleen obj_snake_head aanpassen. Open nu het al bestaande object obj_snake_head en volg onderstaande stappen.

Een richting is voor Game Maker een getal tussen de 0 en 360.

Rechts = 0
Boven = 90
Links = 180
Beneden = 270

Key-Press events toevoegen

De slang mag niet zomaar elke richting op bewegen. Als de slang bijvoorbeeld naar rechts beweegt, dan kan hij niet opeens naar links gaan. We gebruiken de variabele heading om de richting in te stellen.

  1. action_ifvariableVoeg een Key-Press, Left-event toe. Voeg vervolgens een Test Variable-actie toe (tab: control). Bij variable typ je heading en bij value typ je 0. Zet een vinkje bij NOT. Zo controleer je of je niet naar rechts beweegt. Het venster ziet er nu zo uit.
  2. action_variableVoeg hieronder een Set Variable-actie toe (tab: control). Bij variable typ je heading en bij value typ je 180. Zo stel je de richting naar links in. Het venster ziet er nu zo uit.
  3. action_ifvariableVoeg een Key-Press, Right-event toe. Voeg vervolgens een Test Variable-actie toe (tab: control). Bij variable typ je heading en bij value typ je 180. Zet een vinkje bij NOT. Zo controleer je of je niet naar links beweegt. Het venster ziet er nu zo uit.
  4. action_variableVoeg hieronder een Set Variable-actie toe (tab: control). Bij variable typ je heading en bij value typ je 0. Zo stel je de richting naar rechts in. Het venster ziet er nu zo uit.
  5. action_ifvariableVoeg een Key-Press, Up-event toe. Voeg vervolgens een Test Variable-actie toe (tab: control). Bij variable typ je heading en bij value typ je 270. Zet een vinkje bij NOT. Zo controleer je of je niet naar beneden beweegt. Het venster ziet er nu zo uit.
  6. action_variableVoeg hieronder een Set Variable-actie toe (tab: control). Bij variable typ je heading en bij value typ je 90. Zo stel je de richting naar boven in. Het venster ziet er nu zo uit.
  7. action_ifvariableVoeg een Key-Press, Down-event toe. Voeg vervolgens een Test Variable-actie toe (tab: control). Bij variable typ je heading en bij value typ je 90. Zet een vinkje bij NOT. Zo controleer je of je niet naar boven beweegt. Het venster ziet er nu zo uit.
  8. action_variableVoeg hieronder een Set Variable-actie toe (tab: control). Bij variable typ je heading en bij value typ je 270. Zo stel je de richting naar beneden in. Het venster ziet er nu zo uit.

Als je alles goed hebt gedaan ziet het object-venster van obj_snake_head er nu zo uit als in afbeelding 12.

Je hebt nu 4 keer een Key-Press event ingesteld.Afbeelding 12. Je hebt nu 4 keer een Key-Press event ingesteld.

Als je het spel nu opstart, lijkt het alsof er nog niets is veranderd. Je kunt namelijk nog niet bewegen. Op de achtergrond wordt nu echter wel de variabele heading ingesteld wanneer je de pijltjestoetsen indrukt. We gaan het Step-Event gebruiken om te bewegen. Je zult daarna zien dat alles werkt!

Is het bovenstaande niet gelukt? Geen zorgen. Open dan snake2.gmk om verder te gaan.

Bewegen via het Step-Event

Het Step-event moet je zien als één grote lus aan herhalingen. Alle acties die erin staan worden van boven naar beneden uitgevoerd. De snelheid waarmee dat gebeurt is afhankelijk van de room_speed (Zie afbeelding 13). Standaard staat de room_speed ingesteld op 30. Dit betekent dat de acties in het Step-event 30 keer per seconde worden uitgevoerd.

De speed van een room instellen.Afbeelding 13. De speed van een room instellen.

In dit spel wordt de room_speed gebruikt om de snelheid van de slang in te stellen. In level 1 staat de snelheid op 8, in level 2 op 9 en in level 3 op 10. De snelheid van de slang wordt dus in elk level hoger.

Het grid is 16x16. Vandaar dat je steeds het getal 16 in het Step-event ziet staan.

Maak nu zelf het Step-event na, zoals hieronder in afbeelding 14 is weergegeven.

Het Step-event instellen: eindelijk bewegen!Afbeelding 14. Het Step-event instellen: eindelijk bewegen!

Tot slot voegen we nog twee dezelfde acties toe aan het Create-event. Zie afbeelding 15. Op deze manier begint de slang al met twee lichaamsdelen.

Met twee lichaamsdelen beginnen.Afbeelding 15. Met twee lichaamsdelen beginnen.

Is er iets niet helemaal gelukt? Open dan snake_final.gmk voor de volledige versie.

Samenvatting

Gefeliciteerd! Het spel is nu klaar. Lukt het je om het spel uit te spelen?

Je hebt gebruik gemaakt van de variabele heading om de beweegrichting in te stellen. In het Step-event van obj_snake_head gebruik je heading om de x en y coördinaten van de slangenkop aan te passen. Dit gaat met stapjes van 16 pixels, omdat er een grid van 16x16 is gebruikt. Elk lichaamsdeel volgt een eerder gemaakt lichaamsdeel, waardoor je alleen de de kop hoeft te besturen.

Het object obj_controller is persistent en staat daarom alleen in level1. Dit object houdt de score, het aantal levens, de tijd en nog een aantal variabelen bij. Een object dat persistent is blijft bestaan wanneer het gemaakt is, ook in kamers waar je het object niet neerzet.

Een richting is in Game Maker een getal tussen 0 en 360. Je weet inmiddels de waarden die horen bij links (180), rechts (0), boven (90) en beneden (270).

Hoe vaak het Step-Event wordt uitgevoerd is afhankelijk van de room_speed. Bij een room_speed van 8 worden de acties in het Step-event 8 keer per seconde uitgevoerd.

Je hebt ook weer een voorbeeld gezien van recursie. Namelijk, het plaatsen van een stukje voedsel (obj_point). Het Create-event speelt hierbij een grote rol. In dit event wordt namelijk, wanneer dat nodig is, een nieuwe instantie van obj_point aangemaakt. Op die manier kan opnieuw, en opnieuw, en opnieuw het Create-event van obj_point worden aangeroepen, totdat er een geschikte positie voor het stukje voedsel is gevonden.

Extra's

Er zijn nog vele uitbreidingen mogelijk op dit spelletje. Hieronder vind je een lijst met ideeën, maar je mag natuurlijk ook zelf iets verzinnen.