Hello. I am making a puzzle game like this and I have some questions:
1:
The way that blocks are moved around the gameplay area is that the player highlights a pair, presses a button and the two highlighted blocks positions are swapped, how would I manage this inside unity? How can you switch the positions of two objects?
2:
To extend that question, how would I go about telling Unity which pair of blocks I want to be switched? I was thinking
of having the “highlighter” just be an object that the player controls that has a trigger, but how can I detect which blocks are inside of the trigger? The blocks are just going to be cubes(with triggers) with another cube(with a collider) that is a child.
3:
If I set up a series of cubes, will unity automatically keep them in a line if they fall (In the video, when a block is moved to an empty area, it falls straight down, there is no movement on the x axis outside of the player switching the cubes)? If not, how can I keep objects only moving on one axis?
For something like that, I wouldn’t use Unity’s physics or collision detection system at all. Instead, handle the game logic in ‘grid space’ with integer coordinates and deterministic methods (that is, nothing that will be subject to floating-point error). The animations are (presumably) just cosmetic, and can be implemented using the method of your choice (hand-coded, animation clips, iTween, etc.).
The highlighter can be an object that lives in ‘grid space’ just like everything else. Every object (highlighter, cubes, etc.) has both grid coordinates, and world coordinates based on the grid coordinates (with the world coordinates being subject to animation effects).
To swap two items, you would swap the grid coordinates, and then recompute the world coordinates from the grid coordinates. The world coordinates in this case would correspond to the Transform.position property, which is one way you can access and modify the positions of game objects in Unity.
Im sorry but I am a bit confused, how would I set up the grid? Can I do something like every 551 area of world space counts as a single grid space(If thats the case, if its not to much trouble, can you show me an example/direct me to a tutorial of how I would do that)? Or could I use empty objects/cubes to measure the grid(I guess it really doesn’t matter, considering it is all relative, but which one would you do)?
Also, would I even need to have triggers attached to the blocks then (could I just check the distance between all of the blocks of the same type and if one is close then have the “matching function” play)?
The specific representation used is secondary, but sure, a 2-d array would be a logical choice.
The grid specifies and determines the world, not the other way around.
Say you use a 2-d array, where each cell contains whatever information is needed (e.g. a reference to any cube that’s there, whether the cursor is over that cell, etc.). Each cell has integer coordinates, e.g. (2, 5). Given the integer coordinates for a cell, you can easily determine the world-space coordinates for the center of that cell. Say, for example, that the variables ‘originX’ and ‘originY’ represent the lower-left corner of the grid, and the variable ‘gridSize’ represents the width/height of a single cell. Then, the formula to compute a world-space coordinate corresponding to a cell would be:
And similarly for y. (Try drawing this out on paper, and you should see why this is so.)
No triggers or colliders or anything like that. As for checking distances and so forth, you would perform any logic of that kind in grid space rather than world space.
(Note that I’m assuming the game in question is consistently grid-based. I didn’t see anything in the video to indicate otherwise though.)
It depends on the game, more or less, but a 2-d array would be a good place to start. As for what the array should hold, probably a custom data type (e.g. a class) that provides information about what that cell holds (whether there’s a cube there and if so what kind of cube, whether the cursor is over that cell, etc.).
I seem to remember reading that you have to do something special in UnityScript to create 2-d arrays, but I don’t remember what it is. Anyway, perhaps you could narrow your question down a bit. What do you need help with first?
Okay, first can you clarify something for me? I did some searching and I found this. I want to see if I understand the script’s meaning.
var foo = MultiDim.IntArray(100, 200);
foo[52, 49] = 123;
The (100,200) refers to the grids total size in cells, and the 52,49 refers to the specific cell (I am assuming that the origin is the bottom left), and that the 123 refers to whatever code you want to place in regards to that cell?
I am still a little confused as to how I could use this regards to a puzzle game like the one in that video
How can I tell that code about what kind of block is in each cell (and the blocks are moving upwards, wouldn’t that complicate things even more)?
My first throughout was to just have different kinds of blocks, check to see if it is colliding with a block of the same type. I would then move then just move them with a simple translate script and instantiate the blocks in time with that script.
Pretty close. (100, 200) is the total grid size, (52, 49) refers to a specific cell in the grid, and in the example, that cell is assigned a value of 123.
The only part that’s not quite right is about the origin being in the bottom left. A 2-d array is just a simple container for data, and doesn’t have any spatial implications by itself. In short, if the 2-d array is used to represent a regular grid in 2-d space, then the origin is wherever you say it is (and sure, the bottom left is a perfectly reasonable choice).
You’d need to create a custom data type, and then create a 2-d array with that type as the element.
I don’t use UnityScript that much, but here’s a quick C# example:
public class Cell
{
Block block;
bool cursor;
}
That’s a very simple example; in this case, each cell simply stores a reference to any block that’s in that cell (or null if no block is present), and a Boolean variable indicating whether the cursor is currently over that cell. You could of course add any other information you needed as well.
As far as the Wiki script you linked to goes, I think you’d need to add a new function to support the Cell type, i.e.:
public static Cell[,] CellArray (int a, int b) {
return new Cell[a,b];
}
You can do whatever you want of course. But, I’ll say again that if the game itself is grid-based (and it looks like it is), then performing the actual game logic using a grid is the way to go. There’s really no point in dealing with colliders, numerical error, distance checks, and all that sort of stuff if the game itself is strictly grid-based.
One more comment that might help clarify things a bit. There’s a concept in software development called ‘model-view’. In simplified terms, ‘model’ refers to the logic of the underlying simulation, while ‘view’ refers to how the simulation is presented to the user.
Consider, for example, the game Bejeweled. The game is strictly grid-based; there’s a regular 2-d grid of cells, and each cell has a specific type of jewel in it at all times. To relate it back to the earlier example, in this case the grid could probably just be a 2-d array of ints or enums, with each entry specifying what type of jewel is in the cell.
As far as the basic game goes (the original version), the only user-initiated action that can occur is to swap a jewel for one next to it (programmatically, the values of the two cells in questions would be swapped). From there, it may be the case that jewels are removed, in which case other jewels move down as necessary, and new jewels are added in the empty cells.
Ok, so that’s the model. What about the view? The view could be anything. Imagine, for example, that Bejeweled were a simple text game with a grid of numbers, with each cell holding a number from 1 to however many jewel types there are. There’s no animation, no color, no sound - you just click and drag on the numbers to swap them around, and the rest of the gameplay proceeds as usual.
Well, that probably wouldn’t have been that successful as a game. To answer the question of why we’d probably have to get into the theory and psychology of what makes a game enjoyable, but suffice to say that the color, sound, and animation are all part of the experience. If it were just the gameplay, they could’ve released the game as a text game with numbers only, and it would’ve been equally successful. But in practice, people want a more immersive experience that’s pleasing to the senses, and the ‘view’ of the model is what provides that.
In Bejeweled the ‘view’ consists of replacing numbers (essentially) with jewels, which are real-world objects that people can relate to. There’s also cosmetic animation in the form of jewels swapping smoothly, falling down from above, and so on. But what’s important to realize is that none of these things has anything to do with the actual gameplay. They are purely and exclusively part of the view, and not the model. No matter how much the jewels move or animate or interpolate, the game itself is strictly grid-based.
Ok, I wrote more than I intended, but I hope that gives you some insight. I think the point I’m trying to make is that just because you see a cube animate smoothly onscreen doesn’t mean that the underlying representation needs to be continuous, or that you need to use non-deterministic and/or error-prone methods to handle the game logic. The game logic can (and most likely should) be handled in the simplest way possible, using a regular grid, as we’ve been discussing, as the representation for the world. As for aesthetic concerns such as animation, interpolation, and so forth, those are aspects of the view, not the model.
Thanks for all of your help. If you dont mind, I have some more questions:
public static Cell[,] CellArray (int a, int b) {
return new Cell[a,b];
}
Could you please break this down a bit, I dont understand what everything means (I am relatively new to coding and I deal mostly with unity script)? I am still not exactly clear on how I would get the data that represent the block types/cursor into the cells.
If the origin can be anywhere, how can I get it to be at the bottom left?
How would I check to see if two blocks (of the same type) are in cells that are (horizontally) next to each other?
I can’t really help you with the UnityScript side of things - I’ll have to leave that to others. But, I will tell you that the above bit of C# is essentially a workaround for UnityScript’s incomplete support for n-d arrays (or at least that’s my understanding).
Here, however, is an example in C# showing what I mean (typed into post, not compiled or tested):
public class Board
{
struct Cell
{
public int block; // -1 means no block
public bool cursor; // Whether the cursor is over this cell
public Cell(int block)
{
this.block = block;
this.cursor = false;
}
}
Cell[,] cells;
public Board()
{
// Note that in practice you'd want to use constants or variables
// here rather than the 'magic numbers' 10 and 5.
cells = new Cell[10, 5]; // 10 rows by 5 columns
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 5; ++j) {
cells[i, j] = new Cell(-1);
}
}
}
}
Again, this was just typed into the post, so there may be errors.
That’s strictly an issue of how you interpret the array.
A cell is referenced by two integer indices, e.g. i and j. The neighboring cell in either of the four directions can be found by adding or subtracting 1 to i or j. Using this method, for any cell you can easily find the adjacent cell in any direction (don’t forget to handle cells on the edge of the array correctly).