Sign in to follow this  
JasonL220

linear interpolation in pong

Recommended Posts

JasonL220    132
i have been looking around for solutions to get a good rebound angle, i was given this formulea:
int angle = (45 * (paddle_x - (ball_x + (ball_width/2)) - (paddle_width/2))) / (paddle_width/2);
but the person who posted it was writing it from memory andwas slightly drunk, so would someone please take a look and tell me if it is write.

Share this post


Link to post
Share on other sites
jyk    2094
I couldn't quite figure out that formula, but the idea seems to be something like this:
ball_x = center of ball = ball_sprite_x + ball_width / 2
paddle_x = center of paddle = paddle_sprite_x + paddle_width / 2
angle = 45 * ((paddle_x - ball_x) / paddle_extent))
The idea being that the ball bounces diagonally at the corners of the paddle, and more and more 'straight up' as it approaches the center. This isn't particularly realistic, but may be ok for a pong game - I don't know. If this is c++, it seems the use of ints rather than floats might cause some problems there. Also, it can sometimes be more useful to deal with velocities in terms of vectors rather than angles.

Share this post


Link to post
Share on other sites
JasonL220    132
i was thinking of doing the calulation with floats the casting them to ints when the ballx/bally position is sent to the draw function, i asume that when casting to a int from a float that it round to the nearest whole number, correctly.

Share this post


Link to post
Share on other sites
Days    100
Quote:
Original post by JasonL220
i asume that when casting to a int from a float that it round to the nearest whole number


Almost. Converting a float to an int truncates. (not to mention throws a warning, and is not very fast. ie look up how your computer stores floats versus ints, and you will see why)

1 == (int)1.234;
2 == (int 2.999;

Rounding takes a little more effort.

Share this post


Link to post
Share on other sites
JasonL220    132
that wasn't quite what i wanted but is found this would it work?
#define ROUND_FLOAT(x) (((int)(x) + 0.5) < (x)) ? ((int)(x) + 1) : ((int)(x))) and how does it work i've never seen the ? and : operators

edit: ok i see how it works now, but will it throw warnings?

[Edited by - JasonL220 on October 23, 2005 5:59:07 PM]

Share this post


Link to post
Share on other sites
nilkn    960
I don't know about that particular formula you posted, but one method of getting a really good rebound effect is to built an ellipse which approximates the rectangle which specifies the paddle.

The standard equation for an ellipse is

(x-h)^2/a^2 + (y-k)^2/b^2 = 1

where the ordered 2-tuple (h,k) gives the center of the ellipse, and (a,b) gives the half-width and half-height, respectively. If you have your paddle specified by a rectangle given by the 4-tuple R(x,y,w,h), then you can calculate h, k, a and b thusly:

h = (2*R.x + R.w)/2
k = (2*R.y + R.h)/2
a = R.w/2
b = R.h/2

Technically, you could really choose any value of b you want -- the larger the value the more apparent the perturbations to the reflected trajectory of the ball.

Anyway, so you can substitute those into the standard equation for an ellipse, find y' by implicit differentiation, then define the slope of the vector normal to the ellipse at point x as n(x) = -1/y'(x).

So, when the ball hits the paddle, you calculate n(x) and find the normal vector, and then reflect the ball's velocity vector over this normal.

Edit: You can perform rounding on floats with something like this:
template<typename T>
int round(const T num) { return floor(num + 0.5); }


Edit2: There is probably a really clever way of finding the normals or tangents of an ellipse which I am not aware of, so if you choose to use the ellipse method it would probably be advantageous to you to google around a little while looking for a simpler method.

[Edited by - nilkn on October 23, 2005 8:43:16 PM]

Share this post


Link to post
Share on other sites
Days    100
The above poster is absolutely correct, but the solution may be a little over the top for you. I am going to assume that you are relatively new to programming in c/c++ if you do not know the tertiary operator ( ? : )

First off, the tertiary operator is close to an if/else all in one line. It is handy for situations like the one you posted, where you are defining a macro that makes a decision.

now, back to floor and ceil. These are the only (easy to understand) safe way of converting a float to an int that I know of.


#define ROUND_FLOAT(a) (a%1 < 0.5f ? floor(a) : ceil(a))




yes, you do have the overhead of a modulus, and one function call. However you have eliminated all of your warnings, and are leaving nothing up to the compiler when it comes to converting a float to an int in assembly. I hope this helps.

Share this post


Link to post
Share on other sites
JasonL220    132
thanks Days, i'll use that. nilkn I understand the conpect of your idear but dont have any idea how to find the tangent and there for the return angle.

edit: i've have tried to write a test program for the rounding routines but i get this:

test.cpp:6: error: invalid operands of types `const float' and `int' to binary `operator%

in this code:

int ROUND_FLOAT1(const float a)
{
((a%1 < 0.5f) ? (floor(a)) : ceil(a));
return 0;
}

btw i'm compiling with mingw

[Edited by - JasonL220 on October 24, 2005 3:47:33 AM]

Share this post


Link to post
Share on other sites
JasonL220    132
#include <math.h>
#include <stdio.h>

int ROUND_FLOAT1(float a)
{
double intpart, floatpart;
floatpart = modf(a, &intpart);
if(floatpart >= 0.5)
intpart += 1;
return (int)floor(intpart);
}

this is the rounding code i made i cant seem to get the profiling tools to work so i cant test the speed but i t works fine.

Share this post


Link to post
Share on other sites
JasonL220    132
Quote:
Original post by jyk
I couldn't quite figure out that formula, but the idea seems to be something like this:
ball_x = center of ball = ball_sprite_x + ball_width / 2
paddle_x = center of paddle = paddle_sprite_x + paddle_width / 2
angle = 45 * ((paddle_x - ball_x) / paddle_extent))
The idea being that the ball bounces diagonally at the corners of the paddle, and more and more 'straight up' as it approaches the center. This isn't particularly realistic, but may be ok for a pong game - I don't know. If this is c++, it seems the use of ints rather than floats might cause some problems there. Also, it can sometimes be more useful to deal with velocities in terms of vectors rather than angles.


