Could someone explain this line of code?

Hi guys!

I found this code for pixel-perfect collision, but there’s 1 line I can’t grasp…

Here’s the code:


// returns a HashSet of strings that list all the pixels in an image that aren't transparent
	// the pixels contained in the HashSet follow the guideline of:
	// x,y where x is the absolute x position of the pixel and y is the absolute y position of the pixel
	public HashSet<String> getMask(GameObject go){
		
		HashSet<String> mask = new HashSet<String>();
		BufferedImage image = null;
		try {
			image = ImageIO.read(new File (go.getDefaultImageLocation()));
		} catch (IOException e) {
			System.out.println("error");
		}
		int pixel, a;
		for(int i = 0; i < image.getWidth(); i++){ // for every (x,y) component in the given box, 
			for( int j = 0; j < image.getHeight(); j++){
		
		pixel = image.getRGB(i, j); // get the RGB value of the pixel
		a= (pixel >> 24) & 0xff;
		
		if(a != 0){  // if the alpha is not 0, it must be something other than transparent
			mask.add((go.xPos+i)+","+(go.yPos- j)); // add the absolute x and absolute y coordinates to our set
		}
			}
		}
		
		return mask;  //return our set
		
	}

// Returns true if there is a collision between object a and object b	
	public boolean checkCollision(GameObject a, GameObject b){
		
		// This method detects to see if the images overlap at all. If they do, collision is possible
		int ax1 = a.getxPos();
		int ay1 = a.getyPos();
		int ax2 = ax1 + a.getWidth();
		int ay2 = ay1 + a.getHeight();
		int bx1 = b.getxPos();
		int by1 = b.getyPos();
		int bx2 = bx1 + b.getWidth();
		int by2 = by1 + b.getHeight();
		
		if(by2 < ay1 || ay2 < by1 || bx2 < ax1 || ax2 < bx1)
		{
			return false; // Collision is impossible.
		}
		else // Collision is possible.
		{
			// get the masks for both images
			HashSet<String> maskPlayer1 = getMask(player1);
			HashSet<String> maskPlayer2 = getMask(player2);
		
			maskPlayer1.retainAll(maskPlayer2);  // Check to see if any pixels in maskPlayer2 are the same as those in maskPlayer1
			
			if(maskPlayer1.size() > 0){  // if so, than there exists at least one pixel that is the same in both images, thus
				System.out.println("Collision" + count);//  collision has occurred.
				count++;
				return true;
				
				}
			}
			return false;	
		}

This is the line I don’t get:


a= (pixel >> 24) & 0xff;

I have no experience with bitwise operators, but Google revealed that the 0xff notation is alpha-hex shorthand for fully transluscent. And the pixel >> 24 apparently moves the color data to the right 24 bits, but I don’t know what that means. No clue what & means either and what it does to the operands.

Could someone please explain what this line does?

0xff is hex for 255, that’s all, there’s nothing about it that inherently means “alpha”. This particular code is simple bitwise arithmetic for reading the fourth byte from the least significant, i.e. the leftmost byte in a 32-bit word.

If it’s treating it as an alpha, that implies ARGB encoding, or any other encoding that puts the alpha first.

Yeah, that’s what I figured out. It’s a shorthand for alpha as 0xAARRGGBB with the base 16 0-F I am assuming.

What exactly is it setting a equal to? I guess I’m asking what does & do with operands, why is the pixel being moved 24 bits, and why is it and 0xff operands to ‘&’?

‘&’ is the bitwise AND operator.
0xAARRGGBB & 0xff = 0xBB
( 0xAARRGGBB >> 8 ) & 0xff = 0xGG
( 0xAARRGGBB >> 16 ) & 0xff = 0xRR
( 0xAARRGGBB >> 24 ) & 0xff = 0xAA

It’s a way of getting the R, G, B and alpha values for a pixel.

Ah! That’s a little more clear.

How does 8 bits get you to green and 16 get you to red? I’ll guess that it’s no coincidence that there 8 bits in a byte.

8 gives you green, because green starts at the 8th bit (it’s address, if you will). >> shifts in bits, so to get red it’s >> 16 (3rd byte) and so on.

Interesting…

So, getRGB() must return an 0xAARRGGBB notation which you’d have to parse (for lack of a better word) to get the exact color data you want.

What is the 0xff for then? Is that to say I only want 2 bytes out of my 0xAARRGGBB? If I didn’t specify, would I get everything up to >> 24 as well?

Maybe you guys could help me with this.

I’m just screwing around with this code trying to work it, and at most angles it is to-the-pixel collision. At some angles though it is closer than bounding box, but there’s still a gap when it registers a collision. I’ll post my code.


import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashSet;


public class PixelPerfect extends JFrame implements KeyListener, Runnable {

	int x = 0, y = 0, xVel = 0, yVel = 0;
	HashSet<String> maskPlayer1, maskPlayer2;
	JPanel panel = new JPanel();
	BufferedImage b1, b2;
	
	@Override
	public void keyPressed(KeyEvent arg0) {
		
		if(arg0.getKeyCode() == KeyEvent.VK_RIGHT) {
			xVel = 3;
		}
		if(arg0.getKeyCode() == KeyEvent.VK_LEFT) {
			xVel = -3;
		}
		if(arg0.getKeyCode() == KeyEvent.VK_DOWN) {
			yVel = 3;
		}
		if(arg0.getKeyCode() == KeyEvent.VK_UP) {
			yVel = -3;
		}
	}

	@Override
	public void keyReleased(KeyEvent arg0) {
		
		xVel = 0;
		yVel = 0;
	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		
		
	}
	
	public void paint(Graphics g) {
		
		Graphics2D g2d = (Graphics2D)g;
		g2d.setColor(Color.white);
		g2d.fillRect(0,0,300,300);
		
		g2d.drawImage(b1.getSubimage(0, 0, 79, 77), x, y, 79, 77, null);
		g2d.drawImage(b2.getSubimage(0, 0, 67, 60), 200, 200, 67, 60, null);
	}


	public static void main(String[] args) {
		
		new Thread(new PixelPerfect()).start();
	}
	
	public PixelPerfect() {
		
				b1 = new BufferedImage(79, 77, BufferedImage.TYPE_INT_ARGB);
		b2 = new BufferedImage(67, 60, BufferedImage.TYPE_INT_ARGB);
			try {
				b1.createGraphics().drawImage(ImageIO.read(this.getClass().getResource("groudon.gif")),
						0,0,79,77,null);
				b2.createGraphics().drawImage(ImageIO.read(this.getClass().getResource("squirrel.png")),
					0,0,67,60,null);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
			setSize(300, 300);
		add(panel);
		setVisible(true);
		
		addKeyListener(this);
		setFocusable(true);
	}

	@Override
	public void run() {
		
		try {
			while(true) {
				
				update();
				repaint();
				
				Thread.sleep(17);
				
			}
		} catch(Exception ex) {
			
		}
	}

	private void update() {
		
		x += xVel;
		y += yVel;
		
		if(checkCollision()) {

			x -= xVel;
			y -= yVel;
		}
	}

	private boolean checkCollision() {
		
		// This method detects to see if the images overlap at all. If they do, collision is possible
				int ax1 = x;
				int ay1 = y;
				int ax2 = x + 79;
				int ay2 = y + 77;
				int bx1 = 200;
				int by1 = 200;
				int bx2 = 267;
				int by2 = 260;
				
				/*if(by2 < ay1 || ay2 < by1 || bx2 < ax1 || ax2 < bx1)
				{
					return false; // Collision is impossible.
				}
				else // Collision is possible.
				{*/
					// get the masks for both images
					maskPlayer1 = getMask(b1);
					maskPlayer2 = getMask(b2);
				
					maskPlayer1.retainAll(maskPlayer2);  // Check to see if any pixels in maskPlayer2 are the same as those in maskPlayer1
					
					if(maskPlayer1.size() > 0){  // if so, than there exists at least one pixel that is the same in both images, thus
						return true;
					}
					return false;	
				//}
	}

//returns a HashSet of strings that list all the pixels in an image that aren't transparent
	// the pixels contained in the HashSet follow the guideline of:
	// x,y where x is the absolute x position of the pixel and y is the absolute y position of the pixel
	public HashSet<String> getMask(BufferedImage img){
		
		String s = "";
		HashSet<String> mask = new HashSet<String>();
		BufferedImage image = img;

		int pixel, a;
		for(int i = 0; i < image.getWidth(); i++){ // for every (x,y) component in the given box, 
			for( int j = 0; j < image.getHeight(); j++){
		
				pixel = image.getRGB(i, j); // get the RGB value of the pixel
				a = (pixel >> 24) & 0xff;
		
				if(a != 0){  // if the alpha is not 0, it must be something other than transparent
					if(img == b1) {
						s = (x + i) + "," + (y + j);
						mask.add(s); // add the absolute x and absolute y coordinates
					}
					else {
						s = (200 + i) + "," + (200 + j);
						mask.add(s);
					}
				}
			}
		}
		
		return mask;  //return our set
	}

}

It’s sloppy, but I don’t care as I’m just messin’ around.

Here’s a screen of the near-collision.

These are fully-transparent pics.

Any ideas?

0xff is the mask used with the & operator to strip off all bits but the last 8 (0xff is binary 11111111). If you don’t mask, any bits to the left of the byte you’re looking for will be added in. For an int, shifting it by 24 then masking it is kind of redundant, but people write it that way anyway for clarity. Any shift smaller than that does need the mask.

http://en.wikipedia.org/wiki/Bitwise_operation has some okay examples for how bitwise arithmetic works.

This post explains how RGB works and this post explains everything that deals with bitwise operations :slight_smile:

Thanks ra4king, that was really helpful.

Still fiddling with the collision. Maybe it’s just how my move code works is why it seems like it isn’t colliding.

To extract the alpha value from an int that represents a pixel as 0xAARRGGBB there are two options.
(pixel >> 24) & 0xFF
or
pixel >>> 24

The >> operator is a signed shift, that means it “fills” the left side of the int with 1s if the number is negative i.e. if the leftmost bit is 1.

is the unsigned shift operator
e.g.
0xAARRGGBB >> 24 = 0xFFFFFFAA - if AA is bigger then 127, because then it starts with a 1
0xAARRGGBB >>> 24 = 0x000000AA
& 0xFF sets everything to 0 exept the rightmost 8 bits so (0xAARRGGBB >> 24) & 0xFF gives also 0x000000AA