Gravity: 3d Tetris

Hi all,

I would like to take a stack of cubes and destroy the bottom one without the remaining stack bouncing and changing their X or Z coordinates as they fall into place. I am looking for a dropping effect that simply allows the stacked game objects to fall, but without any unsettling randomness, bouncing or chaos. The desired effect would be like a 3d tetris where the above blocks fall straight down and fill in the missing gap. Is there a way I can accomplish this?

Thanks,

Greg

If you don’t use physics for the blocks, you can have them behave any way you like. Either that, or you could maybe do something like

function OnCollisionEnter() {
     rigidbody.Sleep();
}

which would cause an object to completely stop the instant it hits something, though I don’t know how well that would work in practice. If the case of a 3D Tetris I’d probably just handle all the motion myself, since you wouldn’t need anything fancy.

–Eric

Thanks, Eric. I tried that and it sort of works, but I find that the cubes still don’t quite behave properly- kind of bouncing around each other, while some do freeze in the desired position. How would you recommend doing this without physics / gravity?

Once a piece has hit the stack, it doesn’t need a rigidbody any more, so you can delete that component.

What if I wanted to keep deleting cubes on the bottom as they fall into place? Wouldn’t the remaining ones in the stack need to be a rigidbody for gravity?

I’d say, have an array that stores the location of each block, and then translate that to the screen. Here’s a really simplistic example…make a new project, and make an empty game object, then put this script on the empty (call it “Manager”):

static var field : int[];
static var canSpawn : boolean;
var cube : GameObject;

function Start() {
	canSpawn = true;
	field = new int[10];
	field[0] = 1;
	InvokeRepeating("SpawnCube", .1, 2);
}

function SpawnCube() {
	if (canSpawn) {
		Instantiate(cube, Vector3(0, 10, 0), Quaternion.identity);
	}
}

Make a cube, put this script on the cube (doesn’t matter what you call it):

var fallSpeed : float = 2;
private var yLocation = 9;

function Start() {
	if (Manager.field[yLocation] == 1) {GameOver();}
	Manager.field[yLocation] = 1;
	while (Manager.canSpawn) {
		// Go down a "square" if there's nothing immediately below in the array
		if (Manager.field[yLocation-1] == 0) {yield Fall();}
		else {yield;}
	}
}

function Fall() {
	// Make cube "fall down" 1 location in array
	Manager.field[yLocation--] = 0;
	Manager.field[yLocation] = 1;
	// Make cube fall down 1 "square" on-screen
	for (var i : float = yLocation + 1; i > yLocation; i -= Time.deltaTime*fallSpeed) {
		transform.position.y = i+1;
		yield;
	}
	transform.position.y = yLocation+1;	// Just to make it exactly perfect
}

function OnMouseDown() {
	Manager.field[yLocation] = 0;
	Destroy(gameObject);
}

function GameOver() {
	print ("Game Over!");
	Manager.canSpawn = false;
}

Make a prefab, and drag that cube onto the prefab, then get rid of the cube. Click on the empty game object with the manager script, and drag the prefab onto the “Cube” slot. Put the camera at about 6 on the y axis, add a directional light if you want, then run the game. Cubes will spawn at the top of the screen every couple of seconds and fall down. If you click on a cube, it disappears, and any cubes that might have been on top will fall down. If the stack of cubes fills to the top of the screen, oh no! Game over! :wink:

For “real” Tetris, you’d use a 2-dimensional array, but the basic principle would be the same. You’d just have to check several locations “below” in the array, depending on the shape and orientation of the piece. You could of course then expand that to full 3D Tetris, with a 3-dimensional array.

–Eric

Thanks a lot Eric! I will give this a try and see if I can get it to work. I appreciate your help very much!

Have a nice Memorial Day,

Greg

Thank you, I did. This afternoon is rather overcast, though, so I stayed in and, for some reason, ended up making a Tetris engine, when I should have been doing other things. :wink: I don’t really have any intention of making a finished game with it, but maybe somebody can use it for something (if only inspiration). It’s just the bare-bones essentials…move left/right, rotate, make piece fall rapidly, remove filled-in rows. It uses an array for collision detection, so there are no colliders or physics of any kind. If you want to make more/different pieces, you edit the matrix of 1s and 0s on the block prefabs.

(Edit: updated and requires Unity 4.3 now.)

–Eric

38267–76343–$TetrisClone.zip (607 KB)

Eric, this is awesome! Thanks for sharing that with me / us. I have enjoyed learning how this works through reverse engineering, I’m beginning to understand the logic behind some of the scripting that you are using. I appreciate you taking the time to do this and teaching through example.

Thanks,

Greg

Uh, awesome-- I was about to try to make one of these, but then you went and did it.

I’m not (wasn’t) a coder, and this is a good starter for arrays.

If there’s any confusion about the arrays, you might look at this topic if you haven’t already. Essentially, treating a 1D array like a 2D array. As I mentioned in that topic, there are ways of doing “real” 2D arrays, but aside from being slower (though it hardly matters for something like this), it’s often useful or convenient to be able to loop through the entire array using just one index.

(Edit: the update uses 2D arrays. In this case it’s just simpler to understand for most of the functions.)

–Eric

Sweet Eric, thanks! I’m off to check it out now myself… :smile:

i have no need for this but just want to chime in - that’s really cool Eric.

i wish i had your ability to whip stuff up like that ; )

:lol: :lol: :lol: :lol: :lol: :lol: :lol: :lol: :lol: :lol: :roll: :roll: :roll: :roll: :roll: :roll: :roll: :roll: :roll: :roll: :roll:

Dude! dude! Thanks for the help, you may have saved my career.

Hello Eric, first of all thank you very much for the supplied example, it works quite well, but i do get an error message when the first shape has 2 or more cubes and hits the ground.
This is the error i get : IndexOutOfRangeException: Array index is out of range.
Block.CheckBlock (Int32 x, Int32 y, Boolean destructive) (at Assets/TetrisClone Assets/Scripts/Block.js:83)
Block+$Start$39+$.MoveNext () (at Assets/TetrisClone Assets/Scripts/Block.js:48) :face_with_spiral_eyes:

If there is only 1 cube on the ground, the game works perfectly, and i can stack the other shapes and also the rows dissapear when filled.
Do you have any idea on how to fix this error?
Already my thanks again for the nice example :razz:

I hope Eric remembers the code, this thread is a few years old! :slight_smile:

The way to fix the error is to use Unity 2.6 or earlier; it seems to be broken in Unity 3 for some reason, and since I don’t remember the code at all, I have no idea why. :wink: If I have time I’ll look at it later.

–Eric

:smile: Again a lot of thanks.
I was a bit worried that this post was already to old, and if you still looked at it or not.
I will try to see if i can come up with a solution as well, if i know more i will let you know :wink:

Seeing the same here, would be great to find a solution to this if anyone’s managed to fix it.

OK, I finally got around to taking a look. After seeing the scripts, I ended up basically rewriting them, rather than trying to figure out what the problem was (well, it’s been almost 4 years; some of the code was pointless and/or not that great). Aside from being better and more understandable, the code is enhanced somewhat–all pieces can be any arbitrary size, speedups after clearing a given number of rows, playing field (mostly) automatically adjusts based on the size entered in the inspector. (So have fun making a 100x200 field with dozens of 8x8 pieces. :wink: )

–Eric