Recent

Author Topic: collision detection  (Read 28808 times)

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: collision detection
« Reply #45 on: October 14, 2017, 11:12:54 am »
wait if you round it it's not floating point anymore is it?

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: collision detection
« Reply #46 on: October 14, 2017, 11:18:02 am »
wait if you round it it's not floating point anymore is it?
That is correct.

That is why User137 is suggesting to separate the calculations from your actual shape x/y position (in rvk's example these are combined).

That is why you now store the x y coordinates into a separate array (which are of type floating point) and after all calculation is done _then_ you round the floating point value so that it can be stored into your shape x and y position. TShape can only understand an integer coordinate system.

In the last snippet you showed, the code only initializes the start coordinates of the circles, so it has no (visible) influence whatsoever.
« Last Edit: October 14, 2017, 11:20:20 am by molly »

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: collision detection
« Reply #47 on: October 14, 2017, 11:50:13 am »
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Timer1Timer(Sender: TObject);
  2. var
  3.   i: integer;
  4.   vv, uxx, uyy: ValReal;
  5.   vxx, vyy: Single;
  6. begin
  7.  
  8.   //ball
  9.   case direction of
  10.     0: ;
  11.     1: ball[0].left := ball[0].left - ballspeed;
  12.     2: ball[0].left := ball[0].left + ballspeed;
  13.     3: ball[0].Top := ball[0].top - ballspeed;
  14.     4: ball[0].Top := ball[0].top + ballspeed;
  15.   end;
  16.  
  17.  
  18.   ballpos[0].y:=ball[0].top;
  19.   ballpos[0].x:= ball[0].left;
  20.  
  21.  
  22.   //ball using array
  23.   for i := 0 to balllength-2 do
  24.   begin
  25.  
  26.     //to get vectors
  27.     vxx := (ballpos[i].x + 15) - (ballpos[i + 1].x + 15);
  28.     vyy := (ballpos[i].y + 15) - (ballpos[i + 1].y + 15);
  29.  
  30.     //distance between 2 points
  31.     vv := sqrt(sqr(vxx) + sqr(vyy));
  32.  
  33.     //normalised vector
  34.     if vv = 0 then
  35.       continue;
  36.     uxx := vxx / vv;
  37.     uyy := vyy / vv;
  38.  
  39.     if vv > 30 then //when the distance is bigger than 30
  40.     begin
  41.       ballpos[i + 1].x:=ballpos[i + 1].x + (uxx*ballspeed);
  42.       ballpos[i + 1].y:=ballpos[i + 1].y + (uyy*ballspeed);
  43.       ball[i + 1].left := round(ballpos[i + 1].x);
  44.       ball[i + 1].top := round(ballpos[i + 1].y);
  45.     end;
  46.   end;
  47.  
  48. end;                        

hi thank you it works now but i have one more question

at first i coded this to update ablls' positions

Code: Pascal  [Select][+][-]
  1. for i := 0 to balllength-1 do
  2.   begin
  3.    ballpos[i].y:=ball[i].top;
  4.    ballpos[i].x:= ball[i].left;  

but the connect point point became 45 just like the one i coded before so i changed to

Code: Pascal  [Select][+][-]
  1. ballpos[0].y:=ball[0].top;
  2.   ballpos[0].x:= ball[0].left;  
and it works but i don't know why i only have to update the first ball's position

rvk

  • Hero Member
  • *****
  • Posts: 6163
Re: collision detection
« Reply #48 on: October 14, 2017, 12:14:12 pm »
Sidenote:
Why save the positions of the float when you can just move the balls 1 position. If the vector is 0.2 you can just move it 1. The vector is a value of -1..1 so it should move -1, 0 or 1. You don't need to store the float.

So I did this and it worked:
Code: Pascal  [Select][+][-]
  1.     if abs(vv) > 0 then // when the distance of connect points is > 0
  2.     begin
  3.       ball[i + 1].left := ball[i + 1].left + sign(uxx) * ceil(abs(uxx));
  4.       ball[i + 1].top := ball[i + 1].top + sign(uyy) * ceil(abs(uyy));
  5.     end;
(Is there a round up which rounds down when negative? I used sign(x) * ceil(abs(x)) now but is there a single function for this?)

Next you need to use the connection points to move the follow-balls. And you need to keep moving them until they are connected on THAT connection point. Not on any other point.

So you need to use direction of the main ball to determine the connection point.

I used this:
Code: Pascal  [Select][+][-]
  1.     //to get vectors
  2.     // vxx := (ball[i].left - 15) - (ball[i + 1].left - 15);
  3.     // vyy := (ball[i].top - 15) - (ball[i + 1].top - 15);
  4.  
  5.     case direction of
  6.       0: continue; // only start moving when main ball starts
  7.       1:
  8.       begin // dir=left, connect right.x middle.y with with followballs left.x middle.y
  9.         vxx := (ball[i].left + 30) - (ball[i + 1].left);
  10.         vyy := (ball[i].top + 15) - (ball[i + 1].top + 15);
  11.       end;
  12.       2:
  13.       begin // dir=right, connect left.x middle.y with followballs right.x middle.y
  14.         vxx := (ball[i].left) - (ball[i + 1].left + 30);
  15.         vyy := (ball[i].top + 15) - (ball[i + 1].top + 15);
  16.       end;
  17.       3:
  18.       begin // dir=up, connect middle.x bottom.y with followballs middle.x top.y
  19.         vxx := (ball[i].left + 15) - (ball[i + 1].left + 15);
  20.         vyy := (ball[i].top + 30) - (ball[i + 1].top);
  21.       end;
  22.       4:
  23.       begin // dir=down, connect middle.x top.y with followballs middle.x bottom.y
  24.         vxx := (ball[i].left + 15) - (ball[i + 1].left + 15);
  25.         vyy := (ball[i].top) - (ball[i + 1].top + 30);
  26.       end;
  27.     end;

After that vv should be in the range of -1..1 in distance to the real connect points. So move the balls when " if abs(vv) > 0 then ".

This all worked fine for me and there is no need to save the fraction of vv because that would make the follow-balls go slower.

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: collision detection
« Reply #49 on: October 14, 2017, 12:51:41 pm »
error message says

unit1.pas(121,46) Error: Identifier not found "sign"
unit1.pas(121,58) Error: Identifier not found "ceil"
unit1.pas(122,44) Error: Identifier not found "sign"
unit1.pas(122,56) Error: Identifier not found "ceil"

rvk

  • Hero Member
  • *****
  • Posts: 6163
Re: collision detection
« Reply #50 on: October 14, 2017, 12:57:40 pm »
You need to include math in your uses.

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: collision detection
« Reply #51 on: October 14, 2017, 01:20:36 pm »
Code: Pascal  [Select][+][-]
  1. 0: continue;  
it says
unit1.pas(78,8) Error: CONTINUE not allowed
so i deleted the continue and compiled with this
Code: Pascal  [Select][+][-]
  1. 0: ;  
and when i compile it error message comes up saying
project 1 raised exception class 'External: SIGFPE'.

rvk

  • Hero Member
  • *****
  • Posts: 6163
Re: collision detection
« Reply #52 on: October 14, 2017, 01:25:23 pm »
Code: Pascal  [Select][+][-]
  1. 0: continue;  
it says
unit1.pas(78,8) Error: CONTINUE not allowed
so i deleted the continue and compiled with this
Code: Pascal  [Select][+][-]
  1. 0: ;  
and when i compile it error message comes up saying
project 1 raised exception class 'External: SIGFPE'.
Then you are adding this in the wrong place.

Attached is my code.

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: collision detection
« Reply #53 on: October 14, 2017, 01:33:47 pm »
it works really good but i want those to be always attached to each other. is there any way i can do that?

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: collision detection
« Reply #54 on: October 14, 2017, 02:45:00 pm »
@shs:
I am not sure what you meant by always attached to each other.

Do you mean that the balls should be attached to each other right from the start ? If so, then you can achieve that by setting the correct Left/Top coordinates for the shapes when you create your balls.

e.g. adjust these lines:
Code: [Select]
    ball[i].top := ball[i].Height + random(Height - ball[i].Height);
    ball[i].left := ball[i].Width + random(Width - ball[i].Width);
... so that it doesn't contain random coordinates anymore, but calculate them in such a way so that the shapes connect.

How _you_ wish to line up your shapes from the start is entirely up to yourself.
« Last Edit: October 14, 2017, 02:47:18 pm by molly »

rvk

  • Hero Member
  • *****
  • Posts: 6163
Re: collision detection
« Reply #55 on: October 14, 2017, 02:47:45 pm »
No, in my example, when the main ball changes direction the other follow but loose connection momentarily.

it works really good but i want those to be always attached to each other. is there any way i can do that?
This way they stay connected but then the third ball moves wrong when the second changes direction.

Code: Pascal  [Select][+][-]
  1.     //to get vectors
  2.     vxx := (ball[i].left - 15) - (ball[i + 1].left - 15);
  3.     vyy := (ball[i].top - 15) - (ball[i + 1].top - 15);
  4.  
  5.     //distance between 2 points
  6.     vv := sqrt(sqr(vxx) + sqr(vyy));
  7.  
  8.     //normalised vector
  9.     if vv = 0 then continue;
  10.     uxx := vxx / vv;
  11.     uyy := vyy / vv;
  12.  
  13.     if abs(vv) > 30 then // when the distance of connect points is > 0
  14.     begin
  15.       ball[i + 1].left := ball[i + 1].left + sign(uxx) * ceil(abs(uxx));
  16.       ball[i + 1].top := ball[i + 1].top + sign(uyy) * ceil(abs(uyy));
  17.     end;

Otherwise you need to take a whole new approach. You can just calculate the connection point on the main ball each time according to the relative positions of the two. You also determine the wanted connection point on the main ball according to the direction. Then don't connect ball two to the first connection point but subtract 10 degrees each time until you are at the wanted connection point.

I'm working on an example but my math skills are a bit rusty at the moment.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: collision detection
« Reply #56 on: October 14, 2017, 02:52:25 pm »
No, in my example, when the main ball changes direction the other follow but loose connection momentarily.
First of all, nice approach. 2nd, thank you for mentioning because i thought it was my bad eye-sight causing the gap (in my mind)  :D

I'm a bit busy atm, so haven't got a good look yet, but my first incline was that it was caused by rounding the vv variable (up for the 2nd shape, down for the 3th causing the gap under certain conditions).

rvk

  • Hero Member
  • *****
  • Posts: 6163
Re: collision detection
« Reply #57 on: October 14, 2017, 03:14:39 pm »
I've tried to take the other approach of using math to calculatie the connection point according to the coordinates of the ball. Because when the main ball is moving we have a different "wanted" connection point I first calculate the real angle A and then add or subtract 5 to get to the wanted angle.

It works quite well except the third ball sometimes makes a full circle motion around the second ball before settling into its place :D

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Timer1Timer(Sender: TObject);
  2. var
  3.   i: integer;
  4.   a: extended;
  5.   P1, P2, P3: TPoint;
  6. begin
  7.  
  8.   //ball
  9.   case direction of
  10.     0: ;
  11.     1: ball[0].left := ball[0].left - 1;
  12.     2: ball[0].left := ball[0].left + 1;
  13.     3: ball[0].Top := ball[0].top - 1;
  14.     4: ball[0].Top := ball[0].top + 1;
  15.   end;
  16.  
  17.   //ball using array
  18.   for i := 0 to 1 do
  19.   begin
  20.  
  21.     P1 := Point(ball[i].Left + 15, ball[i].Top + 15);
  22.     P2 := Point(ball[i + 1].Left + 15, ball[i + 1].Top + 15);
  23.  
  24.     // first we calculatie the degrees angle between the two balls
  25.     a := RadToDeg(ArcTan2((P2.Y - P1.Y),(P2.X - P1.X)));
  26.     a := DegNormalize(a);
  27.  
  28.     //Caption := a.ToString; // debugline
  29.  
  30.     // then we go 5 degrees to the angle we actually want
  31.     // the angles we want are according to the direction 0, 180, 90 and 270
  32.     // I had to fiddle with this because it wasn't quite right
  33.     case direction of
  34.       1: a := sign(0 - a) * 5 + a;
  35.       2: a := sign(180 - a) * 5 + a;
  36.       3: a := sign(90 - a) * 5 + a;
  37.       4: a := sign(270 - a) * 5 + a;
  38.     end;
  39.     // Caption := Caption + ' ' + a.ToString; // debug line
  40.  
  41.     // now we take the angle a and calculatie the connection point
  42.     // we actually go radius further to the center of the second ball
  43.     P3.x := P1.x + round(30 * cos(degtorad(a)));
  44.     P3.y := P1.y + round(30 * sin(degtorad(a)));
  45.  
  46.     // connect the balls, P3 is center position
  47.     ball[i + 1].left := P3.x - 15;
  48.     ball[i + 1].top := P3.y - 15;
  49.  
  50.   end;
  51.  
  52. end;

Going left and up sometimes the balls take a different path to line up. If you want to fix that I think you need to look at the normalize of the degrees and work with negative degrees to go to the wanted degrees.

rvk

  • Hero Member
  • *****
  • Posts: 6163
Re: collision detection
« Reply #58 on: October 14, 2017, 03:23:32 pm »
Removing the normalize does work a bit.
Bit still the third ball sometimes moves in a weird way but according to the set parameters.

Code: Pascal  [Select][+][-]
  1.     a := RadToDeg(ArcTan2((P2.Y - P1.Y),(P2.X - P1.X)));
  2.     // a := DegNormalize(a);
  3.  
  4.     case direction of
  5.       1: a := sign(0 - a) * 5 + a;
  6.       2: a := sign(180 - a) * 5 + a;
  7.       3: a := sign(90 - a) * 5 + a;
  8.       4: a := sign(-90 - a) * 5 + a;
  9.     end;

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: collision detection
« Reply #59 on: October 14, 2017, 05:26:05 pm »
Ah, that is fun !

Have you tried with 6 shapes (or if you dare, even more) ?  :D

fwiw: when the shapes are more or less 'lined-up' then they wiggle, but that was to be expected with the 5 degree angle approach. Could that be solved by checking the direction of the head, and ignore further calculation if the x coord line up in case going up/down (and Y for left/right) ?

 

TinyPortal © 2005-2018