Talking about Columns game, Actionscript 3, Flash, Game development and Users contributions.
It’s quite a long time I don’t write anything about a Tetris game, my last entry about it was Creation of a complete Flash Tetris game a couple of years ago, so I am happy to show you the complete source code of a Tetris-like game called Columns made by Walter Siracusa, but first play the game:
Move pieces with LEFT, RIGHT and DOWN arrows, and use UP to shift blocks.
The code is commented in french and was ported from an old AS2 script so you may have to adjust it a bit before you can use for your own projects, but all in all it’s a very interesting script which will allow you to create a complete game.
//COLUMNS par Walter Siracusa const TAB_LG:uint=6; //Largeur de la table (en cases) const TAB_HT:uint=13; //Hauteur const BLK_LG:uint=32; //Largeur d'un bloc (en pixels) const BLK_HT:uint=32; //Hauteur const BLK_EMPTY:uint=1; //Constante de vide dans la table Tab (associée à l'image-clé 1 du clip blk_mc) const BLK_LINE:uint=3; //Nb de blocs mininum pour valider un alignement //Les états du jeu : const STATE_MOVE:uint=1; //Descente déplacement au clavier des 3 blocs const STATE_LINE:uint=2; //Détruit les blocs alignés const STATE_FALL:uint=3; //Chute de blocs au dessus du vide //-------------------------------- var Tab:Array=new Array(); var Tab_bool:Array=new Array(); var Tab_blk:Array=new Array(); var State:uint; var Current1:uint,Current2:uint,Current3:uint; var Next1:uint,Next2:uint,Next3:uint; var Breaking:Boolean=false; var Key_UP:Boolean; //Etat de la touche UP (false = relâché, true = enfoncée) var Timer0_drop:uint; var Score:uint=0; var Blk_container=new Sprite(); var Bag:Bag_mc=new Bag_mc(); var Gameover:Gameover_mc=new Gameover_mc(); var blong_snd=new Blong_snd() var disp_snd=new Disp_snd() var zik_snd=new Zik_snd() var zik_chn=zik_snd.play(0,1000) stop(); initGame(); function initGame(){ //Créer la table de base, une table booléene temporaire et une table de référence des blocs for(var i:uint=0;i<TAB_LG;i++){ Tab[i]=new Array(TAB_HT); Tab_bool[i]=new Array(TAB_HT); Tab_blk[i]=new Array(TAB_HT); } //Construit la grille avec des occurences de blk_mc for(var j:uint=0;j<TAB_HT;j++) for(i=0;i<TAB_LG;i++){ Tab[i][j]=BLK_EMPTY; var blk:Blk_mc=new Blk_mc(); Tab_blk[i][j]=blk; blk.x=i*BLK_LG; blk.y=j*BLK_HT; Blk_container.addChild(blk); } addChild(Blk_container); //Contient une grille remplie de blocs //Ajoute une occurence de bag_mc addChild(Bag); Bag.vt=2; Next1=Math.floor(1+Math.random()*6)*10; //10(R),20(V),30(B),40(J),50(M),60(C) Next2=Math.floor(1+Math.random()*6)*10; Next3=Math.floor(1+Math.random()*6)*10; initBag(); score_txt.text=String(Score); Timer0_drop=getTimer(); Breaking=false; Key_UP=false; State=STATE_MOVE; stage.addEventListener(KeyboardEvent.KEY_DOWN,keyboardDown) stage.addEventListener(KeyboardEvent.KEY_UP,keyboardUp) addEventListener(Event.ENTER_FRAME,mainLoop); } function initBag(){ Bag.y=-BLK_HT; //Démarre 1 case au dessus de la table Bag.x=0; Current1=Next1; Current2=Next2; Current3=Next3; Next1=Math.floor(1+Math.random()*6)*10; //10(R),20(V),30(B),40(J),50(M),60(C) Next2=Math.floor(1+Math.random()*6)*10; Next3=Math.floor(1+Math.random()*6)*10; next1_mc.gotoAndStop(Current1); next2_mc.gotoAndStop(Current2); next3_mc.gotoAndStop(Current3); setBag(); } function setBag(){ Bag.blk1_mc.gotoAndStop(Current1); Bag.blk2_mc.gotoAndStop(Current2); Bag.blk3_mc.gotoAndStop(Current3); } //-------------------------------- function mainLoop(evt:Event){ if(!Breaking){ //Aucun bloc en cours de destruction (valeur donnée dans la timeline de clip blk_mc) switch(State){ case STATE_MOVE: bagDown();break; case STATE_LINE: blockLine();break; case STATE_FALL: blockFall(); } } } function keyboardDown(evt:KeyboardEvent){ if(State==STATE_MOVE){ var i_blk:int=Math.floor(Bag.x/BLK_LG); var j_blk:int=Math.floor(Bag.y/BLK_HT); //= -1 au départ //Touches enfoncées if(evt.keyCode==Keyboard.LEFT && Bag.x>0 && (Tab[i_blk-1][j_blk+1]==BLK_EMPTY || drop_mc.visible)) Bag.x-=BLK_LG; else if(evt.keyCode==Keyboard.RIGHT && Bag.x<(TAB_LG-1)*BLK_LG && (Tab[i_blk+1][j_blk+1]==BLK_EMPTY || drop_mc.visible)) Bag.x+=BLK_LG; else if(evt.keyCode==Keyboard.UP && !Key_UP){ //Rotation des blocs de bag Key_UP=true; var tmp:uint=Current3; Current3=Current2; Current2=Current1; Current1=tmp; setBag(); }else if(evt.keyCode==Keyboard.DOWN) Bag.vt=8; //Vitesse de descente maximale de bag } } function keyboardUp(evt:KeyboardEvent){ //Touches relâchées if(evt.keyCode==Keyboard.UP) Key_UP=false; //Autorise UP après chaque relâchement if(evt.keyCode==Keyboard.DOWN) Bag.vt=2; //Vitesse de descente par défaut de bag } function bagDown(){ if(getTimer()>Timer0_drop+1500){ //Temps passé var i_blk:int=Math.floor(Bag.x/BLK_LG); var j_blk:int=Math.floor((Bag.y)/BLK_HT); //Ne touche pas le fond de la grille et pas de bloc dessous => Chute de bag de vt pixels if(Bag.y<(TAB_HT-1)*BLK_HT && (Tab[i_blk][j_blk+1]==BLK_EMPTY || drop_mc.visible)){ next1_mc.gotoAndStop(Next1); //Affiche le bag suivant next2_mc.gotoAndStop(Next2); next3_mc.gotoAndStop(Next3); drop_mc.visible=false; Bag.y+=Bag.vt; }else{ if(Bag.y==(-BLK_HT+Bag.vt)) gameOver(); //Colonne pleine => GAME OVER else{ //Touche le fond ou un bloc => Modifie les blocs de la grille en rapport avec ceux de bag putBlk(i_blk,j_blk,Current1); putBlk(i_blk,j_blk-1,Current2); putBlk(i_blk,j_blk-2,Current3); initBag(); //Nouveau bag State=STATE_LINE; //3 blocs posés => De nouveaux alignements ? => Mode LINE } } }else{ //En attente du timer... drop_mc.visible=true; drop_mc.x=Bag.x; } } function putBlk(i_blk:int,j_blk:int,val:uint){ if(j_blk>=0){ //N'écris pas hors de la table (cas ou bag déborde) Tab[i_blk][j_blk]=val; Tab_blk[i_blk][j_blk].gotoAndStop(val); } } function blockLine(){ var val:uint,nb_blk; Breaking=false; for(var j:int=0;j<TAB_HT;j++) //Initialise la table des booléens for(var i:int=0;i<TAB_LG;i++) Tab_bool[i][j]=false; //Alignements horizontaux for(j=0;j<TAB_HT;j++){ for(var i1:int=0;i1<TAB_LG;i1++){ if(Tab[i1][j]!=BLK_EMPTY){ val=Tab[i1][j]; nb_blk=0; for(var i2:int=i1;i2<TAB_LG;i2++){ if(Tab[i2][j]==val) nb_blk++; else{ i2--; //On ne compte pas le bloc qui est différent break; } } if(nb_blk>=BLK_LINE){ //Alignement entre i1 et i2 Breaking=true; if(i2==TAB_LG) i2--; for(i=i1;i<=i2;i++) Tab_bool[i][j]=true; Score+=(nb_blk*nb_blk); } i1=i2; } } } //Alignements verticaux for(i=0;i<TAB_LG;i++){ for(var j1:int=0;j1<TAB_HT;j1++){ if(Tab[i][j1]!=BLK_EMPTY){ val=Tab[i][j1]; nb_blk=0; for(var j2:int=j1;j2<TAB_HT;j2++){ if(Tab[i][j2]==val) nb_blk++; else{ j2--; break; } } if(nb_blk>=BLK_LINE){ //Alignement entre j1 et j2 Breaking=true; if(j2==TAB_HT) j2--; //On ne compte pas le bloc qui est différent for(j=j1;j<=j2;j++) Tab_bool[i][j]=true; Score+=(nb_blk*nb_blk); } j1=j2; } } } //Alignements diagonales (Gauche-Droite) for(j=0;j<TAB_HT-(BLK_LINE-1);j++){ for(i=0;i<TAB_LG-(BLK_LINE-1);i++){ i2=i; j2=j; val=Tab[i2][j2]; if(val!=BLK_EMPTY){ nb_blk=0; while(i2<TAB_LG && j2<TAB_HT && Tab[i2][j2]==val){ nb_blk++; i2++; j2++; } if(nb_blk>=BLK_LINE){ //Alignement entre (i1;j1) et (i2;j2) Breaking=true; i2--; j2--; i1=i; j1=j; while(j1<=j2) Tab_bool[i1++][j1++]=true; Score+=(nb_blk*nb_blk)*2; } } } } //Alignements diagonales (Droite-Gauche) for(j=0;j<TAB_HT-(BLK_LINE-1);j++){ for(i=TAB_LG-1;i>=(BLK_LINE-1);i--){ i2=i; j2=j; val=Tab[i2][j2]; if(val!=BLK_EMPTY){ nb_blk=0; while(i2>=0 && j2<TAB_HT && Tab[i2][j2]==val){ nb_blk++; i2--; j2++; } if(nb_blk>=BLK_LINE){ //Alignement entre (i2;j2) et (i1;j1) Breaking=true; i2++; //i2>=i1 j2--; i1=i; j1=j; while(j1<=j2) Tab_bool[i1--][j1++]=true; Score+=(nb_blk*nb_blk)*2; } } } } //Parcours la table des booléens pour détruire les blocs alignés if(Breaking){ //Des blocs sont à détruire for(j=0;j<TAB_HT;j++) for(i=0;i<TAB_LG;i++) if(Tab_bool[i][j]){ Tab[i][j]=BLK_EMPTY; Tab_blk[i][j].play(); } score_txt.text=String(Score); State=STATE_FALL; //La destruction entraine peut-être des chutes de blocs => STATE_FALL //Son disp_snd.play(); }else{ State=STATE_MOVE; //Pas ou plus de bloc détruit => pas de chute de bloc => STATE_MOVE Timer0_drop=getTimer(); } } function blockFall(){ var fall:Boolean=false; //Parcours la table de bas en haut (jusqu'à la ligne 1) for(var j:int=TAB_HT-1;j>0;j--) for(var i:int=0;i<TAB_LG;i++) if(Tab[i][j]==BLK_EMPTY && Tab[i][j-1]!=BLK_EMPTY){ //Un bloc au dessus du vide fall=true; //Copie le bloc d'une case vers le bas var val:uint=Tab[i][j-1]; //Valeur du bloc Tab[i][j]=val; Tab_blk[i][j].gotoAndStop(val); //Supprime l'ancienne position du bloc Tab[i][j-1]=BLK_EMPTY; Tab_blk[i][j-1].gotoAndStop(BLK_EMPTY); //Son blong_snd.play(); } if(!fall) State=STATE_LINE; //Pas ou plus de chute => De nouveaux alignements => Mode LINE } function gameOver(){ removeEventListener(Event.ENTER_FRAME,mainLoop); stage.removeEventListener(KeyboardEvent.KEY_DOWN,keyboardDown) stage.removeEventListener(KeyboardEvent.KEY_UP,keyboardUp) addChild(Gameover); Gameover.play(); Gameover.x=107; Gameover.y=91; zik_chn.stop(); }
And of course here is the source code provided by Walter.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.