Search Unity

Gravity: 3d Tetris

Discussion in 'Scripting' started by Greg Farina, May 26, 2007.

  1. Greg Farina

    Greg Farina

    Joined:
    Apr 25, 2007
    Posts:
    47
    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
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    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

    Code (csharp):
    1. function OnCollisionEnter() {
    2.      rigidbody.Sleep();
    3. }
    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
     
  3. Greg Farina

    Greg Farina

    Joined:
    Apr 25, 2007
    Posts:
    47
    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?
     
  4. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    Once a piece has hit the stack, it doesn't need a rigidbody any more, so you can delete that component.
     
  5. Greg Farina

    Greg Farina

    Joined:
    Apr 25, 2007
    Posts:
    47
    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?
     
  6. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    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"):

    Code (csharp):
    1. static var field : int[];
    2. static var canSpawn : boolean;
    3. var cube : GameObject;
    4.  
    5. function Start() {
    6.     canSpawn = true;
    7.     field = new int[10];
    8.     field[0] = 1;
    9.     InvokeRepeating("SpawnCube", .1, 2);
    10. }
    11.  
    12. function SpawnCube() {
    13.     if (canSpawn) {
    14.         Instantiate(cube, Vector3(0, 10, 0), Quaternion.identity);
    15.     }
    16. }
    Make a cube, put this script on the cube (doesn't matter what you call it):

    Code (csharp):
    1. var fallSpeed : float = 2;
    2. private var yLocation = 9;
    3.  
    4. function Start() {
    5.     if (Manager.field[yLocation] == 1) {GameOver();}
    6.     Manager.field[yLocation] = 1;
    7.     while (Manager.canSpawn) {
    8.         // Go down a "square" if there's nothing immediately below in the array
    9.         if (Manager.field[yLocation-1] == 0) {yield Fall();}
    10.         else {yield;}
    11.     }
    12. }
    13.  
    14. function Fall() {
    15.     // Make cube "fall down" 1 location in array
    16.     Manager.field[yLocation--] = 0;
    17.     Manager.field[yLocation] = 1;
    18.     // Make cube fall down 1 "square" on-screen
    19.     for (var i : float = yLocation + 1; i > yLocation; i -= Time.deltaTime*fallSpeed) {
    20.         transform.position.y = i+1;
    21.         yield;
    22.     }
    23.     transform.position.y = yLocation+1; // Just to make it exactly perfect
    24. }
    25.  
    26. function OnMouseDown() {
    27.     Manager.field[yLocation] = 0;
    28.     Destroy(gameObject);
    29. }
    30.  
    31. function GameOver() {
    32.     print ("Game Over!");
    33.     Manager.canSpawn = false;
    34. }
    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! ;)

    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
     
  7. Greg Farina

    Greg Farina

    Joined:
    Apr 25, 2007
    Posts:
    47
    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
     
  8. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    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. ;) 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
     

    Attached Files:

    Last edited: Apr 11, 2011
  9. Greg Farina

    Greg Farina

    Joined:
    Apr 25, 2007
    Posts:
    47
    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
     
  10. Brian-Kehrer

    Brian-Kehrer

    Joined:
    Nov 7, 2006
    Posts:
    411
    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.
     
  11. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    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
     
    Last edited: Apr 10, 2011
  12. HiggyB

    HiggyB

    Unity Product Evangelist

    Joined:
    Dec 8, 2006
    Posts:
    6,183
    Sweet Eric, thanks! I'm off to check it out now myself... :D
     
  13. drJones

    drJones

    Joined:
    Oct 19, 2005
    Posts:
    1,351
    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 ; )
     
  14. runaron

    runaron

    Joined:
    Sep 2, 2009
    Posts:
    1
    :D :D :D :D :D :D :D :D :D :D :roll: :roll: :roll: :roll: :roll: :roll: :roll: :roll: :roll: :roll: :roll:

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

    Gr33nIguana

    Joined:
    Feb 24, 2011
    Posts:
    14
    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) :confused:

    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:
     
  16. callahan.44

    callahan.44

    Joined:
    Jan 9, 2010
    Posts:
    694
    I hope Eric remembers the code, this thread is a few years old! :)
     
  17. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    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. ;) If I have time I'll look at it later.

    --Eric
     
  18. Gr33nIguana

    Gr33nIguana

    Joined:
    Feb 24, 2011
    Posts:
    14
    :D 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 ;)
     
  19. Backman

    Backman

    Joined:
    May 31, 2008
    Posts:
    12
    Seeing the same here, would be great to find a solution to this if anyone's managed to fix it.
     
  20. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    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. ;) )

    --Eric
     
  21. Backman

    Backman

    Joined:
    May 31, 2008
    Posts:
    12
    This is great, thanks a bunch Eric. I'm just learning so reformed code is great. : )

    I just noticed it's possible to overlap one block over the other if your block is falling next to another and you press left/right against it, not a big deal..

    Thanks again!

    [edit] I should probably point out that bug isn't totally straight forward, you need to try to push a block in under another static on.. so you need a hole to the side below a block formation and try to push your block in there, but start pressing left/right half a block before you're right next to that gap. I'm not even sure if that makes sense... need zzzlleeeeep... had a closer look at your stuff, great learning material.
     
    Last edited: Apr 6, 2011
  22. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It's not really a bug (or it's just a visual bug). If you change the falling code so the blocks go down one square at a time instead of smoothly, you see what's "really" happening, and this behavior was possible in the original Tetris if I recall correctly.

    --Eric
     
  23. Backman

    Backman

    Joined:
    May 31, 2008
    Posts:
    12
    Yes just a minor visual bug.. that was actually one of the first things I tried with your code as I wrote something like this in torque and had the exact problem at one point. If you know how to easily fix it feel free to let me know, otherwise I might dig around a bit so no worries.. i'm quite interested in learning your solution. Mine was similar, I used an array for the stored blocks but used collision detection for the player controlled one. Yours look significantly more efficient so it'll be a great lesson. :)

    Thank you.
     
  24. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    You could prevent it from happening by using CheckBlock with the previous row as well as the current row and not allow movement if it would collide, though that would change the gameplay to some extent. Maybe better if you checked the previous row, and if it would collide, wait until the block has finished falling for that square before moving it. That would cause a delay between input and results, though, so maybe it's not better. Maybe best if you just disable smooth falling and use the ol' square-by-square technique. ;)

    --Eric
     
  25. CoolKid808

    CoolKid808

    Joined:
    Oct 9, 2011
    Posts:
    22
    I'm more of an artist myself but I'm learning some coding at the minute, I was just wondering, if I wanted to try and modify it so that everything was turned 90 degrees how would i do so? essentially im looking to have the cubes travel along the z axis coming towards the camera if that makes it clearer.
     
  26. Felipetnh

    Felipetnh

    Joined:
    May 3, 2012
    Posts:
    8
    I'm having a minor problem.
    I can't understand what I have to change to have the "ol' square-by-square technique".
    I've tried everything, but it doesn't work.
     
  27. Ariane.Wanless

    Ariane.Wanless

    Joined:
    Jun 6, 2012
    Posts:
    1
    This code has been immensely helpful! I'm not a coder by inclination, I sort of dabble in it, and try to understand the vague basics about what's going on behind the scenes. But I downloaded this project to get a feel for what's happening here, and I started trying adapt it to make the 3rd dimension actually utilized in Tetris. I was wondering if there was away to adapt the use of matrices into Vector3s, or something, so I can incorporate a Z axis movement? I've been bashing my head against the wall on that one for a while now, so I finally decided to ask.

    Basically I want to create a Tetris game where you can move forward and backwards, and you have to create planes rather than rows to clear. The finer details of the game will include camera movement for better viewing, multiple directions of block movement, and making things visually clearer as to where holes are with translucencies, but that I've pretty much got down. And this code works almost how I want it to for my final game, but despite everything I've tried, I can't seem to figure out a way around the 2D arrays. Any thoughts? I'd be most appreciative!
     
  28. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    I imagine you'd use 3D arrays instead of 2D arrays. Not Vector3, that's something else entirely.

    --Eric
     
  29. alejogn

    alejogn

    Joined:
    Nov 26, 2012
    Posts:
    6
  30. Marcos Suhit

    Marcos Suhit

    Joined:
    Mar 15, 2013
    Posts:
    3
    Hello Friend Eric!!!
    I'm doing a 3d Tetris but I can not understand the logic of the 3D matrices.
    Achieve 2d do ........... Could you help me with the code to see how Eric handles the third dimension.
    Your game is very very very good. I wish I could do something similar.
    Thank you so much!
     
  31. mzlatar

    mzlatar

    Joined:
    Nov 5, 2013
    Posts:
    2
    Hey Eric,

    Thanks for sharing Tetris clone. When I start it in unity only one shape is spawned, and when it hits the ground no more shapes are spawming.
     
  32. Vitor_r

    Vitor_r

    Joined:
    May 23, 2013
    Posts:
    93
    I got this problemt too.
    I removed the "yield" from the line "yield CheckRows (yPos - size, size);" on Manager.js and it spawned the next blocks correctly.

    dont know if this can crash the rest of the game but as far as i played it worked.

    Edit: Thank for the code Eric :p...
     
  33. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    There seems to be a bug with Unity 4.3 involving calling coroutines from other scripts in certain circumstances. To fix it properly, rename the "SetBlock" function to "SetBlock2". Then make a new function:

    Code (csharp):
    1. function SetBlock (blockMatrix : boolean[,], xPos : int, yPos : int) {
    2.     SetBlock2 (blockMatrix, xPos, yPos);
    3. }
    So as long as the coroutine is being called from the same script, it works.

    --Eric
     
  34. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Actually I'm not sure if it's a bug so much as changed behavior, so I updated the project on the first page.

    --Eric
     
  35. mzlatar

    mzlatar

    Joined:
    Nov 5, 2013
    Posts:
    2
    Working great now, thanks Eric!!! :)
     
  36. vezer

    vezer

    Joined:
    Dec 26, 2013
    Posts:
    4
    Eric sorry for the trouble but i have a question about your code these lines in particular :

    for (i = 0; i < fieldWidth; i++) {
    field[i, 0] = true;
    }

    so i understand we did tat to fill the walls with 1 (true) so the block cant pass it ... but here comes my question i tried to play with it a bit and if i understand correctly, if I change the code to :

    for (i = 0; i < fieldWidth; i++) {
    field[i, 1] = true;
    }

    shouldn't the block stop 1 row above the floor, but instead it works fine on the midle and it goes 1 row trough floor in the edges, that's the confusing part if you could take a sec to check it out and explain to me i'd be greatful.
     
  37. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    The bottom row is required to be filled in for reasons stated in the comment. Filling in a row above that makes a completed row, which is removed when a piece falls, so it becomes empty.

    --Eric
     
  38. vezer

    vezer

    Joined:
    Dec 26, 2013
    Posts:
    4
    ow okey, ty :)
     
  39. vezer

    vezer

    Joined:
    Dec 26, 2013
    Posts:
    4
    hey, really sorry for bothering you, but how would one change the texture, so each block has a different 1, i would know how to do this if the "cube" is chield from block, but since it isnt what would you recommand... again rly sorry for bothering you I am new at unity3d still learning
     
  40. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    You can change the Cube prefab.

    --Eric
     
  41. vezer

    vezer

    Joined:
    Dec 26, 2013
    Posts:
    4
    thank you :) works now
     
  42. danidel3d

    danidel3d

    Joined:
    Jul 26, 2013
    Posts:
    10
    Hello, I changed the Eric5h5's JS code to C# and added some colors lines. If somebody find this useful, please download.
     

    Attached Files: