Advertisement

Do i make long/complex code logic or more art assets to simplify code?

Started by April 29, 2017 02:47 AM
21 comments, last by CelticSir 7 years, 6 months ago

Ah code, now we can talk solutions :)

I'm not even half way and its getting quite long and feels inelegant for implementing given the amount of checks and combinations involved.

I agree this looks wrong. It looks like you are testing for a few specific bits. You generally do this with bit masking. Terms you are looking for are bit masking, bit arithmetic, and more generally, bit operations.

Can you tell what the mask is? That is, how did you derive the "if (tile.Mask == 22 || tile.Mask == 18 || tile.Mask == 55 || tile.Mask == 23 || tile.Mask == 54 || tile.Mask == 19)" line ?

I tried to reverse engineer it, but the result is wrong


print(bin(18)) # prints 00010010
print(bin(55)) # prints 00110111
print(bin(23)) # prints 00010111
print(bin(54)) # prints 00110110
print(bin(19)) # prints 00010011

If you check each column, and replace the value by * (dont care) if you compare both a 0 and a 1 sometimes, I get


00010110
00010010
00110111
00010111
00110110
00010011

00*10*1*

There are 3 * bits there, which means there should be 8 cases, but you have only 6, so something is missing. That information should be in the description of your mask.

The trick here is that the * bits are not interesting, so you force them to 0 with an 'and 0' operation. The bits you care about must be preserved, so you force them to stay the same with an 'and 1' operation. That means the bitmask here seems to be [except for the missing cases]:


00*10*1* and 11011010
// second number is the same as the first, with * replaced by 0, and (0/1) replaced by 1

The result of this operation is then 00010010 (again the first number, but only the * replaced by 0)

You can convert 11011010 back to decimal, I prefer hexadecimal, which is 0xDA.

Similarly, 00010010 is 0x12 in hexadecimal number system.

Your first line then becomes "if ((tile.Mask & 0xDA) == 0x12)"

If you try that for all numbers 0..255:


for n in range(0, 256):
    if (n & 0xDA) == 0x12:
        print(n)
Output:
18
19
22
23
50
51
54
55

Values 50 and 51 are missing in your 'if' statement. I don't know why.

Can you find out?

[ you can likely split things out even more, if the Vec3 value is a separate part in the tile mask, you can convert that separately, reducing stuff by a factor 2 or 4. ]

Okay so the way i derived my if statements was placing the tiles in my world, clicking them to get their mask value and then knowing visually what wall it needed i was adding their mask value to the if statements by editing the script as i went...it was a slow and tedious task and i had not got through all combinations which would explain why i have missing values.

The code was basically - incomplete.

Advertisement

Huh, you don't know what the mask value means? It is set somewhere, isn't it? (Or used somewhere other than while rendering, perhaps.)

Huh, you don't know what the mask value means? It is set somewhere, isn't it? (Or used somewhere other than while rendering, perhaps.)

I never took computer science so i don't know much about the lower level binary and hexadecimal stuff, i'm learning as i go - but often i don't know what i don't know if you understand what i mean.

I came across the masking from a blog and followed how to set the tile mask value based on each tile's neighbours since someone suggested the idea to me, but it didn't really cover the next step of connecting the integer value to the wall type needed.

This is where it is set:


public void SetTileMask()
{
    for (int i = 0; i < Tile_List.Count; i++)
    {
        int value = 0;
        Tile tile = Tile_List[i];
        if (Tile_Dictionary.ContainsKey(tile.Position_XY + Vector3.left + Vector3.forward))
            value += 1;
        if (Tile_Dictionary.ContainsKey(tile.Position_XY + Vector3.forward))
            value += 2;
        if (Tile_Dictionary.ContainsKey(tile.Position_XY + Vector3.forward + Vector3.right))
            value += 4;
        if (Tile_Dictionary.ContainsKey(tile.Position_XY + Vector3.left))
            value += 8;
        if (Tile_Dictionary.ContainsKey(tile.Position_XY + Vector3.right))
            value += 16;
        if (Tile_Dictionary.ContainsKey(tile.Position_XY + Vector3.back + Vector3.right))
            value += 32;
        if (Tile_Dictionary.ContainsKey(tile.Position_XY + Vector3.back))
            value += 64;
        if (Tile_Dictionary.ContainsKey(tile.Position_XY + Vector3.back + Vector3.left))
            value += 128;

        tile.SetMask(value);
    }
}

I never took computer science so i don't know much about the lower level binary and hexadecimal stuff, i'm learning as i go - but often i don't know what i don't know if you understand what i mean.
Binary and hexadecimal number systems are actually closer to math, as in they are different ways to write a number. It's a bit like writing "house" in different languages. If you compare the strokes of the pen what they wrote, it seems vastly different, but it's simply the same thing written in other ways.

