#### Howdy, Stranger!

We are about to switch to a new forum software. Until then we have removed the registration on this forum.

# A simple collision system for a Tetris Game + A strange idea

edited May 2016

Hello.

I am making a Tetris game in processing and I was wondering how I would go about making a collision system for my game.

I figured that the collision system would also be tied to the display system of the game, considering I have a vague idea of how it would work.

I'm assuming an easy way to do this would be to use the pixel array as a way of checking whether blocks were next to each other or at the bottom. Keep in mind that the screen resolution is going to be with 35 as the size of the block and a height of 550.

I'm also guessing that having a block class that generates each shape when it is passed into will also help.

Is what I'm saying correct? If so, how would I code this? If not, what is a better solution?

Also, I'm planning of having a special gamemode for my tetris game where after a certain amount of time after a new block is generated (probably an arbitrary number, like 5 seconds) another block comes down which you have no control over until the block you control stops moving.

How would I go about doing this as well?

(a reply soon would be greatly appreciated as the project is due at the end of the working week - other aspects of the project are finished or are towards completion!)

Thanks.

Tagged:

I have seen different people go about making logic like this before.

In general the idea is to keep a boolean array (or a double boolean array if you prefer to think that way) which represents whether or not a block is present in a cell. Lets say that false means that no block is occupying a cell and true means that a block is occupying a cell.

As a block falls, you check if any of the cells directly below it are true / occupied, if it is then you know that the block must stop there. Say you have one of those 2x2 blocks falling, you would be checking the two cells directly below it as it falls to see if they are true / occupied.

The reason to do it this way is to avoid testing collisions with numbers (more efficient). As for display, the boolean array gives enough information to represent the blocks visually but now the logic for display is not tied into the logic for collisions.

If this all makes sense, then perhaps an integer array may be useful instead which works very similarly to the boolean array. 0 could represent no block occupying a cell and any other number could represent that a block is occupying a cell but the advantage is that you could associate the numbers with whatever colors you will need for display.

Personally I don't think of this as object oriented, just tests on a boolean / integer array with the one block falling marked as the "active" one. Seeing as how when a line is filled in Tetris and sections of blocks are removed but not necessarily the entire block, this would make object oriented conditions unnecessarily difficult but not so for a boolean / integer array.

• As said, movements in a Tetris game are highly constrained (no partial lateral block shift), so you don't need to do a pixel-level collision check (unlike a platform game, for example), but a simple check in a block-level grid is enough.

In other terms, have data representing the entities (block & area) to do the collision and alignment logic, and manage the display from it.

• In short, the area is the matrix: `final boolean[][] area = new boolean[ROWS][COLS];`.
Each element represents either the presence or absence of a fixed-size tile square.

• edited July 2014 Answer ✓

hello,

just a few remarks. There are also L and T shaped pieces. It is not easy to know which blocks in the falling piece are "down". Because other blocks within the piece are on the lower site, each time when you rotate.

To avoid the hassle to determine which blocks within the current piece ("L") are on the lower site, you could (and that's the idea here) go upwards from the piles and check for a collision within the grid.

Grids

So you got 2 grids: The entire game grid A and one falling piece with a grid B:

x

x

x

x x x

copy B into A temporarily, check for collision (is there a stone of the piece directly above one pile?) if so, copy B into A permanently, otherwise delete B from A, let it fall by one line and start again.

I made a piece editor once, to create new pieces like (+ or . . or . : )

the blocks within one piece don't have to be connected.

Best, Chrisir ;-)

• Thanks for the help.

I've managed to cobble something that starts to resemble a collision system together here, but I'm getting 'Expecting EOF, got whatever' issues.

I'm fixing some of these by putting them into methods, but this won't work for the movement system or the collision system as they actually have to return stuff.

What can I do to fix this?

Also, how do I do the generation of new blocks?

``````//Collision System for Blicks
//SDD Major Work
//By ---------

boolean collide = false;

int x = 22;
int y = 10;

//declaring arrays
final int[][] ScreenDrawBackground = new int;
final int[][] ScreenDrawPlayerBlock = new int [y][x];
//initially setting the screen background and player block to all zeros

void beginDraw() {
for (int i = 0; i < ScreenDrawBackground.length; i++) {
ScreenDrawBackground[i][i] = 0;
} for (int i = 0; i < ScreenPlayerBlock.length; i++) {
ScreenDrawBackground[i][i] = 0;
}
}
//for line clearing
void clear() {    <<<<<<-------Can't be a void as it needs to return score, but still
if (ScreenDrawBackground[y-1][x] != o) {
for (int i = y-1; i < ScreenDrawBackground.length - y; i++) {
ScreenDrawBackground[i] = 0;
}
score = (1000 * y);
}
}

//for moving a block
if (keyPressed && (key = CODED)) {
//Left
if (keyCode = LEFT) {
//check left
if (ScreenDrawBackground[y][x-1] == 0) {
x --;
} else {
collide = true;
}
} else if (keyCode = RIGHT) {
//check right
if (ScreenDrawBackground[y][x+1] == 0) {
x ++;
} else {
collide = true;
}
} else if (keyCode = DOWN) {
//check down
if (ScreenDrawBackground[y+1][x] == 0) {
y ++;
} else {
collide = true;
}
}
}

//If a collision occurs
if (collide = true) {
//code for collision goes here.
//Essentially, the block is added to ScreenDrawBackground, like this:
arrayCopy(ScreenDrawPlayerBlock, ScreenDrawBackground);
//Then, ScreenDrawPlayerBlock is set to 0s.
for (int i = 0; i < ScreenPlayerBlock.length; i++) {
ScreenDrawBackground[i][i] = 0;
} //At this point, a new block is drawn on top of the screen.
// This will be implemented tommorow as I have no idea how to do that.
}
``````
• Just doing a quick look, I've spotted a bug at line #61:
You're assigning the value `true` to variable collide rather than just checking for that! [..]

• tetris was a topic here some weeks ago

this is what I made back then (since you asked how to start a new block)

it has no collision

most of it is by other guys here in the forum

``````// Object object1;
int possX, possY, time;
int unit = 25;
boolean[] occupied = new boolean[10*20];

Piece currPiece = new Piece();
ArrayList<Piece> pieces = new ArrayList();

void figure1() {
fill(204, 102, 0);
rect(possX * unit, possY * unit, unit, 4 * unit);
}
void figure2() {
fill(204, 12, 100);
rect(possX * unit, possY * unit, 2 * unit, 2 * unit);
}
void figure3() {
fill(55, 102, 10);
rect(possX * unit, possY * unit, unit, unit);
}
void setup() {
size(25 * unit, 20 * unit);
fill(0, 25, 0);
//  object1 = new Object();

String []arrString = new String ;

currPiece=new Piece();
arrString = "000000";
arrString = "000100";
arrString = "000100";
arrString = "001100";
arrString = "000000";
currPiece.gridFill (arrString);
currPiece.colPiece = color(0, 0, 255);

currPiece=new Piece();
arrString = "000000";
arrString = "001000";
arrString = "011100";
arrString = "000000";
arrString = "000000";
currPiece.gridFill (arrString);
currPiece.colPiece = color(255, 0, 0);

currPiece=new Piece();
arrString = "000000";
arrString = "000000";
arrString = "011110";
arrString = "000000";
arrString = "000000";
currPiece.gridFill (arrString);
currPiece.colPiece = color(255, 0, 0);

currPiece=new Piece();
arrString = "000000";
arrString = "000100";
arrString = "000100";
arrString = "000110";
arrString = "000000";
currPiece.gridFill (arrString);
currPiece.colPiece = color(0, 244, 255);

currPiece=new Piece();
arrString = "000000";
arrString = "000110";
arrString = "000110";
arrString = "000000";
arrString = "000000";
currPiece.gridFill (arrString);
currPiece.colPiece = color(255, 0, 0);

newPiece ();
}

void draw() {
fill(255, 0, 0);
text ("hit n for new piece; m rotate", width/2+30, 44);
fall();
display();
currPiece.display();
}

void newPiece () {
println ("new");
currPiece = pieces.get(int(random(pieces.size())));
possY=0;
}

void keyPressed() {
if (key == CODED) {
if (keyCode == LEFT && possX > 0 && !occupied[(possX-1)+possY*10]) possX--;
if (keyCode == RIGHT && possX < 9 && !occupied[(possX+1)+possY*10]) possX++;
if (keyCode == DOWN) drop();
}
else {
if (key == 'm') spin(key);
if (key == 'n') newPiece ();
}
}
void fall() {
if (millis() > time + 1000) {
time = millis();
possY++;
if (possY < 19) {
int index = possX + possY * 10;
int bottomIndex = possX + (possY + 1) * 10;
if (occupied[bottomIndex]) {
// occupied[index] = true;
possY = 0;
}
}
else {
//  occupied[possX+190] = true;
time = millis();
//occupiedY = 0;
}
}
}
void display() {
for (int i = 0; i < 200; i++) {
int x = i % 10;
int y = i / 10;
if (occupied[i])
fill(255, 127, 127);
else
fill(255);
rect(x * unit, y * unit, unit, 3 * unit);
}
fill(127, 127, 255);
rect(possX * unit, possY * unit, unit, unit);
}
void drop() {
for (int i = 19; i >= 0; i--) {
int index = possX+i*10;
if (!occupied[index]) {
occupied[index] = true;
possY = 0;
break;
}
}
}
void spin(char qa) {
if (qa == 'm') {
//rotate(0.25);
currPiece.rotate();
}
}
// ============================================
class Piece {

boolean [][]grid = new boolean ;
color colPiece = color(0, 0, 255);

// **************
// no explicit constructor here yet
// **************

void gridFill (String[] arrString) {
for (int i = 0 ; i < arrString.length; i++) {
for (int j = 0 ; j < arrString.length(); j++) {
char currLetter = arrString [i].charAt(j);
if (currLetter == '1') {
grid [i][j] = true;
}
else {
grid [i][j] = false;
}
}
}
}  // method

void display() {
for (int i = 0 ; i < grid.length; i++) {
for (int j = 0 ; j < grid.length; j++) {
//        int x = i % 10;
//        int y = i / 10;
if (  grid [i][j] )
{
fill(colPiece);
rect(i * unit+possX*unit, j * unit+possY*unit, unit, unit);
}
else
{
// fill(255);
}
}
}
} // method

void rotate() {
boolean [][]temp = new boolean ;
println ("rotate");
// copy
for (int i = 0 ; i < grid.length; i++) {
for (int j = 0 ; j < grid.length; j++) {
temp [i][j]=grid [i][j];
}
}
for (int i = 0 ; i < grid.length; i++) {
for (int j = 0 ; j < grid.length; j++) {
grid [5-j][i]=temp [i][j];
}
}
}
//
}//class

//
``````
• line 61: what gotoloop is saying:

to check for equalness use == so it's

`if (collide == true) {`

or just

`if (collide) {`

The sign = is merely for assinging a value, not for comparison

Best, Chrisir ;-)

• edited July 2014

Thanks.

What do you think is causing the 'Expecting EOF, found 'thing'' error?

• Many times a missing semicolon or closing curly brace can cause that.
I advise you to hit CTRL+T inside Processing's IDE. It aligns and indents the code.
So it's easier to spot if there's anything amiss somewhere!

• Alright, I'm getting closer now.

``````//Collision System for Blicks
//SDD Major Work
//By ---------

int x = 22;
int y = 10;
int rot = 1; //for rotation
public boolean nocollide = true;

//declaring arrays
final int[][] ScreenDrawBackground = new int;
final int[][] ScreenDrawPlayerBlock = new int;
//initially setting the screen background and player block to all zeros

void beginDraw() {
for (int i = 0; i < ScreenDrawBackground.length; i++) {
ScreenDrawBackground[i][i] = 0;
}
for (int i = 0; i < ScreenDrawPlayerBlock.length; i++) {
ScreenDrawBackground[i][i] = 0;
}
}
//for line clearing
void clear() {
if (ScreenDrawBackground[y-1][x] != 0) {
for (int i = y-1; i < ScreenDrawBackground.length - y; i++) {
ScreenDrawBackground[i][i] = 0;
}
score = (1000 * y);
}
}

void createBlock() {
//creating blocks
int choice = int(random(1, 5));
if (choice == 1) {
ScreenDrawPlayerBlock = 0;
ScreenDrawPlayerBlock = 3;
ScreenDrawPlayerBlock = 0;
ScreenDrawPlayerBlock = 4;
ScreenDrawPlayerBlock = 0;
ScreenDrawPlayerBlock = 5;
ScreenDrawPlayerBlock = 0;
ScreenDrawPlayerBlock = 6;
} else if (choice == 2) {
ScreenDrawPlayerBlock = 0;
ScreenDrawPlayerBlock = 4;
ScreenDrawPlayerBlock = 0;
ScreenDrawPlayerBlock = 5;
ScreenDrawPlayerBlock = 1;
ScreenDrawPlayerBlock = 4;
ScreenDrawPlayerBlock = 1;
ScreenDrawPlayerBlock = 5;
} else if (choice == 3) {
ScreenDrawPlayerBlock = 0;
ScreenDrawPlayerBlock = 3;
ScreenDrawPlayerBlock = 0;
ScreenDrawPlayerBlock = 4;
ScreenDrawPlayerBlock = 1;
ScreenDrawPlayerBlock = 4;
ScreenDrawPlayerBlock = 1;
ScreenDrawPlayerBlock = 5;
} else if (choice == 4) {
ScreenDrawPlayerBlock = 0;
ScreenDrawPlayerBlock = 3;
ScreenDrawPlayerBlock = 0;
ScreenDrawPlayerBlock = 4;
ScreenDrawPlayerBlock = 0;
ScreenDrawPlayerBlock = 5;
ScreenDrawPlayerBlock = 1;
ScreenDrawPlayerBlock = 4;
} else if (choice == 5) {
ScreenDrawPlayerBlock = 0;
ScreenDrawPlayerBlock = 4;
ScreenDrawPlayerBlock = 1;
ScreenDrawPlayerBlock = 4;
ScreenDrawPlayerBlock = 2;
ScreenDrawPlayerBlock = 4;
ScreenDrawPlayerBlock = 2;
ScreenDrawPlayerBlock = 5;
} else {
}
}

//for moving a block
void moveBlocks() {
if (keyPressed && (key == CODED)) {
//Left
if (keyCode == LEFT) {
//check left
for (int i = 0; i < 4; i++) {
int bx = ScreenDrawPlayerBlock[i];
int by = ScreenDrawPlayerBlock[i];
if (ScreenDrawBackground[by][bx-1] != 0) {
nocollide = false;
}
}
if (nocollide) {
for (int i = 0; i < 4; i++) {
ScreenDrawPlayerBlock[i]--;
}
}
} else if (keyCode == RIGHT) {
//check right
for (int i = 0; i < 4; i++) {
int bx = ScreenDrawPlayerBlock[i];
int by = ScreenDrawPlayerBlock[i];
if (ScreenDrawBackground[by][bx+1] != 0) {
nocollide = false;
}
}
if (nocollide) {
for (int i = 0; i < 4; i++) {
ScreenDrawPlayerBlock[i]++;
}
}
} else if (keyCode == DOWN) {
//check down
if (ScreenDrawBackground[y+1][x] == 0) {
y ++;
} else {
nocollide = false;
}
} else if (keyCode == UP) {
//rotate
if (ScreenDrawBackground[y][x-1] == 0 && ScreenDrawBackground[y][x+1] == 0 && ScreenDrawBackground[y+1][x] == 0) {
rot ++;
}
}
delay(1000);
ScreenDrawPlayerBlock[i]++;
} //If a collision occurs
if (nocollide == false) {
//code for collision goes here.
//Essentially, the block is added to ScreenDrawBackground, like this:
arrayCopy(ScreenDrawPlayerBlock, ScreenDrawBackground);
//Then, ScreenDrawPlayerBlock is set to 0s.
for (int i = 0; i < ScreenDrawPlayerBlock.length; i++) {
ScreenDrawBackground[i][i] = 0;
} //At this point, a new block is drawn on top of the screen.
// Put New Block thing here
}
}
//for rotation
``````

