Six-Trix
Aqualines
CycleMan
Domino Dilemma
Rhumb Line
All Games...
Six-Trix on flash!
CycleMan
PacHoney Bear
CycleMan
Cram
SuperNim
Abracadabra
Javanoid
Basketball
Well known and Unique Games & Puzzles

 
Home Downloadable Games Free Online Flash Games Free Online Java Games Flash Lessons Portfolio Partners  
 
 
 
 
 
 

How to make a logical game on Flash. Part 2

This is the Chapter 11 from our book "The Flash 8 Game Developing Handbook", ISBN 1-931769-47-8. CD-ROM included. You can buy this book from us for $30 only.

11.3. Writing Auxiliary Functions

Create a nim.as file in the project folder and open it in a text editor.

11.3.1. The Data Section of the Program

Let's start writing the program with the data section (Listing 11.1).
Listing 11.1. The data section of the program
var
 // the depth of the think clip
 thinkdepth=1,
 // the depth of the gameover clip
 gameoverdepth=1,
 // the depths of the youlose and youwin clips
 resultdepth=gameoverdepth+1,
 // the initial depth of the square clips
 squaredepth=resultdepth+1,
 // the number of the squares (and pieces) on the board
 maxpieces=12,
 // the coordinates of the upper left square clip
 x0=50,
 y0=125,
 // the size of a square in pixels
 sqx=70,
 // a variable indicating who makes the move
 // (0 - the gamer, 1 - the computer)
 mymove,
 // the current number of pieces
 numieces,
 // a variable setting a time delay
 waittime,
 // the board (3 groups containing 3, 4, and 5 pieces)
 board=new Array([0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]),
 // an array to store marks
 marked=new Array([0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]);
I believe you understand the purpose of the variables from the comments. I'll describe them in more detail later.

11.3.2. The Code of the Main Program (without Functions)

Leave three empty lines after the data section and enter the code of the main program (Listing 11.2).
Listing 11.2. The main program
//*** The main program ***
// draw the board
var sdepth=squaredepth;
for (var i=0; i < 3; i++)
 for (var j=0; j < 5; j++)
  { if (j < i+3)
     { attachMovie('square','square'+j+i,sdepth);
       eval('square'+j+i)._x=x0+sqx*j;
       eval('square'+j+i)._y=y0+sqx*i;
     }
    ++sdepth;
  }
newGame();
stop();
This code needs some explanation. First, it draws 12 squares that will remain untouched during the game. There can be pieces on the squares, so you'll attach a piece to a square using the attachMovie function. In addition, there can be markers put by the gamer on pieces. So you have three clips two of which being attached to the master clip. The board and marked arrays have five elements in each line, but only the first three elements are used in the first line, and four used in the second. (Generally, ActionScript allows you to declare different dimensions of an array). To make the program simpler, let's assign depths to the squares as if there are five elements in each line. That is, the first square in the upper line has a depth of sdepth=squaredepth, the depth of its neighbor to the right is greater by one, the depth of the first square in the second line is sdepth+5, and that of the first square in the third line is sdepth+10. This is why the ++sdepth statement is located outside the conditional statement. You should name the squares so that it is easy to attach pieces to squares and markers to pieces in a loop. So the square in the ith line and jth column should be named 'square'+j+i. For example, the first square will have the square00 name, and the last will have the square42 name. This is done in the following statement:
attachMovie('square','square'+j+i,sdepth);
The if (j < i+3) condition "cuts off" unused elements in the first two lines.
The
eval('square'+j+i)._x=x0+sqx*j;
eval('square'+j+i)._y=y0+sqx*i;
statements assign each newly created square coordinates in pixels computed from its logical coordinates j and i. The eval('square'+j+i) function returns a reference to the square object, given its name.
After all the squares are arranged, the newGame function is called, and the stop() command is given. The command will stop the movie in the third frame to prevent it from playing cyclically from the first frame to the third. (You might remember that you attached this command to a main timeline frame in Tet-a-Tetris).

11.3.3. Functions of the Main Program

Put the functions from Listings 11.3-11.7 between the data section and the main program. However, the order of the functions isn't important in ActionScript.
Listing 11.3. The showThinking function
// displays "Thinking..." when arg != 0 
// and hides when arg == 0
function showThinking(arg)
{ if (arg)
   { attachMovie('think','think',thinkdepth);
     think._x=185;
     think._y=12;
   }
    else think.removeMovieClip();
}
Listing 11.4. The showGameOver function
// displays "Game over" when arg != 0 
// and hides when arg == 0
function showGameOver(arg)
{ if (arg)
   { attachMovie('gameover','gameover',gameoverdepth);
     gameover._x=185;
     gameover._y=12;
   }
    else gameover.removeMovieClip();
}
Listing 11.5. The showResult function
// when arg == 0, hides the "You lose" or "You win" text
// when arg == 1, displays "You lose"
// when arg == 2, displays "You win"
function showResult(arg)
{ var names=new Array('','youlose','youwin'); 

  if (!arg)
   { youlose.removeMovieClip();
     youwin.removeMovieClip();
   } else
    { attachMovie(names[arg],names[arg],resultdepth);
      var name=eval(names[arg]);
      name._x=12;
      name._y=12;
    }
}
Listing 11.6. The thinking function
// displays "Thinking..." and calls the computerMove function
// after a delay of 1.500 ms
function thinking()
{ if (getTimer() < waittime) return;
  showThinking(1);
  waittime=getTimer()+1500;
  gameact.onEnterFrame=computerMove;
}
This function is called before the computer starts thinking over its move. Delays before and after the appearance of the Thinking: text are necessary to avoid displaying the text and making a move almost simultaneously.
Listing 11.7. The youBegin function
// this is called after the gamer releases the mouse button
// on the "Comp begins" button
function youBegin()
{ if (numpieces == maxpieces)
   // If all pieces are on the board, makes a random move
   anyMove();
}
If the computer makes the first move, the function checks whether all pieces are on the board. When this is the case, it calls the anyMove function (Listing 11.8) to make a random move. If the program computed all variants before the first move, it would always win (at least in this position and with these rules), so the gamer would see the You lose message instantly. Our program is friendly, and it warns the gamer who will inevitably lose that he or she can start a new game.
Listing 11.8. The anyMove function
// making a random move
function anyMove()
{ var i,j,k,rows=new Array(0,0,0);

  // assigning the rows array the number of pieces in three rows
  for (i=0; i < 3; i++)
   for (j=0; j < i+3; j++)
    rows[i]+=board[i][j];
  // finding the row with the maximum number of pieces
  i=2;
  if (rows[1] > rows[2]) i=1;
  if (rows[0] > rows[1]) i=0;
  // removing k pieces from the ith row
  k=2;
  if (rows[i] < 3 || Math.random() < 0.67) k=1;
  for (j=0; j < i+3; j++)
   if (board[i][j])
    { showPiece(0,j,i);
      if (!--k) break;
    }
  // the gamer's move
  mymove=0;
  // hide "Thinking..."
  showThinking(0);
}
You should be careful when making a random move. It is desirable to avoid positions which the gamer can easily analyze. Therefore, the computer should delete few pieces, for example, one or two, and shouldn't leave empty rows after its move. Later, when you learn how to skim through variants, you'll know another method for making a "good" random move. In this function, you declare an array of three elements and assign them the numbers of pieces in each row. Then you assign the i variable the number of the row with the maximum number of pieces. Then you call the Math.random method of the Math object to decide whether one or two pieces should be removed. The computer removes one piece when the ith row contains less than three pieces or when the Math.random method returns a number less than 0.67 (the probability of which is 2/3). Then a loop iterates through all the pieces in the ith row:
for (j=0; j < i+3; j++)
if (board[i][j])
    { showPiece(0,j,i);
      if (!--k) break;
    }
The loop finds a square with a piece (board[i][j]) and removes the piece by calling the showPiece function (Listing 11.9). Then it subtracts one from the k variable and terminates when k becomes equal to zero.
Listing 11.9. The showPiece function
// shows the piece with the (x, y) coordinates when arg != 0 
// and hides the pieces when arg == 0 
function showPiece(arg,x,y)
{ var
   // the reference to the square containing the piece
   name=eval('square'+x+y);

  if (arg)
   { // attaching the piece to the square (the piece depth is 1)
     name.attachMovie('piece','piece',1);
     // computing a reference to the piece clip from the piece name
     name=eval('name.piece');
     // placing the piece in the center of the square
     name._x=0;
     name._y=0;
     // store the coordinates of the piece in its properties j and i
     // to compute the coordinates when the gamer clicks on the piece
     name.j=x;
     name.i=y;
     // each piece will pass its coordinates from the j and i
     // properties to the rel function
     name.onRelease=function()
      { rel(this.j,this.i);
      }
     // creating a piece logically removing a piece from the board
     board[y][x]=1;
   } else
    { // the piece gradually disappears
      --numpieces;
      board[y][x]=marked[y][x]=0;
      // The piece disappears gradually
      eval('name.piece').play();
    }
}
The following fragment of the showPiece function needs some explanation:
name.j=x;
name.i=y;
// each piece will pass its coordinates from the j and i
// properties to the rel function
name.onRelease=function()
{ rel(this.j,this.i);
}
When you create an instance of the piece clip, you add the j and i properties to it. Thanks to this, each instance of the piece clip stores its board coordinates (j is the column number, and i is the row number, numbering begins from zero). In addition, a handler of the mouse release event is created for each piece instance. As a result, when a gamer releases the mouse button on a piece, it passes the rel function its coordinates to inform the main program which piece is clicked. You could implement computation of coordinates in another way by finding the pixel coordinates of the mouse pointer, when the user releases the mouse button, and converting these to the logical coordinates of a square of the board. However, you would additionally have to check whether there is a piece on the square. The solution where the piece tells its coordinates on its own is more convenient.
After the piece is removed, numpieces is decremented by one, zeroes are assigned to the appropriate elements of the board and marked arrays, and the play method of the appropriate piece is called. The piece gradually disappears from the board and destroys itself along with its onRelease event handler using the ActionScript code attached to the piece.
Listing 11.10. The newGame function
// preparing for a new game
function newGame()
{ var i,j;

  for (var i=0; i < 3; i++)
   for (var j=0; j < 5; j++)
    if (j < i+3) showPiece(1,j,i);
  // setting the current number of pieces to the maximum number
  numpieces=maxpieces;
  // the gamer can make a move
  mymove=0;
  // hiding the clip with the result
  showResult(0);
  // hiding the gameover clip
  showGameOver(0);
}
The function in Listing 11.10 puts the pieces by calling the showPiece function, hides any messages, and allows the gamer to make the first move.
Listing 11.11. The rel function
// This function is called when the gamer releases the mouse button
// on any piece. It takes the coordinates of the piece: x and y.
function rel(x,y)
{ // If this is the computer's move, return
  if (mymove) return;
  // Is the piece in the x column and the y row marked?
  if (marked[y][x])
   { // Removing the mark clip from the piece
     eval('square'+x+y+'.piece.mark').removeMovieClip();
     // Removing the mark logically
     marked[y][x]=0;
     return;
   }
  // The gamer clicked on an unmarked piece. Checking for marked
  // pieces in the other rows.
  for (var i=0; i < 3; i++)
   { // Skipping the current row
     if (i == y) continue;
     for (var j=0; j < i+3; j++)
      // A mark piece is found in another row. The attempt 
      // of an illegal move is ignored.
      if (marked[i][j]) return;
   }
  // marking the piece and
  // finding a reference to the required clip from its name 
  var name=eval('square'+x+y+'.piece');
  // attaching the mark clip to the piece (whose depth is 1)
  name.attachMovie('mark','mark',1);
  // getting a reference to the mark clip instance
  name=eval('name.mark');
  // putting it in the center of the piece
  name._x=0;
  name._y=0;
  // marking the piece logically
  marked[y][x]=1;
}

<<Prev.   Next>>


Write to us Site Map
Copyright © 2003-2017 GameIntellect.com. All Rights Reserved.