Implementarea unui joc tip platforma in AS3 (partea I)
28.10.2008
Iata-ne la un tutorial pentru avansati in care vom crea un joc de tip platforma in Action Script 3.
7502 afisari 1 Rating (6 voturi) 45 min

Pasul 1. Programarea personajului principal

Iata-ne la un tutorial pentru avansati in care vom crea un joc de tip platforma in Action Script 3. Sa incepem!

In primul rand alege fundalul negru si un frame rate de 24fps (24 frame-uri pe secunda). Acum treci la realizarea personajului; nu va fi ceva prea artistic, doar un cerculet alb.


Implementarea unui joc tip platforma in AS 3

Dimensiunile sale sunt 25�25 pixeli.

Acum trebuie sa-l transformi intr-un MovieClip si sa ii dai un nume, sa zicem mcMain, astfel incat sa ii poti adauga un cod pentru a face ca acest personaj sa se miste.

Creeaza un nou layer "actions" si plaseaza acest cod pe primul frame:

// Variabilele de mai jos vor retine ce taste sunt apasate 
// Momentan nu avem nevoie de tastele sageata in sus si sageata in jos 
var leftKeyDown:Boolean = false;
var upKeyDown:Boolean = false;
var rightKeyDown:Boolean = false;
var downKeyDown:Boolean = false;
// viteza personajului principal
var mainSpeed:Number = 7;
//adaugam un listener pentru mcMain care il va deplasa 
//in functie de tastele apasate
mcMain.addEventListener(Event.ENTER_FRAME, moveChar);
function moveChar(event:Event):void{
    //verifica ce taste sunt apasate si muta personajul
    if(leftKeyDown){
        mcMain.x -= mainSpeed;
    }
    if(rightKeyDown){
        mcMain.x += mainSpeed;
    }
}
//"ascultam" ce taste sunt apasate
stage.addEventListener(KeyboardEvent.KEY_DOWN, checkKeysDown);
function checkKeysDown(event:KeyboardEvent):void{
    //making the booleans true based on the keycode
    //WASD Keys or arrow keys
    if(event.keyCode == 37 || event.keyCode == 65){
        leftKeyDown = true;
    }
    if(event.keyCode == 38 || event.keyCode == 87){
        upKeyDown = true;
    }
    if(event.keyCode == 39 || event.keyCode == 68){
        rightKeyDown = true;
    }
    if(event.keyCode == 40 || event.keyCode == 83){
        downKeyDown = true;
    }
}
//listener-ul verifica ce taste sunt eliberate
stage.addEventListener(KeyboardEvent.KEY_UP, checkKeysUp);
function checkKeysUp(event:KeyboardEvent):void{
    //initializam variabilele booleene cu false in functie de codul tastei apasate
    if(event.keyCode == 37 || event.keyCode == 65){
        leftKeyDown = false;
    }
    if(event.keyCode == 38 || event.keyCode == 87){
        upKeyDown = false;
    }
    if(event.keyCode == 39 || event.keyCode == 68){
        rightKeyDown = false;
    }
    if(event.keyCode == 40 || event.keyCode == 83){
        downKeyDown = false;
    }
}

Acest cod va face ca personajul sa se miste in stanga si dreapta. Acum trebuie ca personajul sa sara. Pentru asta vei folosi functia "jump" de fiecare data cand tasta sageata in sus e apasata, dar mai intai sa definim cateva variabile:

//variabila booleana care indica daca personajul sare
var mainJumping:Boolean = false;
//viteza de start a saltului
var jumpSpeedLimit:int = 15;
//viteaza curenta a saltului
var jumpSpeed:Number = jumpSpeedLimit;

Urmeaza sa realizezi o functie care va face personajul sa sara; e nevoie de ceva matematica aici:

