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 Code (csharp): 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"): Code (csharp): 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): Code (csharp): 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! 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. 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
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
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 ; )
: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) 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:
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
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
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
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.
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
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.
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
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.
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.
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!
I imagine you'd use 3D arrays instead of 2D arrays. Not Vector3, that's something else entirely. --Eric
hi, you might find this interesting... it took me only 2.5 days to make it, Love Unity3D! http://www.yoambulante.com/en/labs/UnityTetris/
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!
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.
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 ...
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): function SetBlock (blockMatrix : boolean[,], xPos : int, yPos : int) { SetBlock2 (blockMatrix, xPos, yPos); } So as long as the coroutine is being called from the same script, it works. --Eric
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
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.
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
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
Hello, I changed the Eric5h5's JS code to C# and added some colors lines. If somebody find this useful, please download.