I am having trouble figuring out how to accomplish this. I am making a very basic prototype to see if I can figure this out. Basically I want it to work like dominoes. There is one starting block with 1, 2, 3, 4 on each side. I then want the player to place the next block adjacent to it, but ONLY if it has a matching side number. Here is a basic diagram. I have the drag and drop, rotation, grid placement, etc working. I just need some type of bool that changes to true when the two sides are matching, then I will allow the player to place the block.
#Help with domino style mechanic. Black can only be placed if side matches side of other block.
1 messages · Page 1 of 1 (latest)
This is a very interesting problem, and I was typing out a solution on Discord but my math didn't work out so please hold while I open up Unity and try to fix it and I'll get back to you
Okay, I got something. So here's my solution:
What you can do is store the orientation of the block using some enum value - since a block can only be oriented in one of 4 different ways. The number 1 is either facing West (which appears to be default), North, East, or South. So your enum would just look something like this:
enum Face
{
West,
North,
East,
South
}
And then the block orientation can be stored like so:
[SerializeField] private Face _orientation;
If you wanted to, you could have this orientation value be the defining factor in how the sprite is rotated in-game, by doing something like:
transform.localEulerAngles = Vector3.back * (90 * (int) _orientation);
And the reason this works is because enums are just a list of integers, where the first value is 0. If _orientation is Face.West (the default side that the number 1 appears on, so... no orientation at all), then Vector3.back * (90 * 0) which just evaluates to 0. No rotation. If orientation is Face.East (so the block is upside down), then it'd be 90 * 2, leading to a 180 degree rotation of the object. Anyway, that's not the important part.
The way you can determine which number is on which face at any given time is by having a method that accepts which Face to check, and then calculates it like so:
public int GetNumberOnFace(Face whichFace)
{
var faceValue = (int) whichFace;
var orientation = (int) _orientation;
return Loop(faceValue - orientation + 1, 1, 4);
}
private static int Loop(int val, int min, int max)
{
// credit to Rotsor from StackOverflow for this
// https://stackoverflow.com/questions/3057640/math-looping-between-min-and-max-using-mod
int p = max - min + 1;
int mod = (val - min) % p;
if (mod < 0) mod += p;
return min + mod;
}
The Loop method works like modulo (the % operator), except it lets lets you define a minimum and maximum value. So for example Loop(6, 1, 5) gives you 1. Because this clamps the value from 1-5, and any values that go beyond it simply "wrap" to the start again.
The magic part is this:
Loop(faceValue - orientation + 1, 1, 4)
This is essentially "rotating" the requested face to the block's current orientation.
As an example, let's say you have a block at default orientation. And you want to know what value is on the north face at this orientation (which looks like it should be 2).
You call GetNumberOnFace(Face.North), which does Loop(1 - 0 + 1, 1, 4). 1 - 0 + 1 is 2, and wrapped to be in values 1-4 is still 2, so the end result is 2. That's the value on the North face.
Now let's say the block is oriented 180 degrees, so 1 is on the east side. And now we want to know what's on the west side (which is expected to be 3):
GetNumberOnFace(Face.West) performs Loop(0 - 2 + 1, 1, 4), which is Loop(-1, 1, 4) which wraps around and gives us the value 3. (1 is 1, 0 becomes 4, -1 is 3)
That matches what we expect. The west face value is 3 at this orientation
From here you can then determine if the faces match when you place, I'm sure this is plenty for you to start with