45 besökare, 1 medlem och 1 Student är online nu
Loopia

Flash

Spel uppbyggda av mönsterplattor (MX)

DEL 1: grunderna -  till del 2  »

Spel som är uppbyggda av delar som passas ihop till hela ytor (tile based games) har varit vanliga på spelkonsoler som tex Gameboy eller tidiga versioner av PC-spel. Fördelen med den här typen av spel (förutom att de är roliga!) är att de innehåller lite grafik och mycket ActionScript vilket gör att de är relativt snabbladdade. De är dessutom relativt enkla att göra men räkna ändå med en hel del jobb för ganska enkla spel. Du bör alltså ha bra koll på grunderna i Flash innan du börjar med guiden...

Del 2 av denna guide hittar du här »

Matris (array) som beskriver spelplanens mönsterplattor

Mönsterplattorna i spelet kan se ut hur som helst och de kan bestå av både bitmappade bildobjekt och vektorformer som skapats i Flash. Varje mönsterplatta hämtas med hjälp av ActionScript där de identifieras med nummer i en matris (array). En array eller matris är ett objekt som identifieras av ett tal som anger positionen i matrisen. Alla matriser är nollbaserade vilket innebär att det första elementet i matrisen är [0], det andra elementet är [1] det tredje [2] etc. Ett exempel på matris som beskriver en spelplan. De grafiska objekt som används till hela spelplanen är två kvadrater. En gul kvadrat och en vit kvadrat med kantlinje (som utgör rutmönstret):

Två grafiska objekt utgör spelplanen med 16 plattor: vit kvadrat
gul kvadrat
ActionScript-kod som beskriver var plattorna ska placeras. Siffran 0 är den vita kvadraten och siffran 1 är den gula kvadraten:
myMap = [
[0, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 1],
[1, 0, 0, 0]
];
Spelplanen:
...med siffror:
  1. Skapa ett nytt dokument med valfria mått. I exemplet ska mönsterplattorna storlek vara 20 pixlar och spelplanen innehålla 10x10 plattor och dokumentstorleken i exemplet nedan är då 200x200 pixlar.

    Namnge Lagret till "actionscript":

  2. Lägg till en nytt Filmklipp med menyn "Infoga/Symbol" (Insert/Symbol). Ge symbolen namnet "empty" och klicka på knappen "Avancerat" (Advanced):



    Markera valet "Exportera till ActionScript" och se till att namnet "empty" anges som identifierare:



    Detta filmklipp ska vara tomt och ingen fler åtgärd behövs. Alla plattor (kvadrater) kommer med ActionScript att placeras i filmklippet "empty" på scenen och en fördel med detta är att när spelplanen ska ändras eller tas bort, när tex ett spel avslutas, tar man bort hela filmklippet med alla mönsterplattorna. Alternativet är att placera varje platta direkt på scenen men då måste de senare raderas av ett ActionScript.
  3. Skapa ännu ett Filmklipp med namnet "tile" och välj att exportera det till ActionScript:

  4. I filmklippet "tile" ska du ha den grafik som ska utgöra spelplanen. I vårt exempel är det två kvadrater; en fylld och en ofylld med kantlinje. För att få exakta mått när du ritar kvadraterna kan du använda Stödraster med menyn "Visa/Rutnät/Visa rutnät" (View/Grid/Show Grid). Ändra storleken på Stödrastret till den storlek du vill ha på mönsterplattorna med menyn "Visa/Rutnät/Redigera rutnät" (View/Grid/Edit Grid):



    Till mönsterplattan som ska vara "gångarna" väljer du Vit fyllningsfärg och valfri kantlinjefärg:



    Rita ut den första kvadraten och se till att det övre vänstra hörnet hamnar exakt i filmklippets centrummarkör. Viktigt! Om du inte har rätt positionering blir plattorna förskjutna på spelplanen:

  5. Infoga en ny Nyckelbildruta (Keyframe) i bildruta 2 och ändra eller rita en ny fylld kvadrat:



    Filmklippet "tile" är nu klart och består av två kvadrater i varsin Nyckelbildruta. I Biblioteket (CTRL+L) ser du nu dina två filmklipp:

 

