Sign in to follow this  
pascalosti

Help in AI for pong

Recommended Posts

I made my first pong game with sdl. only problem is my ai is lame. 2 things ive tried, hopefully someone can give me better idea for AI. First thing ive tried: have computer pattle follow - ball.x works but impossible to beat (pattle always hits the ball) Second: have computer pattle += or -= speed (slower speed then the ball) when ever the ball moves left or right. Works but the pattle gets more off target the longer you play. Love to hear some new ideas on this.. thank you

Share this post


Link to post
Share on other sites
Try having the computer emulate how I imagine most people play. That is to say, whenever the ball changes direction the computer estimates its final position, and then starts moving to that location. You could easily add in some sort of random offset to make the calculation less than perfect. I'd also recommend you only do it when the ball changes direction, if you do it progressively with each movement you'd probably find the paddle tracks too perfectly.

Haven't tried this myself, just a thought that came to mind.

Share this post


Link to post
Share on other sites
Does the ball speed up over time (i.e. like the longer the game goes, the more the ball speeds up)?
If this is the case, then at some stage the ball should be faster than the paddles anyway.

Anyway, you probably want the computer to be estimating where the ball is going more than just following it (i.e. at the most basic, you'd have a ray that traces out from the ball position towards its direction vector and check where it crosses the paddle's x/y position, depending on whether you're playing horizontally or vertically... don't worry about taking into account the fact that the ball bounces off walls otherwise it probably will be impossible to beat).
When the computer player does these estimates, deviate the value by some small, random amount so you're basically introducing a silly kind of 'human-error' into the AI.

Then what you could also add is some kind of random reaction time to the paddle so that when it needs to change directions to follow the ball, it takes a split-second to do so as opposed to reacting 'immediately'.

Finally, you could make difficulty levels from these settings simply by deviating the target positions and reaction times.

There may be big flaws in this idea, but I'm just thinking out aloud really... Hope it gives you some ideas.

<EDIT> Ooops, beaten to it by a post almost identical (hehehe, though much more concise) to my own!?!?

Share this post


Link to post
Share on other sites
When I play a pong type game, I tend to move the "paddle" with the ball but one thing that always gets me is reaction time. Adding tuita's idea of waiting a split second before actaully moving the paddle would make the AI more human.

Share this post


Link to post
Share on other sites
My pong AI was done pretty much how everyone else mentioned. The computer paddle would estimate where the ball would end up and go there. I implemented a random error offset and a sort of reaction time as well. I had three difficulty settings which would change the error and reation settings a bit to make the computer better or worse.

All the error offset was was a random +/- number of pixels the paddle could be off center by. It was also affected by the speed of the ball so that the faster the ball was the higher the error could be.

My "reaction time" wasn't so much a reaction time I guess. Really what happened was when the ball was hit by the player it cued the computer to make a low accuracy estimate to where the ball was gonna go. Then based on the difficulty setting, the computer made a more accurate estimate based on the distance the ball was from the paddle. So for instance on easy difficulty the computer made a second estimate when the ball was half a paddle length away. On hard difficulty the computer might get a whole 1.5 paddle lengths to make the next more accurate estimate, thus giving it more time to move into position. Since my ball would speed up per paddle hit until it reached a max limit, this time to move into position was important. Compared to the easy difficulty, the hard difficulty had a much easier time keeping the ball in play once the speed maxed out.

Also note that my paddles moved at a set speed. I'm not sure if/how you limit your paddle speed but since I was using arrow keys to move the paddle I had to set it to a reasonable speed. I guess if you are using a mouse/gamepad setup you might have a different system.

Hope that helps

Share this post


Link to post
Share on other sites
Sounds good

but, what equation would you use to estimate where the ball may or will hit? The delayed reaction time i can figure out with rand().

here is a half ass stab at it?
playing up and down, with comp at the top:

//when ball reaches the middle and is going up
if(ball.y == SCREEN_HEIGHT/2 && up == true){
int temp;
temp = ball.x;
//ball moving right and up
if(ball_right == true){
(ball.y / speed )temp;
while(temp != ball.x){
ball.x += speed}
}
//ball moving left and up
if(ball_left == true){
// same as above but -=
}}


Share this post


Link to post
Share on other sites
I did one before where I had the computer move to the y coordinate of the puck. After the computer comes in contact with the puck it takes a defensive position in the middle of the screen. This can cause problems because if the puck gets behind the computer it will not it in its goal.

Share this post


Link to post
Share on other sites
my pong clone

You can download mine if you want. Has source included. It's not very well organized. It was one of the first games I made. Hope it's helpful. Check out the AI_Move() for how my ai works.

Share this post


Link to post
Share on other sites
Your pong works great, love the AI (im still trying to figure it out) hopefully reading from this post it will click.


void AI_Move( const double &delta )
{

if ( g_ball_dy > 0 ) // ball is going down
{
pos = SCREEN_W/2 - BALL_SIZE/2;
guessed = FALSE;
}
else if ( g_ball_dy < 0 ) // ball is going up
{
if ( guessed == FALSE )
{
pos = Guess_Position();
guessed = TRUE;
}
else if ( guessed == TRUE && g_ball_y <= g_ai_paddle_y+PADDLE_WIDTH/2 && difficulty == EASY)
{
int oldpos = pos;
int newpos = g_ball_x;
pos = (oldpos + newpos) / 2;
}
else if( guessed == TRUE && g_ball_y <= g_ai_paddle_y+PADDLE_WIDTH*0.75 && difficulty == NORMAL )
{
int oldpos = pos;
int newpos = g_ball_x;
pos = (oldpos + newpos) / 2;
}
else if( guessed == TRUE && g_ball_y <= g_ai_paddle_y+PADDLE_WIDTH && difficulty == HARD )
{
int oldpos = pos;
int newpos = g_ball_x;
pos = (oldpos + newpos) / 2;
}

}


if ( g_ai_paddle_x + PADDLE_WIDTH/2 < pos-1 ) // if middle of paddle is to the left of ball
{
g_ai_paddle_x += moveSpeed * delta; // move right

if ( g_ai_paddle_x + PADDLE_WIDTH > SCREEN_W)
g_ai_paddle_x = SCREEN_W - PADDLE_WIDTH;
}
else if ( g_ai_paddle_x + PADDLE_WIDTH/2 > pos+1) // if middle of paddle is to the right of ball
{
g_ai_paddle_x -= moveSpeed * delta; // move left

if ( g_ai_paddle_x < 0 )
g_ai_paddle_x = 0;
}

}





int Guess_Position( void )
{
double temp_x = g_ball_x;
double temp_y = g_ball_y;

while ( temp_y > g_ai_paddle_y + PADDLE_HEIGHT )
{
temp_x += g_ball_dx;
temp_y += g_ball_dy;
}

if ( temp_x < 0 )
temp_x = -temp_x;
else if ( temp_x > SCREEN_W )
temp_x = (double)SCREEN_W - (temp_x - SCREEN_W);
real_pos = temp_x;
temp_x += Offset_Position(); // offset the guess

return temp_x;
}

Share this post


Link to post
Share on other sites
I put some more comments in to try to explain it a bit more. It's been a while since I've looked at this. Keep in mind this can all be done in different/better ways. I'm sure I would do it all a bit different now but I'll just try to explain what I did do.


void AI_Move( const double &delta )
{

if ( g_ball_dy > 0 ) // ball is going down
{
// when the ball is going down the AI paddle takes a defensive
// position in the center
pos = SCREEN_W/2 - BALL_SIZE/2;
// reset guessed to false so when ball is going up we can make a
// guess on the position it will end up
guessed = FALSE;
}
else if ( g_ball_dy < 0 ) // ball is going up
{
if ( guessed == FALSE )
{
// make our first guess
pos = Guess_Position();
guessed = TRUE;
}
else if ( guessed == TRUE && g_ball_y <= g_ai_paddle_y+PADDLE_WIDTH/2 && difficulty == EASY)
{
// On EASY difficulty, when the ball is within half a paddle width
// the AI updates it's guessed position with an average between
// the position that it guessed and the actual position of the ball.
// This is what causes the paddle to adjust at the last second
// like a human might do as the ball gets closer.
int oldpos = pos;
int newpos = g_ball_x;
pos = (oldpos + newpos) / 2;
}
else if( guessed == TRUE && g_ball_y <= g_ai_paddle_y+PADDLE_WIDTH*0.75 && difficulty == NORMAL )
{
// Normal difficulty. Same as EASY except the AI gets 3/4 of a
// paddle width to adjust which equates to more time to move into
// position.
int oldpos = pos;
int newpos = g_ball_x;
pos = (oldpos + newpos) / 2;
}
else if( guessed == TRUE && g_ball_y <= g_ai_paddle_y+PADDLE_WIDTH && difficulty == HARD )
{
// Hard difficulty. Same thing here but the AI gets a whole paddle
// width to adjust it's position.
int oldpos = pos;
int newpos = g_ball_x;
pos = (oldpos + newpos) / 2;
}

}

// Ok now we have a position to move toward so the rest just moves the paddle
if ( g_ai_paddle_x + PADDLE_WIDTH/2 < pos-1 ) // if middle of paddle is to the left of ball
{
g_ai_paddle_x += moveSpeed * delta; // move right

// don't let the paddle go out of the screen boundaries
if ( g_ai_paddle_x + PADDLE_WIDTH > SCREEN_W)
g_ai_paddle_x = SCREEN_W - PADDLE_WIDTH;
}
else if ( g_ai_paddle_x + PADDLE_WIDTH/2 > pos+1) // if middle of paddle is to the right of ball
{
g_ai_paddle_x -= moveSpeed * delta; // move left

// don't let the paddle go out of the screen boundaries
if ( g_ai_paddle_x < 0 )
g_ai_paddle_x = 0;
}

}





int Guess_Position( void )
{
// save the current position into a couple temps
double temp_x = g_ball_x;
double temp_y = g_ball_y;

// This just increments the temp_x and temp_y until they cross the
// AI paddles y position ( where it would hit the paddle ). I'm sure
// it could be done a better way but this is how I did it at the time.
while ( temp_y > g_ai_paddle_y + PADDLE_HEIGHT )
{
temp_x += g_ball_dx;
temp_y += g_ball_dy;
}

// After we determine where the ball crosses the paddles Y we need to
// adjust if it went out of the screen boundaries. If it did we need to
// adjust it for a bounce off the edge of the screen.
// If it went off the left side it's easy, just get the opposite of temp_x.
if ( temp_x < 0 )
temp_x = -temp_x;
// Little more to it for the right side. Subtract screen width from temp_x to
// find out how many pixels it went off the screen by and then subtract
// that from the screen width.
else if ( temp_x > SCREEN_W )
temp_x = (double)SCREEN_W - (temp_x - SCREEN_W);
real_pos = temp_x; // this was just a debug display
temp_x += Offset_Position(); // offset the guess

return temp_x; // return our final guessed position
}




Hope it helps. If you have any specific questions I will be happy to try to help.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this