An ANNOYING Bug in my Tetris 3D game?

Started by
1 comment, last by DevFred 14 years, 1 month ago
EDIT: Could it possibly be due to PI not being accurate enough? I sincerely doubt it... Anyway i define PI like this: #define PI 3.14159265358979323846 Whenever i try to rotate the blocks, this bug occurs where sometimes bricks disappear or the block becomes rearranged in a different way. I'm desperate. I've been trying to find out what's wrong for 2 days!! (The game is not complete yet, but i'll post the related code) Here's the ENTIRE Logic File. (Last Function is the one that deals with rotation, it's called by the first function.
#include "stdafx.h"
#include <ctime>
#include "Global.h"

extern INPUTDATA Input;
int SpaceArray[7][15][7];
const int NumBricks = 4;
int Shape;
int FallTime = FALLSPEED;
int MoveTime = 150;
int RotateTime = 150;
bool NewBlock(true);

void InitializeGame()
{
	for (int x=0; x<7; x++)
	{
		for (int y=0; y<15; y++)
		{
			for (int z=0; z<7; z++)
				SpaceArray[x][y][z] = EMPTY;
		}
	}
}

void Logic(OBJECT* pBlock)
{
	static int Time, StartTime = GetTickCount();			// Figure out how much time has passed since last frame
	Time = GetTickCount() - StartTime;
	StartTime = GetTickCount();

	for (int ms = 0; ms < Time; ms++)						// For every millisecond
	{
		--FallTime;											// Reduce time needed to MOVE the block DOWN BY 1 UNIT
		--MoveTime;											// Reduce time needed to MOVE the block by the PLAYER
		--RotateTime;										// Reduce time needed to ROTATE the block by the PLAYER

		if (FallTime < 0)
		{
			MoveBlockDown(pBlock);							// Move the Block down by 1 unit
			FallTime = FALLSPEED;							// Reset FallTime
		}
	}

	if (MoveTime < 0)										// If Block can be moved ( 150 millisecond movement cooldown)
	{
		if (ApplyMovement(pBlock))							// If a move OCCURED and was SUCCESSFUL
			MoveTime = 150;									// Reset Cooldown to 150 milliseconds
	}

	if (RotateTime < 0 && (Input.Keyboard.RotateX == true || Input.Keyboard.RotateY == true || Input.Keyboard.RotateZ == true))										// If Block can be rotated ( 150 millisecond movement cooldown)
	{
		if (ApplyRotation(pBlock))							// If a rotation OCCURED and was SUCCESSFUL
			RotateTime = 150;									// Reset Cooldown to 150 milliseconds
	}
}

