Great Games

Bow Street RunnerQuadradiusChick Chick BOOMMore BeerSomething AmissChromaBlastSeven Deadly SinsAgent Wing DefendersWreckanoidRed BaronOsiris II100th Review!: Pico's Surprise Party

Worth Checking Out

ObversityMatrix RampageEnjoyable Horse RacingEndless Zombie RampageFive 'tilSlingCrazy Pool 2Bow Man 2James The Deep Sea ZebraGlow Monkey: Mission OneNanoquestBlockhead: The GameCat FlingB29 AssaultIslander BoysXtreme Cliff DivingDeflectorSpace Runner 2

Link to us

Here are some button images you can download. We have buttons for fans, and buttons for developers that have been featured on the site.


 

Recent Visitors


July 15th, 2008

Make a game like Lumines with Flash - part 3 - Posted by Emanuele Feronato

Now it’s time to make bricks disappear if they group in a 2×2 square.

Read part 1 and 2 if you did not already.

It’s not difficult to check if bricks form a 2×2 square… and it’s not difficult to remove them from the stage.

The tricky part is making bricks fill the empty spaces left by disappeared bricks and managing combos (fallen bricks can make another 2×2 square, generating more falling bricks, and so on).

I preferred not to have an onEnterFrame on every brick to check if it’s over an empty space and eventually move it, so I created another array called bricks_in_field saving the depth of the brick in that position, so when I remove some bricks I just have to put in the moveable_bricks the depth found in the bricks_in_field array and the “engine” does the rest.

Here it is the actionscript:

