2
\$\begingroup\$

I'm trying to make an ai so the paddles will move to position before the ball reaches it. I'm not sure how to go about it in this case. Here's the game http://cssdeck.com/labs/ping-pong-game-tutorial-with-html5-canvas-and-sounds

// Function to increase speed after every 5 points
function increaseSpd() {
    if(points % 4 == 0) {
        if(Math.abs(ball.vx) < 15) {
            ball.vx += (ball.vx < 0) ? -1 : 1;
            ball.vy += (ball.vy < 0) ? -2 : 2;
        }
    }
}

// Track the position of mouse cursor
function trackPosition(e) {
    mouse.x = e.pageX;
    mouse.y = e.pageY;
}

// Function to update positions, score and everything.
// Basically, the main game logic is defined here
function update() {

    // Update scores
    updateScore(); 

    // Move the paddles on mouse move
    if(mouse.x && mouse.y) {
        for(var i = 1; i < paddles.length; i++) {
            p = paddles[i];
            p.x = mouse.x - p.w/2;
        }       
    }

    // Move the ball
    ball.x += ball.vx;
    ball.y += ball.vy;

    // Collision with paddles
    p1 = paddles[1];
    p2 = paddles[2];

    // If the ball strikes with paddles,
    // invert the y-velocity vector of ball,
    // increment the points, play the collision sound,
    // save collision's position so that sparks can be
    // emitted from that position, set the flag variable,
    // and change the multiplier
    if(collides(ball, p1)) {
        collideAction(ball, p1);
    }


    else if(collides(ball, p2)) {
        collideAction(ball, p2);
    } 

    else {
        // Collide with walls, If the ball hits the top/bottom,
        // walls, run gameOver() function
        if(ball.y + ball.r > H) {
            ball.y = H - ball.r;
            gameOver();
        } 

        else if(ball.y < 0) {
            ball.y = ball.r;
            gameOver();
        }

        // If ball strikes the vertical walls, invert the 
        // x-velocity vector of ball
        if(ball.x + ball.r > W) {
            ball.vx = -ball.vx;
            ball.x = W - ball.r;
        }

        else if(ball.x -ball.r < 0) {
            ball.vx = -ball.vx;
            ball.x = ball.r;
        }
    }



    // If flag is set, push the particles
    if(flag == 1) { 
        for(var k = 0; k < particlesCount; k++) {
            particles.push(new createParticles(particlePos.x, particlePos.y, multiplier));
        }
    }   

    // Emit particles/sparks
    emitParticles();

    // reset flag
    flag = 0;
}

//Function to check collision between ball and one of
//the paddles
function collides(b, p) {
    if(b.x + ball.r >= p.x && b.x - ball.r <=p.x + p.w) {
        if(b.y >= (p.y - p.h) && p.y > 0){
            paddleHit = 1;
            return true;
        }

        else if(b.y <= p.h && p.y == 0) {
            paddleHit = 2;
            return true;
        }

        else return false;
    }
}

//Do this when collides == true
function collideAction(ball, p) {
    ball.vy = -ball.vy;

    if(paddleHit == 1) {
        ball.y = p.y - p.h;
        particlePos.y = ball.y + ball.r;
        multiplier = -1;    
    }

    else if(paddleHit == 2) {
        ball.y = p.h + ball.r;
        particlePos.y = ball.y - ball.r;
        multiplier = 1; 
    }

    points++;
    increaseSpd();

    if(collision) {
        if(points > 0) 
            collision.pause();

        collision.currentTime = 0;
        collision.play();
    }

    particlePos.x = ball.x;
    flag = 1;
}

// Function for emitting particles
function emitParticles() { 
    for(var j = 0; j < particles.length; j++) {
        par = particles[j];

        ctx.beginPath(); 
        ctx.fillStyle = "white";
        if (par.radius > 0) {
            ctx.arc(par.x, par.y, par.radius, 0, Math.PI*2, false);
        }
        ctx.fill();  

        par.x += par.vx; 
        par.y += par.vy; 

        // Reduce radius so that the particles die after a few seconds
        par.radius = Math.max(par.radius - 0.05, 0.0); 

    } 
}
\$\endgroup\$
0

2 Answers 2

1
\$\begingroup\$

Simple solution: Have the paddle always move towards the current horizontal position of the ball. When the x-coordinate of the ball is larger than the x-coordinate of the center of the paddle, move it right, otherwise move it left.

Better solution: Extrapolate where the ball will reach the finish-line and have the paddle move towards that point.

In both solutions you can regulate the game difficulty with the speed of the paddle.

\$\endgroup\$
2
  • \$\begingroup\$ Yes, I have been trying to figure out how to make a loop that figures out where the ball will extrapolate then have the paddle move to that coordinate point. However, I have no idea how to do this. \$\endgroup\$ Jun 16, 2016 at 22:38
  • \$\begingroup\$ @LazerStackr The crude solution would be to simply simulate the trajectory of the ball by creating a copy of the coordinates and run the ball physics just like you already do, but not with one iteration per frame but do it in a loop until it reaches the bottom. You could also solve it mathematically which would certainly be faster, but not as adaptive in case you make the game more complex. \$\endgroup\$
    – Philipp
    Jun 16, 2016 at 22:52
1
\$\begingroup\$

You can make an invisible copy of your ball which you update for as long as it didn't reach the paddle.

Here's an example:

Suppose you have a ball class which looks something like this:

function Ball(x, y, size) {
    this.x = x;
    this.y = y;
    this.size = size;
    this.vx = 0;
    this.vy = 0;
}

Ball.prototype.update = function () {
   // Move the ball.
};

This first thing you want to do in your AI is to make a clone of this ball.

So:

var clone = new Ball(ball.x, ball.y, ball.size);
clone.vx = ball.vx;
clone.vy = ball.vy;

Then you calculate the distance from the paddle and the ball and update the ball for as long as it didn't reach the paddle.

var dx = 0;

do {
    dx = Math.abs(clone.x - paddle.x)

    clone.update();
} while (dx > 10);

Now you can simply grab the Y position of your clone.

Ofcourse the paddle now knows exactly where the ball will go when it reaches the paddle. There are two solutions to fix this:

  1. Make the loop shorter
  2. Add a random value to the final Y position.

Hope this helps

\$\endgroup\$
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .