# 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 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 / 2paddle_x = center of paddle = paddle_sprite_x + paddle_width / 2angle = 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 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 on other sites
Days    100
Quote:
 Original post by JasonL220i 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 on other sites
JasonL220    132
so what is there a way of rounding a float without purducing a warning

##### Share on other sites
Days    100
of course there is :)

go to your MSDN and look for 'floor' and 'ceil'

##### 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 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 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 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 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 on other sites
JasonL220    132
Quote:
 Original post by jykI 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 / 2paddle_x = center of paddle = paddle_sprite_x + paddle_width / 2angle = 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 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 on other sites
Thunder_Hawk    314
Quote:
 Original post by Daysnow, 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 on other sites
jyk    2094
Quote:
Sorry, the extent in this case is half the width of the object. So:
paddle_extent = paddle_width / 2;



##### Share on other sites
JasonL220    132
i have written this code:

// Pong Clone Jason Lovett#include "pong.h"	//include pong.h//increment logic_countervoid update_logic_counter(){	logic_counter++;}END_OF_FUNCTION(update_logic_counter);	//Needed in timing functions, to keep portabilityint 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 collisionsint 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 screenint 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}//mainint 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 ballyspeedtypedef short int sint;	//type sint instead of short inttypedef long int lint;	//type lint instead of long intfloat 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	//doneint Angle();						//Angle declaration		//doneint PaddleMove();					//PaddleMove declaration	//doneint BallMove();						//BallMove declaration		//doneint RePosition();					//RePosition declaration	//doneint DrawGraphics(BITMAP *buffer);	//DrawGraphics declaration	//done///~

##### 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 on other sites
JasonL220    132
i have got the angle code working (well nearly) could you please have a look all code and .exe is at www.jlovett.plus.com/pong.zip