First 2D game - yet another Tetris(tm) clone...

…can be found here:

http://infoether.com/~tom/games/tetris/

This is a very simple implementation of Tetris - no sound, blocks are drawn using Graphics2D.drawRoundRect(), and so on. Everything should work though - the pause function, the “top 5 high scores”, the demo mode, etc. FWIW, I get about 65 FPS on my little Pentium III 1.1GHz laptop.

Thanks for any feedback - this is my first effort in this field so pls be gentle :slight_smile:

Thanks,

Tom

P.S. First I posted this over in the Java 2D section… thanks to zparticle for noticing that it should have been over here to begin with.

Why does Tetris run with 65fps???

What a waste of CPU resources. Consumes 100% of my CPU. Could do it easily with 1%.

Right… it’ll take everything it can get… the game loop is pretty much this:

state.execute();
offScreenImage.drawImage(blahblah);

So it’ll loop as fast as it can.

I put a Thread.yield() inside the game loop, and a Thread.currentThread().setPriority(Thread.MIN_PRIORITY) right as the program starts to try up make it a bit less greedy…

Yours,

Tom


    private final int TICK_TIME = 500;

....

    Thread.sleep( TICK_TIME );

Right, it could just sleep inside the game loop… but wouldn’t that preclude a “row filled” animation or a “piece landed” animation? Because those would need to, you know, fly away in little pieces or something nice and smooth.

On the other hand, I haven’t implemented any animations like that yet, so that’s not a very strong argument :slight_smile:

Tom

Hi there,
Just a question: does this game really need to be based on FPS, considering at 120 FPS (which is what I was getting) i’m not doing anything for 119 of those frames (if it takes just 1 frame to move the block down per second).

Is another possiblity to just have the pieces fire their own doPaint() methods when either A) The user presses a key, or B) when a timeout says to move the piece down. Then, your game loop looks something like this:


gameOver=false;
while (!gameOver)
{
  checkRows(); // will check for completed rows and draw any animations, and move the previous rows down 1 row for each cleared row
  if (checkGameOver())
    gameOver = true;
  waitForAction();
}


waitForAction() could be alerted if the user does the ‘drop block’ action or the ‘block collides with a row’ action. This would eliminate some degree of ‘busy waiting’

There’s still an issue tho, depending on how your timer works…if you do want to do a really elaborate animation (maybe each block explodes in a wonderous shower of pixel-light and sound) should the time required to display the animation halt the timer’s countdown to the next block-lowering-iteration? I think the answer is yes. Therefore, you don’t want to have the ticker in it’s own loop, you probably want to cancel a pending ticker when the player does a ‘drop block’ and kick off a new one…or something like that.

-Chris

Hm, that’s well said. Let’s see…

Note that any explanation I give for doing this as an FPS-based thing will be purely post-action rationalization on my part since I just kind of wrote this the only way I could think of doing it. It’s more of a lack of knowledge on my part than an attempt to do things a particular way. :slight_smile:

Anyhow, yup, let’s see, how to do this without a busy-wait game loop? OK, there could be a timer that fires once a second that kicks off a “piece lower” event that erases and redraws that piece. And the KeyListeners could do a similar thing for rotation and left/right movement.

The animation thing would be interesting.

[much typing]

OK, it was interesting enough that I cobbled together an little “animation” that, in addition to be disconcertingly ugly, gives us something to work with. I’ve uploaded a new version to the web site - http://infoether.com/~tom/games/tetris/.

So, how could I do something like that without a FPS thing? Maybe run the animation in another thread? And then interrupt the thread if the animation needed to be restarted? Maybe that’s a way to do it…

Tom

Hah, good animation (I’m into ugly, I guess). Anyways, it demonstrates one of my points:

The block is continuing to be signaled to drop while the animation is playing…do we want that? Maybe, maybe not. We defintely don’t want it if the animation involves clearing the row (maybe a very high row, very late in the game) and with the block falling befor ethe row is cleared, I could loose the game simply because the animation din’t finish fast enough before the block collided with a non-clear row (I am getting mad just thinking about it).

So, let’s say, for argument’s sake, we don’t want the brick to drop during the animation…that means your game loop should not let the timer controlling the block’s desent continue while the current ‘tick’ is being processed…

Without going into too much detail, I think your game boils down to 2 threads: A user input thread (that AWT or Swing will provide to recieve user input) and your timer thread that should fire off an event of it’s own to signal the block should be moved down. The game only needs to check it’s state (to see if the game is over or if a row is cleared, or the block just falls to the bottom and nothing happens) when either A) The user clicks up arrow or B) The timer triggers. Once this happens, the following chain of code can execute:

Move Block (either 1 space down or all the way down)
Check for row clear
Perform any animations as necessary **
Restart the Timer trigger.

** This action you can either draw to the screen as fast as possible, or you can draw it at a fixed FPS Either way, nothing further should happen in the game (such as blocks moving downwards, etd) until after this chain of code completes.

Like you said, yes, you need to have a way to ‘cancel’ the trigger if the user does something that should abandon the countdown…maybe your Trigger thread can look something like this:


Public class Trigger extends Thread
{
  private int TICK_TIME = 500;
  private boolean aborted = false;

  public setAbort()
  {
    aborted = true;
  }

  public void run()
  {
      try 
     { 
        Thread.sleep(TICK_TIME);
        if (!aborted)
          fireEvent();
     }
  }
}


