Search code examples
javaandroidartificial-intelligence2d-gamespong

Apply Speed to Unbeatable AI Paddle for Simple Pong Game


I have created a simple rendition of the classic Pong game on Android Studio for a college course. At this point, almost everything is ready to go, except for the fact that I created an unbeatable AI for the enemy paddle. I created the paddles and the ball with the default RectF class and change my AI paddle's position based on the ball's current position (I subtract/add by 65 because my paddles' lengths are 130 pixels and it centers the paddle compared to the ball). This essentially allows the enemy paddle to move at an infinite speed because it is matching the ball's speed/position (the ball speed increases with each new level). Here is that method:

public void AI(Paddle paddle) {
    RectF paddleRect = paddle.getRect();
    RectF ballRect = ball.getRect();
    if (ballRect.left >= 65  && ballRect.right <= screenX - 65) {
        paddleRect.left = (ballRect.left - 65);
        paddleRect.right = (ballRect.right + 65);
    }
    if (ballRect.left < 65) {
        paddleRect.left = 0;
        paddleRect.right = 130;
    }
    if (ballRect.right > screenX - 65) {
        paddleRect.left = screenX - 130;
        paddleRect.right = screenX;
    }
}

For reference, here are the relevant parts of my Paddle class:

public Paddle(float screenX, float screenY, float xPos, float yPos, int defaultSpeed){
    length = 130;
    height = 30;
    paddleSpeed = defaultSpeed;
    // Start paddle in the center of the screen
    x = (screenX / 2) - 65;
    xBound = screenX;
    // Create the rectangle
    rect = new RectF(x, yPos, x + length, yPos + height);
}

// Set the movement of the paddle if it is going left, right or nowhere
public void setMovementState(int state) {
    paddleMoving = state;
}

// Updates paddles' position
public void update(long fps){
    if(x > 0 && paddleMoving == LEFT){
        x = x - (paddleSpeed / fps);
    }
    if(x < (xBound - 130) && paddleMoving == RIGHT){
        x = x + (paddleSpeed / fps);
    }
    rect.left = x;
    rect.right = x + length;
}

The fps in the update(long fps) method above is passed through from the run() method in my View class:

public void run() {
    while (playing) {
        // Capture the current time in milliseconds
        startTime = System.currentTimeMillis();
        // Update & draw the frame
        if (!paused) {
            onUpdate();
        }
        draw();
        // Calculate the fps this frame
        thisTime = System.currentTimeMillis() - startTime;
        if (thisTime >= 1) {
            fps = 1000 / thisTime;
        }
    }
}

My paddles and ball constantly update in my onUpdate() method in the View class.

public void onUpdate() {
    // Update objects' positions
    paddle1.update(fps);
    ball.update(fps);
    AI(paddle2);
}

How can I attach a speed limit to my AI paddle using the paddle speed I already define for each new paddle? I've already tried modifying the AI(Paddle paddle) method to incorporate +/- (paddleSpeed / fps) and it didn't affect the paddle seemingly at all. Maybe I just implemented it wrong, but any help would be fantastic!


Solution

  • To make the AI move the paddle at a steady rate rather than jumping to the correct spot, just try to make the middle of the paddle line up with the middle of the ball:

    public void AI(Paddle paddle) {
        RectF paddleRect = paddle.getRect();
        RectF ballRect = ball.getRect();
        float ballCenter = (ballRect.left + ballRect.right) / 2;
        float paddleCenter = (paddleRect.left + paddleRect.right) / 2;
        if (ballCenter < paddleCenter) {
            setMovementState(LEFT);
        }
        else {
            setMovementState(RIGHT);
        }
    }
    

    and then after you call AI(paddle2) inside of onUpdate, call paddle2.update(fps). This way you aren't repeating yourself with the drawing code. You will notice that the AI paddle may not do perfectly if the ball is much faster than the paddle. In this case you can use math to anticipate where the ball will end up and work on getting there.