The balls are repelled from the walls and each other

Need help with a program where several balls push off the walls and hit each other. Here is the code where one ball flies around the shape and is pushed off the walls.

var      
Form1: TForm1;
PosX, Posy, VelX, Vely: single;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Posx:=3;
  PosY:=5;
  VelX:=2;
  VelY:=2;
end;

procedure TForm1.shar;
begin
  PosX:= PosX+VelX;
  PosY:= PosY+VelY;
  if PosX > ClientWidth - Shp1.Width then
  begin
    PosX:= ClientWidth - Shp1.Width;
    VelX:= - VelX;
  end
  else
  if PosX < 0 then
  begin
    PosX:= 0;
    VelX:= -VelX;
  end;
  if PosY > ClientHeight - Shp1.Width then
  begin
    POsY:= ClientHeight - Shp1.Width;
    VelY:= - VelY;
  end
  else
  if PosY < 0 then
  begin
    POsY:= 0;
    VelY:= - VelY;
  end;
  Shp1.Left:= Round(PosX);
  Shp1.Top:= Round(PosY);
end;

procedure TForm1.tmr1Timer(Sender: TObject);
begin
  shar;
end;

end.

I can't figure out how to add more balls and make them repel each other. I will be grateful for any help!

Author: Nikita, 2017-03-23

2 answers

You need to take advantage of OOP and design your classes correctly.
I don't know exactly what the pattern is called (well, maybe someone from the fans of Kant Beck knows the name).
First, you need a class that controls the balls.
TSharManager it must have the properties of initializing objects (InitObjects) and changing them in space when they collide, and drawing them accordingly (DrawObjects).
And also in this class, you need to set the characteristics of the walls. The TShar class itself must contain information about the balloon.
Storing everything in separate variables is a direct path to total confusion and the most difficult debugging.
The TShar class must have properties Radius, LeftCentrPos, TopCentrPos , Color (well, maybe for this task it is not necessary, but it is easy to add), Plotnost (you can neglect physics, but if necessary, it is also easy to add) and most importantly the vector and speed of movement. (You can use the speed of movement in X and Y)
I must say at once that I do not remember the physical formula for the addition of forces at the moment of collision. But in her as a result, these properties should change. That is, there will be a method in which the coordinates of two colliding objects are recalculated. You can understand that they will collide by the fact that the sum of the radii will be equal to the distance between the centers. Unlike a square / rectangle, here the collision does not occur at the moment when the borders touch. Based on the characteristics of the balls, we calculate a new trajectory (vector and velocity). Theoretically, several balls can collide at the same time.But this is already next step. Let's simplify that only two balls collide. You need to go through all the balls and find out if the radii touch. And also find out if the ball will touch the wall. In both cases, the direction of movement and its vector change. I don't know how much it helped, but I think the algorithm should be like this.. There's more math and physics involved. The task is large enough to write code here and create a model.

 5
Author: Albert Fomin, 2017-03-24 19:08:42

The balls, their velocities, and coordinates are entered in arrays. The sizes of all the balls are the same.

procedure bumpWalls; //столкновение со стенами
var
i: Cardinal;
begin
with Form1 do
begin
for i := 0 to BallCount - 1 do
begin
  masPosX[i] := masPosX[i] + masVelX[i]; 
  masPosY[i] := masPosY[i] + masVelY[i]; 

  if masPosX[i] > ClientWidth - Shp1.Width then
  begin
    masPosX[i] := ClientWidth - Shp1.Width;
    masVelX[i] := -masVelX[i];
  end
  else if masPosX[i] < 0 then
  begin
    masPosX[i] := 0;
    masVelX[i] := -masVelX[i];
  end;
  if masPosY[i] > ClientHeight - Shp1.Width then
  begin
    masPosY[i] := ClientHeight - Shp1.Width;
    masVelY[i] := -masVelY[i];
  end
  else if masPosY[i] < 0 then
  begin
    masPosY[i] := 0;
    masVelY[i] := -masVelY[i];
  end;
end;
end;
end;

procedure bumpEachOther;  //столкновение друг с другом
var
h0, h1, i, j: Cardinal;
a, b, dist, bet, x1, x2, y1, y2: extended;
n: integer;
xx0, yy0, xx1, yy1: single;
begin
for i := 1 to 10 do  
begin
for h0 := 0 to ballcount - 1 do
begin
  for h1 := 0 to ballcount - 1 do
    if h0 <> h1 then
    begin
      a := MasPosX[h0] + MasVelX[h0] * 0.001 - MasPosX[h1] - MasVelX[h1] * 0.001;
      b := MasPosY[h0] + MasVelY[h0] * 0.001 - MasPosY[h1] - MasVelY[h1] * 0.001;
      dist := sqrt(sqr(a) + sqr(b));
      if dist <= 241 then
      begin
        bet := arctan2(MasPosY[h1] - MasPosY[h0], MasPosX[h1] - MasPosX[h0]); 
        x1 := masvelx[h0] * cos(-bet) - MasVelY[h0] * sin(-bet);
        y1 := MasVelX[h0] * sin(-bet) + MasVelY[h0] * cos(-bet);
        x2 := MasVelX[h1] * cos(-bet) - MasVelY[h1] * sin(-bet);
        y2 := MasVelX[h1] * sin(-bet) + MasVelY[h1] * cos(-bet);
        MasVelX[h0] := x2 * cos(bet) - y1 * sin(bet);
        MasVelY[h0] := x2 * sin(bet) + y1 * cos(bet);
        masVelX[h1] := x1 * cos(bet) - y2 * sin(bet);
        MasVelY[h1] := x1 * sin(bet) + y2 * cos(bet);
        n := 0;
        xx0 := masvelx[h0];
        yy0 := masvely[h0];
        xx1 := masvelx[h1];
        yy1 := masvely[h1];
        repeat  
          MasPosX[h0] := MasPosX[h0] + xx0 * 0.0011;
          MasPosY[h0] := MasPosY[h0] + yy0 * 0.0011;
          MasPosX[h1] := MasPosX[h1] + xx1 * 0.0011;
          MasPosY[h1] := MasPosY[h1] + yy1 * 0.0011;
          a := MasPosX[h0] - MasPosX[h1];
          b := MasPosY[h0] - MasPosY[h1];
          dist := sqrt(sqr(a) + sqr(b));
          inc(n);
        until (dist > 241) or (n > 50000);

      end;
    end;

  MasPosX[h0] := MasPosX[h0] + MasVelX[h0] * 0.001;
  MasPosY[h0] := MasPosY[h0] + MasVelY[h0] * 0.001;
end;
end;
end;
 2
Author: Nikita, 2017-06-04 13:43:49