Archived

This topic is now archived and is closed to further replies.

Newbie in Tetris hell - please help

This topic is 5726 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

PLease someone, end my torment. I''m doing Tetris and what I along with some help have come up with is two have two arrays, one for the actual gamegrid which is set to 0 showing that it is empty or there is a space. The other array contains 1''s in the shape of a game peice. The arrays: -
  
//Actual playfield array - might need changing work out size

UCHAR blockgrid[NUM_BLOCK_ROWS][NUM_BLOCK_COLUMNS] = {
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	
};

//This will store the game peice

int GameBlock[NUM_BLOCK_ROWS][NUM_BLOCK_COLUMNS] = {
	{1},
	{1},
	{1},
	{1}
	
};
  
What I have next is a nightmare, I am trying to put the GameBlock array onto the block_grid array. So the 1''s represent single blocks on the block_grid. This is what I got: -
  
void Draw_Block(void)
{
	for (int row = 0; row < NUM_BLOCK_ROWS; row++)
	{
		for (int col = 0; col < NUM_BLOCK_COLUMNS; col++)
		{
			if (GameBlock[row][col] == 1)
				{
				block1.x = col * block1.height;
				block1.y = row * block1.width;
				Draw_BOB(&block1, lpddsback);
				}

			if (blockgrid[row][col] == 1)
			{
				block1.x = row * block1.width;
				block1.y = col * block1.height;
				Draw_BOB(&block1, lpddsback);
			}
		}
	}
}
  
It works in that the single blocks are drawn together to represent the game peice but it is out of position on the screen and also when I take out the last if (blockgrid[row etc. statement completely it still works? WHY?? Also if I get rid of the block.x and block.y statements in the top if statement then the block is then drawn in the correct location on the screen but only one block is drawn. I think the rest are being drawn behind it but not sure. What I would appreciate is if someone could talk me through whats going on because I just don''t get it, what is it doing? Also am I doing it the right way, by copying over the bits from one array to another. I am trying to do it in C rather than c++ because it''s easier in C Any help really really appreciated it''s already taken me a month LOL Paul

Share this post


Link to post
Share on other sites
i advise you to code all your figures possibilities.
they will be stored into a 4*4 bit matrix.

ie

....
.
.****
.
.

....
. *
. *
. *
. *

and so on...


And then you know what you have, where you have.

your idea of storing everything in an array is good too.

i can''t tell you more.

hope this help.

Educate the masses ! it''s one behavior !

Share this post


Link to post
Share on other sites
I don''t understand why you need 2 arrays? It looks like you''re doing the same thing to each one.

I would think you only need one array and then you do some simple collision detecting. Where are you running into your problem? Can you drop one block all the way down to the bottom and the problem is when you start with another one...

I need more information.

Share this post


Link to post
Share on other sites
Yeah I was told I needed 2 arrays now unless I made a mistake somewhere I came to the same conclusion that 2 arrays are not needed.

The problem is I can drop one block all the way down no problem but what I can''t do is make a game peice up with four seperate blocks and move all the four blocks down as one entire game peice.

Share this post


Link to post
Share on other sites
The reason the if(Blockgrid[row][column]==1) isn''t useful is that, as far as I can see, you never set anything in the Blockgrid to one.

Second, where is block1 declared? I think the reason you''d only see one block is that it''s a global variable somewhere (thus, always valid memory) and set once. So if you don''t set it again, it just draws the default over and over.

Hope that clarified things for you.

Share this post


Link to post
Share on other sites
Erm, no it doesn''t LOL. I know it should but I just don''t get it, I think I''m losing it LOL.

I get what your saying about the blockgrid == 1 being a waste but setting the block1??

It is declared as a global and loaded in once, but I presumed much in the same way my breakout worked the array is saying if there is a number 1 in there then draw a block so regardless of how many times block is loaded in it will copy the one block loaded in as many times as the array wants (if you get that - cos I don''t).

What I think I was trying to do was was store the game peice in one array and then transfer that over to the main array. for example the game grid would be blank to start so all there would be would be 0''s in it. Once a game peice is asked for then there will be a 1111 in place of some of the 0''s if you see what I mean.

I kinda don''t get it though - thats bad when you dont get what trying to do ya know.

Pk

Share this post


Link to post
Share on other sites
I''m probably missing something, but why do you set the x co-ord of the block to the height times the column if it is a game block, but then set it to the width times the row? Shouldn''t it be the same either way?

Please pardon this if I''ve overlooked something stupid, it''s quite early in the morning .

Share this post


Link to post
Share on other sites
I would suggest adding some debugging code to see what''s happening. Something like this:

  
if (GameBlock[row][col] == 1)
{
cout << "row:" << row << ".col:" << col << endl;
block1.x = col * block1.height; block1.y = row * block1.width;
cout << ".x:" << block1.x << ".y:" << block1.y << endl;
Draw_BOB(&block1, lpddsback);
}
if (blockgrid[row][col] == 1)
{
cout << "row:" << row << ".col:" << col << endl;
block1.x = row * block1.width; block1.y = col * block1.height;
cout << ".x:" << block1.x << ".y:" << block1.y << endl; Draw_BOB(&block1, lpddsback);
}


Then you can look in the console to see when your code is firing and make sure block1.x and .y are getting the values you expect.

Share this post


Link to post
Share on other sites
Ok. I have been there. The thing you need to do is break it into smaller parts.

What works?

What doesn''t work?

First. Break your draw routines into draw block, and a draw background. You can keep the second block of your code in the loops to do that.

You gameblocks only need to be in a 4x4 grid. That is assuming you''re making exactly tetris. Now, until you''re ready to transfer the game blocks to the background grid, you''re going to need to store an x and y offset into the background.
When you go to draw the gameblocks, you have to move the game blocks by the offset.

That might help you out a bit.

Share this post


Link to post
Share on other sites
block1.x = col * block1.height;
block1.y = row * block1.width;

X and Y should be the other way around.

You use the main array to store all the blocks that are set and cannot move. You then use the gamepiece array to store the block that is currently moveing down the screen.

You can set up the gamepiece array two ways:

(1) Use a 4*4 grid and store a offset (X and Y).

for (gridy=0;gridy<4;gridy++) {
block1.y = offsety + gridy
for (gridx=0;gridx<4;gridx++)
{
block1.x = offsetX + gridx;
//draw the block
}
}


(2) use a grid the same size as your main array and store the game piece inside. This is the method your've got, no need for an offset.

Either way will work, its just preference, the first might be a bit simpler.


To draw the screen you draw all the fixed blocks from blockgrid and then draw your moving block overtop. Then you have to start working out how to change gamepieces, how to rotate them and collision detection.

Asuming the first method (I suspect the easiest after thinking about it).

Store all game pieces in a 4*4 grid and store an offset and a couple of vars telling us what shape the object is, and what orientation.

eg.
Line 4*1 or 1*4

to rotate:

    
Switch Case GameBlockShape
{
ClearGameBlockArray();

case "Line" :
if (orientation ==0) // horizontal

{
GameBlock[0][0]=1;
GameBlock[1][0]=1;
GameBlock[2][0]=1;
GameBlock[3][0]=1;
}
else // Vertical

{
GameBlock[0][0]=1;
GameBlock[0][1]=1;
GameBlock[0][2]=1;
GameBlock[0][3]=1;
}

}


And Colision detection:

  

bool Collide;

Switch Case GameBlockShape
{
case "Line" :
If (orientation ==0) // horizontal

{
If (BlockGrid[offsetx][offsety] || BlockGrid[offsetx+1][offsety]
|| BlockGrid[offsetx+2][offsety] || BlockGrid[offsetx+3][offsety]) Collide=True Else Collide=False;
}
else // Vertical

{
If (BlockGrid[offsetx][offsety] || BlockGrid[offsetx][offsety+1]
|| BlockGrid[offsetx][offsety+2] || BlockGrid[offsetx][offsety+3]) Collide=True Else Collide=False;
}

}


Also you will have to check for boundarys to stop the block being moved off the sides of the playing area.

for a line 4*1 orientation horizontal

If (offsetX>0 and offsetx+3
It gets harder with the other shapes (apart from the cube).


Hope this helps.

,Jay

Edit: Or instead of And

[edited by - Jason Zelos on March 22, 2002 5:59:50 PM]

[edited by - Jason Zelos on March 22, 2002 6:05:21 PM]

Share this post


Link to post
Share on other sites
I just finished my Tetris clone and this is what I did:

I did not use a 4x4 array to store the peices; I used a 1x array to store all possible x,y for all possible rotations of 6 peices in a 4x4 grid format. (yeah, [48]ints) I then accessed it by gamepeice# * Rotation# and got [x1][y1][x2][y2]... for square 1,2... etc.

I made two classes; one holds the current game map data (which blocks are filled and the colors) and has methods for collision detection, removing full lines and checks for end of the game; and a game peice class that contains the int [48] array above and 1. creates the peice 2. rotates the peice 3. returns the the x,y''s for each of the four blocks so they can be drawn by my draw routine and used for collision detection by the map class.

I found that it was easiest use more than one array because: When you use one array and put the current game peice in there when you do collision detection you can''t rotate because the game peice will try to occupy some of the same squares that its already in (hmmm does that make sense?)

The biggest problem I had was jumpy FPS due to the crappy win 98 timer.

Share this post


Link to post
Share on other sites
I have also finsihed my tetris clone...and yes, I used a single dimension array of a struct keep track of all possible positions of the blocks. And then a struct to hold piece info. Here they are:

  

struct BLOCK
{
int x;
int y;
int color;

};

BLOCK Blocks[220];//10x21 with a bottom row for colision detection

BLOCK NextBlocks[16];


struct PIECE
{
int position;
int color;
int shape;
int rotation;
bool testUnder;
bool testRight;
bool testLeft;
};

PIECE GamePiece[4];
PIECE OldPiece[4];
PIECE NextPiece;



So all I do is draw every block[] that has a color, all i have to do is change the values of the GamePiece[] elements. Like to move the piece down I do this:


  
for(int i=0;i<=3;i++)
{
GamePiece[i].position+=10;
OldPiece[i].position = GamePiece[i].position;
Blocks[GamePiece[i].position].color = GamePiece[i].color;
}




Most of my testing is based on the color of the blocks, like this test will see if the space under a block is empty:

//psuedo
if(Blocks[ GamePiece[0].position + NumberOfBlocksInRow ].color>0)
{
CheckForClearedLines();
MakeNewPiece();
}


But thats just my way of thinking.
Break;






Share this post


Link to post
Share on other sites
Kinda cool to hear everybody elses Tetris implementations. I went with the typical grid array and a 4x4 game piece("tetrino") array - implementing them as structs. For example:

struct Tetrino
{
int r, g, b; //tetrino color
int blocks[4][4];
int xOffset; //offset from grid upper-left
int yOffset;
int xSize; //"width" of piece
int ySize; //"height" of piece
};

xSize and ySize come in handy for determining if the gamepiece left the playing field.

I handle collision detection by looping through the gamepiece''s blocks array, and seeing if any gamepiece-occupied position also is full in the gamegrid. All gamepiece moves or rotations are handled by creating a temp piece(a proxy), applying the move/rotation to the temp piece, and then checking for collision between the temp piece and the gamegrid. If a collision would occur, I disallow the move and react appropriately - beep at the user, or fuse the piece to the gamegrid, or whatever.

I''m kind of proud of my rotation function. I rotate the entire 4x4 array clockwise through code, and then slide the piece back to the upper-left corner of the array by checking for any leftmost and uppermost all-zero(i.e. empty) rows in the gamepiece array. Since my rotating is done programmatically rather than hard-coded, it will automatically work for any shape game piece.

Share this post


Link to post
Share on other sites
I've been having nightmares all morning about the collision detection code I posted, Its bloody stupid.

All you have to do is:




Collide = False;
for (col=0;col<4;col++) {
for (row=0;row<4;row++) {
if BlockMap[offsetx+row][offsety+col] && GameBlock[row[col] Collide=True;
}
}


This would work for all orientations and game block shapes.
Thats what comes of writing code on a friday night AP (After Pub).

,Jay

Edit: Pub effect again.

[edited by - Jason Zelos on March 23, 2002 6:21:58 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
A little tip:


  
int x[5] = {0, 0, 0, 0, 0};
int y[5] = {0};


Those two lines create equivalent arrays filled with zeroes. Works with structures too and is guarenteed to work in by standard C++.

Share this post


Link to post
Share on other sites
Tetris Project, Code, and EXE.

Uses DirectX7 - DirectDraw, DirectInput.

Its written in VB6, but the main code will convert to C++ easily, I just don''t like the windows mush with C++ for something so small.

Runs in 640*480*16.

http://www.btinternet.com/~jeannie.zelos/tetris.zip

20kb download.

,Jay

Share this post


Link to post
Share on other sites
ahh, i coded one of those about 4 years ago. It was pretty funky because it included a piece editor where you could make and save your own pieces. The functions i used to check the collisions were independant of the shape of the pieces.

What i did was set up my main grid of say 15x40, ( cant remember the official size ;p) each containing a byte with a value. 0 for blank and 1-7 for the different coloured blocks.

Next, i created seven 4x4 arrays into which the piece shaps were loaded. When a piece came into the game (The active piece that falls), i copied the relevant array into a temporary array. To rotate the piece, you need to calcualte how wide and high the piece is, then rotate it by 90 degrees. I'm sure you can figure out how to rotate the values in an array.

When the piece either moved or was rotated. I did a check to see if it had collided with any other piece on the game board. Save the old rotation position, piece position and temp array. Then apply whatever change was required. (rotation or movement). Do a check between the board array and the temporary piece array. (4x4 comparison) If any two values are equal to 1, a collision has occured, otherwise, apply the change. If there was a collision, take the relevant action, eg do not allow the rotation to occur, or lock the piece onto the board array and load a new piece.

Once you get that to work, its very easy to make your own little piece editor and set the game up however you want. I made some particularly nasty piece sets for my game.

Good luck.

-ET


[edited by - Evil_Toaster on March 24, 2002 2:57:44 PM]

Share this post


Link to post
Share on other sites
Back on it with renewed enthusiasm but what I dont get: -

I have the Blockgrid[NUM_BLOCK_ROWS][NUM_BLOCK_COLUMNS] array.

I then replace the game_block array and create a 4*4 grid function using: -


  
for (gridy=0;gridy<4;gridy++) {
block1.y = offsety + gridy
for (gridx=0;gridx<4;gridx++)
{
block1.x = offsetX + gridx;
//draw the block

}
}


The offsety and offsetx vars I set to 0 and put them with the other globals. I put an int in front off the gridy and gridx statements to declare them as ints.

Then in the draw function I simply add the new function for the game peice 4*4 grid and voila


  
void Draw_Block(void)
{
for (int row = 0; row < NUM_BLOCK_ROWS; row++)
{
for (int col = 0; col < NUM_BLOCK_COLUMNS; col++)
{
if (blockgrid[row][col] == 1)
{
block1.y = row * block1.width;
block1.x = col * block1.height;
Draw_BOB(&block1, lpddsback);
}
Init_GamePeice();
}
}
}


I get the impression I''m being stupid again here but all I get is 1 block.

Also I can''t seem to find anything on passing information bewteen seperate arrays?

Pk

Share this post


Link to post
Share on other sites


  
for (gridy=0;gridy<4;gridy++)
{
block1.y = offsety + gridy
for (gridx=0;gridx<4;gridx++)
{
block1.x = offsetX + gridx;
if (GamePiece[gridx][gridy]==1) { //draw block }

}
}


You still need an array to hold the game piece data.

Also where you used initGamePiece in drawblocks, it should be after the loops and I''d just stick the above code in there without calling any functions etc.

You need to understand that the grid is an array[4][4] (which I believe is 0-3,0-3 not 0-4,0-4). The offset is the top,left of the grids position in the main block array.

To copy from one array to the other:

blockarray[OffsetX+x][OffsetY+y] = GamePiece[x][y];

Look at the source I posted a link to, specificly the TObject class and the main form, print them out and understand how the logic works.

,Jay

Share this post


Link to post
Share on other sites
Still having a few probs, I downloaded the VB code and looked at it but to be honest it was just making things worse.

Here''s what I got for the Draw code - but I still get only 1 block: -


  
//Draw the block parts

void Draw_Block(void)
{
for (int row = 0; row < NUM_BLOCK_ROWS; row++)
{
for (int col = 0; col < NUM_BLOCK_COLUMNS; col++)
{
if (blockgrid[row][col] == 1)
{
block1.y = row * block1.width;
block1.x = col * block1.height;
Draw_BOB(&block1, lpddsback);
}

}
}
for (gridy = 0; gridy<4; gridy++)
{
block1.y = offsety + gridy;
for (gridx1 = 0; gridx<4; gridx++)
{
block1.x = offsetx + gridx;
if (GameBlock[gridx][gridy]==1)
{
Draw_BOB(&block1,lpddsback);
}
}
}

}


The for (gridy) statement is out of the top for loops. Am I missing the obvious (again?)

Pk

Share this post


Link to post
Share on other sites
Heres my version DelphiX Tetris

Coupla things to check..

* make sure you''re not accidentally drawing them all in the same position

* make sure that there *is* actually more than one block

* check the loop, make sure its looping through all the grid

its usually the silliest mistakes that you think could never happen do happen.

Share this post


Link to post
Share on other sites