Hej, och välkomna tillbaka till “Den där gången jag byggde Snake 2”, en serie texter om den där gången jag byggde Snake 2. När sist jag lämnade er hade jag precis lyckats konstruera ett rutnät, som enbart fungerade i Chrome. Rafflande!

Att bygga spelplanen var så klart en nödvändig plats att börja på, utan den så är det svårt att gå vidare, men det är också den tråkigaste delen i projektet och jag var glad att nu äntligen kunna gå vidare till den eponyma ormen.

Så, i nästa version av spelet la jag in en tre pixlar lång, orörlig orm. Ingen imponerande uppdatering kanske, men jag gjorde faktiskt lite mer än att bara byta färg på tre pixlar. Inte jättemycket mer, men lite.

I min förra text pratade jag lite om arrays, som jag beskrev lite som en lista. En extremt klok beskrivning, om jag får säga det själv. I alla fall, för att ändra färg på de tre rutorna som utgjorde ormen stoppade jag namnen på rutorna i en array, och skickade sen den arrayen till en funktion som bytte färg på dem, som jag stulit från min svallvågssida.

snake = [r25c33, r25c34, r25c35]

snake.forEach(colorChange)

async function colorChange(divid) {
                $(divid).css('background-color', 'black');
                await sleep(1000)
//                $(divid).css('background-color', 'white');
}
function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
}

Medan funktionen för att skapa spelplanen har hållit sig någorlunda likadan genom alla versioner av spelet, så finns i princip ingenting av koden ovan kvar i den nuvarande versionen av mitt Snake. Koden var väldigt illa anpassad för vad jag försökte göra, men det visste jag inte riktigt ännu.

Man kan också se en rad där i som är utkommenterad med två snedstreck i början, vilket innebär att den inte kommer att köras. Originellt hade den här funktionen som syfte att byta färg på ett antal rutor i en array, vänta en sekund (eller 1000 millisekunder) och sedan byta tillbaka färgen. Eftersom jag inte ville att ormen skulle försvinna igen efter en sekund så kommenterade jag ut den raden, så nu byter funktionen bara färg på rutorna, väntar en sekund och gör sen… inget.

Vi har en orm, dags att sätta den i rörelse. I koden ovan definierade vi ormen som en array av rutor, nu behöver vi alltså uppdatera den arrayen, genom att ta bort rutan där svansen tidigare var och lägga till en ny ruta framför huvudet, och sedan upprepa det.

setInterval(function(){
        head = snake[snake.length - 1].split(/\D/g)
        headr = parseInt(head[2])
        headc = parseInt(head[3])
        next = "#r" + headr + "c" + (headc + 1);
        $(snake[0]).css('background-color', 'white');
        snake.splice(0, 1)
        snake.push(next)
        colorChange(snake)
}, 200);

setInterval är en metod för att köra funktioner om och om igen med en fast intervall, i det här fallet 200 millisekunder. Så vad ovan kod gör är att fem gånger i sekunden räkna ut vilken som var nästa ruta ormen skulle flytta sig till och lägga till en i arrayen, samtidigt som den plockar bort den sista.

head = snake[snake.length - 1].split(/\D/g)
headr = parseInt(head[2])
headc = parseInt(head[3])

Vad den här koden gör är att den plockar ut ormens “huvud” och sparar dess rad och kolumn som separata variabler. För att plocka ut ett specifikt värde ur en array så skriver man namnet på arrayen, följt av en hakparentes med vilket nummer i listan värdet har. Så om man har en array som heter frukt och innehåller apelsin, äpple och kiwi, så kommer frukt[2] ge oss kiwi (eftersom arrayen börjar på noll).

Eftersom huvudet är den sista siffran i arrayen och ormen kommer att ändra längd över spelets gång, så kan jag inte bara skriva in snake[2] här och vara nöjd så, utan jag måste basera värdet på ormens nuvarande längd. Som tur är finns det en färdig funktion för det i Javascript, som heter “length”. Så “snake.length” ger mig antalet värden i ormens kropp, och genom att ta snake.lengt – 1 så får jag ut vilket nummer den sista rutan har (igen, eftersom arrayen börjar på 0).

Så, “head = snake[snake.length – 1]” sätter variabeln head till det sista värdet i variabeln snake. Men riktigt där är vi inte klara, för vi vill också dela upp huvudet i sina beståndsdelar. Vilket är en helt normal mening att skriva. Som ni kanske minns har rutorna namn som “r25c35”, där 25 är raden vi befinner oss på och 35 är kolumnen. För att kunna korrekt ändra ormens position behöver jag ha dem separerade. Vilket javascript som tur är också har en färdig funktion för.

Split” låter mig dela upp en sträng till flera separata värden baserat på en “delimiter”, eller avgränsare, vilket helt enkelt är vilket tecken funktionen ska klippa efter. Har du exempelvis någonsin använt filformatet .csv vet du kanske att det står för comma separated values, vilket innebär att det är en lista med kommatecken mellan varje värde, och när program läser den listan så använder de kommat som avgränsare.

I det här fallet har jag dock inte komman, eller någon annat specifikt tecken att klippa efter. Jag vill klippa efter r, igen efter 25 och sen en gång till efter c. Som tur är finns det metoder för att komma runt det, exempelvis genom att använda “allt som inte är en siffra” som avgränsare, vilket man gör genom att använda “\D”.

Formatet på split är “split(/AVGRÄNSARE/)”, eller i det här fallet mer specifikt “split(/AVGRÄNSARE/g)”, där g:et står för “global” och innebär att hela strängen ska splittas på det här viset. Utan det lilla g:et så skulle split nöja sig med att splitta vid första tillfället och sedan ta helg.

Så, allt det ledde oss alltså till “head = snake[snake.length – 1].split(/\D/g)“, vilket ger oss en ny array som heter head som innehåller alla delar av ormens huvud. Och i de följande två raderna plockar vi ut delarna vi vill ha och lägger dem som egna variabler.

headr = parseInt(head[2])
headc = parseInt(head[3])

Nu kanske det känns lite förvirrande att det är just värde 2 och 3 vi plockar ut och det är för att jag har glömt nämna att jag i den här versionen uppdaterat namnen på rutorna till att börja med en hashtag, så istället för exempelvis “r25c35” heter de nu “#r25c35”, vilket är för att hashtags används för att signalera att något är ett id på en div, vilket är vad det här är.

Så när vi delar upp strängen “#r25c35” till en array med allting utom siffror som avgränsare så blir värde 0 det som är framför #, det vill säga ingenting, värde 1 det som är mellan # och r, det vill säga ingenting, värde 2 det som är mellan r och c, det vill säga 25 och värde 3 det som är efter c, det vill säga 35. Sådär, solklart?

Jag har ont i huvudet.

När vi fått ut de värdena kan vi så ta reda på vilken nästa ruta som ska in i ormkroppen är.

next = "#r" + headr + "c" + (headc + 1);

I det här stadiet vill jag bara att ormen ska röra sig åt åt ett håll, så allt jag vill är att flytta den en kolumn åt höger. Vilket är varför jag låter headr, värdet som berättar vilken rad vi är på, vara detsamma, och lägger till ett på headc, värdet som berättar vilken kolumn vi är i.

$(snake[0]).css('background-color', 'white');

Därefter tar jag det första värdet i arrayen, som är ormens svanstopp, och gör den vit, så att ormen inte bara fortsätter bli längre när huvudet sticker iväg framåt. Falkögda läsare kan här se att jag inte använder mig av ren Javascript-kod, utan av jQuery, vilket är ett bibliotek till javascript och kan kännas igen på att raden börjar med ett dollartecken, men vi ska absolut inte gå in på det här, jag la precis sex stycken på att förklara “split”, det får räcka.

snake.splice(0, 1)

När vi tagit bort färgen på den sista rutan behöver vi också ta bort den ur arrayen, vilket vi gör med “splice“, som jag säger åt att börja på nummer noll i listan och ta bort ett element, det vill säga ta bort det första värdet.

snake.push(next)
colorChange(snake)

Sen använder vi “push” för att stoppa in nästa ruta i arrayen för ormkroppen, och så använder vi colorChange-funktionen för att göra ormen svart, vilket i praktiken bara ändrar färgen på den nya rutan, eftersom resten av ormen redan var svart.

Resultatet av det här blir en orm som sticker iväg åt höger så fort sidan laddas och sedan fortsätter åt höger tills den lämnar skärmen, för att aldrig synas till igen. Vilket tro det eller ej är något vi räknar som ett stort framsteg. Och också var vi avslutar det här avsnittet.

I nästa episod kommer vi äntligen se introduktionen av en av Snake 2s centrala funktioner, det vill säga att ormen kan röra sig genom en vägg och komma ut på andra sidan, och om vi har riktig tur även förmågan att styra ormfan. Missa inte det!