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.
public void move(int ballY){
if(opponent.y >= 566){
opponent.y = 566 ;
}
if(opponent.y <= 50){
opponent.y = 50;
}
if (opponent.y < ballY) {
down = true;
up = false;
opponent.y += 3;
} else if (opponent.y > ballY) {
down = false;
up = true;
opponent.y -= 3;
}
In the GamePlay class change it like this adding another timer.
Timer timer2 = new Timer(17, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
opponent.move(ball.ball.y);
collision();
}
});