Sign in to follow this  
Ekim_Gram

There just has to be an easier way of doinig this (Matrix related)

Recommended Posts

Ekim_Gram    418
Well, I'm starting a Tetris clone finally and I'm going to try and do it by myself. I'm going to be taking it in very small steps and pieces, making several small programs to eventually merge them into one which will hopefully end up as a Tetris clone. Well, to start my goal, I'm beginning with the pieces. I plan on using matrices to represent the pieces. The only problem is, I feel like I'm going the wrong way with this stuff syntactically. Here's my code to 'rotate' the values in a matrix to the left:
// a 2x2 matrix
typedef struct
{
	float m[2][2];		// the rows and columns
} matrix2x2;

matrix2x2* MatrixRotateLeft2x2(matrix2x2 *matrixA)
{
	// Rotate a matrix's values to the left
	
	matrix2x2 *M_Temp = new matrix2x2;		// A temporary matrix
	// Copy the original matrix to the temporary one
	for (int row = 0; row < 2; row++)
	{
		for (int col = 0; col < 2; col++)
		{
			M_Temp->m[row][col] = matrixA->m[row][col];
		}
	}

	/* Here's the formula for rotating a 2x2 matrix left
	| m00 = m01  m01 = m11 |
	| m10 = m00  m11 = m10 |
	Simple, eh? */

	// Now rotate the values
	matrixA->m[0][0] = M_Temp->m[0][1];
	matrixA->m[0][1] = M_Temp->m[1][1];
  matrixA->m[1][0] = M_Temp->m[0][0];
	matrixA->m[1][1] = M_Temp->m[1][0];

	delete M_Temp;
	return matrixA;
}

And if any of you are interested, he's a sample program I wrote to test it:
int main()
{
	std::cout << "Assigning Matrix A...\n";
	matrix2x2 *M_A = new matrix2x2;
	M_A->m[0][0] = 0;
	M_A->m[0][1] = 2;
	M_A->m[1][0] = 1;
	M_A->m[1][1] = 3;
	std::cout << "Here are Matrix A's current values...\n";
	for (int row = 0; row < 2; row++)
	{
		for (int col = 0; col < 2; col++)
		{
			std::cout << M_A->m[row][col];
		}
		std::cout << std::endl;
	}
	std::cout << "Rotating Matrix A's values 1 to the left...\n";
	M_A = MatrixRotateLeft2x2(M_A);
	std::cout << "Here are the new values for Matrix A...\n";
	for (int row = 0; row < 2; row++)
	{
		for (int col = 0; col < 2; col++)
		{
			std::cout << M_A->m[row][col];
		}
		std::cout << std::endl;
	}
	delete M_A;
	return 0;
}

The biggest part I'm concerned about though are the following lines of code:
matrixA->m[0][0] = M_Temp->m[0][1];
matrixA->m[0][1] = M_Temp->m[1][1];
matrixA->m[1][0] = M_Temp->m[0][0];
matrixA->m[1][1] = M_Temp->m[1][0];
Must I hard code it all like that or is there a more efficient/faster way to do so?

Share this post


Link to post
Share on other sites
SiCrane    11839
You can probably replace your code with this:

matrix2x2 * MatrixRotateLeft2x2(matrix2x2 * matrixA) {
float temp = matrixA->m[0][0];
matrixA->m[0][0] = matrixA->m[0][1];
matrixA->m[0][1] = matrixA->m[1][1];
matrixA->m[1][1] = matrixA->m[1][0];
matrixA->m[1][0] = temp;
return matrixA;
}


What you have is a little overkill-ish.

Share this post


Link to post
Share on other sites
ajas95    767
a more flexible way to store your blocks, instead of matrices, is a list of 2D coords relative to the upper left corner of a block, along with the width, height, and number of positions of the block. Like:

int block_coords[4][] = { {0, 1}, {1, 0}, {1, 1}, {2, 0} };
int width = 3;
int height = 2;
int num_positions = 2;

then, if you ever want to have more interesting blocks, it's trivial. You don't have restrictions.

I've also found it may be better to store all the positions for each block also, and just index into that list rather than computing rotations. The reason is that you don't actually want the block to rotate around a fixed point, and there's no simple equation that works in all cases (especially the T block). If you look at commercial Tetris games, that's what they do because that's what feels right.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Thanks a bunch to both of you. (rating++) While I'm still going to work on my Matrix "engine" I'll try out the idea ajas95 suggested but could you give me a little bit more detail of what your giving me? Maybe it's the fact that I have to leave in a few minutes to practice with my band but I just can't totally figure out what your saying right now.

Share this post


Link to post
Share on other sites
ajas95    767

| |
| |
| |
| Pos |
| + __ __ |
| |C |D | |
| +--+--+--' |
| |A_|B_| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|_______________________|

So, the block is positioned within the well at point Pos, where that little plus sign is. There's no actual brick at that point, but it's still the upper left corner of the block. The bricks are positioned at A=(0,1), B=(1,1), C=(1,0), and D=(2,0) relative to the plus sign. So you can calculate the position of any of these 4 bricks within the well by adding its position within the block to the block's position within the well. Say the block is at 1,4 in the well (which is kindof approximately where it is in the diagram).

Then brick A is at position (0,1) + (1,4) = (1,5). And brick D is at position (2,0) + (1,4) = (3,4). So hopefully you get the idea. So, when you go to rotate the block, suddenly A, B, C, and D all have different positions within the block (but the block doesn't move in the well). An example of the new positions would be A=(0,0) B=(0,1) C=(1,1) and D=(1,2). So you could either try and find some formula that calculates these new values on the fly, or you can just store them. I recommend just storing them:

int well_pos[2];
int num_flips = 0;
int num_positions = 2;

brick_pos[2][4][2] =
{ { {0,1}, {1,1}, {1,0}, {2,0} },
{ {0,0}, {0,1}, {1,1}, {1,2} }
};

because the block can be in 1 of 2 positions. You can use num_flips to index into brick_pos to determine where each brick is in the current position. So to rotate the block you increment num_flips and % it by num_positions. You can move the whole block around by adjusting well_pos.

So, you can use all this to calculate each brick's position within the well:

int brick_Ax = block.well_pos[0] + block.brick_pos[num_flips][0][0];
int brick_Ay = block.well_pos[1] + block.brick_pos[num_flips][0][1];

int brick_Bx = block.well_pos[0] + block.brick_pos[num_flips][1][0];
int brick_By = block.well_pos[1] + block.brick_pos[num_flips][1][1];

etc.

You then use these brick positions to see whether what you're about to do (lower the block, rotate the block) is legal, by whether any bricks already in the well (or the walls) overlap with and of the bricks' new positions.

Alright, that's plenty for now :)

Share this post


Link to post
Share on other sites
Deebo    128
Why not create a matrix class and add functions that will manipulate it any way you see fit.

typedef enum
{
Up,
Down,
Left,
Right
} TDirection;

class CMatrix2x2
{
public:
// standard constructors/destructor and accessors go here

void Translate(const EDirection dir);
void Rotate(const EDirection dir); // Only Left and Right valid here
private:
float m[2][2];
};


Or better yet make it a dynamic so you can make a XxY matrix using the constructor:

CMatrix little(2, 2);
CMatrix* big = new CMatrix(4, 4);


This way you can have different size matrices on the fly (easy, medium, and hard difficulty levels) and easily modify matrices for multiplayer games

int difficulty[3][2]; // set your matrix size per difficulty level here
CMatrix* players[MAX_PLAYERS]

if(new player)
players[number of players] = new CMatrix(difficulty[current][0], difficulty[current][1]);

for(number of players)
{
players[i]->Translate(get input);
players[i]->Rotate(get input);
}

// update screen here


Something like that makes it much, much easier than hard coding everything. If you dont know how to make a matrix class, I'll be happy to help.

Share this post


Link to post
Share on other sites
Ekim_Gram    418
Wow, I'm making really slow progress with this but I'm getting there. I've decided to create a struct that will represent the block. So far this is what I have:


enum COLOR {Red = 1, Blue = 2, Green = 3, Yellow = 4, Orange = 5};

typedef struct
{
COLOR color; // The color of the block
int positions; // How many different positions does this block have?
} SBlock;



As you can see, it's nothing impressive. My main question is, how would I represent the different types of blocks? There are the | blocks, the T blocks in the game, and the one you drew in your diagram. Should I make another struct that will hold each coordinate for each of that different type of block's position that will have an SBLOCK struct in it? Something like


typedef struct
{
SBLOCK block;
int coordinates[][];
int positions[x][y][z]
};


Or something like that. Just typing this post showed me some design clashes already like having the positions int in the SBLOCK struct. Now another question is arising. Should I just make different structs for each and every game piece there is? I want to go about this as efficently as possible but this project is proving much more difficult than I imagined it to be.

Also, would a moderator kindly move this topic to the Game Programming forum seeing as how it's going way off topic and I could probably get more help there than here (not that ajas95 isn't doing a wonderful job or anything.)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this