import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyListener; import java.awt.event.KeyEvent; import java.awt.Graphics2D; // Used for anti-aliasing import java.awt.RenderingHints; // Used for anti-aliasing import javax.swing.JFrame; import javax.swing.Timer; import javax.swing.ImageIcon; public class GraphicsMoveAndCollideWithKeyboardAndJFrame extends JFrame implements ActionListener, KeyListener { private Timer timer; Font font = new Font("Helvetica", Font.BOLD, 14); FontMetrics metrics = this.getFontMetrics(font); // The benefit of using the 'ImageIcon' class over the 'Toolkit' class // is that unlike the 'Toolkit' class, which doesn't actually load the // image until it is displayed, the 'ImageIcon' class fully loads the // image when the object is created, making it possible to immediately // determine and use the dimensions of the image private Image apple = new ImageIcon("data_files/apple.png").getImage(); private Image alien = new ImageIcon("data_files/alien.png").getImage(); private int width = 400, height = 250; private boolean collision, pressedLeft, pressedRight, pressedUp, pressedDown; private int appleX, appleY, alienX, alienY; public static void main(String[] args) { // Create an instance of the 'GraphicsMoveAndCollideWithKeyboardAndJFrame' class new GraphicsMoveAndCollideWithKeyboardAndJFrame(); } // Constructor public GraphicsMoveAndCollideWithKeyboardAndJFrame() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(width, height); setTitle("Collision Detection on a JFrame"); setLocationRelativeTo(null); setResizable(false); setVisible(true); setFocusable(true); addKeyListener(this); collision = false; appleX = 100; appleY = 120; alienX = width; alienY = 80; // Set and start a new Swing timer to fire every 10 milliseconds // (after an initial delay of 500 milliseconds); this timer, // along with the distance (number of pixels) that the apple and // alien move with each cycle, controls how fast the objects move // on the frame timer = new Timer(10, this); timer.setInitialDelay(500); timer.start(); } // This method will be called whenever the user presses a key, as well // as automatically by the timer (necessary for the alien to move // across the frame) public void actionPerformed(ActionEvent e) { if (pressedLeft && appleX > 4) appleX -= 2; if (pressedRight && appleX < width - 14) appleX += 2; if (pressedUp && appleY > 24) appleY -= 2; if (pressedDown && appleY < height - 14) appleY += 2; if (alienX < 0) alienX = width; alienX -= 1; repaint(); checkCollisions(); } // Create a rectangle around the apple, and another rectangle around // the alien; then check to see if the two rectangles have collided public void checkCollisions() { Rectangle rApple = new Rectangle(appleX, appleY, apple.getWidth(null), apple.getHeight(null)); Rectangle rAlien = new Rectangle(alienX, alienY, alien.getWidth(null), alien.getHeight(null)); if (rApple.intersects(rAlien)) collision = true; } // Check to see if the user has PRESSED an arrow key public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); if (key == KeyEvent.VK_LEFT) pressedLeft = true; if (key == KeyEvent.VK_RIGHT) pressedRight = true; if (key == KeyEvent.VK_UP) pressedUp = true; if (key == KeyEvent.VK_DOWN) pressedDown = true; } // Check to see if the user has RELEASED an arrow key public void keyReleased(KeyEvent e) { int key = e.getKeyCode(); if (key == KeyEvent.VK_LEFT) pressedLeft = false; if (key == KeyEvent.VK_RIGHT) pressedRight = false; if (key == KeyEvent.VK_UP) pressedUp = false; if (key == KeyEvent.VK_DOWN) pressedDown = false; } // This empty method is needed to avoid an Eclipse error message above public void keyTyped(KeyEvent e) { } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { // This line causes graphics and text to be rendered with anti-aliasing // turned on, making the overall display look smoother and cleaner ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if (!collision) { // Draw/Redraw the frame background so that previous instances of // the graphics are not left behind and visible on the frame g.setColor(Color.BLACK); g.fillRect(0, 0, width, height); // Draw/Redraw the apple and the alien g.drawImage(apple, appleX, appleY, this); g.drawImage(alien, alienX, alienY, this); } else { // A collision has occurred, so finish the program timer.stop(); String message = "Collision Detected!"; // Center the "collision" message in the frame g.setColor(Color.white); g.setFont(font); g.drawString(message, (getWidth() - metrics.stringWidth(message)) / 2, getHeight() / 2); } // This line synchronizes the graphics state by flushing buffers containing // graphics events and forcing the frame drawing to happen now; otherwise, // it can sometimes take a few extra milliseconds for the drawing to take // place, which can result in jerky graphics movement; this line ensures // that the display is up-to-date; it is useful for animation, since it // reduces or eliminates flickering Toolkit.getDefaultToolkit().sync(); } }