0
\$\begingroup\$

I am following a tutorial on YouTube for making a 2D game. There is no clear explanation on what its actually doing.

I get bit-shifting and & operator but I don't know what they mean in this context and I understand basic Java implementation.

I've done some basic trial and error with the below code by seeing how it works, I see the effects happening but don't quite comprehend on what it is supposed to be doing in the code.

Could someone please explain how the lines marked with "//*******" work in the given context?

public class Screen {
    public static final int MAP_WIDTH= 64;
    public static final int MAP_WIDTH_MASK= MAP_WIDTH - 1;
    public static final int PIXEL_SIZE= 8;
    public static final int PIXEL_SIZE_MASK= MAP_WIDTH - 1;
    public int[] tiles = new int[MAP_WIDTH*MAP_WIDTH];
    public int[] colours = new int[MAP_WIDTH*MAP_WIDTH*4];
    public int xOffset = 0;
    public int yOffset = 0;
    public int width;
    public int height;
    public SpriteSheet sheet;
    public Screen(int width, int height, SpriteSheet sheet) {
        this.width = width;
        this.height = height;
        this.sheet = sheet;
        // ************ explain what the for loop is doing
        for(int i=0; i< (tiles.length); i++) {
            colours[i*4+ 0] = 0xff00ff;
            colours[i*4+ 1] = 0x0000ff;
            colours[i*4+ 2] = 0xffff00;
            colours[i*4+ 3] = 0xffffff;
        }
    }
    public void render(int[] pixels, int offset, int row) {
        //current x and y offset is 0 meaning that the player/map isn't moving in either direction - changing them repeats the map
        // >>3 - same as multiplying by 8 (size of pixel) 
            //(0 * 8 ) + yOffset,        (height * 8) + yOffset
        // ************ what is the >> doing in this context?
        for(int yTile = (0 + yOffset) >> 3; yTile<=(height + yOffset) >> 3; yTile++) { 
            // ************ what actually is yMin?
            int yMin = (yTile * PIXEL_SIZE) - yOffset; 
            // ************ what actually is yMax?
            int yMax = yMin + PIXEL_SIZE; 
            //sanity check if you go off the map - otherwise would crash
            if (yMin<0) yMin=0; // yMin could be below 0 because of the yOffset variable being changed is greater than (yTile * PIXEL_SIZE)
            if (yMax>height) yMax = height; // yMax could be above height because of the yOffset variable being changed
            // see above; applies to xTile as well
            for(int xTile = (0 + xOffset) >> 3; xTile<=(width + xOffset) >> 3; xTile++) {
                int xMin = (xTile * PIXEL_SIZE) - xOffset;
                int xMax = xMin + PIXEL_SIZE;
                if(xMin<0) xMin=0;
                if (xMax>width) xMax = width;
                 // ************ obviously this gives current tile you're on but what does & do in this context?
                int tileIndex = (xTile &(MAP_WIDTH_MASK)) + (yTile &(MAP_WIDTH_MASK))* MAP_WIDTH;
                for (int y = yMin; y < yMax; y++){
                    // ************ what does & do in this context?
                    int sheetPixel = ((y + yOffset) & PIXEL_SIZE_MASK)*sheet.width + ((xMin + xOffset)& PIXEL_SIZE_MASK);
                    // ************ is the tilePixel individual pixels in the tile?
                    int tilePixel = offset + xMin + y * row;
                    for(int x = xMin; x< xMax; x++) {
                        // ************ what is tileIndex * 4 doing?
                        int colour = tileIndex * 4 + sheet.pixels[sheetPixel++];
                        pixels[tilePixel++] = colours[colour];
                    }
                }
            }
        }
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ If the tutorial you follow doesn't explain its code properly and confuses you by using unnecessarily complex language features, then you might want to look for a better tutorial. A lot of tutorials you find on YouTube seem to be from people who care more about showing off their programming skills than about actually educating people. \$\endgroup\$
    – Philipp
    Commented Mar 12, 2020 at 16:04

1 Answer 1

1
\$\begingroup\$
for(int i=0; i< (tiles.length); i++) {
        colours[i*4+ 0] = 0xff00ff;
        colours[i*4+ 1] = 0x0000ff;
        colours[i*4+ 2] = 0xffff00;
        colours[i*4+ 3] = 0xffffff;
}

The For-Loop at the start is generating groups of four colour entries based on how many tiles you have.

It's a little convoluted to read at a glance and given choice I'd probably not do it that way, but it's pretty efficient nonetheless.

The rest is essentially a way to offset your coordinate system to account for the individual tiles being multiple pixels in size.
The tiles are eight pixels in each axis, so it's going through telling every pixel in each tile what colour it needs to be.

Bitshifting by 3 is essentially taking the number in binary and pushing each number up a slot. eg: 5 >> 3 is 101 becoming 101000, which is 40. This is equivalent to multiplying by 8, which is a 1 and three zeros behind it in binary. The bitshift value is the number of 0s being added.

In this case, it serves nicely to calculate how many pixels we've got between steps so we can jump to the start of the next tile with each step of the loop. the individual pixels are handled inside the loop.

Single Ampersands are used in Bitwise operations as well as logical conditions, Wikipedia has the details on this here

\$\endgroup\$
5
  • \$\begingroup\$ Thanks for the quick answer, that makes more sense now, where exactly would the line of code be to tell it to loop the tiles as I understand that the for loop just iterates through all the tiles? I understand the & sign but I don't understand what it is used for in this context. \$\endgroup\$
    – David Rees
    Commented Mar 12, 2020 at 14:32
  • \$\begingroup\$ The tiles are being iterated in two nested For Loops, one for the Y axis, the second for the X axis, essentially it's going through it row by row. Then inside that, it handles the individual pixels of each tile in two more nested for-loops for their own tiny grids which handle the intervening pixel positions that the bigger loops aren't dealing with. \$\endgroup\$ Commented Mar 12, 2020 at 14:36
  • \$\begingroup\$ each tile is a grid of pixels which the sprite-sheet is being mapped onto. \$\endgroup\$ Commented Mar 12, 2020 at 14:38
  • \$\begingroup\$ Okay, I see that now that I am looking at it, but my last question is about this line of codeint tileIndex = (xTile &(MAP_WIDTH_MASK)) + (yTile &(MAP_WIDTH_MASK))* MAP_WIDTH obviously its giving you the tileIndex that you are on by giving you the (x,y) coordinates as I can see the formula being [x + y* width] but what is the & for and why is it ANDing with the MAP_WIDTH_MASK \$\endgroup\$
    – David Rees
    Commented Mar 12, 2020 at 14:44
  • \$\begingroup\$ I'm not very up on Bitwise operators, but as far as I can understand, it's essentially using the bitwise operator to help add the left-to-right indexes of each row to the top-to-bottom indexes. I believe it's directly equivalent to (tileY*GridWidth + tileX) but maybe deals with some subtleties I've not noticed. Just another way to do do things. Remember that Bitwise operators like this are effectively performing binary arithmetic behind the scenes, so you can exploit that behaviour in interesting ways. \$\endgroup\$ Commented Mar 12, 2020 at 14:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .