2D bouncing at an angle. SOLVED

Posted By: Crypton

2D bouncing at an angle. SOLVED - 11/13/09 18:16

Basically I'm creating a pong game for learning purposes and I have come to a point where I need to change direction of my "ball".

My question is, how could I calculate the angle that ball must bounce off when colliding with the defined edge and with platforms?

Right now I have something like this (inside function main):
//ball_dir is randomly generated value between 30 and 150.
Code:
//Move ball with a direction
         ballx += spd*cosv(ball_dir)*time_step;
         bally += spd*sinv(ball_dir)*time_step;
         
         //Collision with "walls"
         -------------------------------------
         if ((ballx > game_minx & ballx+6 < game_maxx)){ //game_minx = 1/3 of screen_size.x and game_maxx = 2/3 screen_size.x  
            
            ball_dir = ball_dir; //Keep the direction
         }else{//If out of boundaries
            ball_dir = (180 - abs(ball_dir)); //Change the direction
         }

         //Checking collision with platforms!
         if (rect_collision(P_ball.pos_x, P_ball.pos_y, P_ball.size_x, P_ball.size_y, P_ai.pos_x, P_ai.pos_y, P_ai.size_x, P_ai.size_y)
            | rect_collision(P_ball.pos_x, P_ball.pos_y, P_ball.size_x, P_ball.size_y, P_player.pos_x, P_player.pos_y, P_player.size_x, P_player.size_y)){
            ball_dir = (180 - abs(ball_dir)); //Trying to change dir here.
         }



But (180 - dir) doesn't always work. I have also searched the internet for vectors to calculate new vector to move on, but I don't know how to implement them in LiteC or is it even practical in this case.

Any suggestion solving this?
Posted By: muffel

Re: 2D bouncing at an angle. - 11/13/09 19:38

I would use vec_bounce

muffel
Posted By: Rei_Ayanami

Re: 2D bouncing at an angle. - 11/13/09 19:41

i think this doesn't work in 2D wink
Posted By: muffel

Re: 2D bouncing at an angle. - 11/13/09 19:47

why??
if you sets the z-value allways to zero, it should work in 2D, I think.

muffel
Posted By: Joey

Re: 2D bouncing at an angle. - 11/14/09 11:04

you have to mirror the colliding direction along the normal. that's simple and works in every dimension, given you're in hilbert space.

n normal
c colliding vector
b bouncing vector

b = |<c,n>|*n + (c+|<c,n>|*n) = 2*|<c,n>|*n + c

to implement it you only need to know that |<,>| is abs(vec_dot(...)) here and the normal points away from the surface and has length 1 (use vec_normalize).

sample:
your screen has coordinates x growing from left to right, y from top to bottom. your ball has speed (5,3), the normal of your right screen side is (-1,0). then b is
b = 2*|<(5,3),(-1,0)>|*(-1,0) + (5,3) = 2*|5*(-1)+3*0|*(-1,0) + (5,3) = 10*(-1,0) + (5,3) = (-5,3)
as expected.

another example. your surface normal is angular in the top left, so the normal is something like (3,4)/5 (this is normalized to 1!). your ball has speed (-3,-10), so b is
b = 2*|<(3,4)/5,(-3,-10)>|*(3,4)/5 + (-3,-10) = 2*|(-9/5-40/5)|*(3,4)/5 + (-3,-10) = (8.76,5.68)
and again the length is preserved, as expected.

i hope you get it done now wink

greetings, joey.

edit: if you want to use your own variables, not vectors, know that
|<a,b>| = abs(ax*bx + ay*by)
as i used it in the examples. normalizing surface vectors can also be done by hand, just use
n_normalized = n / |<n,n>| = n / ||n||
Posted By: Crypton

Re: 2D bouncing at an angle. - 11/14/09 16:17

Thanks! Seems logical enough but still having problems implementing.
basically as I can see that formula is calculated by vec_bounce, so i tried to use it. Doesn't work the way it should..

Tried to make
VECTOR vBall;
definitions for my ball vector but engine started crashing.

So I tried with this, seems logical to me. The LiteC version of your given formula:
vec_cross(vBall, 2*abs(vec_dot(vBall, vector(1,0,0))), vector(1,0,0));


//EDIT:
Tried also with


if (vBall[1]+6 > game_maxx){ //Right side of the game area
var a = 2*abs(vec_dot(vBall, vector(1,0,0)));
vBall = vec_scale(vBall, a);
vBall = vec_add(vBall, vBall);
}

as I forgot to add vBall at the end. But still, same effect.