what is ment by paddle_extent?

Share this post


Link to post
Share on other sites
Days    100
Sorry about the use of the modulus in my example, it was very late for me, and Hurricane Wilma was en-route :p You have it right now tho.

Share this post


Link to post
Share on other sites
Thunder_Hawk    314
Quote:
Original post by Days
now, back to floor and ceil. These are the only (easy to understand) safe way of converting a float to an int that I know of.

#define ROUND_FLOAT(a) (a%1 < 0.5f ? floor(a) : ceil(a))



Float's don't have a modulus operator, so that isn't going to compile. I don't see what's wrong with the good ol' rounding formula here: int x = int(float_x + 0.5f);

I would point out however, that if you're doing this rounding specifically for drawing purposes (to avoid filtering and whatnot), you should probably try to hold off on this step until you actually send the data to be drawn (in other words, always keep track of the position/velocity with floats and cast them to ints when drawing), or you risk the possibility of significant inconsistancy between machines running at different speeds.

Share this post


Link to post
Share on other sites
jyk    2094
Quote:
what is ment by paddle_extent?
Sorry, the extent in this case is half the width of the object. So:
paddle_extent = paddle_width / 2;

Share this post


Link to post
Share on other sites
JasonL220    132
i have written this code:

// Pong Clone Jason Lovett

#include "pong.h" //include pong.h

//increment logic_counter
void update_logic_counter()
{
logic_counter++;
}
END_OF_FUNCTION(update_logic_counter); //Needed in timing functions, to keep portability

int angle()
{
switch(ballspeedx)
{
case 2 : //if ballspeedx is 4
{
int centreofball = ballleft + (ballwidth / 2); //find centre of ball
int centreofpaddle = paddle1left + (paddlewidth / 2); //find centre of paddle
angleofreflection = 45 * ((centreofpaddle - centreofball) / (paddlewidth / 2)); //convert to angle between 45 and -45
break;
}
case -2 : //if ballspeedx is -4
{
int centreofball = ballleft + (ballwidth / 2); //find centre of ball
int centreofpaddle = paddle2left + (paddlewidth / 2); //find centre of paddle
angleofreflection = 45 * ((centreofpaddle - centreofball) / (paddlewidth / 2)); //convert to angle between 45 and -45
break;
}
}
return roundfloat(angleofreflection);
}

//check for collisions
int CollisionDetect()
{
if((ballleft <= paddle1right) && (ballbottom >= paddle1top) && (ballright >= paddle1left) && (balltop <= paddle1bottom)) //if ball is within paddle1
{
ballspeedx = 4; //invert xdir
ballspeedy = angle(); //calculate yspeed
}
if((ballright <= paddle2left) && (ballbottom >= paddle2top) && (ballleft <= paddle2right) && (balltop <= paddle2bottom)) //if ball is within paddle2
{
ballspeedx = -4; //invert xdir
ballspeedy = angle();//calculate yspeed
}
if(ballright >= SCREEN_W)
{
RePosition();
p1score++;
}
if(ballleft <= 0)
{
RePosition();
p2score++;
}
return 0;
}

int PaddleMove()
{
if(key[KEY_UP])
paddle2top -= 4;
if(key[KEY_DOWN])
paddle2top += 4;
if(key[KEY_W])
paddle1top -= 4;
if(key[KEY_S])
paddle1top += 4;
return 0;
}

int BallMove()
{
ballleft += ballspeedx;
balltop += ballspeedy;
return 0;
}

int RePosition()
{
balltop = (SCREEN_H / 2 + (rand()%36)) - (ballwidth / 2);
ballleft = SCREEN_W / 2 - (ballwidth / 2);
int rand1 = (rand()%1)+1;
if (rand1 == 1)
{
ballspeedx = 2;
}
else
{
ballspeedx = -2;
}
return 0;
}

