Recent

Author Topic: Problem with arrays  (Read 4265 times)

bustee

  • Newbie
  • Posts: 3
Problem with arrays
« on: June 26, 2017, 01:26:36 am »
Hi everyone  :D

I'm new to Pascal and Lazarus and try to program the game snakes at the moment. It all runs quite fine so far, but I have a few issues with the array I use.
The issues are:
  • When the array is created and I try to close the program, I get the following error: raised exception class 'External: SIGSEGV'. When I kill myself without growing (i.e. the array never contained elements and has length 0), the close; command works fine (Line 66). This means, it should be an error caused by the array or its elements
  • I don't really know how to properly delete elements from the array, so if I just set the length of the array to 0,
     the  objects it contained still exist and are visible in the client. This is the reason why I set the visibility to false before setting the length to 0 in the code (Line 66).

Here is the code

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
  9.   LCLType, StdCtrls;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     food: TShape;
  17.     Label1: TLabel;
  18.     Label2: TLabel;
  19.     Label3: TLabel;
  20.     Label4: TLabel;
  21.     Snake: TShape;
  22.     Timer1: TTimer;
  23.     procedure FormCreate(Sender: TObject);
  24.     procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  25.     procedure gameLoop(Sender: TObject);
  26.     procedure collision;
  27.     procedure Label3Click(Sender: TObject);
  28.     procedure Label4Click(Sender: TObject);
  29.   private
  30.     { private declarations }
  31.   public
  32.     { public declarations }
  33.   end;
  34.  
  35. var
  36.   Form1: TForm1;
  37.   le, ri, up, dow, lost : boolean;
  38.   tail: array of tshape;
  39.   tailLength, laufVariable: integer;
  40.  
  41. implementation
  42.  
  43. {$R *.lfm}
  44.  
  45. { TForm1 }
  46.  
  47. procedure TForm1.collision;
  48. begin
  49.   if (snake.Top > clientheight) or (snake.Top < 0) or (snake.Left > clientwidth) or (snake.Left < 0) then
  50.   begin
  51.     lost:=true;
  52.   end;
  53.   for laufVariable := 1 to (tailLength - 1)do
  54.   begin
  55.        if (snake.Top = tail[laufVariable].Top) and (snake.Left = tail[laufVariable].Left) then lost:=true;
  56.   end;
  57. end;
  58.  
  59. procedure TForm1.Label3Click(Sender: TObject);
  60. begin
  61.   label1.Visible:=false;
  62.   label2.Visible:=false;
  63.   label3.Visible:=false;
  64.   label4.Visible:=false;
  65.   for Laufvariable := 0 to taillength -1 do
  66.   begin
  67.     tail[laufVariable].Visible:=false;
  68.   end;
  69.   setlength(tail,0);
  70.   snake.Top:=160;
  71.   snake.Left:=200;
  72.   ri := true;
  73.   le := false;
  74.   up:= false;
  75.   dow:=false;
  76.   lost:=false;
  77.   tailLength:=0;
  78.   food.Top:=random(30)*20;
  79.   food.Left:=random(30)*20;
  80.   timer1.Enabled:=true;
  81. end;
  82.  
  83. procedure TForm1.Label4Click(Sender: TObject);
  84. begin
  85.   tail:=nil;
  86.   close;
  87. end;
  88.  
  89. procedure TForm1.gameLoop(Sender: TObject);
  90. begin
  91.    collision;
  92.    if lost then
  93.    begin
  94.         timer1.Enabled:=false;
  95.         label2.Caption:='Du hast '+ inttostr(taillength) +' Punkte erreicht!';
  96.         label1.Visible:=true;
  97.         label2.Visible:=true;
  98.         label3.Visible:=true;
  99.         label4.Visible:=true;
  100.    end;
  101.    if ri then
  102.    begin
  103.    laufvariable := taillength -1;
  104.    while laufVariable > 0 do
  105.    begin
  106.         tail[laufVariable].Left:= tail[laufVariable-1].Left;
  107.         tail[laufVariable].Top:= tail[laufVariable-1].Top;
  108.         dec(laufVariable);
  109.    end;
  110.    if taillength > 0 then
  111.       begin
  112.            tail[0].Left:=Snake.Left;
  113.            tail[0].Top:=Snake.Top;
  114.       end;
  115.    Snake.Left:=Snake.Left + 20;
  116.    end
  117.    else if le then
  118.    begin
  119.    laufvariable := taillength-1;
  120.    while laufVariable > 0 do
  121.     begin
  122.          tail[laufVariable].Left:= tail[laufVariable-1].Left;
  123.          tail[laufVariable].Top:= tail[laufVariable-1].Top;
  124.          dec(laufVariable);
  125.     end;
  126.    if taillength > 0 then
  127.    begin
  128.         tail[0].Left:=Snake.Left;
  129.         tail[0].Top:=Snake.Top;
  130.    end;
  131.    Snake.left:=Snake.Left - 20;
  132.    end
  133.    else if dow then
  134.    begin
  135.    laufvariable := taillength-1;
  136.    while laufVariable > 0 do
  137.    begin
  138.         tail[laufVariable].Left:= tail[laufVariable-1].Left;
  139.         tail[laufVariable].Top:= tail[laufVariable-1].Top;
  140.         dec(laufVariable);
  141.    end;
  142.    if taillength > 0 then
  143.       begin
  144.            tail[0].Left:=Snake.Left;
  145.            tail[0].Top:=Snake.Top;
  146.       end;
  147.    Snake.Top:=Snake.Top + 20;
  148.    end
  149.    else
  150.    begin
  151.       laufvariable := taillength-1;
  152.    while laufVariable > 0 do
  153.    begin
  154.         tail[laufVariable].Left:= tail[laufVariable-1].Left;
  155.         tail[laufVariable].Top:= tail[laufVariable-1].Top;
  156.         dec(laufVariable);
  157.    end;
  158.    if taillength > 0 then
  159.       begin
  160.            tail[0].Left:=Snake.Left;
  161.            tail[0].Top:=Snake.Top;
  162.       end;
  163.    Snake.Top:=snake.Top -20;
  164.    end;
  165.    if (snake.Top=food.Top) and (snake.Left = food.Left) then
  166.    begin
  167.      food.Top:=random(30)*20;
  168.      food.Left:=random(30)*20;
  169.      inc(tailLength);
  170.      setLength(tail, tailLength);
  171.      laufvariable := taillength;
  172.      while laufVariable > 0 do
  173.      begin
  174.         tail[laufVariable]:= tail[laufVariable - 1];
  175.         dec(laufVariable);
  176.      end;
  177.      tail[0]:= Tshape.Create(Form1);
  178.      tail[0].Top:=snake.Top;
  179.      tail[0].Left:=snake.Left;
  180.      tail[0].Height:=snake.Height;
  181.      tail[0].Width:=snake.Width;
  182.      tail[0].parent:=Form1;
  183.      timer1.Interval:=trunc(timer1.Interval * 0.95);
  184.    end;
  185. end;
  186.  
  187. procedure TForm1.FormCreate(Sender: TObject);
  188. begin
  189.   ri := true;
  190.   le := false;
  191.   up:= false;
  192.   dow:=false;
  193.   lost:=false;
  194.   tailLength:=0;
  195.   food.Top:=random(30)*20;
  196.   food.Left:=random(30)*20;
  197. end;
  198.  
  199. procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState
  200.   );
  201. begin
  202.   if (key=VK_RIGHT) and (le=false) then
  203.   begin
  204.     ri := true;
  205.     le := false;
  206.     up:= false;
  207.     dow:=false;
  208.   end else
  209.   if (key=VK_LEFT) and (ri=false) then
  210.   begin
  211.     ri := false;
  212.     le := true;
  213.     up:= false;
  214.     dow:=false;
  215.   end else
  216.   if (key=VK_UP) and (dow=false) then
  217.   begin
  218.     ri := false;
  219.     le := false;
  220.     up:= true;
  221.     dow:=false;
  222.   end else
  223.   if (key=VK_DOWN) and (up=false) then
  224.   begin
  225.     ri := false;
  226.     le := false;
  227.     up:= false;
  228.     dow:=true;
  229.   end;
  230. end;
  231.  
  232. end.
  233.  

