* * *

Author Topic: double loop for a program with the pythagoras  (Read 4282 times)

Handoko

  • Hero Member
  • *****
  • Posts: 2378
  • My goal: build my own game engine using Lazarus
Step 1 - Remove Useless Items
« Reply #15 on: January 11, 2018, 05:20:45 pm »
Step 1 - Remove Useless Items

These should be removed:
- Image2
- Timer2
- Global variables: zwischenspeicher1, zwischenspeicher2, c, c2, j, i, d


Note:
Good programmers usually avoid using global variables, use global variable only when you really need it.

Because variable c has been removed from global scope, now add the variable c it into:
- Procedure TForm1.FormCreate
- Procedure TForm1.Timer1Timer


This code still buggy. But you can download the code for comparison. I also formatted the code to make it more readable.

Code: Pascal  [Select]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, Forms, Controls, Graphics, StdCtrls, ExtCtrls;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     Button2: TButton;
  17.     Image1: TImage;
  18.     Timer1: TTimer;
  19.     procedure Button1Click(Sender: TObject);
  20.     procedure Button2Click(Sender: TObject);
  21.     procedure FormCreate(Sender: TObject);
  22.     procedure Timer1Timer(Sender: TObject);
  23.   end;
  24.  
  25. var
  26.   Form1 : TForm1;
  27.   mx    : array[1..20] of integer;
  28.   my    : array[1..20] of integer;
  29.   vx    : array[1..20] of integer;
  30.   vy    : array[1..20] of integer;
  31.   r     : array[1..20] of integer;
  32.  
  33. implementation
  34.  
  35. {$R *.lfm}
  36.  
  37. { TForm1 }
  38.  
  39. procedure TForm1.Button1Click(Sender: TObject);
  40. begin
  41.   Timer1.Enabled := True;
  42. end;
  43.  
  44. procedure TForm1.Button2Click(Sender: TObject);
  45. begin
  46.   Timer1.Enabled := False;
  47. end;
  48.  
  49. procedure switch (Var a,b:integer);
  50. var
  51.   zwischenspeicher: Integer;
  52. begin
  53.   zwischenspeicher := a;
  54.   a := b;
  55.   b := zwischenspeicher;
  56. end;
  57.  
  58. procedure pythagoras;
  59. var
  60.   d: Real;
  61.   j,i, vx, vy : Integer;
  62. begin
  63.   for j := 1 to 20 do
  64.     for i := 2 to 20 do begin
  65.       d := sqrt(sqr(mx[j]-mx[i])+sqr(my[j]-my[i]));
  66.       if d <= r[j]+r[i]+12 then begin
  67.         switch(vx, vx);
  68.         switch(vy, vy);
  69.       end;
  70.     end;
  71. end;
  72.  
  73. procedure TForm1.FormCreate(Sender: TObject);
  74. var
  75.   c: Integer;
  76. begin
  77.   Randomize;
  78.   Form1.Color    := clPurple;
  79.   DoubleBuffered := True;
  80.   Timer1.Enabled := False;
  81.   for c :=  1 to 20 do begin
  82.     r[c] := 20;
  83.     mx[c] := Random(Image1.Width);
  84.     my[c] := Random(Image1.Height);
  85.     vx[c] := Random(10);
  86.     vy[c] := Random(10);
  87.   end;
  88. end;
  89.  
  90. procedure TForm1.Timer1Timer(Sender: TObject);
  91. var
  92.   c: Integer;
  93. begin
  94.   with image1.canvas do begin
  95.     for c := 1 to 20 do begin
  96.       Pen.Color   := clBlack;
  97.       Brush.Color := clBlack;
  98.       Ellipse(mx[c]-r[c], my[c]-r[c], mx[c]+r[c], my[c]+r[c]);
  99.       mx[c] := mx[c] + vx[c];
  100.       my[c] := my[c] + vy[c];
  101.       Pen.Color   := clPurple;
  102.       Brush.Color := clPurple;
  103.       Ellipse(mx[c]-r[c], my[c]-r[c], mx[c]+r[c], my[c]+r[c]);
  104.     end;
  105.   end;
  106.   for c:= 1 to 20 do begin
  107.     if my[c]+r[c] >= Image1.Height then vy[c] := -vy[c];
  108.     if mx[c]+r[c] >= Image1.Width  then vx[c] := -vx[c];
  109.     if my[c]-r[c] < 0              then vy[c] := -vy[c];
  110.     if mx[c]-r[c] < 0              then vx[c] := -vx[c];
  111.   end;
  112. end;
  113.  
  114. end.
« Last Edit: January 12, 2018, 03:33:22 am by Handoko »

bradyhartsfield

  • New member
  • *
  • Posts: 41
Re: double loop for a program with the pythagoras
« Reply #16 on: January 11, 2018, 05:22:22 pm »
Code: Pascal  [Select]
  1. procedure pythagoras;
  2.   var d : real;
  3.   var j,i, vx, vy : integer;
  4. begin
  5.   for j := 1 to 20 do
  6.     for i := 2 to 20 do begin
  7.     d := sqrt(sqr(mx[j]-mx[i])+sqr(my[j]-my[i]));
  8.     if d <= r[j]+r[i]+12 then begin
  9.     vx[j] := -vx[j];
  10.     vy[j] := -vy[j];
  11.   end;
  12.  end;
  13. end;

i tried it like this:
Code: Pascal  [Select]
  1. procedure pythagoras;
  2. var c,g, vx, vy : integer;
  3.     d : real;
  4. begin
  5.   for c := 1 to 20 do
  6.   for g := 2 to 20 do begin
  7.     d := sqrt(sqr(mx[c]-mx[g])+sqr(my[c]-my[g]));
  8.     if d <= r[c]+r[g]+12 then begin
  9.     vx[c] := -vx[c];
  10.     vy[c] := -vy[c];
  11.   end;
  12.  end;
  13. end;
here i need to stay that i am using c and g now, because i just created a new project to try different things and i used c and g in that. anyways, if i try it like above there comes the error "Illegal qualifier" and the c from
Code: Pascal  [Select]
  1. vx[c] := -vx[c];
is marked red.

regards
brady

EDIT: i just saw the answer from Handoko, i will look at it now.

Handoko

  • Hero Member
  • *****
  • Posts: 2378
  • My goal: build my own game engine using Lazarus
Step 2 - Fixing the Procedure "pythagoras"
« Reply #17 on: January 11, 2018, 05:24:07 pm »
Step 2 - Fixing the Procedure "pythagoras"

These are wrong:
switch(vx, vx);
switch(vy, vy);


It should be:
Code: Pascal  [Select]
  1. switch(vx[j], vx[i]);
  2. switch(vy[j], vy[i]);

Don't overlaps the for-loop. The correct for-loop is:
for j := 1 to 20 do
  for i := (j+1) to 20 do

 
Remove the extra +12 from the distance calculation:
Code: Pascal  [Select]
  1. r[j]+r[i]+12

Now remove the useless variables: vx, vy

Code: Pascal  [Select]
  1. procedure pythagoras;
  2. var
  3.   d: Real;
  4.   j,i: Integer;
  5. begin
  6.   for j := 1 to 20 do
  7.     for i := (j+1) to 20 do begin
  8.       d := sqrt(sqr(mx[j]-mx[i])+sqr(my[j]-my[i]));
  9.       if d <= r[j]+r[i] then begin
  10.         switch(vx[j], vx[i]);
  11.         switch(vy[j], vy[i]);
  12.       end;
  13.     end;
  14. end;
« Last Edit: January 12, 2018, 10:36:37 am by Handoko »

bradyhartsfield

  • New member
  • *
  • Posts: 41
Re: Step 1 - Remove Useless Items
« Reply #18 on: January 11, 2018, 05:26:21 pm »
Step 1 - Remove Useless Items

These should be removed:
- Image2
- Timer2
- Global variables: zwischenspeicher1, zwischenspeicher2, c, c2, j, i, d


Note:
Good programmers usually avoid using global variables, use global variable only when you really need it.

Because variable c has been removed from global scope, now add the variable c it into:
- Procedure TForm1.FormCreate
- Procedure TForm1.Timer1Timer


This code still buggy. But you can download the code for comparison. I also formatted the code to make it more readable.

Code: Pascal  [Select]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, Forms, Controls, Graphics, StdCtrls, ExtCtrls;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     Button2: TButton;
  17.     Image1: TImage;
  18.     Timer1: TTimer;
  19.     procedure Button1Click(Sender: TObject);
  20.     procedure Button2Click(Sender: TObject);
  21.     procedure FormCreate(Sender: TObject);
  22.     procedure Timer1Timer(Sender: TObject);
  23.   end;
  24.  
  25. var
  26.   Form1 : TForm1;
  27.   mx    : array[1..20] of integer;
  28.   my    : array[1..20] of integer;
  29.   vx    : array[1..20] of integer;
  30.   vy    : array[1..20] of integer;
  31.   r     : array[1..20] of integer;
  32.  
  33. implementation
  34.  
  35. {$R *.lfm}
  36.  
  37. { TForm1 }
  38.  
  39. procedure TForm1.Button1Click(Sender: TObject);
  40. begin
  41.   Timer1.Enabled := True;
  42. end;
  43.  
  44. procedure TForm1.Button2Click(Sender: TObject);
  45. begin
  46.   Timer1.Enabled := False;
  47. end;
  48.  
  49. procedure switch (Var a,b:integer);
  50. var
  51.   zwischenspeicher: Integer;
  52. begin
  53.   zwischenspeicher := a;
  54.   a := b;
  55.   b := zwischenspeicher;
  56. end;
  57.  
  58. procedure pythagoras;
  59. var
  60.   d: Real;
  61.   j,i, vx, vy : Integer;
  62. begin
  63.   for j := 1 to 20 do
  64.     for i := 2 to 20 do begin
  65.       d := sqrt(sqr(mx[j]-mx[i])+sqr(my[j]-my[i]));
  66.       if d <= r[j]+r[i]+12 then begin
  67.         switch(vx, vx);
  68.         switch(vy, vy);
  69.       end;
  70.     end;
  71. end;
  72.  
  73. procedure TForm1.FormCreate(Sender: TObject);
  74. var
  75.   c: Integer;
  76. begin
  77.   Randomize;
  78.   Form1.Color    := clPurple;
  79.   DoubleBuffered := True;
  80.   Timer1.Enabled := False;
  81.   for c :=  1 to 20 do begin
  82.     r[c] := 20;
  83.     mx[c] := Random(Image1.Width);
  84.     my[c] := Random(Image1.Height);
  85.     vx[c] := Random(10);
  86.     vy[c] := Random(10);
  87.   end;
  88. end;
  89.  
  90. procedure TForm1.Timer1Timer(Sender: TObject);
  91. var
  92.   c: Integer;
  93. begin
  94.   with image1.canvas do begin
  95.     for c := 1 to 20 do begin
  96.       Pen.Color   := clBlack;
  97.       Brush.Color := clBlack;
  98.       Ellipse(mx[c]-r[c], my[c]-r[c], mx[c]+r[c], my[c]+r[c]);
  99.       mx[c] := mx[c] + vx[c];
  100.       my[c] := my[c] + vy[c];
  101.       Pen.Color   := clPurple;
  102.       Brush.Color := clPurple;
  103.       Ellipse(mx[c]-r[c], my[c]-r[c], mx[c]+r[c], my[c]+r[c]);
  104.     end;
  105.   end;
  106.   for c:= 1 to 20 do begin
  107.     if my[c]+r[c] >= Image1.Height then vy[c] := -vy[c];
  108.     if mx[c]+r[c] >= Image1.Width  then vx[c] := -vx[c];
  109.     if my[c]-r[c] < 0              then vy[c] := -vy[c];
  110.     if mx[c]-r[c] < 0              then vx[c] := -vx[c];
  111.   end;
  112. end;
  113.  
  114. end.

Okay, i did that, i have football training now, will be online in about two and a half hours.
Thank you for helping!

regards
brady

Handoko

  • Hero Member
  • *****
  • Posts: 2378
  • My goal: build my own game engine using Lazarus
Step 3 - Fix Procedure Timer1Timer
« Reply #19 on: January 11, 2018, 05:27:11 pm »
Step 3 - Fix Procedure Timer1Timer

You have procedure pythagoras for calculating and doing the bouncing but you forgot to put it in Timer1Timer. So put it at the very beginning of TForm1.Timer1Timer.

I saw you draw a black circle to clear the old circle position. It is very wrong for doing animations especially games. It may work (sometimes) but it usually has bad effect. On your case, I can clearly see some black shadow appears on wrong circles (because you did not do z-order calculation)

The solution is to clear the whole screen before start painting the other things:
Pen.Color   := clBlack;
Brush.Color := clBlack;
Clear;


Code: Pascal  [Select]
  1. procedure TForm1.Timer1Timer(Sender: TObject);
  2. var
  3.   c: Integer;
  4. begin
  5.   pythagoras;
  6.   with image1.canvas do begin
  7.     Pen.Color   := clBlack;
  8.     Brush.Color := clBlack;
  9.     Clear;
  10.     for c := 1 to 20 do begin
  11.       mx[c] := mx[c] + vx[c];
  12.       my[c] := my[c] + vy[c];
  13.       Pen.Color   := clPurple;
  14.       Brush.Color := clPurple;
  15.       Ellipse(mx[c]-r[c], my[c]-r[c], mx[c]+r[c], my[c]+r[c]);
  16.     end;
  17.   end;
  18.   for c:= 1 to 20 do begin
  19.     if my[c]+r[c] >= Image1.Height then vy[c] := -vy[c];
  20.     if mx[c]+r[c] >= Image1.Width  then vx[c] := -vx[c];
  21.     if my[c]-r[c] < 0              then vy[c] := -vy[c];
  22.     if mx[c]-r[c] < 0              then vx[c] := -vx[c];
  23.   end;
  24. end;
