Some Java Game Ideas


<<Previous | ToC | Next >>

This page lists some ideas that you might program in GameEngine. You may have other ideas -- Tell us! -- if we think you can do it in the time you have, we'll add it to the list.

We don't tell you how to write your code, you do that! But we do give you some implementation details that might be helpful.

More important, we want you to succeed, so we will insist that you think hard about how your game needs to work, and write your Design down, and then follow your Design. This is so important, you will not receive any credit for working on this game unless you do that.

Not to worry, we want you to succeed. If you have trouble organizing your thoughts into a coherent Design, a Mentor will work with you. If you can code to the Design, you will be a competent programmer anybody will want to hire, and you can make lots of money and have lots of fun doing it. After you learn to create a good Design without our help, you can be the Lead Programmer and make even more money 
 

Game Ideas

Squares Falling from the Sky
Tic-Tac-Toe
Snake
Tetris
Card Games

New Widgets

Several of these games require new game elements appearing throughout the game. Probably the easy way to do this is have one of each kind of widget you want to create on the fly, then use it as a prototype you send to the NewGameWgt method to clone. Say you made a square widget named "BaseSquare" in GameMaker. Then when your game requires a new square like it, do something like this:
GameWgt myNewWgt = myGame.NewGameWgt(-1,top,left, 0,0,0, color,velo, null,BaseSquare);
GameWgt parentWgt = JavaGame.GetIxWgt(BaseSquare.GetParent());
parentWgt.AddElemt(myNewWgt.GetRefNum());
where top and left are the position of the new widget, color and velo are the new color and (packed) velocity to use, or 0 if you want the same. If your BaseSquare is hidden, the new widget will become visible when you give it a new vertical position top.

The first line creates a clone widget, but it will not be drawn on the game board unless it is in the widget hierarchy from the game board. The second line there finds who is the parent of the BaseSquare, and the third line adds your new widget as a child of that same parent.
 

Squares Falling from the Sky

(Sorry, no graphic) Most of what you learned in Pong can be used in this game. Instead of a ball moving back and forth, you have individual colored squares falling from the top (like the Pong ball, only they are square, use the "SkyRec" tool), and the paddle on the bottom that you can slide left or right to catch (or miss) the falling squares. If you have only a small number of squares visible at a time, create them all in GameMaker and hide the ones you are not using.

If you want them to pile up or otherwise hang around, you can make new widgets on the fly.

Design First

This is an easy game to start with. Think about what you want to do, then build your Design and get it approved.

Tic-Tac-Toe

Long ago I figured out a relatively easy way to make the computer play an aggressive (but not perfect: it can be beaten) game of Tic-Tac-Toe, so it has become my favorite way to get comfortable with a new programming language or environment. So I added it to the sequence of programs the students could write in learning Java, but it was too hard for most students. I put more effort into explaining how to do it, so now I think it is maybe harder than Pong or Falling Squares, but certainly easier than a card game or Tetris.

The advantage is that (unlike the other programs in this page) everything is explained here, and it's pretty impressive to show off, especially when you do it in the Game Engine -- but you can also do it in ASCII graphics or even in English!

Snake

I think the original version of this just adds colored squares to the board attached to the previous "head" in the direction of the arrow key most recently pressed. Look up the rules online, I don't think this is too hard for the time we have.