ACTIONSCRIPT:

  1. // declaring some setup variables
  2. // number of horizontal cells
  3. grid_width = 16;
  4. // number of vertical cells
  5. grid_height = 10;
  6. // size of the cell
  7. tile_size = 30;
  8. // offset in pixels fron the left side of the stage
  9. x_offset = 10;
  10. // offset in pixels from the top side of the stage
  11. y_offset = 10;
  12. // number of different colors that can be displayed in a brick
  13. different_colors = 3;
  14. // boolean values saying if I should wait for the left (or right, up…) key to be released
  15. // this is used to make the player move bricks tapping arrow keys instead of just pressing them
  16. wait_left = false;
  17. wait_right = false;
  18. wait_up = false;
  19. wait_down = false;
  20. // flag indicating if blocks are falling
  21. falling = false;
  22. // array containing the game field data
  23. field = new Array();
  24. // array containing bricks position
  25. bricks_in_field = new Array();
  26. // array containing the bricks I can move
  27. moveable_bricks = new Array();
  28. // initializing and drawing the play field and the bricks position fields
  29. for (x=0; x<grid_width; x++) {
  30.     field[x] = new Array();
  31.     bricks_in_field[x] = new Array();
  32.     for (y=0; y<grid_height; y++) {
  33.         field[x][y] = 0;
  34.         bricks_in_field[x][y] = 0;
  35.         // look how I det ermine cells position according to tile size and offsets
  36.         cell = _root.attachMovie(“brick”, “brick_”+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:x*tile_size+x_offset, _y:(y+2)*tile_size+y_offset});
  37.         // first frame = empty cell
  38.         cell.gotoAndStop(1);
  39.     }
  40. }
  41. // calling the function that will place four bricks on the stage
  42. place_bricks();
  43. // main function, to be executed at every frame
  44. _root.onEnterFrame = function() {
  45.     // if blocks aren’t falling
  46.     if (!falling) {
  47.         // checking if a block is the upper left one of a four block square
  48.         for (x=0; x<grid_width; x++) {
  49.             for (y=0; y<grid_height; y++) {
  50.                 if (field[x][y] != 0 and field[x][y] == field[x+1][y] and field[x][y] == field[x+1][y+1] and field[x][y] == field[x][y+1]) {
  51.                     // physically removing the bricks
  52.                     _root[“brick_”+bricks_in_field[x][y+1]].removeMovieClip();
  53.                     _root[“brick_”+bricks_in_field[x][y+2]].removeMovieClip();
  54.                     _root[“brick_”+bricks_in_field[x+1][y+1]].removeMovieClip();
  55.                     _root[“brick_”+bricks_in_field[x+1][y+2]].removeMovieClip();
  56.                     // updating field array
  57.                     field[x][y] = 0;
  58.                     field[x][y+1] = 0;
  59.                     field[x+1][y+1] = 0;
  60.                     field[x+1][y] = 0;
  61.                     // checking upper bricks to make them fall
  62.                     start_y = y-1;
  63.                     while (field[x][start_y]>0) {
  64.                         moveable_bricks.push(bricks_in_field[x][start_y+1]);
  65.                         start_y–;
  66.                     }
  67.                     start_y = y-1;
  68.                     while (field[x+1][start_y]>0) {
  69.                         moveable_bricks.push(bricks_in_field[x+1][start_y+1]);
  70.                         start_y–;
  71.                     }
  72.                     falling = true;
  73.                 }
  74.             }
  75.         }
  76.         // place new bricks only if no bricks are falling
  77.         if (!falling and moveable_bricks.length == 0) {
  78.             place_bricks();
  79.         }
  80.         // this is how I detect if a key was tapped:     
  81.         // when it’s pressed, I wait for it to be released (in this case: not pressed)
  82.         // thanks to the wait_<direction> variable
  83.         if (Key.isDown(Key.LEFT)) {
  84.             wait_left = true;
  85.         } else {
  86.             if (wait_left) {
  87.                 // if the left key has been tapped, move the four bricks on the left
  88.                 for (x=0; x<4; x++) {
  89.                     // this "if" is used to determine if the bricks are still inside the game field
  90.                     if ((_root[“brick_”+moveable_bricks[x]]._x-x_offset)/tile_size-_root[“brick_”+moveable_bricks[x]].pos%2>0) {
  91.                         _root[“brick_”+moveable_bricks[x]]._x -= tile_size;
  92.                     }
  93.                 }
  94.                 // reset variable, now I must wait again for a key to be pressed
  95.                 wait_left = false;
  96.             }
  97.         }
  98.         // same routine for the right key
  99.         if (Key.isDown(Key.RIGHT)) {
  100.             wait_right = true;
  101.         } else {
  102.             if (wait_right) {
  103.                 for (x=0; x<4; x++) {
  104.                     if ((_root[“brick_”+moveable_bricks[x]]._x-x_offset)/tile_size-_root[“brick_”+moveable_bricks[x]].pos%2<14) {
  105.                         _root[“brick_”+moveable_bricks[x]]._x += tile_size;
  106.                     }
  107.                 }
  108.                 wait_right = false;
  109.             }
  110.         }
  111.         // when the DOWN arrow is pressed, I must rotate the bricks clockwise
  112.         // block 0: moves to the right and becomes block 1
  113.         // block 1: moves down and becomes block 3
  114.         // block 2: moves up and becomes block 0
  115.         // block 3: moves to the left and becomes block 2
  116.         if (Key.isDown(Key.DOWN)) {
  117.             wait_down = true;
  118.         } else {
  119.             if (wait_down) {
  120.                 for (x=0; x<4; x++) {
  121.                     switch (_root[“brick_”+moveable_bricks[x]].pos) {
  122.                     case 0 :
  123.                         _root[“brick_”+moveable_bricks[x]].pos = 1;
  124.                         _root[“brick_”+moveable_bricks[x]]._x += tile_size;
  125.                         break;
  126.                     case 1 :
  127.                         _root[“brick_”+moveable_bricks[x]].pos = 3;
  128.                         _root[“brick_”+moveable_bricks[x]]._y += tile_size;
  129.                         break;
  130.                     case 2 :
  131.                         _root[“brick_”+moveable_bricks[x]].pos = 0;
  132.                         _root[“brick_”+moveable_bricks[x]]._y -= tile_size;
  133.                         break;
  134.                     case 3 :
  135.                         _root[“brick_”+moveable_bricks[x]].pos = 2;
  136.                         _root[“brick_”+moveable_bricks[x]]._x -= tile_size;
  137.                         break;
  138.                     }
  139.                 }
  140.                 wait_down = false;
  141.             }
  142.         }
  143.         // when the UP arrow is pressed, I must rotate the bricks counter-clockwise
  144.         // block 0: moves down the right and becomes block 2
  145.         // block 1: moves to the left and becomes block 0
  146.         // block 2: moves to the right and becomes block 3
  147.         // block 3: moves up and becomes block 1
  148.         if (Key.isDown(Key.UP)) {
  149.             wait_up = true;
  150.         } else {
  151.             if (wait_up) {
  152.                 for (x=0; x<4; x++) {
  153.                     switch (_root[“brick_”+moveable_bricks[x]].pos) {
  154.                     case 0 :
  155.                         _root[“brick_”+moveable_bricks[x]].pos = 2;
  156.                         _root[“brick_”+moveable_bricks[x]]._y += tile_size;
  157.                         break;
  158.                     case 1 :
  159.                         _root[“brick_”+moveable_bricks[x]].pos = 0;
  160.                         _root[“brick_”+moveable_bricks[x]]._x -= tile_size;
  161.                         break;
  162.                     case 2 :
  163.                         _root[“brick_”+moveable_bricks[x]].pos = 3;
  164.                         _root[“brick_”+moveable_bricks[x]]._x += tile_size;
  165.                         break;
  166.                     case 3 :
  167.                         _root[“brick_”+moveable_bricks[x]].pos = 1;
  168.                         _root[“brick_”+moveable_bricks[x]]._y -= tile_size;
  169.                         break;
  170.                     }
  171.                 }
  172.                 wait_up = false;
  173.             }
  174.         }
  175.         // when SPACE key is pressed, I don’t wait for its release but I detect the key at once
  176.         if (Key.isDown(Key.SPACE)) {
  177.             // letìs made bricks fall…
  178.             falling = true;
  179.         }
  180.     } else {
  181.         //if the blocks are falling
  182.         // blocks_landed variable will count the number of bricks that already touched the ground
  183.         // or that cannot fall anymore because they are over other bricks
  184.         blocks_landed = 0;
  185.         for (x=0; x<moveable_bricks.length; x++) {
  186.             // calculating x and y position of the brick in the array
  187.             x_pos = (_root[“brick_”+moveable_bricks[x]]._x-x_offset)/tile_size;
  188.             y_pos = (_root[“brick_”+moveable_bricks[x]]._y-y_offset)/tile_size-1;
  189.             // determining if the block can fall. There are two conditions:
  190.             // 1: its position is less than zero. It means the block is outside the grid, in its starting position
  191.             // 2: its position is lower than the grid height and the tile under the block is empty
  192.             if ((y_pos<0) or ((y_pos<grid_height) and (field[x_pos][y_pos] == 0))) {
  193.                 // updating field array
  194.                 field[x_pos][y_pos] = _root[“brick_”+moveable_bricks[x]]._currentframe;
  195.                 field[x_pos][y_pos-1] = 0;
  196.                 // physically moving the brick
  197.                 _root[“brick_”+moveable_bricks[x]]._y += tile_size;
  198.             } else {
  199.                 // if the brick cannot move down, increase the number of blocks landed
  200.                 blocks_landed++;
  201.             }
  202.         }
  203.         // if all four bricks landed successfully…
  204.         if (blocks_landed == moveable_bricks.length) {
  205.             for (x=0; x<moveable_bricks.length; x++) {
  206.                 x_pos = (_root[“brick_”+moveable_bricks[x]]._x-x_offset)/tile_size;
  207.                 y_pos = (_root[“brick_”+moveable_bricks[x]]._y-y_offset)/tile_size-1;
  208.                 // saving in the brick array the name of the brick landed on (x_pos,y_pos)
  209.                 bricks_in_field[x_pos][y_pos] = moveable_bricks[x];
  210.             }
  211.             // reset variable to false
  212.             falling = false;
  213.             // reset moveable_bricks array
  214.             moveable_bricks = new Array();
  215.         }
  216.     }
  217. };
  218. // function to place four bricks on the stage
  219. function place_bricks() {
  220.     // placing the four bricks
  221.     for (x=0; x<4; x++) {
  222.         // again, look how I determine bricks position according to tile size and offsets
  223.         brk = _root.attachMovie(“brick”, “brick_”+_root.getNextHighestDepth(), _root.getNextHighestDepth(), {_x:(grid_width/2+(x%2))*tile_size+x_offset, _y:y_offset+tile_size*Math.floor(x/2)});
  224.         // setting a random color for the brick (frames 2 to different_colors+1)
  225.         brk.gotoAndStop(Math.floor(Math.random()*different_colors)+2);
  226.         // saving brick position
  227.         // 0: up left
  228.         // 1: up right
  229.         // 2: bottom left
  230.         // 3: bottom right
  231.         brk.pos = x;
  232.         // saving the depth of the brick into the moveable_bricks array
  233.         // if you look how did I assign brick names, you’ll see that I can determine a brick name
  234.         // starting from its depth. It’s simply "brick_"+<the_depth>
  235.         moveable_bricks[x] = brk.getDepth();
  236.     }
  237. }

And this is the result:

Now wait for the next step to handle timing events.

Download the source.

Bookmark this page on Digg, Kinja, FURL, Redit & other sites

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.