I guess I need at this point to figure out downwards collisions/preventing an out-of-bounds error, but also how to transfer the 'nocollide' to things outside the method, as well as figuring out how to only prevent movement rather than stopping the block. Does anyone have any suggestions for this?

• edited July 2014

Alright, I've gotten some real life help to create what is pretty much an almost-completed Game & Collision system.

It's coded in Java, so it wasn't much work to convert it to processing.

However, If I wanted to put this into the game itself, what would I do? As in, how would I fit this into the void setup/game as well as displaying the 2-d array? Each block is supposed to be 35 pixels wide.

``````public boolean endGame = false;

public static void main(argc, argv[]) {    <<<<------- Left in for accuracy stuff.
//setup
int score = 0;
int board [][] = new int ;
boolean filled = false;
int randNum;

for (int i = 0; i < board.height(); i++) { //Sets the left side of the board to a value of 2, and the right side to a value of 3
board[i] = 2;
board[i][board.length()-1] = 3;
}

for (int i = 0; i < board.length(); i++) { //Sets the bottom of the board to a value of 4
board[board.height()-1][i] = 4;
}

while (filled == false) {
//Checking if the top of the board is being touched
for (int i = 1; i < board.length()-1; i++) {
if (board[i] != 0){
filled = true;
break;
}
}

randNum = Math.random()*10;

int[][] currBlock = createBlock(randNum);

playGame(board, currBlock);

}

}

int[][] createBlock(int randNum, int[][] board) {
//Create the block;

/*
* No matter what type of block is created, we want to spawn the block at the the top of the board
* So, we simply set the area where the block is being spawned on the board to 1s
* If there already exists a 1 where the block is being spawned, we know then that the created block will
cause the pieces to touch the top
* Therefore
*/

//Say we want to spawn a square on the board

if (randNum == 1) {  //This will create a 'block shape' at the top of the board which will be manipulated in playGame()
if (board == 1 ||  //This will check if a block already exists where the new block is being spawned
board == 1 ||  //If a block already exists then end game
board == 1 ||
board == 1) {
endGame = true;
}
board = 1; //line
board = 1;
board = 1;
board = 1;
}

if (randNum == 2) {
if (board == 1 ||
board == 1 ||
board == 1 ||
board == 1) {
endGame = true;
}
board = 1; //square
board = 1;
board = 1;
board = 1;
}

if (randNum == 3) {
if (board == 1 ||
board == 1 ||
board == 1 ||
board == 1) {
endGame = true;
}
board = 1; //Z
board = 1;
board = 1;
board = 1;
}

if (randNum == 4) {
if (board == 1 ||
board == 1 ||
board == 1 ||
board == 1) {
endGame = true;
}
board = 1;//T
board = 1;
board = 1;
board = 1;
}

if (randNum == 5) {
if (board == 1 ||
board == 1 ||
board == 1 ||
board == 1) {
endGame = true;
}
board = 1;//L
board = 1;
board = 1;
board = 1;
}
else{}

return board;
}