A number in the decimal number system (what we normally use) is thus the same as a number in the binary number system, and the same as a number in a hexadecimal number system. Binary and hexadecimal stuff is not different than any math you do now. You can add, subtract, and multiply in those number systems just as easily as you can in the decimal system.

The only reason to use binary numbers is that 'and' and 'or' work on bits, and there is a one-to-one mapping between bits and digits in a number written in the binary number system. This makes manual computation of the result of an 'and' operation much much much simpler. Hexadecimal number systems are popular, because binary zeroes and ones get very long and error-prone very quickly. A single hexadecimal digit can express 4 binary digits, so I reduce writing by a factor 4, by using hexadecimal notation. Experienced users of the hexadecimal number system however never look at the digits, they see the underlying bit patterns of each digit. This much alike you not seeing 1, 3, 6 if I write 136.

Practical application of binary number systems are not very common in CS, you find it much more in electro-mechanical control systems, ie in computers controlling some device. Small computer systems like Raspberry Pi, and pretty much every device driver is filled with it. Digital systems within Electrical Engineering use it a lot.

Enough number theory, back to the problem:

I came across the masking from a blog and followed how to set the tile mask value based on each tile's neighbours since someone suggested the idea to me, but it didn't really cover the next step of connecting the integer value to the wall type needed.
Ah, the joys of random Internet blogs giving incomplete pictures of everything :)

If you see a value as a sum of power-of-two values (3 == 1 + 2, 98 = 64 + 32 + 2, etc), each power of two is a single bit (= a position in a number written in the binary number system), so you can easily test for such values using an 'and' ((value & 2) == 2) or ((value & 2) == 0). In that way you can disect your value back to your 8 cases, in 8 if statements.

You can also check for combinations, eg the "right" vector occurs in 4, 16, and 32. You can test for that like

if ((value & 4) != 0 || (value & 16) != 0 || (value & 32) != 0)

or together

if ((value & (4+16+32)) != 0)

You may want to read bit arithmetic and bit masking at wikipedia.

An alternative direction is to ditch the bit masks, and invent a data description that better fits your needs in the rendering. That comes back to my previous suggestion, look at what simple code you want in rendering, then work your way back to what data values you want to have.

You can also check for combinations, eg the "right" vector occurs in 4, 16, and 32

You kind of lost me here. Going clockwise from north east to north and so on, the numbers i have are: 1,2,4,16,128,64,32,8

So wouldn't a right wall piece be only the value of 16?

Like if you see this example:

http://i.imgur.com/E5tZhlN.png

All those corner pieces values are: 22, 23, 151, 183, 55 though i am missing some combinations when i draw it out. If i was to use the if statements to simplify it, what exactly am i checking for in these values to detect they all simply are the same visual tile ? The if(value & .. ) is bit confusing how i connect that to all the possible values.

Like say i have if((value & 2) != 0, am i simply checking to see if that given tile requires a wall piece along it's north edge? Since a north tile neighbour is + 2 to the value? Its kinda hard to connect the numbers to what the end result it.

Advertisement

It seems you have very little idea about bits, numbers, and how they relate it seems.

I would need a few hours face-to-face at least to explain how numbers work, how binary numbers work, how you can convert back and forth between various number systems (such as decimal, binary, and perhaps hexadecimal), how binary numbers are related to bits, how computers use bits to store integers, the bit operations 'and', 'or', and 'xor', and how you can use them to manipulate integers as a collection of bits. From there we can discuss bitmasks and their uses. It is not terribly difficult, but it's a lot, and there are a few deep ideas in there that you need to grasp or you get nowhere.

In this single post, I have no chance whatsoever to explain all that to you :(

To get forward, I would suggest that you forget about bitmasks. It's too complicated to understand at this time. Instead make several variables in the tile, one for each thing that you must draw. Then in a function like SetTileMask (but not that one, as it has the wrong name), set the variables.

It seems you have very little idea about bits, numbers, and how they relate it seems.

I would need a few hours face-to-face at least to explain how numbers work, how binary numbers work, how you can convert back and forth between various number systems (such as decimal, binary, and perhaps hexadecimal), how binary numbers are related to bits, how computers use bits to store integers, the bit operations 'and', 'or', and 'xor', and how you can use them to manipulate integers as a collection of bits. From there we can discuss bitmasks and their uses. It is not terribly difficult, but it's a lot, and there are a few deep ideas in there that you need to grasp or you get nowhere.

In this single post, I have no chance whatsoever to explain all that to you :(

To get forward, I would suggest that you forget about bitmasks. It's too complicated to understand at this time. Instead make several variables in the tile, one for each thing that you must draw. Then in a function like SetTileMask (but not that one, as it has the wrong name), set the variables.

Yeah it appears i need to learn this stuff. I don't want to take up all your time, so i'll go seek out a book on it.

Thanks for the advice though, it is much appreciated !

This topic is closed to new replies.

Advertisement