Nästan varje spel kan anses ha en huvudfunktion som innehåller all spellogik, och som körs antingen när användaren gör någonting eller efter en viss tid. Denna cykel av att köra samma kärnfunktion om och om igen kallas spelet loop, och är avgörande att förstå för någon form av spelutveckling.
Du har förmodligen spelat brädspelet Chutes and Ladders (eller ormar och stegar som vi kallar det i Storbritannien).
(Fotokredit incurable_hippie på Flickr)
Varje spelare rullar dynan (eller spinnar spinnaren) och förflyttar fram antalet kvadrater som anges. Torget de landar på kan leda dem att glida bakåt eller klättra framåt flera utrymmen. Spelaren vinner spelet när de kommer till sista kvadraten.
Så, i bilden ovan, gör landning på Square 6 dig klättra fyra rutor till Square 10; landning på Square 19 gör att du släpper tillbaka 15 rutor till Square 4; och landning på Square 64 innebär att du vinner spelet.
Anta nu att du spelar en spelare för att träna. Du gör samma sak som ovan, om och om igen, tills du når Square 64. Hur skulle du representera detta i kod?
Du skulle förmodligen börja med att skapa en matris för att lagra värdena på rutorna. De flesta element skulle innehålla noll, men några skulle innehålla antingen ett positivt tal (indikerar en stege) eller ett negativt tal:
Notera: Detta är pseudokod, inte AS3
var specialSquares: Array = []; specialSquares [0] = 0; // kvadraten spelarna börjar, före 1 specialSquares [1] = 0 ;? specialSquares [6] = +4 ;? specialSquares [19] = -15;
? och så vidare. Då skulle du ha en funktion för att flytta spelaren baserat på numret på dö:
funktion movePlayer (rutor: Nummer) newSquare = currentSquare + rutor; newSquare + = specialSquares [newSquare]; currentSquare = newSquare;
Du kan då placera det här inne i en större funktion som representerar en hel tur:
funktion takeATurn () diceNumber = random (1, 6); // slumptal mellan 1 och 6 movePlayer (diceNumber); om (currentSquare == 64) // spelare har vunnit! spelet över
Denna funktion, takeATurn ()
, inkapslar kärnspelslogiken för singelspelare Chutes och Ladders. Men hur får vi faktiskt den här funktionen att springa? Det finns flera alternativ:
Vi kunde lägga en knapp på skärmen och ringa det takeATurn ()
varje gång den klickas. Om du någonsin har spelat Facebook Scrabble eller Words With Friends, har du sett detta alternativ i åtgärd.
Vi kunde göra takeATurn ()
kör varje sextio sekunder.
Egentligen är detta alternativ lite mer komplicerat än det kan tyckas. I praktiken ser vi aldrig några spel utan några spelarens inmatning; utan interaktion kan det inte riktigt betraktas som ett spel. Men fortfarande har vissa spel ett inslag av "kalendertid". Tänk FarmVille: du, spelaren, plantera dina grödor, och sedan några minuter (eller timmar) utvecklas de lite längre från frön till skott till frukt. Och i vissa civilisationslägen ges du en viss tid (säga fem minuter) för att göra alla dina drag för en "tur"; När de fem minuterna är upp, utlöses kärnspelets logikfunktion.
Vissa spel använder en blandning av dessa två alternativ: Mafia Wars har till exempel en resurs som heter "energi" som fyller på en enhet var femte minut. du tar åtgärder i spelet genom att använda denna resurs, så att kärnspelets logikfunktion fortfarande utlöses av en användaraktivitet, den är bara begränsad av tiden.
Detta är ett vanligt förekommande mönster för de flesta spel: En kod som innehåller kärnspelslogiken utlöses upprepade gånger. Vi kallar det här spelet loop.
Det finns en term för åtgärden eller tidsperioden som också utspelar kärnspelslogikoden: a bock (som ljudet som en klocka gör).
Så i civilisationen är fästet var femte minut. I ord med vänner spelar du din tur orsaker en fästing. Med andra ord går spelslingan en gång per fält.
Super Mario Bros verkar inte passa in i någon av dessa kategorier. Mario svarar på spelarens inmatning? och ändå händer allting utan att du behöver göra någonting (Goombas går runt, timern räknar ner, objekten faller). Är där två spel loopar?
Nej. Det är bara en, och det utlöses enbart efter tiden - men med en kryssning på bara en bråkdel av en sekund.
I civilisationen har du en period på fem minuter för att mata in allt du vill göra i den aktuella svängen, före matchen "ticks" och kör spelet igen baserat på all din insats. Så om du säger, i Turn 23, att du vill att dina krigare ska attackera en rådjur, då i Turn 24 kommer alla att få vilt för middag.
Det är detsamma med Mario. Om du trycker på Hoppa-knappen under ett fält, kommer Mario att börja hoppa i nästa iteration av spelet loop.
Observera att du inte måste din Hoppa pressa för att inträffa precis som kärnspelets logikfunktion utlöses - alla dina handlingar under en kryssperiod registreras och används under nästa iteration av spelet loop.
Allt spellogik hanteras i spelslingan. Men det finns mer att spela än sin logik, grafiken är det stora exemplet.
Teckningsgrafik till skärmen är hårt arbete för datorn. Låt oss anta att du har ett actionspel med ett fält av 1/60: e sekund; det borde få spelet att känna att det reagerar vätskigt på spelarens kontroller. Men vad händer om spelarens dator är för långsam för att köra hela koden för spellogiken (svara på inmatning, simulera tyngdkraften, löpande AI-rutiner) och rita allt till skärmen inom 1 / 60th av en sekund?
I det här scenariot kan vi använda två separata slingor: en spelslinga och a rita slingan. Vi kunde sedan köra dragslingan med en mycket lägre frekvens än spelslingan; låt oss säga att vi uppdaterar skärmhalvan så ofta, dvs varje 1/30: e sekund.
Mängden bearbetningseffekt som krävs av spelet kan variera från nivå till nivå. Tänk på en shoot-up: de första nivåerna kommer att ha väldigt få fartyg på skärmen, för att underlätta spelaren försiktigt, medan de sista nivåerna kan ha dussintals fiendens fartyg och hundratals kulor som alla flyger runt samma scen på en gång. Spelslingan måste räkna ut hur alla dessa föremål ska röra sig, och dragslingan måste göra varje, så det kan ha varit möjligt att springa både spelslingan och dragslingan var 1/60: e sekund vid början av spelet, i slutet måste något ge.
Det är i allmänhet enklare att sakta ner dragslingan än spelslingan, om du måste välja. Justering av spelet slingans tick längd innebär att justera allt i ditt spel som är baserat på tiden; Om Mario kör med en hastighet på 20 pixlar / sekund, och du designar spelet med en fästlängd på 1/60: e sekund, måste du flytta honom 1/3 av en pixel per ficka. Om du justerar spelslingan för att ha en fästlängd på 1/30 sekund, måste du justera detta till 2 / 3rds av en pixel per fäst - och det är även en enkel förändring jämfört med att hålla fysikberäkningar och AI-rutiner konsekvent.
Av den anledningen strävar spel ofta mot att hålla spelets slinga konsistens konsekvent och sakta ner slingan om mer ström behövs. Om du någonsin har slagit på FPS-räknaren (kort för ramar per sekund, hur många gånger rullebanan körs per sekund) i en första person shooter, har du sett den ändras beroende på hur mycket som finns på skärmen ; dragslingans uppdateringshastighet justeras automatiskt. Spelet kan se domar - som en live streaming video på en långsam internetuppkoppling - men om det inte körs på en dator med mycket mindre ström än spelutvecklarna hade i åtanke kommer alla objekt i spelvärlden att fortsätta att flytta och interagera med rätt hastighet.
För en bra artikel som förklarar hur Flash hanterar detta, kolla Sean Christmanns post på "Elastic Racetrack".