Now, if the player does something that should halt the trigger, just call setAbort() on the trigger. Every time you ‘restart the timer trigger’ you create a new trigger object. Now, this violates rule number 1 of all game programming: do NOT create excessive objects…(especially in this case, thread objects), but it will get the job done. With more work, you could use Thread.inturrupt() to wake up the thread so that it’s in a state to reuse. This would save a lot of resources.

-Chris

Bah, I don’t think I answered your main question which was where to do the animation thread: But do it in the main game loop, you don’t want any other action to take place while the animation is playing, so just make the main game loop thread call an animation routine and after it’s finished continue with the game (create a new trigger, etc). You may want to ignore user input while the animation is playing (easily indicated by using a boolean variable)

-Chris

The more I think about it the more I agree that the “loop as fast as you can” design is not good for some games.

For example, a Othello game could just sit and wait for user input, and then spend as much cycles as necessary flipping pieces and calculating scores and exploding with light and sound. Then it could go back to sleep and wait for the next move. Actually, I guess it would need a background thread to be analyzing possible moves and such… assuming it was a player against computer game.

What about arcade games though? Maybe Tetris isn’t really an arcade game per se… although when the “lower piece” speed is down to 100 ms it seems fairly arcadish. Hm. At the same time though, Herkules’ question still seems appropriate - “why should x consume 100% of my CPU?”. Even if it is Asteroids or Space Invaders or some such, gobbling 100% of CPU seems rude.

Re-reading your post again now… the thing that bothers me about “land the piece, then play the animation, then continue the game” is that it seems a bit stilted. I mean, part of the fun is that a lot of stuff is going on at once - I’m rotating a piece, the animation from the last piece is still going, the animation from the last time I filled up a row is fading away (at least, if there was such an animation). On the other hand, all that could probably be done using separate threads.

Here’s a question - how could that animation be accomplished without redrawing the underlying board every time the circles get bigger? Hm, I guess I could draw a clipped region of the board, then do the animation… and the clipped area could be dependent on the largest circle size… hm. Or maybe there’s some Java 2D ImageFilter thing for that…

Thanks for the ideas and feedback,

Tom

I my mind there isn’t anything wrong with taking 100% CPU for a full screen game because the player isn’t (at least I wouldn’t be) doing anything else. However it can be annoying to have an applet or windowed game up that hammers the machine.

[quote]I my mind there isn’t anything wrong with taking 100% CPU for a full screen game because the player isn’t (at least I wouldn’t be) doing anything else.
[/quote]
I don’t agree. Yes, the PLAYER doesn’t do anything else, but his machine might do!
Love to play while compiling, printing, e.g…
Or my machine is used as a dedicated Quake-server while I’m playing Tetris?

In general, for a multi-purpose, multi-tasking, maybe multi-user platform, don’t assume anything what the user does or does not.

Yup, it makes sense to use as few resources as possible.

I put a Thread.currentThread.sleep(20) in the game loop; that trims CPU usage to about 30% without causing flickering or anything like that. So that’s a little better.

Tom

You hit the nail right on the head with your othello example…those sort of games (and I think tetris is just like those games except there’s a timer that forces you to make your move, etc) aren’t really ‘fps’ types of games (although they could be, as your game demonstratres).

Second thing i wanted to say is always ALWAYS program games with the most efficient use of resources in mind. That means be consious of thread creation, object creation, busy loops, etc…I’m not saying you should cripple good design for maximum efficiency, but in the realm of game programming, elegent design (flexability, extendability, etc) may take a back seat to getting the fastest amount of performance…all things in balance tho.

Third, as far as thread creation, in games, I’d avoid it. Your turn-based game makes sense in that you’d want the computer to do work about calculating moves while the player decides what he is going to do, however, doesn’t the player’s move change the state of the board and therefore the work the AI just did in the separate thread need to be re-calculated based on the new board? For FPS based games, same thing with the AI, the AI will need to decide what to do after the player’s avatar has performed it’s action for its ‘tick’…a separate thread will not help you here, I don’t think.

Also, separate threads for animation is also risky, because one thread may starve and so one of your little animated guys may be frozen (there’s a post about doing NPC animation in another board (check the 2d forum). The more common design is to have 1 animation thread that checks each drawable element and draws only things that say need drawing.

Anyways, food for thought. Most of all, have fun.

-Chris

Very cool, thanks for the thoughtful response.

FWIW, I was just reading some stuff out there on Othello algorithms. Seems like some people create an “evaluation thread” while the human player is thinking. The thread considers each possible human player move and evaluates the best possible response move - so when the player finally does go, the computer has some cached responses. Cool stuff.

Thanks again,

Tom

check out my tetris. maybe it will give you good ideas

http://www.mandrixx.net/tootris.html

keep on the good work

Wow dude, that’s awesome! Nice and smooth. Very cool.

The brickout game is awesome, too… I’m working on one right now and it sure doesn’t look as good as that! Oh well.

See ya,

Tom

I changed the controls on my version to match yours… whoever suggested it way back when, you’re right: the down arrow should simply lower the block, not drop it.

http://infoether.com/~tom/games/tetris/

See ya,

Tom

tcopeland:

When a block gets to the bottom of the window you should be able to move it side to side for a small period of time. This allows you to slide under a fixed block to fill a gap.

Hm, you’re right, currently it just goes ahead and plants the piece without waiting. I’ll look at it… thanks…

Tom