Arrays in GamesNow you might be saying to yourself that this is all fine and good, but are arrays really that useful when I’m making a game. Well the answer is yes. There are several games that can be built with arrays as the fundamental element and we will cover some of them here. An important skill to learn is taking the new concepts that you learn with any programming language and then thinking about how you could use them when doing game programming or just doing programming in general. By taking the concepts and looking at them from all angles you end up building yourself a toolkit of options and skills that can be brought into action on command. PacManI think that most people have played Pacman or a game similar to it. The goal of the game is to collect as many coins as possible without being killed by the evil ghosts that come around and try to kill you. You will notice in my version of the game on my website I used evil pacmen rather than ghosts. The first part of our PacMan game that we want to look at is how to setup our array and how to draw what the array represents on the screen. The squares on our board will consist of either black (not a wall) or blue (wall) squares. On top of those squares that are not a wall there is the possibility for a coin or one of our pacmen to be there. So we will have one of 4 possibilities:
Now you might be saying, "Isn’t it possible for a pacman and a coin to be on the same square?" This will happen, but for drawing purposes we would only draw the pacman because he will have eaten the coin. To store the information for our board we will want to have a two dimensional array of characters. We will then store one of five characters in each element of this array: ‘e’ for enemy pacman, ‘p’ for our pacman, ‘c’ for coin, ‘n’ for a wall, and ‘b’ for nothing. In the init portion of our applet we will need to initialize our array with these character values to setup our board. We have two options when considering how to go about initializing our board: read the board characters in from a file or hardcode the values in the source code. Either of these options is perfectly fine, but you will find that by reading the board in from a file you make it easier to rotate through a variety of maps; your code will be easier to read; and it will be easier to edit your boards. Now that we have our board initialized the next step is to figure out how we can draw it. In order to draw the base portion of our board (wall or no wall) we need the following chunk of code. switch (board[count1][count2]) { case 'n': offscr.setColor(Color.blue); break; default: offscr.setColor(Color.black); break; } offscr.fillRect(boardx+count2*blocksize,boardy+count1*blocksize, blocksize, blocksize); The code block above is going to be located inside a double for loop with the first for loop using count1 and the second one using count2. The switch statement should be fairly understandable. The goal of the switch is to pick the color we will draw for the square (blue for the wall; black for nothing). The switch statement uses the character in our two dimensional array as a basis for its decision. After we have picked the color all that is left to do is draw the rectangle that represents the element of the array that we are currently on. In order to draw this rectangle we use the following variables:
The result of this code by itself would be to draw the board that we have created without displaying the coins or pacmen. In order to display the coins all we have to do is draw a filled oval at the appropiate spot on our board if the square has the letter c in it. The last part left, as far as the display is concerned, is how we will draw the pacmen. This part is really up to you and your creativity but what I decided to do is use a filled arc. By using a filled arc and a little timer I was able to set up my little pacmen with mouths that open and close. You will notice in my code, however, that I have put the drawing code for my pacmen inside a class that is used for my pacman and the enemy pacmen. The reason for this is that it makes my code a lot neater and also gives me the ability to easily change the number of enemy pacmen that I have. The next part that we need to discuss is how to represent the data and actions that are associated with the pacmen in the game. The actions that a pacman can perform are: move, draw, and change direction. The first two are fairly obvious in what they do, but the use of the third one might not be immediately apparent. The reason a pacmen has to be able to change directions is that I want the mouth to be pointed in the direction that he is going. If you were to leave this ability out the game will still be okay, but it will be visually lacking. When you are making games like this you have to remember that the user will notice little details like this and if it is at all possible you should take care of them. The direction change will happen when the user presses one of the arrow keys on the keyboard so we will need to use what we learned last time about the keyDown method. The drawing of the pacman will be fairly simple and will involve drawing a filled arc that may be a circle if the mouth is closed or have a gap if the mouth is open. Out of the three actions that a pacman will perform the ability to move is the most complex in terms of all the options that must be considered. The options that we must keep in mind are: will he hit a wall ,another pacman, a coin, or nothing at all if he moves to the next square based on his current direction. The data that we need to keep track of for a pacman are: whether the mouth is open; how long it takes for the mouth to open or close, the size of the mouth angle; the direction he is facing; whether he is controlled by the user or the computer; the current speed and maximum speed; the x and y location on the board; the color that he is drawn in; and a counter to keep track of how long it has been since he opened or closed his mouth. You may wish to add or remove items from this list of data that we are keeping track of, but I think that you will find that this is a good place to start. After we have the pacmen set up, all that is left is to increase the score when a player goes over a coin and deal with what happens when the player dies. If you wanted you could also add in an introduction screen and even multiple levels for the user to play on. This covers the basic topics that you will need to know when sitting down to program PacMan for yourself. You can also look at my web page (www.cpsc.ucalgary.ca/~kinga) to take a look at my solution. TetrisTetris, for those of you who have not played it before, is a game in which pieces of different shapes fall from the top of the screen and land on the bottom of the board area or on top of other pieces. When an entire row of the board is filled in with parts of pieces the row disappears, the rows above it shift down, and the player gets points. As the user gets more and more rows disappearing the speed at which the pieces fall is increased. If the user should ever fill the board to the very top without being able to eliminate any rows then they lose. The first part of the tetris game that we will look at is the board. The representation and setup of the board will be almost identical to that of the PacMan board. The following are the various possibilities for a square on our board:
For my version of the game that I created I had 5 different piece types that could fall down so I had the following characters that I looked for: y for yellow, r for red, b for blue, g for green, p for magenta, and n for black. To take this information stored in my two dimensional array and use it to draw the board on the screen I need to use the same style of switch statement that I showed you for pacman with the following as the case statements: case 'y': offscr.setColor(Color.yellow); break; case 'r': offscr.setColor(Color.red); break; case 'b': offscr.setColor(Color.blue); break; case 'g': offscr.setColor(Color.green); break; case 'p': offscr.setColor(Color.magenta); break; case 'n': offscr.setColor(Color.black); break;I also end up using the same line of code to draw these rectangles (squares) on the screen. The biggest part of making your Tetris game is creating the shapes that will fall and enabling them to rotate and collide properly. For the version that I have made I used the following shapes:
After you figure out how the basic shapes work you can experiment with your own shapes and variations. The first consideration that we must look at is how do we pick the type of piece that will fall. I recommend setting up some random number like we discussed in part I and assigning a range of values to each of the pieces that you have. Once you have decided on the piece type that you want to have you can then place it on the board. You will notice that in my code I have stored the four board array locations of my piece in an array so that I can keep track of my piece locations with ease. Every time the piece moves we need to clear its previous location on the board and then put it in its new location on the board. Once we have a piece moving down the board we need to allow the user to move and rotate it. The first piece of this puzzle is to watch for keyboard events. You will need to allow the user to rotate his piece as well as move it left and right. Moving a piece left or right isn’t hard, but whenever you are moving a piece (left, right, down, rotating) you will need to make sure that you check to see if the new position is legal. An illegal position would be one where the piece overlaps another piece or moves off the board. If ,when we try to move our piece down, we discover that it is illegal then we know that this piece cannot be moved any lower and we can stop moving it and start the next piece. The hardest part of dealing with the movement of pieces is allowing them to rotate. You will notice that in my code for the rotation I break it down into the cases for each piece. Obviously we don’t need to worry about rotating the square since its appearance never changes no matter how much we rotate it, but we need to look at all the other pieces. We will take a look at the rotation for one piece and then you can look at my code for how the others will work.
When dealing with the rotation of the piece it is important to just look at the relative position change. In the transition from the first diagram to the second you will notice that the y-value of block number four decreases by one and the x-value decreases by one. In the transition from diagram two to three the y-value of block four again decreases by one, but the x-value increases by one. In order to code the rotations in for all the pieces I recommend that you draw out the transition diagram for every piece and go step by step through your code accounting for every possibility. Since we are dealing with our tetris game in terms of arrays rather than just screen positions this rotation process is more complicated, but this representation makes a lot of other parts of the game (row elimination and collisions) much easier. As with the regular piece movement you need to make sure that before you let a piece be rotated you first check to see whether the new position is legal or not. In fact you will end up performing this task so often I would recommend that you set up a method that can perform this task (in my code this method is called colorCheck(). After we have moved the current piece as far down as it can go we must check the current state of the board and see if there are any rows that are completely full and if so then we must eliminate them. You will notice that in my example solution on my web page I start at the bottom of my board and work my way up. For every row that you eliminate you will give the user additional points based on the difficulty level and the number of rows they were able to eliminate at one time. You now should have a basic understanding of what is involved in creating your own Tetris game. If you have any questions about this you can check out my version on my web page (www.cpsc.ucalgary.ca/~kinga) or you can email me (kinga@cpsc.ucalgary.ca). Other Potential Array Based GamesIn addition to the two games that we have looked at here in detail there are many other games that could be created by using an array base. A couple examples of other games are Nibbles and Snafu. Nibbles is a popular game that a lot of you have probably seen coded in Basic. The game consists of two or more "snakes" moving around the board area trying to beat the other snakes to the power-ups that appear randomly on the board. The more power-ups you eat the longer your snake gets and the more difficult it is to maneuver around. This game can be expanded to allow for a variety of maps to be used and to allow for different power-ups that could shrink your "snake" or reverse the direction in which all of the "snakes" are moving. Snafu is a game that some of you may remember from the old Commodore days. The game consists of two "snakes" moving around a map like nibbles, but the snakes leave a trail behind so the number of valid squares that the "snakes" can move to is continuously decreasing. The first "snake" to hit itself, the other "snake", or the wall loses. You can even create maze style games or variations on PacMan and Tetris. The main idea to remember when you are deciding what game you would like to create is to be creative. Coming Soon!!!Now that we are comfortable with arrays we can move on to discussing AWT, artificial intelligence topics, and how to pass parameters to our java applets. These topics will be discussed in the next part of this series as we move away from the basics into the more advanced topics. If have any questions or comments feel free to email me at kinga@cpsc.ucalgary.ca. All of the sample programs related to what I have discussed here are located on my web page (www.cpsc.ucalgary.ca/~kinga). Thanks again for reading this series and sending me numerous emails with your comments and questions. |