OBJECT* CreateNewObject()
{
	time_t t;
	time(&t);
	srand(t);

	OBJECT* pBlock = new OBJECT[NumBricks];			// Allocate Memory To Hold 4 Bricks per Block

	Shape = rand()% 70;				// Generate A Random Shape
	if (Shape < 10) Shape = OSHAPE;
	if (Shape >= 10 && Shape < 20) Shape = ISHAPE;
	if (Shape >= 20 && Shape < 30) Shape = TSHAPE;
	if (Shape >= 30 && Shape < 40) Shape = SSHAPE;
	if (Shape >= 40 && Shape < 50) Shape = ZSHAPE;
	if (Shape >= 50 && Shape < 60) Shape = LSHAPE;
	if (Shape >= 60 && Shape < 70) Shape = JSHAPE;
	
	switch(Shape)									// Building The Shapes
	{
	case OSHAPE:									// OSHAPE
		{
			pBlock[0].x = rand() % 6;				// Create The Brick which acts as a Pivot For Rotation (Always Brick 0)
			pBlock[0].z = rand() % 6;
			pBlock[0].y = 2;						// Place At the top (2): 0 and 1 are reserved to store unrendered bricks

			pBlock[1].x = pBlock[0].x + 1;
			pBlock[2].x = pBlock[1].x;
			pBlock[3].x = pBlock[0].x;

			pBlock[1].z = pBlock[0].z;
			pBlock[2].z = pBlock[3].z = pBlock[0].z + 1;

			pBlock[1].y = pBlock[2].y = pBlock[3].y = pBlock[0].y;
		} break;

	case ISHAPE:
		{
			pBlock[0].x = rand() % 7;
			pBlock[0].z = rand() % 4 + 1;
			pBlock[0].y = 2;

			pBlock[1].x = pBlock[2].x = pBlock[3].x = pBlock[0].x;
			pBlock[1].z = pBlock[0].z - 1;
			pBlock[2].z = pBlock[0].z + 1;
			pBlock[3].z = pBlock[2].z + 1;

			pBlock[1].y = pBlock[2].y = pBlock[3].y = pBlock[0].y;
		} break;

	case TSHAPE:
		{
			pBlock[0].x = rand() % 5 + 1;
			pBlock[0].z = rand()% 7;
			pBlock[0].y = 2;

			pBlock[1].x = pBlock[0].x - 1;
			pBlock[2].x = pBlock[0].x + 1;
			pBlock[3].x = pBlock[0].x;

			pBlock[1].z = pBlock[2].z = pBlock[3].z = pBlock[0].z;
			
			pBlock[1].y = pBlock[2].y = pBlock[0].y;
			pBlock[3].y = pBlock[0].y - 1;
		} break;

	case SSHAPE:
		{
			pBlock[0].x = rand() % 5 + 1;
			pBlock[0].z = rand() % 7;
			pBlock[0].y = 2;

			pBlock[1].x = pBlock[0].x - 1;
			pBlock[2].x = pBlock[0].x;
			pBlock[3].x = pBlock[2].x + 1;

			pBlock[1].z = pBlock[2].z = pBlock[3].z = pBlock[0].z;

			pBlock[1].y = pBlock[0].y;
			pBlock[2].y = pBlock[3].y = pBlock[0].y - 1;
		} break;

	case ZSHAPE:
		{
			pBlock[0].x = rand() % 5 + 1;
			pBlock[0].z = rand() % 7;
			pBlock[0].y = 2;

			pBlock[1].x = pBlock[0].x + 1;
			pBlock[2].x = pBlock[0].x;
			pBlock[3].x = pBlock[2].x - 1;

			pBlock[1].z = pBlock[2].z = pBlock[3].z = pBlock[0].z;

			pBlock[1].y = pBlock[0].y;
			pBlock[2].y = pBlock[3].y = pBlock[0].y - 1;
		} break;

	case LSHAPE:
		{
			pBlock[0].x = rand() % 7;
			pBlock[0].z = rand() % 6;
			pBlock[0].y = 1;

			pBlock[1].x = pBlock[2].x = pBlock[3].x = pBlock[0].x;

			pBlock[3].z = pBlock[0].z + 1;
			pBlock[1].z = pBlock[2].z = pBlock[0].z;

			pBlock[3].y = pBlock[2].y = pBlock[0].y + 1;
			pBlock[1].y = pBlock[0].y - 1;
		} break;

	case JSHAPE:
		{
			pBlock[0].x = rand() % 7;
			pBlock[0].z = rand() % 6 + 1;
			pBlock[0].y = 1;

			pBlock[1].x = pBlock[2].x = pBlock[3].x = pBlock[0].x;

			pBlock[3].z = pBlock[0].z - 1;
			pBlock[1].z = pBlock[2].z = pBlock[0].z;

			pBlock[3].y = pBlock[2].y = pBlock[0].y + 1;
			pBlock[1].y = pBlock[0].y - 1;
		} break;
	}
	
	UpdateSpaceArray(pBlock, SAMEBLOCK);

	return pBlock;
}

void UpdateSpaceArray(OBJECT* pBlock, int Type)
{	
	for (int Num=0; Num<NumBricks; Num++)
		SpaceArray[pBlock[Num].x][pBlock[Num].y][pBlock[Num].z] = Type;	
}

int MoveBlockDown(OBJECT* pBlock)
{
	if (CheckForCollision(pBlock) && WithinWalls(pBlock, 0, 1, 0))
	{
		UpdateSpaceArray(pBlock, EMPTY);

		for (int Num=0;Num<NumBricks;Num++)
			++pBlock[Num].y;
	
		UpdateSpaceArray(pBlock, SAMEBLOCK);
	}

	else
	{
		for (int Num=0;Num<NumBricks;Num++)
			SpaceArray[pBlock[Num].x][pBlock[Num].y][pBlock[Num].z] = FULL;
		NewBlock = true;
	}

	return 0;
}

bool CheckForCollision(OBJECT* pBlock)
{
	for (int Num=0;Num<NumBricks;Num++)
	{
		if (SpaceArray[pBlock[Num].x][pBlock[Num].y + 1][pBlock[Num].z] == FULL)
			return false;
	}
	return true;
}

bool WithinWalls(OBJECT* pBlock, int x, int y, int z)
{	
	for (int Num=0;Num<NumBricks;Num++)
	{
		if ((pBlock[Num].x + x > 6) || (pBlock[Num].x + x < 0) ||
			(pBlock[Num].y + y > 14) ||
			(pBlock[Num].z + z > 6) || (pBlock[Num].z + z < 0))
			return false;
	}
	return true;
}

bool ApplyMovement(OBJECT* pBlock)
{
	if (Input.Keyboard.MoveForward == true)						// If the Block is being moved FORWARDS
	{
		for (int Num=0;Num<NumBricks;Num++)						// For every brick
		{
			if (SpaceArray[pBlock[Num].x][pBlock[Num].y][pBlock[Num].z - 1] == FULL)	// If the moved block intersects
				return false;															// another block, return false
		}
		if (!WithinWalls(pBlock, 0, 0, -1))						// If the Moved Block is NOT inside the walls, return false
			return false;

		UpdateSpaceArray(pBlock, EMPTY);						// Move is Valid. Empty Original Block position
		for (int Num=0; Num<NumBricks; Num++)					// For every brick in the block
				pBlock[Num].z -= 1;								// Move the brick
		UpdateSpaceArray(pBlock, SAMEBLOCK);					// Fill New Block position
		return true;											// Move successful
	}

	if (Input.Keyboard.MoveBackward == true)						// If the Block is being moved BACKWARDS
	{
		for (int Num=0;Num<NumBricks;Num++)						// For every brick
		{
			if (SpaceArray[pBlock[Num].x][pBlock[Num].y][pBlock[Num].z + 1] == FULL)	// If the moved block intersects
				return false;															// another block, return false
		}
		if (!WithinWalls(pBlock, 0, 0, 1))						// If the Moved Block is NOT inside the walls, return false
			return false;

		UpdateSpaceArray(pBlock, EMPTY);						// Move is Valid. Empty Original Block position
		for (int Num=0; Num<NumBricks; Num++)					// For every brick in the block
				pBlock[Num].z += 1;								// Move the brick
		UpdateSpaceArray(pBlock, SAMEBLOCK);					// Fill New Block position
		return true;											// Move successful
	}

	if (Input.Keyboard.MoveRight == true)						// If the Block is being moved TO THE RIGHT
	{
		for (int Num=0;Num<NumBricks;Num++)						// For every brick
		{
			if (SpaceArray[pBlock[Num].x + 1][pBlock[Num].y][pBlock[Num].z] == FULL)	// If the moved block intersects
				return false;															// another block, return false
		}
		if (!WithinWalls(pBlock, 1, 0, 0))						// If the Moved Block is NOT inside the walls, return false
			return false;

		UpdateSpaceArray(pBlock, EMPTY);						// Move is Valid. Empty Original Block position
		for (int Num=0; Num<NumBricks; Num++)					// For every brick in the block
				pBlock[Num].x += 1;								// Move the brick
		UpdateSpaceArray(pBlock, SAMEBLOCK);					// Fill New Block position
		return true;											// Move successful
	}

	if (Input.Keyboard.MoveLeft == true)						// If the Block is being moved TO THE LEFT
	{
		for (int Num=0;Num<NumBricks;Num++)						// For every brick
		{
			if (SpaceArray[pBlock[Num].x - 1][pBlock[Num].y][pBlock[Num].z] == FULL)	// If the moved block intersects
				return false;															// another block, return false
		}
		if (!WithinWalls(pBlock, -1, 0, 0))						// If the Moved Block is NOT inside the walls, return false
			return false;

		UpdateSpaceArray(pBlock, EMPTY);						// Move is Valid. Empty Original Block position
		for (int Num=0; Num<NumBricks; Num++)					// For every brick in the block
				pBlock[Num].x -= 1;								// Move the brick
		UpdateSpaceArray(pBlock, SAMEBLOCK);					// Fill New Block position
		return true;											// Move successful
	}
}

bool ApplyRotation(OBJECT* pBlock)
{
	OBJECT* pTempBlock = new OBJECT[4];

	int rMatrix[3] = {0,0,0};
	int FinalMatrix[3] = {0,0,0};

	int RotateArX[3][3] = { 1, 0, 0,
							0, cos(Input.Keyboard.Angle), -sin(Input.Keyboard.Angle),
							0, sin(Input.Keyboard.Angle), cos(Input.Keyboard.Angle), };
	
	int RotateArY[3][3] = { cos(Input.Keyboard.Angle), 0, sin(Input.Keyboard.Angle),
							0,1,0,
							-sin(Input.Keyboard.Angle),0, cos(Input.Keyboard.Angle), };
	
	float RotateArZ[3][3] = { cos(Input.Keyboard.Angle), -sin(Input.Keyboard.Angle), 0,
							sin(Input.Keyboard.Angle), cos(Input.Keyboard.Angle), 0,
							0,0,1,};

	for (int Num=0;Num<NumBricks;Num++)					// For every Brick in the Block
	{
		rMatrix[0] = pBlock[Num].x - pBlock[0].x;		// Fill rMatrix with x,y,z values relative to the pivot Block (0)
		rMatrix[1] = pBlock[Num].y - pBlock[0].y;
		rMatrix[2] = pBlock[Num].z - pBlock[0].z;

		if (Input.Keyboard.RotateX)							// If the Player rotated the Block around X
		{
			for (int j=0;j<3;j++)
				FinalMatrix[j] = rMatrix[0] * RotateArX[j][0] + rMatrix[1] * RotateArX[j][1]
								+ rMatrix[2] * RotateArX[j][2];
		}

		if (Input.Keyboard.RotateY)							// If the Player rotated the Block around Y
		{
			for (int j=0;j<3;j++)
				FinalMatrix[j] = rMatrix[0] * RotateArY[j][0] + rMatrix[1] * RotateArY[j][1]
								+ rMatrix[2] * RotateArY[j][2];
		}

		if (Input.Keyboard.RotateZ)							// If the Player rotated the Block around Z
		{
			for (int j=0;j<3;j++)
				FinalMatrix[j] = rMatrix[0] * RotateArZ[j][0] + rMatrix[1] * RotateArZ[j][1]
								+ rMatrix[2] * RotateArZ[j][2];
		}

		pTempBlock[Num].x = pBlock[0].x + FinalMatrix[0];		// Fill pTempBlock with the new rotated block location
		pTempBlock[Num].y = pBlock[0].y + FinalMatrix[1];
		pTempBlock[Num].z = pBlock[0].z + FinalMatrix[2];
	}

	if (!WithinWalls(pTempBlock,0,0,0))						// If the rotated Block is not inside the Grid Box walls,
	{														// deallocate the temporary Block and return false
		delete [] pTempBlock;
		return false;
	}

	if (!CheckForCollision(pTempBlock))						// If the rotated Block collides with other Bricks,
	{														// deallocate the temporary Block and return false
		delete [] pTempBlock;
		return false;
	}

	UpdateSpaceArray(pBlock, EMPTY);						// If everything clears, Clear the old Block positions
	for (int i=0;i<NumBricks;i++)							// For every Brick
	{
		pBlock.x = pTempBlock.x;						// Update Positions
		pBlock.y = pTempBlock.y;
		pBlock.z = pTempBlock.z;
	}
	UpdateSpaceArray(pBlock, SAMEBLOCK);					// Update the SpaceArray with the new Block positions

	delete [] pTempBlock;									// Deallocate memory
	return true;											// Rotation Successful, return true;
}




[Edited by - Waaayoff on February 25, 2010 1:37:52 PM]
"Spending your life waiting for the messiah to come save the world is like waiting around for the straight piece to come in Tetris...even if it comes, by that time you've accumulated a mountain of shit so high that you're fucked no matter what you do. "
Advertisement
SOLVED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

The Z rotation matrix was a float! not an int! so i was getting results like 0.00000004 instead of 0 due to the percision of PI like i predicted!!




W0000000000000000000000000000000000000000000000000T I'M SO HAPPY!!
"Spending your life waiting for the messiah to come save the world is like waiting around for the straight piece to come in Tetris...even if it comes, by that time you've accumulated a mountain of shit so high that you're fucked no matter what you do. "
Quote:Original post by Waaayoff
#define PI 3.14159265358979323846

That's a little overkill, double only has 16 decimal digits of precision.

This topic is closed to new replies.

Advertisement