« Last Edit: January 11, 2018, 06:08:32 pm by Handoko »

Handoko

  • Hero Member
  • *****
  • Posts: 2378
  • My goal: build my own game engine using Lazarus
Step 4 - Some Minor Improvements
« Reply #20 on: January 11, 2018, 05:36:28 pm »
Step 4 - Some Minor Improvements

Set anchoring for the image and resize the form, add these code into TFrom1.FormCreate:
Image1.Anchors := [akTop, akLeft, akRight, akBottom];
Width  := 800;
Height := 600;


In your Timer1Timer, you can merge to those 2 for-loops together:
for i := 1 to 20 do begin         

I saw you use variable c for looping. Usually programmers use i (and then j, k, ...). So change all those variables' names. By doing so, your code will look like written by a pro.

Code: Pascal  [Select]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, Forms, Controls, Graphics, StdCtrls, ExtCtrls;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     Button2: TButton;
  17.     Image1: TImage;
  18.     Timer1: TTimer;
  19.     procedure Button1Click(Sender: TObject);
  20.     procedure Button2Click(Sender: TObject);
  21.     procedure FormCreate(Sender: TObject);
  22.     procedure Timer1Timer(Sender: TObject);
  23.   end;
  24.  
  25. var
  26.   Form1 : TForm1;
  27.   mx    : array[1..20] of Integer;
  28.   my    : array[1..20] of Integer;
  29.   vx    : array[1..20] of Integer;
  30.   vy    : array[1..20] of Integer;
  31.   r     : array[1..20] of Integer;
  32.  
  33. implementation
  34.  
  35. {$R *.lfm}
  36.  
  37. { TForm1 }
  38.  
  39. procedure TForm1.Button1Click(Sender: TObject);
  40. begin
  41.   Timer1.Enabled := True;
  42. end;
  43.  
  44. procedure TForm1.Button2Click(Sender: TObject);
  45. begin
  46.   Timer1.Enabled := False;
  47. end;
  48.  
  49. procedure switch (var a, b: Integer);
  50. var
  51.   zwischenspeicher: Integer;
  52. begin
  53.   zwischenspeicher := a;
  54.   a := b;
  55.   b := zwischenspeicher;
  56. end;
  57.  
  58. procedure pythagoras;
  59. var
  60.   d: Real;
  61.   i, j: Integer;
  62. begin
  63.   for i := 1 to 20 do
  64.     for j := (i+1) to 20 do begin
  65.       d := sqrt(sqr(mx[j]-mx[i])+sqr(my[j]-my[i]));
  66.       if d <= r[i]+r[j] then begin
  67.         switch(vx[i], vx[j]);
  68.         switch(vy[i], vy[j]);
  69.       end;
  70.     end;
  71. end;
  72.  
  73. procedure TForm1.FormCreate(Sender: TObject);
  74. var
  75.   i: Integer;
  76. begin
  77.   Randomize;
  78.   Image1.Anchors := [akTop, akLeft, akRight, akBottom];
  79.   Width  := 800;
  80.   Height := 600;
  81.   Color  := clPurple;
  82.   DoubleBuffered := True;
  83.   Timer1.Enabled := False;
  84.   for i :=  1 to 20 do begin
  85.     r[i] := 20;
  86.     mx[i] := Random(Image1.Width);
  87.     my[i] := Random(Image1.Height);
  88.     vx[i] := Random(10);
  89.     vy[i] := Random(10);
  90.   end;
  91. end;
  92.  
  93. procedure TForm1.Timer1Timer(Sender: TObject);
  94. var
  95.   i: Integer;
  96. begin
  97.   pythagoras;
  98.   with image1.canvas do begin
  99.     Pen.Color   := clBlack;
  100.     Brush.Color := clBlack;
  101.     Clear;
  102.     for i := 1 to 20 do begin
  103.       mx[i] := mx[i] + vx[i];
  104.       my[i] := my[i] + vy[i];
  105.       if my[i]+r[i] >= Image1.Height then vy[i] := -vy[i];
  106.       if mx[i]+r[i] >= Image1.Width  then vx[i] := -vx[i];
  107.       if my[i]-r[i] < 0              then vy[i] := -vy[i];
  108.       if mx[i]-r[i] < 0              then vx[i] := -vx[i];
  109.       Pen.Color   := clPurple;
  110.       Brush.Color := clPurple;
  111.       Ellipse(mx[i]-r[i], my[i]-r[i], mx[i]+r[i], my[i]+r[i]);
  112.     end;
  113.   end;
  114. end;
  115.  
  116. end.