ActionScript som hämtar mönsterplattorna

Filmklippet som innehåller de två kvadraterna som ska placeras ut på spelplanen är klart. Nu återstår ett ActionScript som hämtar kvadraterna ur filmklippet och placerar dem enligt det mönster du själv väljer. Här används matrisen som beskrivs i punkt 1 men nu innehåller den 10 kolumner och 10 rader, totalt 100 kvadrater.

Exempel:

  1. Se till att du befinner dig på scenen och inte i ett filmklipp. Infoga Actionscriptet nedan i Scen 1 och bildruta 1:



    Här är koden som du kan kopiera/klistra in i paletten Actions:

    fscommand("allowscale", "false");
    fscommand("showmenu", "false");
    // matrisen anger kartan där 1 är fyllda och 0 är ofyllda bitar
    myMap = [[1,1,1,1,1,1,1,1,1,1],
    [1,0,0,0,0,0,0,0,0,1],
    [1,0,1,0,0,0,0,0,0,1],
    [1,0,0,0,0,1,0,0,0,1],
    [1,0,0,0,0,0,0,0,0,1],
    [1,0,0,0,0,0,0,1,0,1],
    [1,0,0,1,0,0,0,0,0,1],
    [1,0,0,0,0,0,1,0,0,1],
    [1,0,0,0,0,0,0,0,0,1],
    [1,1,1,1,1,1,1,1,1,1]];

    // anger plattornas bredd och höjd
    game = {tileW:20, tileH:20};
    // plattor man kan gå igenom
    game.Tile0 = function () { };
    game.Tile0.prototype.walkable = true;
    game.Tile0.prototype.frame = 1;
    // väggplattor
    game.Tile1 = function () { };
    game.Tile1.prototype.walkable = false;
    game.Tile1.prototype.frame = 2;
    // bygger upp kartan
    function buildMap(map) {
    // lägger till ett tomt filmklipp och filmklippet med plattorna
    _root.attachMovie("empty", "tiles", 1);
    // deklarerar klipp i spelobjektet
    game.clip = _root.tiles;
    // kartans dimensioner
    var mapWidth = map[0].length;
    var mapHeight = map.length;
    // loop för att placera plattorna på scenen
    for (var i = 0; i<mapHeight; ++i) {
    for (var j = 0; j<mapWidth; ++j) {
    // namn på ny platta
    var name = "t_"+i+"_"+j;
    // skapa nytt plattobjekt i spelet
    game[name] = new game["Tile"+map[i][j]]();
    // bifogar filmklippets platta och placerar ut den
    game.clip.attachMovie("tile", name, i*100+j*2);
    game.clip[name]._x = (j*game.tileW);
    game.clip[name]._y = (i*game.tileH);
    // skickar filmklippets platta till rätt ram
    game.clip[name].gotoAndStop(game[name].frame);
    }
    }
    }
    // skapar kartan
    buildMap(myMap);
    stop();
  2. Om du vill ändra placeringen av plattorna (kvadraterna) gör du det med siffrorna i matrisen där alla värden 1 är en fylld kvadrat och värde 0 är en ofylld kvadrat:

    myMap = [[1,1,1,1,1,1,1,1,1,1],
    [1,0,0,0,0,0,0,0,0,1],
    [1,0,1,0,0,0,0,0,0,1],
    [1,0,0,0,0,1,0,0,0,1],
    [1,0,0,0,0,0,0,0,0,1],
    [1,0,0,0,0,0,0,1,0,1],
    [1,0,0,1,0,0,0,0,0,1],
    [1,0,0,0,0,0,1,0,0,1],
    [1,0,0,0,0,0,0,0,0,1],
    [1,1,1,1,1,1,1,1,1,1]];


    Testa ditt filmklipp med CTRL+Enter!
 

Din spelfigur

Spelplanen är definierad och det är dags att placera ut spelfiguren som du ska flytta runt i spelplanen.