//functia care realizeaza saltul
function mainJump():void{
    //daca personajul nu se afla in timpul unui salt
    if(!mainJumping){
        //atunci incepe saritura
        mainJumping = true;
        jumpSpeed = jumpSpeedLimit*-1;
        mcMain.y += jumpSpeed;
    } else {
        //altfel continua saritura
        //calcule matematice care modifica viteza 
        //in timpul saltului
        if(jumpSpeed < 0){
 
            jumpSpeed *= 1 - jumpSpeedLimit/75;
            if(jumpSpeed > -jumpSpeedLimit/5){
                jumpSpeed *= -1;
            }
        }
        if(jumpSpeed > 0 && jumpSpeed <= jumpSpeedLimit){
            jumpSpeed *= 1 + jumpSpeedLimit/50;
        }
        mcMain.y += jumpSpeed;
        //cand personajul atinge podeaua, saritura s-a terminat
        //acest cod va fi schimbat la crearea nivelurilor
        if(mcMain.y >= stage.stageHeight - mcMain.height){
            mainJumping = false;
            mcMain.y = stage.stageHeight - mcMain.height;
        }
    }

Chiar ca e un cod complicat, nu? Nu te-ai fi gandit ca realizarea unui simplu joc platforma ar fi asa grea. Vezi, de aceea acest tutorial e pentru avansati. In partea a doua vei invata cum sa creezi un nivel cu blocuri pe care sa se poata merge.



Pasul 2. Crearea nivelului

In continuare, trebuie sa creezi blocuri ce vor tine loc de un nou nivel. Pentru a face asta vei folosi siruri, de asemenea, vei crea si alte variabile ce tin de nivel. Scrie acest cod in partea de sus:

//VARIABILE DE NIVEL
//nivelul curent
var lvlCurrent:int = 1;
/*Codificarea pentru matricea nivelului:
1: Bloc obisnuit
X: Personajul principal
*/
//Variabila X va retine personajul
var X:String = 'MAIN';
//the array for level 1
var lvlArray1:Array = new Array(
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,0,X,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
);

E vorba de o matrice cam mare, dar sper ca nu va fi prea greu de inteles. Urmatorul lucru pe care trebuie sa-l faci este creerea unei functii care formeaza nivelul, iar pentru asta vei avea noi variabile:

//randul curent
var row:int = 0;

Urmatorul pas consta in alcatuirea unei clase ce va avea toate codurile pentru blocuri. E nevoie de un nou fisier extern ActionScript numit "Block.as". Acestuia, trebuie sa ii atasezi urmatorul cod:

package{
    import flash.display.Sprite;
    import flash.display.MovieClip;
    import flash.events.*;
 
    //sprites sunt movie clip-uri fara nici un frame
    public class Block extends Sprite{
        //variabila _root este o referinta la radacina documentului
        private var _root:Object;
 
        public function Block(){
            //acest cod va fi executat o singura data
            addEventListener(Event.ADDED, beginClass);
            //acest cod va fi executat continuu
            addEventListener(Event.ENTER_FRAME, eFrame);
        }
 
        private function beginClass(event:Event):void{
            // definim radacina documentului
            _root = MovieClip(root);
        }
 
        private function eFrame(event:Event):void{
 
        }
    }
}

Vom completa acest cod mai incolo, momentan, trebuie sa definesti functia care va situa aceste blocuri pe scena ajutandu-te de urmatorul cod scris la sfarsitul frame-ului:

//crearea nivelului
//variabila blockHolder va contine toate blocurile
var blockHolder:Sprite = new Sprite();
//adaugam blocurile pe scena
addChild(blockHolder);
function createLvl():void{
    //aflam nivelul curent pe care suntem
    var lvlArray:Array = MovieClip(root)['lvlArray'+lvlCurrent];
    //aflam pana unde se intinde nivelul
    //acesta va fi folosit pentru a stii cand sa trecem la randul urmator
    //vor fi intotdeauna 16 randuri
    //ceea ce inseamna ca formatarea lvl va fi foarte stricta
    var lvlColumns:int = Math.ceil(lvlArray.length/16);
    //cream nivelul
    for(var i:int = 0;i<lvlArray.length;i++){
        if(lvlArray[i] == 1){
            //verificam daca trebuie sa trecem la nivelul urmator
            //daca i este divizibil la numarul de coloane
            if(i/lvlColumns == int(i/lvlColumns)){
                row ++;
            }
 
            //cream un nou bloc
            var newBlock:Block = new Block();
            //desenam blocul
            newBlock.graphics.beginFill(0xFFFFFF /*Culoarea formei*/,1/*Transparenta formei - 1 pentru opac*/);
            //desenam un patrat
            newBlock.graphics.drawRect(0,0,25,25);
            //schimbam coordonatele blocului
            newBlock.x = (i-(row-1)*lvlColumns)*newBlock.width;
            newBlock.y = (row-1)*newBlock.height;
            //punem blocul pe scena
            blockHolder.addChild(newBlock);
        } else if (lvlArray[i] == 'MAIN'){
            mcMain.x = (i-(row-1)*lvlColumns)*newBlock.width;
            mcMain.y = (row-1)*newBlock.height;
        }
    }
    //resetam variabila row
    row = 0;
}
 
//apelam functia createlvl
createLvl();

Recapituleaza aceasta parte si incearca sa o intelegi. De acest tip de cod ai nevoie daca vrei sa devii un developer mai bun. In partea ce va urma vei invata cum sa adaugi coduri acestor blocuri pentru a le face sa interactioneze cu personajul.



Pasul 3. Programarea nivelului

Acum ca ai aranjat toate blocurile pe scena, le poti adauga si cateva coduri. In primul rand, trebuie sa faci in asa fel incat ele sa fie singurul lucru pe care sa stea personajul principal, iar pentru asta ai de inlocuit acest cod in functia mainJump:

// cand personajul atinge podeaua, saritura s-a terminat
// acest cod va fi schimbat la crearea nivelurilor
if(mcMain.y >= stage.stageHeight - mcMain.height){
    mainJumping = false;
    mcMain.y = stage.stageHeight - mcMain.height;
}

Cu acesta:

//cand personajul atinge podeaua, saritura s-a terminat
//aceasta bucla verifica daca personajul a atins vreun bloc
for(var i:int = 0;i<blockHolder.numChildren; i++){
    //preia blocul curent
    var hitBlock:DisplayObject = blockHolder.getChildAt(i);
    //verifica daca acesta a fost atins si daca personajul 
    //se afla deasupra blocului
    if(mcMain.hitTestObject(hitBlock) && mcMain.y < hitBlock.y){
        mainOnGround = false;
        //termina saritura
        mainJumping = false;
        //modifica coordonatele personajului astfel incat 
        //acesta sa fie deasupra blocului
        mcMain.y = hitBlock.y - mcMain.height;
        //iesim din bucla
        break;
    }
}

In partea ce urmeaza trebuie sa faci in asa fel incat personajul sa cada atunci cand nu e pe un bloc. Mai intai, defineste o variabila booleana mainOnGround in partea de sus initializeaz-o cu false. Daca mcMain loveste un bloc in functia mainJump, seteaza variabila ca true. Sper ca nu e nevoie sa te invat cum. Mergi mai departe si adauga urmatorul cod la moveChar():

//verifica daca personajul se afla pe sol
//parcurge din nou bucla pentru a verifica daca a atins vreun bloc
for(var i:int = 0;i<blockHolder.numChildren; i++){
    //preia blocul curent
    var hitBlock:DisplayObject = blockHolder.getChildAt(i);
    // verifica daca acesta a fost atins si 
    //daca personajul se afla deasupra blocului
    if(mcMain.hitTestObject(hitBlock) && mcMain.y < hitBlock.y){
        //initializam mainOnGround cu true
        mainOnGround = true;
        //iesim din bucla 
        break;
    }
 
    mainOnGround = false;
}
 
//personajul va cadea daca nu se afla pe sol
if(!mainOnGround){
    mainJumping = true;
}

In urmatoarea etapa trebuie sa faci ca personajul sa sara de pe caramizi daca le loveste in partea de dedesubt. In caz contrar el ar reusi sa ajunga in varful caramizilor venind din partea de jos si nu iti doresti asta. Pentru realizarea acestui lucru va trebui sa schimbi bucla "for" din functia mainJump cu:

for(var i:int = 0;i<blockHolder.numChildren; i++){
    //preia blocul curent
    var hitBlock:DisplayObject = blockHolder.getChildAt(i);
    //verifica daca personajul a lovit blocul
    if(mcMain.hitTestObject(hitBlock)){
        //verifica daca personajul se afla in cadere
        if(jumpSpeed>0){
            //daca da, termina saltul
            mainJumping = false;
            //si seteaza-i coordonatele pentru 
            //a se afla deasupra blocului
            mcMain.y = hitBlock.y - mcMain.height;
            //se afla pe un bloc, deci initializam 
            //mainOnGround cu true
            mainOnGround = true;
            //iesim din bucla
            break;
        } else {
            jumpSpeed = Math.abs(jumpSpeed);
            //altfel personajul se indeparteaza de bloc
            mcMain.y = hitBlock.y + hitBlock.height + 1;
        }
 
    }
}

Daca vei testa, vei vedea ca personajul sare cand loveste blocul. Ultimul lucru pe care il vei face este miscarea fundalului odata cu personajul principal, daca acesta se misca prea departe in partea stanga sau dreapta. Ca sa poti face acest lucru trebuie sa schimbi lvlArray1 cu:

var lvlArray1:Array = new Array(
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,X,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
);

Acum trebuie sa editezi functia createLvl pentru a centra personajul principal, iar pentru a face ca acest cod sa mearga trebuie sa inlocuiesti functia standard cu:

function createLvl():void{
    //afla nivelul curent 
    var lvlArray:Array = MovieClip(root)['lvlArray'+lvlCurrent];
    //afla pana unde tine nivelul
    //pentru a stii cand sa trecem la randul urmator
    //vor fi intotdeauna 16 randuri
    //ceea ce va face ca formarea lvl sa fie foarte stricta
    var lvlColumns:int = Math.ceil(lvlArray.length/16);
    //cream nivelul
    for(var i:int = 0;i<lvlArray.length;i++){
//verificam daca trebuie sa trecem la nivelul urmator
//daca i este divizibil la numarul de coloane
        if(i/lvlColumns == int(i/lvlColumns)){
            row ++;
        }
        if(lvlArray[i] == 1){
            // cream un nou bloc
            var newBlock:Block = new Block();
            //desenam blocul
            newBlock.graphics.beginFill(0xFFFFFF/*Culoarea formei*/,1/*Transparenta formei - 1 pentru opac*/);
            //desenam un patrat
            newBlock.graphics.drawRect(0,0,25,25);
            //schimbam coordonatele blocului
            newBlock.x = (i-(row-1)*lvlColumns)*newBlock.width;
            newBlock.y = (row-1)*newBlock.height;
            //adaugam blocul pe scena
            blockHolder.addChild(newBlock);
        } else if (lvlArray[i] == 'MAIN'){
            mcMain.x = (i-(row-1)*lvlColumns)*newBlock.width;
            mcMain.y = (row-1)*newBlock.height;
        }
    }
    //reseteaza variabila row
    row = 0;
    //centram ecranul pe personajul principal
    //aceasta variabila ne va spune cu cat trebuie deplasat ecranul
    //250 e aproximativ pozitia personajul, deci folosim aceasta valoarea
    var mainMove:int = 250 - mcMain.x;
    //muta personajul si intreg nivelul impreuna cu el
    mcMain.x += mainMove;
    blockHolder.x += mainMove;
}

De acum inainte ecranul va fi centrat pe personajul principal indiferent de nivel si de locul unde il asezi. In continuare, ai nevoie ca fundalul sa se miste odata cu personajul pentru a-l putea urmari in orice moment. Asta chiar va fi usor - in functia moveChar() inlocuieste:

if(leftKeyDown){
    mcMain.x -= mainSpeed;
}
if(rightKeyDown){
    mcMain.x += mainSpeed;
}

Cu:

if(leftKeyDown){
    blockHolder.x += mainSpeed;
}
if(rightKeyDown){
    blockHolder.x -= mainSpeed;
}

Usor, nu? Mai e o singura problema pe care vreau sa o rezolvi pana sa trecem la pasul urmator. Personajul nu sare indeajuns de mult, asa ca va trebui sa recodam putin aceasta parte:

//continua saltul daca se afla in aer
if(jumpSpeed < 0){
    jumpSpeed *= 1 - jumpSpeedLimit/75;
    if(jumpSpeed > -jumpSpeedLimit/5){
        jumpSpeed *= -1;
    }
}
if(jumpSpeed > 0 && jumpSpeed <= jumpSpeedLimit){
    jumpSpeed *= 1 + jumpSpeedLimit/50;
}
mcMain.y += jumpSpeed;
Inlocuieste cu acest cod:
//continua saltul daca se afla in aer
if(jumpSpeed < 0){
    jumpSpeed *= 1 - jumpSpeedLimit/125;
    if(jumpSpeed > -jumpSpeedLimit/5){
        jumpSpeed *= -1;
    }
}
if(jumpSpeed > 0 && jumpSpeed <= jumpSpeedLimit){
    jumpSpeed *= 1 + jumpSpeedLimit/50;
}
mcMain.y += jumpSpeed;

De asemenea modifica jumpSpeedLimit la 20.


Copyright © 2008-2010 E-LEARN.ro. Toate drepturile rezervate. Conceput si realizat de Neokinetics Software.