public void playGame(board, block) {
boolean canLeft = true;
boolean canRight = true;
boolean bottom = false;

while (bottom == false) {

//Collision detection
for (int i = 0; i < 24-1; i++) {
if (board[i] == 1) {
canLeft = false;
}

if (board[i][board.length()-2] == 1) {
canRight = false;
}
}

for (int i = 1; i < board.length()-2; i++) {
if (board[24-2][i] == 1) {
bottom = true;
}
}

//Player controls

if (keyPressed && (key == CODED)) {
//Left
if (keyCode == LEFT) {
if (canLeft = true) {
for (int i = 0; i < 10; i++) {
if (i = 1) {
board[i]--;
}
}
}
} else if (keyCode == RIGHT) {
if (canRight = true) {
for (int i = 0; i < 10; i++) {
if (i = 1) {
board[i]++;
}
}
}
} else {}

dropBlockByOne(board);
playerControl(board);

//If block is at the bottom, set it in stone

if (bottom == true) {
for (int i = 0; i < board.length(); i++) {
for (int j = 0; j < board.height(); j++) {
board[i][j] = 5;
}
}

checkIfLineExists(board);

return;
}
}
}

int[][] board(int[][] board) {
for (int i = 0; i < board.length(); i++) {
for (int j = 0; j < board.height(); j++) {
if (board[i][j] == 1) {
board[i+1][j] = 1;
board[i][j] = 0;
}
}
}

return board;
}

int[][] checkIfLineExists(int[][] board) {
//If the current line is entirely 1, then change to 0, copying every line above down 1, and set counter to 0
//If counter is equal to the height of the board, then scan has finished, return the board as it stands

int counter = 0;
int y = 0;

while (counter != board.height()) {
int countLengthOfBoard = 0;

for (int x = 1; x < board.length()-2; x++) {
if (board[y][x] == 5) {
countLengthOfBoard++;
}
}

if (countLengthOfBoard == board.length()-1) {
for (int x = 1; x < board.length()-2; x++) {
board[y][x] = 0;
}
counter = 0;
x = 0;
y = 0;
}
else {
x = 0;
y++;
counter++;
}
}
}
``````
• edited July 2014

I also plan on using this interface for the game, so here is that. Ignore terrible colours. • If you either store 0 or 1 into your 2D matrix array, declaring it as `boolean` instead would make it easier! ;)

P.S.: `public static void main(argc, argv[]) {` seems a mix of C & Java code! :P

• In your processing code it says in the 1st line collision of Blicks

Do you mean bricks?

Also it says SDD major works

• edited July 2014

I'd rather store it as an Integer.

Blicks is the name of the game.

SDD is Software Design Development, a school subject. This is a project for this. Yes, the help I have been getting from here is allowed since I haven't been able to ask anyone else for help in real life until now.

So...I'm pretty sure I could do a For loop in which I find the numbers of the array and set various fills and rect()s, while I also set the background to the above image and having the score displayed as text. Is this the right method?

• I'd rather store it as an Integer.

At least lemme demonstrate why `boolean[][]` would be easier: O:-)

`if (board[i][j] == 1)` would be just `if (board[i][j])`.
`if (board[i][j] == 0)` would be just `if (!board[i][j])`.

And invert the states would be `board[i][j] ^= true;`.
Compare that to this 1 you'd have to use: `board[i][j] = board[i][j] == 0? 1 : 0;`.

Now you can make a conscious choice between `boolean[][]` & `int[][]`! (*)

• Oh right. I understand now. Unfortunately, I just realised that the boolean thing won't work because initially the sides and the bottom are set to different numbers (2 and 3 for the sides, 4 for the bottom, 5 for the settled blocks) so that it can prevent out-of-bounds errors (It can't accidentally delete the sides or bottom or top.)

Regardless, do you think there is any way of doing collision with this system?

• In a Tetris type game, collision is based on whether a tile is on or off! It's just 2 states!
Outta-bounds is about any coordinates < 0 or >= length. No need for other states!

Before each bottom tile of the piece descends 1 line, we gotta check whether the position right below it is turned off.
Otherwise we gotta ourselves a collision. And the piece is finished and stays in place!