SoCoder -> Article Home -> Basic Game Engines
Created : 05 January 2008
Edited : 05 January 2008
System : Windows
Language : Blitz
Tetris Part Three : MovementA rather messy tutorial to help people make decent Tetris games.
How to make a decent Tetris game.
Part Three - Movement
This tutorial is half created to help Garand, but also because I'm sick of playing rubbish Tetris clones.
You can find part one of this tutorial here, and part two here.
Everyone knows that "Gameboy Tetris" was the best one going, but no-one ever seems to make them like that anymore.
So here's a list of things you'll need in order to make the game well, as well as chunks of code, and a few moans and gripes along the way.
I'll be doing this in Blitz, but the rules are about the same for all languages, and you should be able to follow them along with whichever language you're using. (maybe! Although it is a bit of a mess! I'm not very good at describing code!)
Smooth Moves (How to do classic oldstyle KeyDelay/KeyRepeat things)
Up to now we've left the left and right controls as Tap-style motion. We'll now tweak it to be more gameboy like.
Start off by adding the two globals MoveDelay, MoveSpeed and MoveNextSpeed. Set them all to 15.
What we want to do is this. If the key's held, move. Then wait 15 frames. If we're still holding onto the key, move again. Then wait 2 frames, move, wait 2 again, move, repeat.
(note that 15 and 2 might not be the right speed. We can tweak this later to get the right feel to the game.)
We'll start with the left key..
If KeyDown(203) and MoveDelay>MoveSpeed then MoveDelay=0:MoveSpeed=MoveNextSpeedlayerX=PlayerX-1:MoveNextSpeed=2
If held, shift, then set delay back to 0, speed to the next delay speed, and then reduce the delay speed ready for the next time.
Repeat that for the right movement and then after that, we want a line to count the moveDelay.
if Keydown(203) or Keydown(205) then MoveDelay=MoveDelay+1
And then one to reset everything if you let go of those keys.
if Keydown(203)=0 and Keydown(205)=0 then MoveDelay=15:MoveSpeed=15:MoveNextSpeed=15
For future reference, you can use this method in all sorts of situations. Even windows uses KeyDelay/KeyRepeat if you hold a key down.
So, now that the blocks are moving around smoother than they used to, we can start to do checks to the left and right, to see if we really can move them about..
Into our two lines of movement, add "And CanMove(-1)" to the left movement check, and And CanMove(1) to the right movement check.
If KeyDown(203) and MoveDelay>MoveSpeed and CanMove(-1) then MoveDelay=0:MoveSpeed=MoveNextSpeedlayerX=PlayerX-1:MoveNextSpeed=2
This'll stop us moving the block when we're not meant to be, but only once we've added the CanMove(PlusX) function.
Basically, you want to repeat what we did for the Below() function, but instead of checking below, check X+PlusX and if anything's there, return false.
Before you land
If you try out our version now, you'll notice that you can't really slide blocks under other ones like you should be able to.
In Gameboy Tetris there's a small section of time from hitting the ground to actually being triggered as landing. Ours doesn't. The second our block hits the floor, that's it.
So, we'll have to add another small delay to take care of that.
Add LandDelay and LandSpeed to the global list, making Speed 20 and Delay 0.
Whenever we move left or right, reset LandDelay to 0, so that we could potentially move across the width of the level, if we had the chance.
Within the Landing section, stick most of it inside an If, checking that LandDelay>LandSpeed, and add a LandDelay=LandDelay+1 to count up to the full speed of a land.
Also, the drop code should now be wrapped around by a check that nothing is below.
Give it another go, and you should now find that you can slide things in below other bits.
Still, it's getting a bit dull constantly using those default blocks, isn't it.
Time to add a bit of randomness to the procedings.
Back up to the top of our list, add us an array called Bag, with 28 slots.. (Dim Bag(28))
Then something to keep track of where we are.. (Global BagPos)
Next we'll add 2 functions.
The first is NewBag()
In here, we'll fill "Bag" with 28 blocks. 4 of each block, 1 of each rotation. That's 28.
And then we'll do a quick shuffle. Imagine it's a deck of card layed on the table, and you'll understand what the code's doing.
That shuffles a list as good as we can.
Then reset BagPos to 1.
That's our NewBag function. Call that right at the start, just after you've created the array, so that the bag gets filled and we're ready to go.
Next we'll need a FromBag function. This grabs the next entry from the bag (BagPos) and returns it. It also adds one to BagPos, and if BagPos>28, it asks for a new bag.
Add a NextBlock and NextRotate to the globals, and right at the start, set them up with blocks from the random bag.
And then, during the landing code, copy the Next Block over to the Player's block, and insert a new random block into the Next settings.
Sorted. Now when we play we'll get a steady stream of blocks. And a nice random selection, too.
Every 4 out of 28 blocks will the I bar. 4 will be L's, 4 J's and so on. It keeps things random, whilst not making them so random you never get any I bars!
Of course, you could do it the other way, and leave the player desperately needing that never appearing block. Whichever you feel is most fun/mean!
To help the player, we'll give them a little display of what's coming up.
Remember that we used a 4x4 grid to hold each block, so the Next box should be 4x4, too.
We can either use rectangles, or predrawn images to create the box. In the example we'll draw it.
Use a scale of colors, and draw concecutive boxes.
To draw the Next block, copy the code that drew the player's block, move it to draw at (18+2)*32 x (2+2)*32, and then change all the PlayerBlock/PlayerRotate to NextBlock/NextRotate instead.
So, give that a go, and you'll be able to play a fairly decent game of Tetris.
There's a few things we need to do before we can be happy with our game, though, and we'll deal with a couple of those in the last part of our tutorial, part 4.
For now, you can, as always, download things up to this point, and hopefully play around with the code enough to make your own additions.