Does anyone know what I do wrong? I cannot really figure it out at the moment!

Thanks!!!!
« Last Edit: June 26, 2017, 01:28:39 am by bustee »

Akira1364

  • Hero Member
  • *****
  • Posts: 561
Re: Problem with arrays
« Reply #1 on: June 26, 2017, 02:54:15 am »
There are, uh, several issues here. First of all, what exactly is the TTimer used for? I'm assuming it must have its OnTimer event set to call the "gameLoop" procedure? Otherwise I don't see how this application would actually do anything that resembles a game when you run it. Secondly, the reason the food shapes are still visible when you alter the array length is because they are TComponent descendants, and you're creating them as children of the form itself. The only time they will actually be "deleted" is if you manually call their Free method (as in tail[SomeIndex].Free), or when the form is closed (since all TComponent descendants are automatically freed whenever their parent component is itself freed.) There's various other things I could point out but I'm not sure it's worth it without more information first...
« Last Edit: June 26, 2017, 02:55:55 am by Akira1364 »

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Problem with arrays
« Reply #2 on: June 26, 2017, 03:42:18 am »
Hello bustee,
Welcome to the forum.

Can you please provide the complete source code. It will be much easier to inspect your code by running your program.

To do it copy all files to a new folder, except the exe, *.bak, and lib folder, don't forget to include the image. Compress the folder and send the zip file to this forum. If the zip file is too big, try to exclude the images.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9794
  • Debugger - SynEdit - and more
    • wiki
