Tae-young Kim
Tae-young Kim

Reputation: 1

Java Pong Game Help. Weird bug regarding paddles not responding to my key movements and pause button also not working

Ok, so for some reason, when player 1's paddle is going down at the very bottom of the screen, the game starts spazzing out. Both players paddles freeze up and stop responding to keyboard input, and the pause button stops working as well. However, the ball keeps moving and bounces off the walls and paddles as if nothing has happened. I first thought it was a problem with the panel losing focus, and added a focusListener so that if the panel loses focus it will immediately grab the focus again. However that did not fix this strange bug. Then I thought something was wrong with my KeyListener so after doing research online, changed to using keybindings because they were apparently better. However, even that didn't work, and now I'm stumped and need your help. Also, before I added two player functionality my pong game was a single player game, and did not have this bug. However, the single racket was controlled with the up and down keys. I know it's a lot of code, but any help is greatly appreciated. Thank you

Main Class

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TableTennis
{
    private final static int WIDTH = 700, HEIGHT = 500;
    private JFrame window = new JFrame();
    //Constructor
    public TableTennis()
    {
        window.setTitle("Table Tennis");
        window.setSize(WIDTH,HEIGHT);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setResizable(false);
        //Centers the window on the screen
        window.setLocationRelativeTo(null);
        PongPanel panel = new PongPanel();
        Container pane = window.getContentPane();
        pane.add(panel);
        /*panel.addFocusListener(new FocusAdapter()
        {
            public void focusLost(FocusEvent ev)
            {
                panel.requestFocus();
            }
        });*/
        panel.setFocusable(true);
        panel.requestFocusInWindow();
        window.setVisible(true);
    }//end of constructor
    public static void main(String [] args)
    {
        new TableTennis();
    }//end of main
}//end of class

PongPanel Class

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.sound.sampled.*;
import java.net.*;
//public class PongPanel extends JPanel implements KeyListener, ActionListener, FocusListener
public class PongPanel extends JPanel implements ActionListener, FocusListener
{
    //Instance variables
    private int playerScore, player2Score, numberOfTimesResumed, numberOfTimesPaused;
    private HumanRacket r1;
    private Ball b1;
    private ComputerRacket r2;
    private HumanRacket r3;
    private boolean gameRunning, playerWin, player2Win, gamePaused, onePlayerGame, twoPlayerGame;
    private Timer timer;
    private Font font;
    private int ballBounces;
    private JButton playerVsPlayerButton, playerVsComputerButton;
    //Constructor;
    public PongPanel()
    {
        playerScore = 0;
        ballBounces = 0;
        player2Score = 0;
        gameRunning = false;
        playerWin = false;
        player2Win = false;
        gamePaused = false;
        font = new Font("Courier", Font.BOLD, 16);
        setBackground(Color.black);
        r1 = new HumanRacket(20, 210);
        b1 = new Ball();
        r2 = new ComputerRacket(b1);
        r3 = new HumanRacket(660,210);
        playerVsPlayerButton = new JButton("Two Player");
        playerVsPlayerButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                twoPlayerGame = true;
                gameRunning = true;
            }
        });
        playerVsComputerButton = new JButton("One Player");
        playerVsComputerButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                onePlayerGame = true;
                gameRunning = true;
            }
        });
        playerVsPlayerButton.setBackground(Color.WHITE);
        playerVsComputerButton.setBackground(Color.WHITE);
        playerVsPlayerButton.setFocusable(false);
        playerVsComputerButton.setFocusable(false);
        timer = new Timer(33, this);
        timer.start();
        //this.addKeyListener(this);
        this.addFocusListener(this);
        this.add(playerVsPlayerButton);
        this.add(playerVsComputerButton);
        //Key Bindings for keys that are pressed
        this.addKeyBindingPressed(KeyEvent.VK_W, "Player 1 paddle move up", (evt) ->{
            r1.setUpAccel(true);
        });
        this.addKeyBindingPressed(KeyEvent.VK_S, "Player 1 paddle move down", (evt) -> {
            r1.setDownAccel(true);
        });
        this.addKeyBindingPressed(KeyEvent.VK_P, "Pause Game", (evt) ->{
            if(!gamePaused && gameRunning) {
                gamePaused = true;
                this.pause();
                numberOfTimesPaused++;
                repaint();
            }//end of if
        });
        this.addKeyBindingPressed(KeyEvent.VK_R, "Resume Game", (evt) -> {
            if(numberOfTimesResumed < numberOfTimesPaused)
            {
                this.resume();
                gamePaused = false;
                numberOfTimesResumed++;
            }//end of if
        });
        this.addKeyBindingPressed(KeyEvent.VK_UP, "Player 2 paddle move up", (evt) ->{
            r3.setUpAccel(true);
        });
        this.addKeyBindingPressed(KeyEvent.VK_DOWN, "Player 2 paddle move down", (evt) ->{
            r3.setDownAccel(true);
        });
        //Key bindings for keys that are released
        this.addKeyBindingReleased(KeyEvent.VK_W, "Player 1 paddle stop moving up", (evt) ->{
            r1.setUpAccel(false);
        });
        this.addKeyBindingReleased(KeyEvent.VK_S, "Player 1 paddle stop moving down", (evt) ->{
            r1.setDownAccel(false);
        });
        this.addKeyBindingReleased(KeyEvent.VK_UP, "Player 2 paddle stop moving up", (evt) ->{
            r3.setUpAccel(false);
        });
        this.addKeyBindingReleased(KeyEvent.VK_DOWN, "Player 2 paddle stop moving down", (evt) ->{
            r3.setDownAccel(false);
        });
    }//end of constructor
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        if(gameRunning)
        {
            this.remove(playerVsPlayerButton);
            this.remove(playerVsComputerButton);
        }//end of if
        if(gameRunning == false && playerWin == false && player2Win == false)
        {
            g.setColor(Color.white);
            g.setFont(font);
            g.drawString("Table Tennis ", 300, 100);
            g.drawString("Score 5 to win", 290, 130);
            g.drawString("Player 1 uses W and S keys to move", 190, 160);
            g.drawString("Player 2 uses up and down keys to move", 200, 190);
            g.drawString("Press P to Pause and R to Resume", 210, 220);
            g.drawString("Created by: Tae-young Kim ", 0, 465);
        }//end of if
        else if(playerWin == true)
        {
            if(onePlayerGame)
            {
                g.setColor(Color.white);
                g.setFont(font);
                g.drawString("You Win!", 315, 100);
            }
            else if(twoPlayerGame)
            {
                g.setColor(Color.white);
                g.setFont(font);
                g.drawString("Player 1 Wins!", 310, 100);
            }
        }//end of if
        else if(player2Win == true)
        {
            if(onePlayerGame)
            {
                g.setColor(Color.white);
                g.setFont(font);
                g.drawString("Game Over", 315, 100);
            }
            else if(twoPlayerGame)
            {
                g.setColor(Color.white);
                g.setFont(font);
                g.drawString("Player 2 Wins", 310, 100);
            }
        }//end of if
        else if(gamePaused)
        {
            g.setColor(Color.white);
            g.setFont(font);
            g.drawString("Game Paused", 310, 100);
            g.drawString("Press R to resume", 300, 130);
        }//end of else if
        //Prints out player score
        g.setColor(Color.white);
        g.setFont(font);
        g.drawString(String.valueOf(playerScore), 50 , 40);
        g.drawString(String.valueOf(player2Score), 640, 40);
        r1.paint(g);
        b1.paint(g);
        if(onePlayerGame)
        {
            r2.paint(g);
        }
        else if(twoPlayerGame)
        {
            r3.paint(g);
        }
    }//end of paintComponent method
    /*public void keyPressed(KeyEvent e)
    {
        if(e.getKeyCode() == KeyEvent.VK_UP)
        {
            r3.setUpAccel(true);
        }//end of if
        if(e.getKeyCode() == KeyEvent.VK_DOWN)
        {
            r3.setDownAccel(true);
        }//end of else if
        if(e.getKeyCode() == KeyEvent.VK_P)
        {
            if(!gamePaused && gameRunning) {
                gamePaused = true;
                this.pause();
                numberOfTimesPaused++;
                repaint();
            }//end of if
        }//end of else if
        if(e.getKeyCode() == KeyEvent.VK_R)
        {
            if(numberOfTimesResumed < numberOfTimesPaused)
            {
                this.resume();
                gamePaused = false;
                numberOfTimesResumed++;
            }//end of if
        }//end of else if
        if(e.getKeyCode() == KeyEvent.VK_W)
        {
            r1.setUpAccel(true);
        }
        if(e.getKeyCode() == KeyEvent.VK_S)
        {
            r1.setDownAccel(true);
        }
    }//end of keyPressed method
    @Override
    public void keyReleased(KeyEvent e)
    {
        if(e.getKeyCode() == KeyEvent.VK_UP)
        {
            r3.setUpAccel(false);
        }//end of if
        if(e.getKeyCode() == KeyEvent.VK_DOWN)
        {
            r3.setDownAccel(false);
        }//end of else if
        if(e.getKeyCode() == KeyEvent.VK_W)
        {
            r1.setUpAccel(false);
        }
        if(e.getKeyCode() == KeyEvent.VK_S)
        {
            r1.setDownAccel(false);
        }
    }//end of keyReleased method
    public void keyTyped(KeyEvent e)
    {
        //Method not useful for this program
    }//end of keyTyped method*/
    public void actionPerformed(ActionEvent e)
    {
        if(gameRunning)
        {
            r1.move();
            b1.move();
            if(onePlayerGame)
            {
                r2.move();
            }
            else if(twoPlayerGame)
            {
                r3.move();
            }
            b1.increaseSpeed(ballBounces);
            this.checkBallRacketCollision();
            this.addScore();
            this.checkForWin();
            repaint();
            this.endGameIfOver();
        }//end of if
    }//end of actionPerformed method
    public void checkBallRacketCollision()
    {
        if(b1.getXPos() <= r1.getX() + 1)
        {
            if( b1.getYPos() >= r1.getY() && b1.getYPos() <= r1.getY() + 80)
            {
                b1.setXVel(b1.getXVel() * -1);
                ballBounces++;
                playBounceSound();
            }//end of if
        }//end of if
        if(onePlayerGame)
        {
            if(b1.getXPos() +15 >= r2.getX())
            {
                if((b1.getYPos() + 7) >= r2.getY() && b1.getYPos() <= r2.getY() + 80)
                {
                    b1.setXVel(b1.getXVel() * -1);
                    ballBounces++;
                    playBounceSound();
                }//end of if
            }//end of if
        }
        else if(twoPlayerGame)
        {
            if(b1.getXPos() + 15 >= r3.getX())
            {
                if((b1.getYPos() + 7) >= r3.getY() && b1.getYPos() <= r3.getY() + 80)
                {
                    b1.setXVel(b1.getXVel() * -1);
                    ballBounces++;
                    playBounceSound();
                }
            }
        }
    }//end of checkBallRacketCollsion method
    public void addScore()
    {
        if(b1.getXPos() < 1)
        {
            player2Score++;
            playScoreSound();
            b1.setXPos(350);
            b1.setYPos(250);
            b1.generateRandomXVelocity();
            b1.generateRandomYVelocity();
            this.pause();
            this.resumeDelay();
            b1.setSpeedIncreaseBoolean(true);
            ballBounces = 0;
        }//end of if
        //If ball is behind racket end the round
        else if(b1.getXPos() > 0 && b1.getXPos() < r1.getX() -10)
        {
            if(b1.getYPos() > r1.getY() && b1.getYPos() < (r1.getY() + 80))
            {
                player2Score++;
                playScoreSound();
                b1.setXPos(350);
                b1.setYPos(250);
                b1.generateRandomXVelocity();
                b1.generateRandomYVelocity();
                this.pause();
                this.resumeDelay();
                b1.setSpeedIncreaseBoolean(true);
                ballBounces = 0;
            }//end of if
        }//end of else if
        if(b1.getXPos() > 699)
        {
            playerScore++;
            playScoreSound();
            b1.setXPos(350);
            b1.setYPos(250);
            b1.generateRandomXVelocity();
            b1.generateRandomYVelocity();
            this.pause();
            this.resumeDelay();
            b1.setSpeedIncreaseBoolean(true);
            ballBounces = 0;
        }//end of if
        //If ball is behind computer racket end the round
        if(onePlayerGame)
        {
            if(b1.getXPos() > (r2.getX() + 10) && b1.getXPos() < 700)
        {
            if(b1.getYPos() > r2.getY() && b1.getYPos() < (r2.getY() + 80))
            {
                playerScore++;
                playScoreSound();
                b1.setXPos(350);
                b1.setYPos(250);
                b1.generateRandomXVelocity();
                b1.generateRandomYVelocity();
                this.pause();
                this.resumeDelay();
                b1.setSpeedIncreaseBoolean(true);
                ballBounces = 0;
            }//end of if
        }//end of else if
        }
        if(twoPlayerGame)
        {
            if(b1.getXPos() > (r3.getX() + 10) && b1.getXPos() < 700)
            {
                if(b1.getYPos() > r3.getY() && b1.getYPos() < (r3.getY() + 80))
                {
                    playerScore++;
                    playScoreSound();
                    b1.setXPos(350);
                    b1.setYPos(250);
                    b1.generateRandomXVelocity();
                    b1.generateRandomYVelocity();
                    this.pause();
                    this.resumeDelay();
                    b1.setSpeedIncreaseBoolean(true);
                    ballBounces = 0;
                }
            }
        }
    }//end of addScore method
    public void pause()
    {
        this.timer.stop();
    }//end of pause method
    public void resumeDelay()
    {
        this.timer = new Timer(33,this);
        timer.setInitialDelay(1500);
        timer.start();
    }//end of resume method
    public void resume()
    {
        this.timer = new Timer(33,this);
        timer.start();
    }//end of resume
    public void checkForWin()
    {
        if(playerScore == 5)
        {
            playerWin = true;
            gameRunning = false;
        }//end of if
        else if(player2Score == 5)
        {
            player2Win = true;
            gameRunning = false;
        }//end of if
    }//end of checkForWin method
    public void endGameIfOver()
    {
        if(playerWin || player2Win)
        {
            this.timer.stop();
        }//end of if
    }//end of endGameIfOver method
    public void playBounceSound()
    {
        try {
            URL soundURL1 = getClass().getClassLoader().getResource("audio/pong sound effect 2.wav");
            AudioInputStream ais = AudioSystem.getAudioInputStream(soundURL1);
            Clip clip = AudioSystem.getClip();
            clip.open(ais);
            clip.start();
        } catch(Exception ex) {
            System.out.println("Error with playing bounce sound.");
            ex.printStackTrace();
        }
    }//end of playBounceSound method
    public void playScoreSound()
    {
        try
        {
            URL soundURL2 = getClass().getClassLoader().getResource("audio/Pong Sound effect 1.wav");
            AudioInputStream ais2 = AudioSystem.getAudioInputStream(soundURL2);
            Clip clip1 = AudioSystem.getClip();
            clip1.open(ais2);
            clip1.start();
        }//end of try
        catch(Exception e)
        {
            System.out.println("Error with playing score sound.");
            e.printStackTrace();
        }//end of catch
    }//end of playScoreSound method
    public void focusGained(FocusEvent e)
    {

    }
    @Override
    public void focusLost(FocusEvent e) {
        this.requestFocusInWindow();
    }
    public void addKeyBindingPressed(int keyCode, String description, ActionListener action)
    {
        InputMap im = this.getInputMap(this.WHEN_IN_FOCUSED_WINDOW);
        ActionMap am = this.getActionMap();
        im.put(KeyStroke.getKeyStroke(keyCode, 0, false), description);
        am.put(description, new AbstractAction()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                action.actionPerformed(e);
            }
        });
    }
    public void addKeyBindingReleased(int keyCode1, String description1, ActionListener action1)
    {
        InputMap im1 = this.getInputMap(this.WHEN_IN_FOCUSED_WINDOW);
        ActionMap am1 = this.getActionMap();
        im1.put(KeyStroke.getKeyStroke(keyCode1,0,true), description1);
        am1.put(description1, new AbstractAction()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                action1.actionPerformed(e);
            }
        });
    }
}//end of PongPanel class

Ball Class

import javax.swing.*;
import java.awt.*;
import java.util.*;
public class Ball
{
    private int x, y, xVel, yVel;
    private boolean speedIncrease;
    public Ball()
    {
        speedIncrease = true;
        x = 350;
        y = 250;
        xVel = generateRandomXVelocity();
        yVel = generateRandomYVelocity();
    }//end of Ball constructor
    public void paint(Graphics g)
    {
        g.setColor(Color.white);
        g.fillOval(x,y,15,15);
    }//end of paint method
    public void move()
    {
        x += xVel;
        y += yVel;
        if(y < 10)
        {
            yVel *= -1;
        }//end of if
        else if(y > 460)
        {
            yVel *= -1;
        }//end of if
    }//end of move method
    public int getXPos()
    {
        return x;
    }//end of getXPos method
    public int getYPos()
    {
        return y;
    }//end of getYPos method
    public void setXVel(int xVelocity)
    {
        xVel = xVelocity;
    }//end of setXVel method
    public int getXVel()
    {
        return xVel;
    }//end of getXVel method
    public int getYVel()
    {
        return yVel;
    }//end of getYVel method
    public int generateRandomXVelocity()
    {
        Random generator = new Random();
        xVel = (generator.nextInt(2) + 6) * getRandomDirection();
        return xVel;
    }//end of generateRandomXVelocity method
    public int generateRandomYVelocity()
    {
        Random generator = new Random();
        yVel = generator.nextInt(2) + 6;
        return yVel;
    }//end of generateRandomYVelocity method
    public int getRandomDirection()
    {
        Random generator = new Random();
        int rand = generator.nextInt(2);
        if(rand == 0)
        {
            return 1;
        }//end of if
        else
        {
            return -1;
        }//end of else
    }//end of getRandomDirection method
    public void setXPos(int xPosition)
    {
        x = xPosition;
    }//end of setXPos method
    public void setYPos(int yPosition)
    {
        y = yPosition;
    }//end of setYPos method
    public void increaseSpeed(int ballBounces)
    {
        if(ballBounces == 3 && speedIncrease)
        {
            if(xVel > 0 && yVel > 0)
            {
                xVel+=3;
                yVel+=3;
                speedIncrease = false;
            }//end of if
            else if(xVel >0 && yVel < 0)
            {
                xVel+=3;
                yVel-=3;
                speedIncrease = false;
            }//end of else if
            else if(xVel <0 && yVel > 0)
            {
                xVel-=3;
                yVel+=3;
                speedIncrease = false;
            }//end of else if
            else
            {
                xVel-=3;
                yVel-=3;
                speedIncrease = false;
            }//end of else
        }//end of if
    }//end of increaseSpeed
    public void setSpeedIncreaseBoolean(boolean incomingInput)
    {
        speedIncrease = incomingInput;
    }//end of setSpeedIncreaseBoolean method
}//end of class

Racket Interface

import java.awt.*;
public interface Racket
{
    public void paint(Graphics g);
    public void move();
    public int getY();
}//end of interface

HumanRacket Class

import java.awt.*;
public class HumanRacket implements Racket
{
    //Instance variables
    private final double GRAVITY = 0.95;
    private int x,y;
    private double yVel;
    private boolean upAccel, downAccel;
    //Constructor
    public HumanRacket(int xLoc, int yLoc)
    {
        x = xLoc;
        y = yLoc;
        yVel = 0;
        upAccel = false;
        downAccel = false;
    }//end of constructor
    //Methods
    public void paint(Graphics g)
    {
        g.setColor(Color.white);
        g.fillRect(x,y,1,80);
    }//end of draw method
    public void move()
    {
        if(upAccel)
        {
            yVel -= 4;
            //Caps the speed at a certain point
            if(yVel < -12)
            {
                yVel = -12;
            }//end of if
        }//end of if
        else if(downAccel)
        {
            yVel += 4;
            //Caps the speed at a certain point
            if(yVel > 12)
            {
                yVel = 12;
            }//end of if
        }//end of else if
        else if(!upAccel && !downAccel)
        {
            yVel *= GRAVITY;
        }//end of else if
        y += yVel;
        //Prevents racket from leaving screen
        if(y > 390)
        {
            y = 390;
        }//end of if
        else if(y < 0)
        {
            y = 0;
        }//end of else if
    }//end of move method
    public void setUpAccel(boolean input)
    {
        upAccel = input;
    }//end of setUpAccel method
    public void setDownAccel(boolean input)
    {
        downAccel = input;
    }//end of setDownAccel method
    public int getY()
    {
        return y;
    }//end of getY accessor method
    public int getX()
    {
        return x;
    }//end of getX accessor method
}//end of class

ComputerRacket Class

import java.awt.*;
import javax.swing.*;
import java.util.*;
public class ComputerRacket implements Racket
{
    private int x, y;
    private double yVel;
    private int HALFWAY_POINT = 350;
    Random generator;
    Ball b1;
    public ComputerRacket(Ball whiteBall)
    {
        x = 660;
        y = 210;
        b1 = whiteBall;
        generator = new Random();
        yVel = 0;
    }//end of constructor
    public void paint(Graphics g)
    {
        g.setColor(Color.white);
        //g.fillRect(x,y,20,80);
        g.fillRect(x,y,1,80);
    }//end of paint method
    public void move()
    {
        this.setYVel(Math.abs(b1.getYVel()));
        int randomelyGeneratedNum = generateRandomNumber();
        if(b1.getXPos() >= HALFWAY_POINT)
        {
            if(randomelyGeneratedNum == 0 || randomelyGeneratedNum == 1 || randomelyGeneratedNum == 2)
            {
                if( b1.getYPos() > y + 40)
                {
                    y += yVel;
                }//end of if
                else
                {
                    y -= yVel;
                }//end of else
            }//end of if
            else if(randomelyGeneratedNum == 3)//Overcorrect
            {
                if(b1.getYPos() > y + 40)
                {

                    y += yVel + 2;
                }//end of if
                else
                {
                    y -= yVel + 2;
                }//end of else if
            }//end of else if
            else//Undercorrect
            {
                if(b1.getYPos() > y + 40)
                {
                    y += yVel - 2;
                }//end of if
                else
                {
                    y -= yVel - 2;
                }//end of else
            }//end of else
        }//end of if
        //Move around with ball but slightly slower
        else
        {
            if(b1.getYPos() > y )
            {
                y += 3;
            }//end of if
            else
            {
                y -= 3;
            }//end of else
        }//end of else
        //Prevents racket from leaving screen
        if(y > 390)
        {
            y = 390;
        }//end of if
        else if(y < 0)
        {
            y = 0;
        }//end of else if
    }//end of move method
    public int getY()
    {
        return y;
    }//end of getY method
    public int getX()
    {
        return x;
    }//end of getX method
    public int generateRandomNumber()
    {
        int randomNumber = 0;
        randomNumber = generator.nextInt(5);
        return randomNumber;
    }//end of generateError
    public void setYVel(int ballSpeed)
    {
        //yVel = ballSpeed - 0.9;
        yVel = ballSpeed * 0.85;
    }//end of setYVel method
}//end of class

Upvotes: 0

Views: 338

Answers (2)

Tae-young Kim
Tae-young Kim

Reputation: 1

Okay, the reason why it worked on my windows laptop but not on my Mac is because of mac's secondary keys. When I would hold down s, instead of repeatedly typing s it would instead pop up a menu that would contain s with accent and etc. It was messing with my keybindings so I fixed it by disabling it in the terminal This was what I entered: Defaults write -g ApplePressAndHoldEnabled -bool false

Upvotes: 0

Krishnanshu Gupta
Krishnanshu Gupta

Reputation: 174

Don't know what you mean. I tried your code in eclipse and it works fine for me for 1 Player and 2 Player. The only problem is that the ball goes under the screen. To fix this, you have to change the bottom coordinate check pixel position from 460 to 440.

public void move()
{
    x += xVel;
    y += yVel;
    if(y < 10)
    {
        yVel *= -1;
    }//end of if
    else if(y > 460)//here make this 440 from 460
    {
        yVel *= -1;
    }//end of if
}//end of move method

Upvotes: 0

Related Questions