PXT: Snake
Skrevet av: Håvard Nygård Jakobsen
Oversatt av: Stein Olav Romslo
Introduksjon
Ein eller annan variant av Snake har eksistert på datamaskiner heilt sidan slutten av 1970-talet. Mange vaksne kjenner spelet frå Nokia sine mobiltelefonar, medan mange born kjenner det frå moderne versjonar som slither.io.
I spelet styrer me ein slange rundt på skjermen, og slangen må unngå å krasje i kanten av skjermen og seg sjølv. Slangen veks når den et mat som dukkar opp tilfeldige stader, og spelet går fortare og fortare etter kvart som slangen veks.
I denne oppgåva brukar me engelske namn på klossar og variablar. Dette er mellom anna for at det skal vere enklare å finne att innebygde funksjonar når me byttar mellom klossprogrammering og Javascript, sidan funksjonane har engelske namn i Javascript. Det er veldig vanleg at programmerarar brukar engelske namn på funksjonar og variablar. Dette gjer det mellom anna enklare å poste kode på internettforum og få hjelp frå heile verda.
Denne oppgåva er ganske lang, men me tek det steg for steg og forklarar undervegs. La oss setje i gong.

Steg 1: Teikne slangen
Det fyrste me treng er ein liten kodesnutt som teiknar slangen vår. Skjermen består av 5x5 ledlys. Desse kan me skru av og på som me vil med litt kode. For å teikne slangen treng me noko som kan passe på kor me skal teikne den. Til det skal me bruke eit array, ein type variabel som inneheldt ei liste med verdiar. I lista vår brukar me to verdiar for å teikne ein bit av slangen. Den fyrste verdien seier kva kolonne me skal teikne i (X
), og den neste seier kva rad me skal teikne i (Y
). Saman får me ein koordinat (X, Y)
for ledlyset som me skal skru på.

Steg for steg
No treng me kode for å teikne slangen. For å gjere det enklare å halde oversikt over programmet vårt, så gjer me dette med ein funksjon.
Kvifor startar me på 0
og går til lengda minus éin?
Tenk deg at du har ein stabel med ark, til dømes ei oppgåve som denne. Kor mange gonger må du bla for å lese den fyrste sida? Kor mange gonger må du bla for å lese alle arka? Slik fungerer eit array, du startar i posisjon 0, og må bruke antal minus éin for å bla gjennom alle. Viss det er vanskeleg å forstå, så kan du prøve å tenke "slik er det berre" no, og så blir du vant til det seinare.


Test prosjektet
Prøv spelet i simulatoren for å teste koden så langt. Sjekk at det blir teikna to punkt.
Eigentleg er det me skriv noko som heiter Typescript. Det er ein variant av Javascript. I vanleg Javascript treng me ikkje bruke type på variablar, men det må ein nokre stader i Typescript. Til dømes må me spesifisere at ein variabel som skal innehalde tal skal gjere det med let x: number
.
Då har me det me treng for å teikne slangen. Men det er litt keisamt at den berre står stille. Det må me gjere noko med!
Steg 2: Slithering snake
No skal me få slangen til å bevege seg. Sidan slangen kan bevege seg opp, ned, til venstre og til høgre, så treng me ein variabel som seier kva retning den er på veg akkurat no. Me beveger slangen ved å leggje til eit nytt punkt på starten, og å ta bort det siste punktet på halen.
Tips
I denne oppgåva brukar me både klossprogrammering og handskrive kode. Før me byttar mellom klossprogrammering og Javascript kan det vere lurt å lagre spelet. Det brukar å gå fint å bytte mellom desse sjølv om nokre av klossane kan bli grå. Det hender at Makecode ikkje forstår at noko kode forsvinn, då er det veldig greitt å ha eit lagra punkt å gå tilbake til. Men du treng ikkje å bry deg viss det berre er nokre variablar som flyttar seg litt på skjermen.
Steg for steg
function updateSnake(){ }
x = snake[0] y = snake[1]
if (direction == 'up') { y = y - 1; } if (direction == 'down') { y = y + 1; } if (direction == 'left') { x = x - 1 } if (direction == 'right') { x = x + 1 }
snake.unshift(y); snake.unshift(x); snake.pop(); snake.pop();
basic.forever(function () { drawSnake(); updateSnake(); })
Test prosjektet
Prøv koden i simulatoren for å teste koden så langt.
-
basic.forever(function () { basic.clearScreen(); drawSnake(); updateSnake(); })
-
basic.forever(function () { basic.clearScreen(); drawSnake(); updateSnake(); basic.pause(1000); })
Steg 3: Styring
No er det på tide å leggje inn styring av slangen. Men fyrst lagar me ein liten startskjerm.
Steg for steg



Test prosjektet i simulatoren
No skal slangeikonet visast til du trykkar på ein knapp, då startar spelet. Men me treng meir kode for å styre. Når ein speler skal A-knappen styre slangen 90 grader mot venstre frå noverande retning, medan B-knappen styrer slangen 90 grader mot høgre.
Steg for steg
input.onButtonPressed(Button.A, function () { if (isPlaying) { if (direction == 'up') { direction = 'left'; } else if (direction == 'left') { direction = 'down'; } else if (direction == 'down') { direction = 'right'; } else if (direction == 'right') { direction = 'up'; } } else { isPlaying = true } }) input.onButtonPressed(Button.B, function () { if (isPlaying) { if (direction == 'up') { direction = 'right'; } else if (direction == 'right') { direction = 'down'; } else if (direction == 'down') { direction = 'left'; } else if (direction == 'left') { direction = 'up'; } } else { isPlaying = true; } })
Test prosjektet
Prøv spelet i simulatoren for å teste koden så langt. Sjekk at styringa virkar.
No kan du styre slangen, men det er eit lite problem. Viss me trykkar fort to gonger på ein knapp går slangen i motsett retning. Det vil me ikkje, sidan det tyder at slangen går gjennom seg sjølv, og det blir berre tull.
Steg for steg
input.onButtonPressed(Button.A, function () { if (isPlaying) { if (buttonPressed) { return; } buttonPressed = true; } })
Test prosjektet
Prøv spelet i simulatoren for å teste koden så langt. Viss alt stemmer no er det berre eitt knappetrykk som gjeld for kvart hakk slangen beveger seg.
Steg 4: GAME OVER!
Men me kan jo styre slangen sjølv om den køyrer utanfor skjermen. Det skal sjølvsagt ikkje vere lov!
Steg for steg
function checkGameOver(x: number, y: number) { if(x < 0 || x > 4 || y < 0 || y > 4) { direction = 'up'; snake = [2, 1, 2, 2] basic.showIcon(IconNames.Skull); basic.pause(2000); basic.showIcon(IconNames.Snake); isPlaying = false; } }
Test prosjektet
På tide å prøve spelet på micro:bit
Steg 5: Litt lyd, takk!
Steg for steg
music.playTone(Note.C5, 20)
music.beginMelody(music.builtInMelody(Melodies.Wawawawaa), MelodyOptions.Once);
Test prosjektet
Kople til hovudtelefonar eller ein høgtalar til micro:bit-en og sjekk at du får lyd. Test i simulatoren viss du ikkje har moglegheit til å kople til noko.
Steg 6: Mat
No kan me styre slangen, det blir game over, og me har lyd. På tide å leggje til mat slik at me får eit skikkeleg spel. Maten skal me generere på ein tilfeldig stad, men me må passe på at det ikkje er på slangen.
Steg for steg
let foodX: number = 0 let foodY: number = 0
function generateFood(){ foodX = Math.randomRange(0, 4); foodY = Math.randomRange(0, 4); }
function isOnSnake(myX: number, myY: number) { for (let index = 0; index <= snake.length - 1; index+=2) { if (myX === snake[index] && myY === snake[index+1]) { return true; } } return false; }
function generateFood() { foodX = Math.randomRange(0, 4); foodY = Math.randomRange(0, 4); if (isOnSnake(foodX, foodY)) { generateFood(); } }
function drawFood() { led.plot(foodX, foodY); }
basic.forever(function () { if (isPlaying) { basic.clearScreen() drawFood(); drawSnake(); basic.pause(1000); updateSnake(); } })
Test prosjektet
Test i simulatoren for å sjekke at maten blir teikna.
No har me laga maten, då gjenstår det berre å ete den. Korleis veit me om me er på riktig stad for å ete maten? Jo, viss x
og y
i updateSnake()
er dei same som foodX
og foodY
. Då skal slangen vekse med eit punkt. Og korleis gjer me det? Me let berre vere å fjerne det siste punktet på halen i updateSnake()
! Smart?
Steg for steg
if (x == foodX && y == foodY) { music.beginMelody(music.builtInMelody(Melodies.BaDing), MelodyOptions.Once); generateFood(); } else { snake.pop(); snake.pop(); }
function checkGameOver(x: number, y: number) { if (x < 0 || x > 4 || y < 0 || y > 4 || isOnSnake(x,y)) { direction = 'up'; snake = [2, 1, 2, 2] music.beginMelody(music.builtInMelody(Melodies.Wawawawaa), MelodyOptions.Once); basic.showIcon(IconNames.Skull); basic.pause(2000); basic.showIcon(IconNames.Snake); isPlaying = false; } }
if (x === foodX && y === foodY) { music.beginMelody(music.builtInMelody(Melodies.BaDing), MelodyOptions.Once); updateRate *= 0.95; generateFood(); } else { snake.pop(); snake.pop(); } buttonPressed = false updateRate -= 5;
basic.forever(function () { if (isPlaying) { basic.clearScreen(); drawSnake(); drawFood(); basic.pause(updateRate); updateSnake(); } })
Test prosjektet
Prøv spelet på micro:bit og sjekk at alt fungerer.
Steg 7: Litt pynt
No har me i grunnen eit fungerande spel. Men me skal pynte litt på det for å gjere det endå betre. Det kan vere vanskeleg å sjå maten nokre gonger, fordi den kan kome kor som helst, og er lik slangen. For å gjere det enklare skal me få den til å blinke. Det gjer me ved å bruke input.runningTime()
. Denne funksjonen gir oss antal millisekund sidan micro:bit-en vart skrudd på.
Steg for steg
function drawFood() { const currentTime = input.runningTime(); if(currentTime%500 > 250){ led.plot(foodX, foodY); } }
lastUpdateTime = input.runningTime();
basic.forever(function () { if (isPlaying) { basic.clearScreen(); drawSnake(); drawFood(); const currentTime = input.runningTime(); if(currentTime - lastUpdateTime >= updateRate) { updateSnake(); lastUpdateTime = currentTime; } } })
Test prosjektet på micro:bit
Prøv spelet på micro:bit. Forhåpentlegvis fungerer det brillefint. Gratulerer, du har gjort ferdig spelet!
Her kjem eit par utfordringar!
Utfordring
Legg til score og highscore som blir vist når du døyr. Spel ein liten melodi og vis "New highscore" viss spelaren slo rekorden.
Tips: Du kan bruke lengda til snake-arrayet til å rekne ut poeng.
Utfordring
Styr slangen automagisk. Få den til å gå rundt og finne mat sjølv, samstundes som den prøver å ikkje krasje.
Tips: Du har allereie skrive kode som sjekkar om slangen køyrer utanfor eller kolliderer med seg sjølv. Du kan bruke den same koden til å sjekke posisjonen og endre retning (direction
) mot høgre eller venstre viss den krasjar, finne ny posisjon og sjekke om den krasjar der òg.
For å finne maten kan du snu mot den når du kjem på same rad eller kolonne som maten.
Forbedre denne siden
Funnet en feil? Kunne noe vært bedre?
Hvis ja, vennligst gi oss tilbakemelding ved å lage en sak på Github eller fiks feilen selv om du kan. Vi er takknemlige for enhver tilbakemelding!