Re: Problem with arrays
« Reply #3 on: June 26, 2017, 04:11:50 am »
Have you tried range checking?

Line 170 and following
Code: Pascal  [Select][+][-]
  1.     laufvariable := taillength;
  2.      while laufVariable > 0 do
  3.      begin
  4.         tail[laufVariable]:= tail[laufVariable - 1];
  5.         dec(laufVariable);
  6.      end;

looks like you access an element outside the allocated array.

Such out of bound errors can fail at any time (immediate or any time later), and they can fail with any error.


bustee

  • Newbie
  • Posts: 3
Re: Problem with arrays
« Reply #4 on: June 26, 2017, 06:56:54 am »
@Martin

Thanks! That was it. I didn't see that and actually thought that I would get an error straight away when that array position is called. Thanks for pointing it out. It now works. I still don't know how to do item 2 from my list, though.

@Handoko

I compressed the file as you said. It is available here: https://ufile.io/6rzgd

@Akira

Maybe look at the file I uploaded for Handoko. The timer is of course starting the gameloop when the ontimer event happens. I will try to use .free, but I first read up on it.


Thanks for the help, everyone :)

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Problem with arrays
« Reply #5 on: June 26, 2017, 07:15:32 am »
How to reproduce your issue?

No problem here. I tested it on Linux 64-bit.

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Problem with arrays
« Reply #6 on: June 26, 2017, 07:23:26 am »
You use SetLength to empty the array, it is okay, but because the items inside the array are TShape, you have to free it manually:

Code: Pascal  [Select][+][-]
  1. var
  2.   i: Integer;
  3. //...
  4.   for i := Low(tail) to High(tail) do
  5.     tail[i].Free;
  6.   SetLength(tail, 0);

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 844
Re: Problem with arrays
« Reply #7 on: June 26, 2017, 08:25:31 am »
Can't reproduce exception. Can you provide some info, about how to reproduce it? But yeah, TShape objects aren't freed anywhere in your code.
You use SetLength to empty the array, it is okay, but because the items inside the array are TShape, you have to free it manually:

Code: Pascal  [Select][+][-]
  1. var
  2.   i: Integer;
  3. //...
  4.   for i := Low(tail) to High(tail) do
  5.     tail[i].Free;
  6.   SetLength(tail, 0);
You can't do it, at least on Windows - it causes exception, as form still holds references to this objects. You should use this code instead:
Code: Pascal  [Select][+][-]
  1.         for I := 0 to Length(tail) - 1 do begin
  2.           RemoveControl(tail[I]);
  3.         end;
  4.  
No Free call is needed, as, I guess, RemoveControl does it automatically. At least in my case Free call causes exception.
« Last Edit: June 26, 2017, 08:27:57 am by Mr.Madguy »
Is it healthy for project not to have regular stable releases?
Just for fun: Code::Blocks, GCC 13 and DOS - is it possible?

bustee

  • Newbie
  • Posts: 3
Re: Problem with arrays
« Reply #8 on: June 26, 2017, 02:55:38 pm »
Thanks guys  :D

You cannot reproduce the exception, because Martin_fr told me the reason it occurred and I corrected it already. But thanks for letting me know about the .free method. I didn't know about it. I think all my questions are answered.


Thanks a lot guys!

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Problem with arrays
« Reply #9 on: June 26, 2017, 03:35:16 pm »
It is fun to do graphics and game programming. Would you like to participate a contest? Winning the contest is not the goal, it just fun to show others what you're doing and see what are others doing:

http://forum.lazarus.freepascal.org/index.php/topic,35313.0.html

See you there.

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: Problem with arrays
« Reply #10 on: June 26, 2017, 07:46:53 pm »
I'm new to Pascal and Lazarus and...
I made refactoring, because some issue:
1. Global variables
2. Naming (and a non-persistent name case)
3. and so on.
See Code. Learn :)

 

TinyPortal © 2005-2018