//draw the graphics to the buffer the blit to the screen
int DrawGraphics(BITMAP *buffer)
{
clear_bitmap(buffer); //make sure the bitmap is blank before drawing
rectfill(buffer, paddle1left, paddle1top, paddle1right, paddle1bottom, makecol(255,255,255));
rectfill(buffer, paddle2left, paddle2top, paddle2right, paddle2bottom, makecol(255,255,255));
circlefill(buffer, ballleft, balltop, (ballwidth / 2), makecol(255,255,255));
blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H); //blit to screen (double buffering)
return 0; //success
}

//main
int main(int argv, char **argc[])
{
allegro_init(); //initialise allegro
install_timer(); //initialise timer routines
install_keyboard(); //initialise keyboard routines

srand(time(NULL)); //seed the rand runction with the time to get better random numbers

set_color_depth(16); //set colour depth
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); //set graphics mode to fullscreen 640x480

sint quitit = 0; //quit variable
p1score = 0;
p2score = 0;

LOCK_VARIABLE(logic_counter); //needed on timing variables to keep portability
LOCK_FUNCTION(update_logic_counter); //needed on timing functions to keep portability
install_int_ex(update_logic_counter, BPS_TO_TIMER(60)); //set the timer rate to 60 frames per second (tick per second)

BITMAP *buffer = create_bitmap(640, 480); //create buffer bitmap for extra speed
clear_bitmap(buffer); //make sure the bitmap is empty

paddle2top = (SCREEN_H/2 - paddlewidth); //set paddle2top
paddle2left = (SCREEN_W - paddlewidth - 10); //set paddle2left
paddle1top = (SCREEN_H/2 - paddlewidth); //set paddle1top
paddle1left = paddlewidth; //set paddle1left

RePosition(); //set the starting point for the ball
ballspeedy = 1;

while(!quitit) //if quitit = 0 loop
{
while(logic_counter) ///if logic_counter is 1 loop
{
ballbottom = balltop + ballwidth; //set ballbottom
ballright = ballleft + ballwidth; //set ballright
paddle1bottom = paddle1top + paddlehieght; //set paddle1bottom
paddle1right = paddle1left + paddlewidth; //set paddle1right
paddle2bottom = paddle2top + paddlehieght; //set paddle2bottom
paddle2right = paddle2left + paddlewidth; //set paddle2right
CollisionDetect(); //call the collision detection routine
PaddleMove(); //call the paddle move routine
BallMove(); //call the ball move routine
DrawGraphics(buffer); //call the draw grpahics routine and pass the bitmap buffer
logic_counter--; //decrement logic_counter
}
if(key[KEY_ESC]) quitit++; //if esc is pressed then the loop will quit
}
destroy_bitmap(buffer); //release the buffer bitmap memory
return 0; //success
}
END_OF_MAIN(); //needed to keep portability
///~




//Pong Clone, Jason Lovett

#include <allegro.h> //include allegro header
#include <stdlib.h> //for rand
#include <time.h> //use for paramater to srand to get a more random number
#include <roundfloat.h> //round the angle float to an int to get a valid ballyspeed

typedef short int sint; //type sint instead of short int
typedef long int lint; //type lint instead of long int

float angleofreflection;
sint ballspeedx;
sint ballspeedy;
const sint paddlewidth = 16;
const sint ballwidth = 8;
const sint paddlehieght = 40;
sint paddle1top, paddle2top, balltop;
sint paddle1left, paddle2left, ballleft;
sint paddle1bottom, paddle2bottom, ballbottom;
sint paddle1right, paddle2right, ballright;
sint paddlehity;
sint p1score, p2score;
volatile sint logic_counter;

int CollisionDetect(); //CollisionDetect declaration //done
int Angle(); //Angle declaration //done
int PaddleMove(); //PaddleMove declaration //done
int BallMove(); //BallMove declaration //done
int RePosition(); //RePosition declaration //done
int DrawGraphics(BITMAP *buffer); //DrawGraphics declaration //done
///~



download the .exe to see the prob ,<a>http://www.jlovett.plus.com/pong.zip, thanks

Share this post


Link to post
Share on other sites
JasonL220    132
have been tring to debug my code with gdb(mingw) but i have not found it particly useful, could someone give me some tips on using it?

i have found the bug but the angle calculation code does not work it always bounces of at 90* to the paddle.


int angle()
{
switch(ballspeedx)
{
case 2 : //if ballspeedx is 4
{
int centreofball = ballleft + (ballwidth / 2); //find centre of ball
int centreofpaddle = paddle1left + (paddlewidth / 2); //find centre of paddle
angleofreflection = 45 * ((centreofpaddle - centreofball) / (paddlewidth / 2)); //convert to angle between 45 and -45
break;
}
case -2 : //if ballspeedx is -4
{
int centreofball = ballleft + (ballwidth / 2); //find centre of ball
int centreofpaddle = paddle2left + (paddlewidth / 2); //find centre of paddle
angleofreflection = 45 * ((centreofpaddle - centreofball) / (paddlewidth / 2)); //convert to angle between 45 and -45
break;
}
}
return roundfloat(angleofreflection);
}



the .exe can be found at www.jlovett.plus.com/programmig/pong/pong.exe

thanks

[Edited by - JasonL220 on October 26, 2005 12:07:56 PM]

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