Snippet consisting parts with ball:
(Collision part is somewhere in the middle of main()

Code:
///////////////////////////////
#include <acknex.h>
#include <default.c>

var ball_dir;
var ballx;
var bally;

var vBall[3];
var spd = 20;

var game_start = 0;
var game_minx = 267;
var game_maxx = 533;



PANEL* P_player =
{
   //pos_x = 0; 
   pos_y = 550;
   size_x = 100;
   size_y = 10;
   flags = SHOW | LIGHT;
}

PANEL* P_ai =
{
   pos_x = 0;
   pos_y = 50;
   size_x = 100;
   size_y = 10;
   flags = SHOW | LIGHT;
} 

PANEL* P_ball =
{
   pos_x = 0;
   pos_y = 0;
   size_x = 6;
   size_y = 6; 
   flags = SHOW | LIGHT;
}

function rect_collision(var x1, var y1, var w1, var h1, var x2, var y2, var w2, var h2)
{ 
   
	if (x1 > (x2 + w2) | (x1 + w1) < x2){return (0);}
	if (y1 > (y2 + h2) | (y1 + h1) < y2){return (0);}
	return (1);
}

function hcenter_panel(PANEL* panel)
{
   panel.pos_x = (screen_size.x - panel.size_x)/2;
   //panel.pos_y = (screen_size.y - panel.size_y)/2;
}

function launch_ball()
{
   ball_dir = -60; //-random2(30, 150);
   vBall = vector(spd*cosv(ball_dir)*time_step, spd*sinv(ball_dir)*time_step, 0);
}

function trace_mouse(PANEL* panel)
{
   panel.pos_x = mouse_pos.x-50;
   panel.pos_x = clamp(panel.pos_x,game_minx, game_maxx-100);
}

//==============================================================================================
function main()
{
   video_mode = 7; 
   mouse_mode = 4; 
   random_seed(0);
   wait(3);
   
   hcenter_panel(P_player);
   hcenter_panel(P_ai);
   vec_set(P_ball.blue,vector(0,0,200));
   
   while(1)
   {
      
      trace_mouse(P_player); //move platform with the mouse
      
      
      if (game_start == 0){
         
         //ball is moving with the platform. Works!
         vBall[1] = P_player.pos_x + (P_player.size_x/2) - 3;
         vBall[2] = P_player.pos_y - P_ball.size_y - 1;
         
         //Hitting a left button launches the ball
         if (mouse_left == 1){
         launch_ball();
         game_start = 1;
         }
         
      }else{
         //Keep the ball moving. Wroks!
         vBall[1] += spd*cosv(ball_dir)*time_step;
         vBall[2] += spd*sinv(ball_dir)*time_step;
         
         
         //Collision with walls! ------------------------------------
         if (vBall[1] < game_minx){ //Left side of the game area
         vec_cross(vBall, 2*abs(vec_dot(vBall, vector(1,0,0))), vector(1,0,0));
         //vec_bounce(vBall, vector(1,0,0));
         }
         
         if (vBall[1]+6 > game_maxx){ //Right side of the game area
         vec_cross(vBall, 2*abs(vec_dot(vBall, vector(-1,0,0))), vector(-1,0,0));
         //vec_bounce(vBall, vector(-1,0,0));
         }

         
         if (rect_collision(P_ball.pos_x, P_ball.pos_y, P_ball.size_x, P_ball.size_y, P_ai.pos_x, P_ai.pos_y, P_ai.size_x, P_ai.size_y)
            | rect_collision(P_ball.pos_x, P_ball.pos_y, P_ball.size_x, P_ball.size_y, P_player.pos_x, P_player.pos_y, P_player.size_x, P_player.size_y)){
            //ball_dir = (180 - abs(ball_dir));
         }
         //-----------------------------------------------------------
      }
      //Keep the panel moving along those coordinates
      P_ball.pos_x = vBall[1]; //ballx;
      P_ball.pos_y = vBall[2]; //bally;
      
      //moving AI Platform.
      P_ai.pos_x = P_ball.pos_x - ((P_ai.size_x-P_ball.size_x)/2);
      P_ai.pos_x = clamp(P_ai.pos_x,game_minx, game_maxx-100);
      
            
      draw_line(vector(game_minx,0,0),NULL,100); // move to first corner   
      draw_line(vector(game_maxx,0,0),vector(0,0,255),100);   
      draw_line(vector(game_maxx,599,0),vector(0,0,255),100);   
      draw_line(vector(game_minx,599,0),vector(0,0,255),100);   
      draw_line(vector(game_minx,0,0),vector(0,0,255),100);
      
   wait(1);
   }
   
}
//==============================================================================================



Looking forward to know what i'm doing wrong.
Posted By: Joey

Re: 2D bouncing at an angle. - 11/14/09 19:57

it has nothing to do with the cross product. why haven't you tried implementing it word by word as i posted above? it's always slightly modified (which makes it not working). you have to be more careful.

vBall = vec_scale(vBall, a);

i'm not scaling vBall but the normal, this line is wrong. also your normal seems to be pointing in the wrong direction (or it is correct and your coordinate system is different. i just thought i should mention it).

joey
Posted By: Crypton

Re: 2D bouncing at an angle. - 11/14/09 21:19

mm yes I got carried away. Didn't think that LiteC was able to multiply vectors like that and looked depthlessly into cross like a multiplication, just got known about it tongue. My code has changed a lot since my last post.

I actually have been able to get the calculation right:

Code:
[code]var c[3] = {480, 543, 0};
var n[3] = {-1, 0, 0};
var b[3];

//n = vec_normalize(n,1);
// b = 2*|<c,n>|*n + c  Bounce vector's formula.
var a;

function main()
{
   video_mode = 7;
   wait(3);
   
   a = 2*abs(vec_dot(c, n));
   vec_set(b, vector(a*n[0], a*n[1],0));
   vec_add(b, c);
}



This is giving me right answers. But Placing it into my pong thing, it won't do the same job.

Code:
//Collision with walls! ------------------------------------
         if (vBall[0] < game_minx){ //Left side of the game area
         
         // b = 2*|<c,n>|*n + c  Bounce vector's formula.
         //Into Parts:
         //a = 2*|c,n|
         //we change (0,0,0) to (a*(-1), a*0, 0) with vec_set
         //add (480, 543,0) and (-a, 0, 0)
         a = 2*abs(vec_dot(vBall, nvec_minx));
            vec_set(vBounce, vector(a*nvec_minx[0], a*nvec_minx[1],0));
            vec_add(vBall, vBounce);

         }



I personally think my movement code for the ball is messing things up, but I can't see any other way of moving my ball...

//Keep the ball moving.
vBall[0] += spd*cosv(ball_dir)*time_step;
vBall[1] += spd*sinv(ball_dir)*time_step;

...to be more precise. I think that bounce vector is right but I can't make it influence ball's movement.
Posted By: Joey

Re: 2D bouncing at an angle. - 11/14/09 23:39

yes, well, you have to alter ball_dir... lol. if you'd said that earlier...

given ball_dir is measured in degrees, starting at 0 when the ball flies to the right and moving counter-clockwise when increasing (90° means up).
then you use a surface angle alpha, measured the same (horizontal plane has 0°, left and right window plane 90°. then you just use

ball_dir += 2*(alpha - ball_dir);

joey.

by the way, the first method is more flexible since you can get surface normals via tracing.
Posted By: Sepiantum

Re: 2D bouncing at an angle. - 11/15/09 03:30

ball_dir = -ball_dir;
Posted By: Joey

Re: 2D bouncing at an angle. - 11/15/09 11:45

no, that won't work.

that advice is reminiscent of
http://www.opserver.de/ubb7/ubbthreads.p...true#Post255669

weird, how people throw useless help-balls at everyone.
Posted By: Crypton

Re: 2D bouncing at an angle. - 11/18/09 20:28

Okey, got it working!

Code:
var vVelocity[3]; //Ball speed vector!
var vBounce[3]; //Bounce vectro that gets copied to vVelocity

var a;

//normal vectors of edges
var nvec_minx[3] = {1, 0, 0 };
var nvec_maxx[3] = {-1, 0, 0 };
//=======================================================
         // b = 2*|<c,n>|*n + c  Bounce vector's formula.
         /*
         a = 2*abs(vec_dot(c, n));
         vec_set(c, vector(a*n[0], a*n[1],0));
         vec_add(c, c);
         */

//nvec_maxx = vec_normalize(nvec_maxx,1);
a = 2*abs(vec_dot(vVelocity, nvec_maxx));
vec_set(vBounce, vector(a*nvec_maxx[0], a*nvec_maxx[1],0));
vec_add(vVelocity, vBounce);



does basically all the magic and it works. The issue I had with the moving was that my previous vector had wrong values. Sometimes it had speed values and sometimes it had coordinates stored in it.

So I needed to have a vector that stores speed values only! And then changing panel's position according to it. So this is my solution.

Edit: Although I have seen now that when ball gets in some steep angle or smth it suddenly amplifies it's speed and does wierd stuff. So the calculation isn't always perfect though...
vec_bounce() dind't give the same result as rewritten formula...

Thanks Joey!
© 2024 lite-C Forums