« Last Edit: January 11, 2018, 05:42:29 pm by Handoko »

Handoko

  • Hero Member
  • *****
  • Posts: 2378
  • My goal: build my own game engine using Lazarus
Re: double loop for a program with the pythagoras
« Reply #21 on: January 11, 2018, 05:40:08 pm »
Now, the code should work like what you want.

But, there still 2 serious bugs:
- Balls sticking together
- Ball sticking at the edge

Well I know how to solve the issues above. I ever wrote Arcanoid and I got these issues too. But if I don't think you're now ready for it, so I think it is enough here now.
« Last Edit: January 11, 2018, 06:33:03 pm by Handoko »

molly

  • Hero Member
  • *****
  • Posts: 2345
Re: double loop for a program with the pythagoras
« Reply #22 on: January 11, 2018, 05:47:16 pm »
Thank you Handoko !

I think the first order of business was for TS to get some  moving balls on his form. Now TS is able to spot the inaccuracies and think on how to address those.

@TS:
Code can still be improved a little (without directly addressing remaining issues), but you probably have (other) restrictions that prevent form doing so.

One thing you can address though is making use of globals (yes, now it is allowed  :) ) to define the number of balls for easy customization or as another example the max radius.

Also when i read this:
Code: [Select]
    mx[i] := Random(Image1.Width);
    my[i] := Random(Image1.Height);

Then ask yourself if that is correct. A picture tells more than a thousand words, so you will see soon enough what is wrong with that  ;)

edit: addressing the right person.
« Last Edit: January 11, 2018, 06:00:30 pm by molly »

Handoko

  • Hero Member
  • *****
  • Posts: 2378
  • My goal: build my own game engine using Lazarus
Re: double loop for a program with the pythagoras
« Reply #23 on: January 11, 2018, 05:56:16 pm »
Did you mean it should be:
Code: Pascal  [Select]
  1. mx[i] := Random(Image1.Width - 2*radius) + radius;
  2. my[i] := Random(Image1.Height - 2*radius) + radius;

And there was a bug in my code:
The Image1's size right after the form expanded does not has accurate values because the form has not 'actually' created so the calculation isn't accurate.

molly

  • Hero Member
  • *****
  • Posts: 2345
Re: double loop for a program with the pythagoras
« Reply #24 on: January 11, 2018, 05:59:26 pm »
Crêpes Suzette  :)

I should have been more careful in my post. those where meant for TS, not you Handoko  :-[

But, yes that is exactly what i meant  :)

bradyhartsfield

  • New member
  • *
  • Posts: 41
Re: double loop for a program with the pythagoras
« Reply #25 on: January 11, 2018, 09:57:06 pm »
Hey,

thanks for all your help!

Now i have one more question:
Quote
Set anchoring for the image and resize the form, add these code into TFrom1.FormCreate:
Image1.Anchors := [akTop, akLeft, akRight, akBottom];
Width  := 800;
Height := 600;
for what is that? because i dont just want to copy but to understand why i am doing things.

regards
Nick



Handoko

  • Hero Member
  • *****
  • Posts: 2378
  • My goal: build my own game engine using Lazarus
Re: double loop for a program with the pythagoras
« Reply #26 on: January 12, 2018, 03:27:54 am »
Set the width and height of the form. The anchors is to set the image to automatic grow larger or smaller if its parent (the form) resized.

bradyhartsfield

  • New member
  • *
  • Posts: 41
Re: double loop for a program with the pythagoras
« Reply #27 on: January 12, 2018, 06:12:29 pm »
Hey,

ah okay, my program is now working! thank you all for your help and especially handoko for that step by step tutorial.

regards,
brady

Kays

  • Full Member
  • ***
  • Posts: 112
  • Whasup!?
    • KaiBurghardt.de
Re: double loop for a program with the pythagoras
« Reply #28 on: January 18, 2018, 07:21:05 pm »
[…]
Code: Pascal  [Select]
  1. d := sqrt(sqr(mx[j]-mx[i])+sqr(my[j]-my[i]));
FYI, you can shorten/simplify that expression with Math.hypot to
Code: Pascal  [Select]
  1. d := hypot(mx[j]-mx[i], my[j]-my[i]);
Yours Sincerely
Kai Burghardt

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus