I am coding a Java pong game that is almost complete except that the AI is acting quite oddly I am not sure why it's acting the way it does honestly.
It seems to move up and down rather quickly and has a tendency to appear to teleport and get stuck then suddenly teleport. Main class to start things:
public class Pong {
Board board = new Board();
public void frame() {
JFrame b = new JFrame("Pong");
b.setSize(905,705);
b.setLocation(300,60);
b.setResizable(false);
b.setVisible(true);
b.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
b.add(board);
}
public static void main(String[] args) {
Pong start = new Pong();
start.frame();
}
}
The board class:
public class Board extends JPanel {
GamePlay play = new GamePlay(0,0,900,900);
public Board(){
// addKeyListener((KeyListener) play.player);
addKeyListener((KeyListener) play);
setFocusable(true);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.black);
g2.fill(play.a);
g.setColor(Color.WHITE);
board(g);
g2.setColor(Color.white);
g2.fill(play.opponent.opponent);
g2.fill(play.ball.ball);
if(play.playerScore == 5){
g.setColor(Color.WHITE);
g.setFont(new Font("game over",Font.BOLD,20));
g.drawString("You win!", 300, 300);
g.drawString("press space bar to restart.", 300, 350);
}
if (play.opponentScore == 5){
g.setColor(Color.WHITE);
g.setFont(new Font("game over",Font.BOLD,20));
g.drawString("You lose!", 300, 300);
g.drawString("press space bar to restart.", 300, 350);
}
repaint();
}
public void board(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Stroke stroke1 = new BasicStroke(4f);
g2d.setColor(Color.white);
g2d.setStroke(stroke1);
g2d.drawRect(20, 50, 850, 600);
g2d.setColor(Color.white);
float[] dashingPattern2 = {10f, 4f};
Stroke stroke2 = new BasicStroke(4f, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER, 1.0f, dashingPattern2, 0.0f);
g2d.setStroke(stroke2);
g2d.drawLine(435, 50, 435, 650);
g.setFont(new Font("arial",Font.PLAIN,30));
g.drawString(""+play.playerScore, 20, 35);
g.drawString(""+play.opponentScore, 855, 35);
}
}
The GamePlay class is more or less just to make things run:
public class GamePlay extends JPanel implements ActionListener,KeyListener {
public int x,y,z,c;
public int playerScore = 0;
public int opponentScore = 0;
boolean over = false;
Rectangle a;
Opponent opponent = new Opponent(835,300,15,80);
Ball ball = new Ball(400,350,20,20);
public GamePlay(int x,int y,int z,int c){
this.x = x;
this.y = y;
this.z = z;
this.c = c;
a = new Rectangle(x, y, z, c);
timer.start();
}
public void collision(){
opponent.move();
opponent.getBallPos(ball.ball.y);
if(ball.ball.intersects(opponent.opponent)){
ball.right = false;
}
if(ball.ball.intersects(opponent.opponent)){
ball.right = false;
}
if(ball.ball.x >= 862){
playerScore = playerScore + 1;
}
if(ball.ball.x <= 4){
opponentScore = opponentScore + 1;
}
}
Timer timer = new Timer(5, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//opponent.move();
collision();
if(playerScore ==5 || opponentScore == 5){
over = true;
timer.stop();
}
//repaint the screen
if(ball.right == false){
//collision();
// opponent.move();
ball.move();
//repaint();
}
if(ball.right == true){
//collision();
//opponent.move();
ball.move();
//repaint();
}
}
});
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'actionPerformed'");
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE) {
if(over == true){
timer.start();
opponentScore = 0;
playerScore = 0;
opponent.opponent.x = 835;
opponent.opponent.y = 300;
over = false;
repaint();
}
}
}
@Override
public void keyReleased(KeyEvent arg0) {
}
@Override
public void keyTyped(KeyEvent arg0) {
}
}
The balls class (of course it controls the ball):
public class Ball extends JPanel{
public int ballXpos;
public int ballYpos;
public int ballWidth;
public int ballHeight;
boolean right = false;
boolean up = true;
Random random = new Random();
Rectangle ball;
public Ball(int ballXpos, int ballYpos, int ballWidth, int ballHeight){
this.ballXpos = ballXpos;
this.ballYpos = ballYpos;
this.ballWidth = ballWidth;
this.ballWidth = ballHeight;
up = random.nextBoolean();
right = random.nextBoolean();
ball = new Rectangle(ballXpos, ballYpos, ballWidth, ballHeight);
//move();
}
/* to make the ball move properly when hit by paddles have it boolean paddels up means the ball direction means up down moving paddle means ball goes down
* can be down using boolean true and false but maybe can be done with less lines of code using variebles
*
*/
public void move(){
if(right == false){
ball.x = ball.x - 1;
}
if(right == true){
ball.x = ball.x + 1;
}
if(up == true){
ball.y = ball.y - 1;
}
if(up == false){
ball.y = ball.y + 1;
}
if(ball.x >= 863){
ball.x = 400;
up = random.nextBoolean();
right = random.nextBoolean();
}
if(ball.x <= 3){
ball.x = 400;
up = random.nextBoolean();
right = random.nextBoolean();
}
if(ball.y <= 38){
up = false;
}
if(ball.y >= 630){
up = true;
}
}
}
And the AI class:
public class Opponent {
public int opponentXpos;
public int opponentYpos;
public int opponentWidth;
public int opponentHeight;
public int ballPos;
Rectangle opponent;
public Opponent(int opponentXpos, int opponentYpos, int opponentWidth, int opponentHeight){
this.opponentXpos = opponentXpos;
this.opponentYpos = opponentYpos;
this.opponentWidth = opponentWidth;
this.opponentWidth = opponentHeight;
opponent = new Rectangle(opponentXpos, opponentYpos, opponentWidth, opponentHeight);
}
public void move(){
if(opponent.y >= 570){
opponent.y = 570 ;
}
if(opponent.y <= 50){
opponent.y = 50;
}
if(opponent.y <= ballPos){
opponent.y = opponent.y + 1;
}
if(opponent.y >= ballPos){
opponent.y = opponent.y = - 1;
}
if(opponent.y == ballPos){
opponent.y = opponent.y;
}
}
public void getBallPos(int ball){
this.ballPos = ball;
}
}
I have tried to move around where I call for the opponents move method, I have negated the issue somewhat but cannot fix it completely.
I expect of course the paddle to move smoothly like the ball does and try to follow the ball rather than moving up and down the way it does.
Maybe I need to implement a separate action listener for the AI rather than using the one for the ball.
Issue is solved.
Int the opponent class change the movement into this.
In the GamePlay class change it like this adding another timer.