Exempel:

  1. Infoga ett nytt Filmklipp med namnet "char":

  2. Rita ut din spelfigur i bildruta 1. Spelfiguren bör vara något mindre än de kvadrater som är mönsterplattor. OBS! Se till att centrumpunkten hamnar mitt i figuren.

    Lägg till ActionScript stop(); i den första nyckelbildrutan:

  3. Ändra i ditt ActionScript på två ställen för att initiera spelfiguren. Den första koden som skall läggas till är:

    // deklarerar spelfiguren. xtile och ytile är den platta som spelfiguren startar i
    char = {xtile:2, ytile:1};



    Koden anger det nya objektet "char" som ju ska innehålla all information om din spelfigur tex rörelser styrka och andra egenskaper. Egenskaperna "xtile:2" och "ytile:1" är den platta spelfiguren står på dvs den 2:a raden och den 3:e kolumnen (matrisen börjar ju alltid på 0):

  4. Den andra koden som ska läggas till är:

    // lägger till spelfigurens filmklipp
    game.clip.attachMovie("char", "char", 10000);
    // deklarerar klippet i spelobjektet
    char.clip = game.clip.char;
    // räknar ut startpositionen
    char.x = (char.xtile*game.tileW)+game.tileW/2;
    char.y = (char.ytile*game.tileH)+game.tileH/2;
    // lägger till spelfigurens dimension till spelobjektet, hälften av klippet bredd och höjd
    char.width = char.clip._width/2;
    char.height = char.clip._height/2;
    // placerar ut spelfiguren
    char.clip._x = char.x;
    char.clip._y = char.y;


    Först hämtas det nya filmklippet "char" från biblioteket i game.clip och sökvägen läggs till i objektet "char". Som ett alternativ till "xtile" och "ytile" (se ovan), som ju räknar antalet plattor, så räknas nu pixlarnas koordinater ut. Den aktuella positionen räknas ut genom att numret på plattan spelfiguren befinner sig på multipliceras med med storleken på plattan och delas med hälften för att få en centrerad position. Spelfigurens halva storlek räknas fram för att senare användas för kalkylering av spelarens form vid rörelser:



    Testa ditt filmklipp med CTRL+Enter!
 

Flytta spelfiguren

Prova exemplet nedan med fem varianter av spelfiguren. Den femte är start- och slutläget dvs innan och efter att Piltangenterna används och är ju den första bildrutan i varje filmklipp (som inte innehåller någon animation, se punkt 3:2 ovan). Klicka i spelplanen och flytta med piltangenterna!

Exempel:


[klicka i spelplanen och flytta sedan
spelfiguren med Piltangenterna]

  1. I detta exempel används 4 st varianter av spelfiguren; höger, vänster, upp och ner. Om din spelfigur ska vara helt statisk och inte byta utseende använder du bara den spelfigur du gjorde i punkt 3 ovan men när du bygger egna spel kommer du förmodligen att vilja ha ännu fler varianter av din spelfigur som tex klättrande, flygande, hoppande, skjutande, samlande, sovande mm...

    Infoga 4 st nya filmklipp och gör en enkel animation som motsvarar den riktning din spelfigur kommer att röra sig i. Exemplet nedan visar den första varianten av spelfiguren som ska animeras för rörelse uppåt. Den består av två nyckelbildrutor (Keyframes) där den första bildrutan innehåller grundfiguren och där den andra bildrutan innehåller grundfiguren och en rikningspil.

    OBS! När du gör din egen valfria animation bör du se till att den första bildrutan innehåller den "stillastående" figuren (riktningspilen i detta exempel syns ju först i bildruta 2).

    Grundfiguren i den första nyckelbildrutan:



    Grundfiguren och Pilen (animationen) i den andra nyckelbildrutan:


    Fortsätt med de övriga 3 filmklippen som ska innehålla varianter för spelfigurens rörelser åt vänster, höger och nedåt.
  2. Öppna filmklipper "char" och skapa skapa 5 bildrutor varav 4 ska vara nyckelbildrutor och innehålla de 4 filmklipp du gjort.

    Dra och placera ut var och ett av de fyra nya filmklippen till bildruta 1, 2, 4 och 5.

    OBS! Ordningen måste vara:

    bildruta 1: spelfigur_up
    bildruta 2: spelfigur_left
    bildruta 3: statisk (men visar innehållet i nyckelbildruta 2)
    bildruta 4: spelfigur_right
    bildruta 5: spelfigur_down

    Denna ordning motsvarar PILTANGENTERNAS ordning när du sedan använder ActionsScript för att koppla dem till filmklippen; Pil Upp - Pil vänster - Pil Höger - Pil Ner

  3. Ange hastigheten i pixlar som spelfiguren ska röra sig när du använder piltangenterna för att styra den. Lägg till "speed:4" i huvudscriptet:

    speed:4

  4. Det tomma Filmklippet "empty" som sedan tidigare beskriver spelplanen i huvudscriptet ska nu även användas för att känna om tangenttryckningar används i spelet. Dra det tomma filmklippet till scenen. Se till att det är markerat och tilldela det ActionScript:

    onClipEvent (enterFrame) {
    _root.detectKeys();
    }



  5. Tangenterna PIL UPP, PIL VÄNSTER, PIL HÖGER och PIL NER ska kopplas till filmklippet med spelfiguren och de 5 olika varianterna som du nu har placerat i egna bildrutor. Principen är att PIL UPP ska kopplas till bildruta 1 och PIL VÄNSTER till bildruta 2 osv... När du släpper Piltangenterna så ska spelfiguren återgå till startläget som i vårt exempel är bildruta 1 i varje filmklipp av spelfigurens varianter (stillastående, se punkt 4:1 ovan).

    Kopiera koden nedan:

    // anger förflyttning i X- och Y-led
    function moveChar(ob, dirx, diry) {
    ob.x += dirx*ob.speed;
    ob.y += diry*ob.speed;
    ob.clip.gotoAndStop(dirx+diry*2+3);
    ob.clip._x = ob.x;
    ob.clip._y = ob.y;
    return (true);
    }
    function detectKeys() {
    var ob = _root.char;
    var keyPressed = false;
    if (Key.isDown(Key.RIGHT)) {
    keyPressed = _root.moveChar(ob, 1, 0);
    } else if (Key.isDown(Key.LEFT)) {
    keyPressed = _root.moveChar(ob, -1, 0);
    } else if (Key.isDown(Key.UP)) {
    keyPressed = _root.moveChar(ob, 0, -1);
    } else if (Key.isDown(Key.DOWN)) {
    keyPressed = _root.moveChar(ob, 0, 1);
    }
    // spelfigurens animation
    if (!keyPressed) {
    ob.clip.char.gotoAndStop(1);
    } else {
    ob.clip.char.play();
    }




    Testa filmen med CTRL+ENTER!

Koden ovan sätter en variabel till _root.char som innehåller all information om spelfiguren. Med variabeln keyPressed kontrolleras om någon Piltangent använts eller inte. Om någon av piltangenterna används anropas funktionen moveChar som flyttar spelfiguren i någon riktning. if (Key.isDown(Key.RIGHT)) keyPressed = _root.moveChar(ob, 1, 0); anger att en piltryckning åt höger flyttar spelfigurens filmklipp åt höger i X-led och ingenting i Y-led. Värden som används är 1 eller -1 för förflyttning respektive 0 för ingen förflyttning. Om däremot ingen pilttangent längre används återgår spelfiguren till sitt startläge som i vårt exempel är bildruta 1 filmklippen": if (!keyPressed) {ob.clip.char.gotoAndStop(1);

Uträkningen av vilken bildruta i filmklippet "char" som ska hämtas vid tryckning på någon av de 4 piltangenterna sker i funktionen function moveChar(ob, dirx, diry) där variabeln ob.clip.gotoAndStop(dirx+diry*2+3); räknar ut numret på bildrutan enligt exemplet nedan:

PIL UP: X=0 Y=-1 vilket ger 0+(-1*2)+3 som ger summan 1 dvs bildruta nr 1
PIL NED: X=0 Y=1 vilket ger 0+(1*2)+3 som ger summan 5 dvs bildruta nr 5
PIL VÄNSTER: X=-1 Y=0vilket ger -1+(0*2)+3 som ger summan 2 dvs bildruta nr 2
PIL HÖGER: X=1 Y=0 vilket ger 1+(0*2)+3 som ger summan 4 dvs bildruta nr 4

Det är just denna uträkning som hämtar de olika varianterna av spelfiguren som du gjorde i punkt 4:2

 

Väggarna som stoppar spelfiguren

När du byggde upp spelplanen/kartan i punkt 2:1 ovan så angav du att två typer av plattor skulle användas. Den ena typen ska vara tillåtna att gå igenom, de ofyllda plattorna i vårt exempel:

// plattor man kan gå igenom
game.Tile0 = function () { };
game.Tile0.prototype.walkable = true;
game.Tile0.prototype.frame = 1;

Den andra typen ska inte vara tillåtna att gå igenom och ska fungera som "väggar", de fyllda plattorna i vårt exempel:

// väggplattor
game.Tile1 = function () { };
game.Tile1.prototype.walkable = false;
game.Tile1.prototype.frame = 2;

Som du märker när du testar din spelplan så kan du fortfarande gå igenom alla plattor och det är dags att sätt stopp för detta nu genom att lägga till två koder. Det färdiga exemplet nedan visar hur din spelfigur ska stanna intill en vägg:

Exempel:


[klicka i spelplanen och flytta sedan
spelfiguren med Piltangenterna]

  1. Den första funktionen getMyCorners identifierar spelfigurens fyra hörnpunkter. Funktionen hämtar spelfigurens ytterpunkter och räknar fram vilka plattor den befinner sig över.

    Lägg till koden nedan:

    function getMyCorners(x, y, ob) {
    // hitta hörnpunkterna
    ob.leftX = Math.floor((x-ob.width)/game.tileW);
    ob.rightX = Math.floor((x+ob.width-1)/game.tileW);
    ob.downY = Math.floor((y+ob.height-1)/game.tileH);
    ob.upY = Math.floor((y-ob.height)/game.tileH);
    // kontrollera om spelplattorna är väggar
    ob.upleft = game["t_"+ob.upY+"_"+ob.leftX].walkable;
    ob.downleft = game["t_"+ob.downY+"_"+ob.leftX].walkable;
    ob.upright = game["t_"+ob.upY+"_"+ob.rightX].walkable;
    ob.downright = game["t_"+ob.downY+"_"+ob.rightX].walkable;
    }




    Funktionen hämtar X- och Y-koordinaterna för spelfigurens centrumpunkt samt namnet på spelfigurens objekt. Spelfiguren kan ju befinna sig på flera plattor och genom att hämta värdet för spelfigurens höjd och dividera det med plattornas höjd beräknas vilken platta som spelfigurens lägsta punkt befinner sig i.
  2. Tidigare har du angivit förflyttning i sidled med funktionen moveChar och den ska nu ersättas med en funktion som räknar ut om alla hörnen kan förflyttas utan att kollidera med "väggen".

    Radera den befintliga koden nedan:


    Ersätt den kod du raderat med samma funktion moveChar men nu med annat innehåll. Nu ska funktionen räkna ut om alla hörnen kan förflyttas utan att kollidera med "väggen". Om det går så ska spelfiguren röra sig. Om om det inte går så ska spelfiguren inte bara stoppas utan dessutom placeras alldeles intill väggen. Hastigheten du valt för din spelfigurs rörelse (4 pixlar i vårt exempel) skulle ju annars stoppa spelfiguren "mitt i steget" före väggen men koden nedan räknar ut och placerar spelfiguren alldeles intill väggen istället.

    Kopiera och klistra in koden nedan:

    function moveChar(ob, dirx, diry) {
    // Förflyttning vertikalt
    getMyCorners(ob.x, ob.y+ob.speed*diry, ob);
    // om riktningen är uppåt
    if (diry == -1) {
    if (ob.upleft and ob.upright) {
    ob.y += ob.speed*diry;
    } else {
    // träff mot väggen, placering av spelfiguren intill väggen
    ob.y = ob.ytile*game.tileH+ob.height;
    }
    }
    // om riktningen är nedåt
    if (diry == 1) {
    if (ob.downleft and ob.downright) {
    ob.y += ob.speed*diry;
    } else {
    // träff mot väggen, placering av spelfiguren intill väggen
    ob.y = (ob.ytile+1)*game.tileH-ob.height;
    }
    }
    // Förflyttning horisontellt
    getMyCorners(ob.x+ob.speed*dirx, ob.y, ob);
    // om riktningen är vänster
    if (dirx == -1) {
    if (ob.downleft and ob.upleft) {
    ob.x += ob.speed*dirx;
    } else {
    // träff mot väggen, placering av spelfiguren intill väggen
    ob.x = ob.xtile*game.tileW+ob.width;
    }
    }
    // om riktningen är höger
    if (dirx == 1) {
    if (ob.upright and ob.downright) {
    ob.x += ob.speed*dirx;
    } else {
    // träff mot väggen, placering av spelfiguren intill väggen
    ob.x = (ob.xtile+1)*game.tileW-ob.width;
    }
    }
    // uppdatera spelfigurens position
    ob.clip._x = ob.x;
    ob.clip._y = ob.y;
    // vänd i riktningen, återgå till startfiguren
    ob.clip.gotoAndStop(dirx+diry*2+3);
    // räknar ut spelplattan som spelfigurens centrum befinner sig i
    ob.xtile = Math.floor(ob.clip._x/game.tileW);
    ob.ytile = Math.floor(ob.clip._y/game.tileH);
    return (true);
    }



    Testa din film med CTRL+ENTER! Så här kan ditt färdiga exempel se ut:

Exempel:


[klicka i spelplanen och flytta sedan
spelfiguren med Piltangenterna]

OBS! Du kan spara ner Flashfilmen som används i denna guide om du behöver titta närmare på koden och objekten. Klicka på filmnamnet nedan:

game1_exempel.fla »

Tips! Centrumpunkten på din spelfigur räknas ut baserat på den första bildrutan i filmklippet som innehåller din spelfigur. När din spelfigur stannar upp och placeras mot en vägg så är det från figuren i den första bildrutan som måtten hämtas. Se alltså till att alla dina spelfigurer har det "stillastående utseendet" i filmklippets första bildruta!

Exemplet nedan visar filmklippet som visar spelfigurens rörelse uppåt:

Den första bildrutan visar spelfiguren före animationen:



Den andra bildrutan visar spelfiguren efter animationen:



Om centrumpunkten skulle hämtas i bildruta 2 (ovan) så skulle måtten bli fel eftersom scriptet hämtar objektet i bildruta 1 som placeras ut intill väggen när spelfiguren stoppas.
 

Gör spelplanen större

Om du vill ha en större spelplan ökar du både Dokumentstorleken och Matrisens storlek (se punkt 1) och anger var mönsterplattorna ska placeras ut.

  1. Ändra dokumentets dimension. Se till att bredd och höjd är jämnt delbart med storleken på dina mönsterplattor. I exemplet är bredden 500 pixlar = 25 mönsterplattor och höjden 300 pixlar = 15 mönsterplattor då mönsterplattornas (tiles) storlek är 20 pixlar:

  2. Ändra Matrisen genom att lägga till motsvarande antal kolumner och rader (i exemplet används 25 kolumner och 15 rader). Placera ut "väggarna" genom att ange siffran "1" i matrisen:

  3. Resultatet ser du när du kör filmen med CTRL+ENTER!

    Exempel:

Fortsättning på spelguiden hittar du här:
DEL 2: dörrar, hopp och moln »

Tack till TonyPa för inspiration (Tile based Games) »