import java.awt.*; import java.awt.event.*; import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D; import java.util.HashMap; import java.util.HashSet; import javax.swing.*; public class Game extends JPanel implements KeyListener, ActionListener { private int height, width; // the height and width of the screen private Timer t = new Timer(5, this); // the 't' variable makes sure that there is a initial delay before the same starts off private boolean first; //game state (starting/playing) private HashSet<String> keys = new HashSet<String>(); // pad private final int SPEED = 1; //the speed of the paddles private int padH = 10, padW = 40; // paddle width/height private int bottomPadX, topPadX; // these represent the top and the bottom paddles in the game private int inset = 30; // this helps determine the distance between the paddle // - and the top and bottom screen boundaries // ball private double ballX, ballY, velX = 1, velY = 1, ballSize = 20; //ball position, ball velocity, ball size // score private int scoreTop, scoreBottom; // keep track of game record public Game() { addKeyListener(this); // it helps to read the commands given through the keyboard setFocusable(true); // keylisterer knows that it needs to look for the movement through keys setFocusTraversalKeysEnabled(false); // since the argument is set to false, it moves the focus away from tab and shift keys first = true; // sets the game state to true to start playing t.setInitialDelay(100); // sets initial delay for the movement of the ball t.start(); // set the delay for every movement of the ball } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; // create an object for graphics (rectangles) height = getHeight(); // get game frame/screen size width = getWidth(); // initial positioning if (first) { bottomPadX = width / 2 - padW / 2; // setups for the paddles positions - in the middle of the screen topPadX = bottomPadX; ballX = width / 2 - ballSize / 2; // setups for the ball positions - in the middle of the screen ballY = height / 2 - ballSize / 2; first = false; // setup completed } // bottom pad Rectangle2D bottomPad = new Rectangle(bottomPadX, height - padH - inset, padW, padH); // creating the object for bottom paddle g2d.fill(bottomPad); // top pad Rectangle2D topPad = new Rectangle(topPadX, inset, padW, padH); // creating paddle object for the top paddle g2d.fill(topPad); // ball Ellipse2D ball = new Ellipse2D.Double(ballX, ballY, ballSize, ballSize); // creating the ball object for the game g2d.fill(ball); // scores String scoreB = "Bottom: " + new Integer(scoreBottom).toString(); // saving the score of the bottom paddle String scoreT = "Top: " + new Integer(scoreTop).toString(); // saving the score of the top paddle g2d.drawString(scoreB, 10, height / 2); // printing the score of the bottom paddle in the screen g2d.drawString(scoreT, width - 50, height / 2); // printing the score of the top paddle in the screen } @Override public void actionPerformed(ActionEvent e) { // side walls if (ballX < 0 || ballX > width - ballSize) { // making sure ball is horizontally within the frame (left&right) velX = -velX; // reverse the ball position if trying to go out } // top / down walls if (ballY < 0) { // similarly, for vertical position velY = -velY; // reverse the ball position vertically ++ scoreBottom; } if (ballY + ballSize > height) { // similarly, for the vertical position of bottom paddle velY = -velY; ++ scoreTop; // points are incremented if the paddle is missed by opponent } // bottom pad if (ballY + ballSize >= height - padH - inset && velY > 0) // similar to the previous parts if (ballX + ballSize >= bottomPadX && ballX <= bottomPadX + padW) velY = -velY; // top pad if (ballY <= padH + inset && velY < 0) if (ballX + ballSize >= topPadX && ballX <= topPadX + padW) velY = -velY; ballX += velX; ballY += velY; // pressed keys if (keys.size() == 1) { if (keys.contains("LEFT")) { // left key is pressed bottomPadX -= (bottomPadX > 0) ? SPEED : 0; // move the bottom paddle to the left } else if (keys.contains("RIGHT")) { // right key is pressed bottomPadX += (bottomPadX < width - padW) ? SPEED : 0; } } // AI double delta = ballX - topPadX; if (delta > 0) { // move right if ball is to the right of the paddle topPadX += (topPadX < width - padW) ? SPEED : 0; } else if (delta < 0) { // move left if ball is to the left of the paddle topPadX -= (topPadX > 0) ? SPEED : 0; } repaint(); } @Override public void keyTyped(KeyEvent e) {} @Override public void keyPressed(KeyEvent e) { int code = e.getKeyCode(); // get which key is pressed switch (code) { case KeyEvent.VK_LEFT: keys.add("LEFT"); break; case KeyEvent.VK_RIGHT: keys.add("RIGHT"); break; } } @Override public void keyReleased(KeyEvent e) { int code = e.getKeyCode(); // get which key is released switch (code) { case KeyEvent.VK_LEFT: keys.remove("LEFT"); break; case KeyEvent.VK_RIGHT: keys.remove("RIGHT"); break; } } }