Kid's Programming Language: Santa's Gifts
- Posted: Dec 01, 2006 at 1:42 AM
- 1,078 Views
|This article is in a series in which we are recreating classic video games in KPL code—in this article, Santa's Gifts|
Time Required: 1-3 hours
Software: Kid's Programming Language
One way to get started programming games is to pick a popular game that is fun to play, that has all of the rules already made up, and develop a program that just transfers that game to the computer. Doing that much will help beginning programmers raise their programming skills as they code and tweak their own rendition of the fun game. A Christmastime example of that method accompanies this article, programmed using a relatively new programming language designed to help beginners gain programming skills. Kids' Programming Language (KPL) is a simplified but modern programming language and development environment that introduces beginners to the basic programming concepts. Just as many famous sports players start out playing sports while they're young, KPL is a tool kids can use to program computers while they are still young. With KPL being a free download, it is well within their budget!
The referenced KPL game is called Santa's Gifts, but it is very similar in nature to the popular Tetris genre of falling objects that need to be properly positioned for optimum points. The rules and game play is simple to learn, but strategically placing the falling objects will give the advanced players higher scores. Using the arrow keys to move the objects from side to side allows the player to position them where they want. Pressing the Down arrow key lets the object drop. When three or more objects of the same type are positioned together, they form a group that is removed from the drop zone, adding some number of points to the player's score. The strategic part of the game is to try to build groups of four or five items, or to try to cause chain reactions where the removal of one group causes another group to be formed and removed. Both of those methods yield more points than just creating groups of three. There is a time aspect to the play as well. The player can't take all day to decide where to position the next item. The time to decide is decreased as the levels progress, which will cause the player to have to recognize certain patterns that score better, decide on a strategy to complete those patterns, and go for it in a relatively short period of time.
If at all possible, create the game on a piece of paper first, or use pieces of paper to represent objects in the game, and set it all out on a table top to run through the game a few times. Get input and feedback from other game players, and check it over to see if the rules are easy to learn, and if there is opportunity for advanced players to gain an advantage at beating the game. You'll want to iron out the problems and any other conflicts on paper as much as possible before they become problems while writing the game code. It is much easier to change a rule on paper than retrofit a new rule into the computer program. For the simpler games, some may do all of that planning and checking in their head, as I know I did on more than a few occasions, but it cannot be stressed enough to do the planning first, to avoid scrapping or re-writing whole sections of code.
As I mentioned before about the sports heroes playing the sport while they were young, it takes many years to develop the skills needed to play professionally. They certainly didn't do everything right while they were learning. Expect a little of that in yourself. Those professional players didn't quit, and they kept going until they made it to the top. That sort of perseverance is what you'll need to get past the few failures that may happen. If you can't get the programming to work one way, try another route. Don't be discouraged about starting a project over, or trying to do it in a new way, especially as you begin to develop your skills. Mentors, or others familiar with the tools you are using, are a good source of information and can help you find the right path, instead of the trial and error mode of learning.
Begin a new game by writing the storyline. Describe where the player is coming from, and where he has to get to. Include the objects or obstacles he will meet along the way, and then move on to creating the rules of engagement. Pretend your table top is your computer screen and cut out pieces of paper to represent the objects the player will see on the screen. Play the game several times, taking notes of any conflicts or other ideas that will be included in the game. Refine the movements and game play such that a child can learn it fairly quickly and figure out how to add something the advanced players can use to gain an upper hand. Begin coding the program by adding just a shell that shows how the screen will look, and provide the means to start the game, and whatever needs to happen to end the game. Then start adding routines to get the game up and running. For example, if there is going to be five levels to the game where each level shows a different screen, then start with a loop in your main procedure that iterates 1 to 5, that will call the routines to draw the different screens as they are needed. Just get the basic shell in place as the starting point. Then add the objects that make up the game, such as adding the player to the screen, and allowing him to move in each of the levels. Then add the objects to the different screens, or whatever the player will be interacting with, and so on. Piece by piece, build the game by providing the skeleton and then adding the meat. You can do that on the whole game level, and on a finer level for different routines. Be mindful of saving your work at different milestones, and then working with a copy from there. You should save your work periodically, at various milestones, so that if the day happens where your file gets corrupted, or you code yourself into a corner, you can go back and make another copy of the last milestone and get back into it, instead of having to start all over from scratch.
For those who are going to be looking at Santa's Gifts source code, I want to point out a couple techniques that might be useful in your own games. The first is in translating a one-dimensional array into something that represents the two-dimensional screen; specifically, checking for objects that are in the immediate area of the player. The second is the method I used to create the fading points that are shown when groups are removed from the play area. For people who do not yet have a copy of KPL, you can learn more about it from www.kidsprogramminglanguage.com.
KPL only supports arrays of a single dimension, so representing two-dimensional space takes a bit of doing. In particular, X and Y coordinates have to be translated into an Index value that points to an element in the array. In general terms, transposing between the two can be shown by the following code:
// XMax is the maximum extent of the 2D space in the horizontal direction X = Index Mod XMax Y = Index / XMax Index = X + (Y * XMax)
That works when the arrays begin with the first element at index 0. Currently KPL begins its arrays at an index of 1, (but that may change!), so the above code becomes:
X = (Index - 1) Mod XMax
Y = (Index - 1) / XMax
Because the KPL single dimension array uses the Index value to reference its elements, it is more often easier to work with the 2D grid cells by manipulating the Index value, instead of the X and Y values. When the game code has to check for any objects in a grid cell adjacent to the player, it can test the next cell to the right by adding 1 to the player's Index value, and the cell to the left by subtracting 1 from the player's Index value. Similarly, to check the next cell above or below the player, XMax can be subtracted or added (respectively) to the player's Index value. Of course boundary checks are needed to avoid looking above the top edge or below the bottom edge, which are easily handled by testing the adjusted Index value to be between zero and the upper bound of the KPL array. But boundary checks on the right or left edge are more difficult to handle when using the Index value.
To represent a checkerboard, for example, the KPL array would hold elements indexed from 1 to 64 which represent the 8 X 8 grid. A value at Index 1 is the same value for the grid coordinate (0, 0) or (1, 1) depending on which value you prefer to begin numbering with. Assuming the upper left cell is at (1, 1) then the next cell to the right of the upper left cell is at (2, 1) with an index of 2, (3, 1) is Index 3, (4, 1) is Index 4, and so on to the upper right cell which is at (8, 1) corresponding to the KPL array Index value of 8. The cell below the upper left corner cell is at (1, 2) which equates to an index value of 9. And so it goes with the Index value incrementing by one as the grid cells are traversed left to right and top to bottom.
The trouble arises when the player is at the right or left edge, because adding one when the player is at the right edge, or subtracting one when the player is at the left edge will actually be referencing a cell from a different row. If the player is at cell (8, 1) or Index 8, then the code must not add 1 for the adjacent test because the player is at the edge; there is no cell at (9, 1).
One way to avoid overstepping the boundary is to convert the Index value back into its X and Y coordinates so you can test X in comparison with XMax. But there may be many places where such a check is made, which would require many such conversions. Even if centrally located in a function somewhere, the code must be called, which takes some amount of time, repeatedly, over and over, every time such a test is needed.
The method I used instead of repeated boundary conversions effectively adds a blank cell to the right edge of the 2D space. The KPL array was lengthened to account for there being a cell there, but it was never used for player movements. What it did was avoid the need for special case tests for the right or left edges. Upper and lower boundaries were still in place, but adding that extra cell meant I could simplify the code used to test the adjacent cells. I could safely increment the Index and check for objects for tests to the right, and I could safely decrement the Index value and check for objects to the left because there was that extra cell at the end of each row. Tests to the left when the player was at the left edge found a blank cell (obviously no object there), and tests to the right when the player was at the right edge also found a blank cell. With a little tradeoff in memory usage, I simplified my code considerably. Check out the CheckAdjacent routine in the game source code. It turned out to be nice uniform code that tests for upper or lower boundaries ahead of comparing the objects for similarity. That is the code used to find all the members of the same type for inclusion into a grouping. If a similar gift is found in an adjacent cell, then adjacent cells to that one have to checked for further similar gifts. If checking there finds one in an adjacent cell, then that new one has to have its adjacent cells checked as so on, to find all the gifts of the same type that are next to each other. You'll note the repetitive nature of those tests made for a good place to use a recursive call (where some routine calls itself to complete its task), but recursion is entirely another topic, worthy of its own detailed discussion.
The second technique I wanted to mention allowed me to print text on the screen and have it fade away. It was just one of those what-if discoveries I made while looking for a simple way to show the points for the currently removed group, without it remaining on the screen too long. I had used the Status area, but I didn't like how the points shown there seemed to be more like debugging information and not really a part of the game. What I did was take part of the screen image and make it partially transparent using my favorite paint program. I placed that translucent image in a sprite and used KPL's StampSprite method to transfer the image to the screen. I found that I could print text to that area, and periodically stamp that translucent sprite over the text which would gradually erase the text. I also used that method to provide the BRIGHTNESS constant you'll find near the top of the listing. It controls the brightness of the background image. I didn't want the background image to be so bright as to distract from the animated gift images. I wanted a kind of lower-contrast image to avoid that distraction. When I found the translucent sprite could be stamped in place several times to build up to being opaque, I decided that would be how I could lower the contrast of the background, by making the background sprite translucent. It has to be translucent over some color or shade, and that is what the BRIGHTNESS value controls: it decides the brightness of the gray color used behind the translucent background image.
One final note on playability. On faster computers you may find that the program runs way too fast to play. That is the way I have grown accustomed to designing programs. Design them so they can play faster than the human can because the computer can easily be slowed down to let the human catch up, but it is usually more difficult (or nearly impossible) to try to speed up a program when it runs too slow. Also near the top of the listing is a TIMEDELAY constant you can adjust to slow down the game more to your liking and abilities.
I hope you enjoy playing Santa's Gifts, and that you'll take up writing and sharing programs of your own design! If you need beta testers for your KPL program, or have questions or comments, do visit the KPL forums available from links in the help menu of the KPL environment.