I sometimes tell people "I write games, I don't play them," but this one I think bit me. It is rumored (like I wouldn't know) that the snake doesn't grow past some defined length, which means that most of the time the squares on the tail are disappearing as fast as they are added at the head. The only way you can know what square to erase is to memorize the whole snake in some kind of array, then effectively slide the widgets from the front to the tail, where they are deleted. This is separate from hiding the squares on the board, but the widget reference in this array tells you which widget to erase next.

Design First

I think this is a mid-level game, the simple (all squares) version is not too hard to start with and it gives you an opportunity to learn an important FIFO data structure. Think about what you want to do, then build your Design and get it approved.

First-In-First-Out

The data structure you need to save this information in is called a FIFO (First-In, First-Out) queue, and the most efficient (minimal moving the data around) way to do it is called a "circular" buffer, which is an array with two index pointers, one indicating where the next entry is added (that would be the head of your snake), and the other indicating where to delete (at the tail). When either pointer reaches the end of the array, it is effectively restarted at the front. The usual way to do this is to make the length of the array a power of two so you can use the & operator (which is faster than the modulus = remainder operator % on most hardware) to trim the current count to the size of the buffer. If this is an array of widgets, then when you pop off the tail widget, you know everything you need to know to hide the widget (= shorten the tail).

The approved way to do this is with its own class, but for something this small, you can just put these two methods and three variables in your code where they will be used. You need to decide what's the longest your snake needs to grow, then allocate an array to accommodate it. For example, if you decide you want snakes to grow to the full  size of a 20x20 game board, you would need 20*20=400 units in your array, rounded up to the next power of two = 512.

final int maxQ = 512;
int front = 0, back = 0;
GameWgt[] theQ = new GameWgt[maxQ];

void Add2Front(GameWgt me) {
  if (front==back+maxQ) CrashAndBurn(); // array is full (do whatever you need to do)
  myAry[front&(maxQ-1)] = me;
  front++;} //~Add2Front

GameWgt GetFromBack() {
  int there = back;
  if (back==front) return null; // nothing there
  back++; // gotta do this before exit
  return myAry[there&(maxQ-1)];} //~GetFromBack

Then when you  add a widget whom to the front of your snake, you also call Add2Front(whom); and when the snake has grown long enough, you call  GetFromBack().HideSho(false);  Of course these little snippets are incomplete, you need to count the number of widgets inside your snake, and maybe do something with the widget you took off the back (besides hide it).

One version of snake I saw had a rounded head and tail that moved as a unit, and it got longer only as it ate apples. You could overlap Ball widgets for the head and tail with square "SkyRec" widgets for the body, all moving the same speed. Turning corners would require another Ball widget stopped on the corner. This is pretty tricky, and probably too hard for a term project.
 

Tetris

You might want to Google this name for the rules, but the basic idea is that you have these "tetronimos" (4-square shapes) falling from the sky and sticking to the ground or whatever previous shapes they bump into. I would do one falling tetronimo by ganging together four SkyRec widgets with a fixed downward velocity until they Bump into the board edge or a fixed tetronimo square. Once it stops, replace the tetronimo sprite widgets with four simple squares the same color (created on the fly), the re-use the sprite widgets for a new falling tetronimo, a new color.

The rules for shifting or rotating the falling tetronimo are a little complicated, but not insurmountable.

Because Tetris is a fixed game board size, another way to do it is to hand-edit a list of square widgets for every possible square position on the board (two or three hundred at most, see "Widget Specification Text"). This has actually been tried and is known to work, and has the advantage of working in the first versions of JavaScript (when it becomes available).

Design First

Managing the tetronimos is rather tricky, you might want to save this for a second game. Think about what you want to do, then build your Design and get it approved.

Your Own Sprites

The GameEngine has a Sprite widget type, but it is not (yet) fully supported in the GameMaker edit window. You can use what you have by creating (for example) a Ball sprite in GameMaker, then adding components to it in your Startup code. If you want fancy shapes, you can replace the pixel map of the ball with a pattern of your own choosing. Alternatively, you can hide the circle and add rectangles of whatever sizes and colors you need. Be sure to set the sprite size big enough to show them, and make it the parent of any subwidgets you add.

Assume that you created a Ball sprite in GameMaker named "Tsprite" and two rectangles "Rone" and "Rtwo", here's the Java code to turn them into the purple "L" Tetris sprite in the image above:

int sRfNo = Tsprite.GetRefNum(), // the sprite refnum
    tmpint = Tsprite.AddElemt(Rone.GetRefNum())+Tsprite.AddElemt(Rtwo.GetRefNum());
GameWgt tmpWgt = JavaGame.GetIxWgt(Tsprite.GetIxData(0,0)); // gets the circle icon
if (tmpWgt != null) tmpWgt.HideSho(false); // hide it
Rone.SetParent(sRfNo);
Rtwo.SetParent(sRfNo);
Rone.SetPosn(0,0); // position relative to sprite
Rtwo.SetPosn(20,0);
Rone.SetSize(20,10); // assume 10x10 grid..
Rtwo.SetSize(10,20);
Rone.SetColor(0x9900FF); // = purple
Rtwo.SetColor(0x9900FF);
Tsprite.SetSize(40,40); // big enough for any tetronimo inside

Card Games

There are numerous games with rules of varying complexity that all work with a standard 52-card deck. Except for the face cards and possibly the aces, images of the cards are reasonably easy to reproduce in the GameEngine. You can create stylized (boxy) faces, or make your own icon bit-map images the way I did for the Kitchen computer, or just punt with a large letter. The important thing to remember is that the appearance of these cards does not define the essence of the game, it is the rules of the play.

Design First

We suggest you decide on a card game that is not too complicated, and then focus first on letting the computer keep score while humans play the game. After you get that working, you might consider how to have the computer play one side, but that is pretty hard, don't even try until the scorekeeping is working well. Think about what you want to do, then build your Design and get it approved.


The 52 cards can be numbered sequentially (0 to 51, or if you include jokers, to 52 or 53), then the card number (1 for ace, 11 for jack, etc) and the suit are fixed static attributes of that card number, so the undealt deck and each player's hand (and any discard piles, if significant) are simple arrays of numbers. No complicated data structures are needed. The 52 images can be kept in an array of GameWgt (if you use complicated icons) or a String[] array of card names if you are doing an ASCII (text) version.

The number of the card (1to 13 with 0=joker) and suit are easily extracted by any of several simple algorithms. If you number the suits alphabetically (as defined for most games) or switch diamond to be lowest so that the colors alternate in the sequence (the other common ranking, which is useful when alternating colors is desirable: odd is black, even is red) then you have a single number (1 to 4, or computationally simpler 0 to 3) for the suit and another simple integer (1 to 13, or 0 to 13 including jokers) and a simple multiply-add (number*4+suit) gives you the card number (offset by +2 or +4, which is easily subtracted). Going the other way is fast and simple (see Bit Operations and Packed Numbers), or if the math is too intimidating, maintain a final (constant) 53-element array for each attribute you want to extract (name, number, suit). Don't let the OOPS bigots persuade you to build some fancy class structure for the cards, all it does is add extra unnecessary code and complexity and execution time to the simplest part of your game.

Shuffling the deck is probably the least obvious thing you need to do, so there are a zillion websites eager to tell you how. The best will make 52 calls on Random to pick a card number to exchange the next card with. Some suggest making a second array, but every time you use new to create an array or object, it uses more system resources than almost anything you could do with inline code, perhaps even worse than a bubble* sort. For a card game that extra time is probably smaller than the impatience factor in the human players, but it's a bad habit to get into -- unless of course the data structure is absolutely essential for the game (or other application) you are designing.

* Bubble Sort -- During the 2008 Presidential campaign Obama made a campaign stop at Google, and during the Q&A session, some shill in the audience asked "What is the most efficient way to sort a million 32-bit integers?" To which the politician was obviously prepped to reply "I think the bubble sort would be the wrong way to go." You can Google a video of the exchange, or why the bubble sort is generally considered the worst possible sort (except for less than a few dozen elements it's far simpler, and therefore faster than the others).

The Bubble Sort is simple enough to understand: run through the array in order, exchanging every pair that is out of order, repeating until no exchanges happen. In the worst case it's slightly under N2 exchanges; the theoretical best is NlogN. For a million elements NlogN is 20 million exchanges (compared to almost a trillion); for 32 elements it's 160 compared to 475, still a 3x difference, but partly compensated by less code per exchange (and far less programming time to get it right).
 

Others TBA


<<Previous | ToC | Next >>

Revised: 2022 December 23