Search code examples
javabitwise-operatorsbufferedimagegame-development

Difficulty understanding image loading date for java game development


I am creating a java game with the reference of RealtutsGML's java game programming series. I am having a lot of trouble understanding how certain parts of this code works. I understand the getWidth and getHeight of the image part but within the for loop, I am lost.

The Wizard class is the player and the block is the barrier surrounding the map. The map is a 64 by 64 image that I made in photoshop which consists of a bunch of red pixels that represent where the Block objects are supposed to be spawned in, as well as a single green pixel which represent the Wizard/Player spawn location.

    private void loadLevel(BufferedImage image) {
    int w = image.getWidth();
    int h = image.getHeight();

    for(int xx = 0; xx < w; xx++) {
        for(int yy = 0; yy < h; yy++) {
            int pixels = image.getRGB(xx, yy);
            int red = (pixels >> 16) & 0xff;
            int green = (pixels >> 8) & 0xff;
            int blue = (pixels) & 0xff;

            if(red == 255) 
                handler.addObject(new Block(xx * 32, yy * 32, ID.Block));
            if(green == 255)
                handler.addObject(new Wizard(xx * 32, yy * 32, ID.Player, 
                handler));
        }
    }
}

The parts I am struggling to understand is int pixels = image.getRGB(xx, yy) Does this mean pixels stores the values of Red, Green and Blue, if so how can pixels store multiple values?

The next part I don't understand is

 int red = (pixels >> 16) & 0xff;
 int green = (pixels >> 8) & 0xff;
 int blue = (pixels) & 0xff;

Why do we shift pixels for the red, blue and green variables right by 16 and 8, and then add & 0xff onto them?

The final part is why we multiply the xx and yy values within the handler.addObject method by 32. Each block object and wizard object is 32 by 32 but why do we need to multiply the whole image by 32.

I have already looked at the oracle site for explaining the & bitwise operator and it did help a little but I still struggle to understand how it works in this context.


Solution

  • A single pixel can be stored in a (32-bit) integer.

    Each of the components of color RGB range from 0 to 255, where (0,0,0) is black, (255,255,255) is white, and then you have all the colors in between. 0 to 255 can be stored in 8-bits, which means you can store RGB data in 24-bits. The next 8 bits may be unused, or used to store alpha data, or whatever, but that's not important here.

    A pixel can therefore be read as an integer, and is typically how you would work with image data because the values are integers.

    Bitwise operators are used to "extract" specific parts of the integer, because the first 8 bits store blue data, the next 8 bits store green data, and the next 8 bits store red data. Note that by "first", I am reading from right to left, as a lot of data is stored in little endian even though it looks reversed to humans.

    If you don't know how bitwise shifting works you can read it here: What are bitwise shift (bit-shift) operators and how do they work?. Basically, it's an easy way to get the bits you want.

    So if you imagine your 24 bits of color data in a 32-bit integer as follows:

    rrrrrrrrggggggggbbbbbbbb
    

    By saying pixels >> 8, you get

            rrrrrrrrgggggggg
    

    But if you read the resulting value as-is, you'll get all that extra red data that you don't want. So you & with 0xff in order to keep the last 8 bits which is your green component, and then remove (or zero out) any other bits.

    As for the block and wizard positions at intervals of 32, my best guess would be your game map is represented as a grid with tiles of size 32x32. Why? Cause if all your sprites were stores one pixel from one another you'll just have a mess. The use of an image to create the spawn points is done by mapping from tile coordinates (on your image) to pixel coordinates on the screen. That is to say, pixel (0,0) in your image is the top-left corner of the grid, while pixel (0, 1) in your image represents one tile below (which is 32 pixels in-game).

    Basically, you have a 64x64 tile map, and the game will initialize the positions of the objects on the screen assuming each tile is 32x32 in size, using your image as a way for you to "draw out" the layout of the map.