Recent

Author Topic: how to delete the canvas rectangle  (Read 51561 times)

Handoko

  • Hero Member
  • *****
  • Posts: 3653
  • My goal: build my own game engine using Lazarus
Re: how to delete the canvas rectangle
« Reply #150 on: October 09, 2017, 01:40:16 pm »
+1 bytebites

Also don't forget the reset all game variables (score, SnakeIsGrowing, FoodPos, etc). :-X

Note:
The explanation about using buffer in the game has not finished. I still need more time.

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #151 on: October 09, 2017, 04:07:31 pm »
i did that but it is still not working

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #152 on: October 09, 2017, 04:10:27 pm »
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button2Click(Sender: TObject);
  2. var
  3. SnakeSegment:prect;
  4. begin
  5.   count.visible:=true;
  6.   nameeee.visible:=false;
  7.   scoreeeee.visible:=false;
  8.   shape2.visible:=false;
  9.   button2.visible:=false;
  10.    button3.visible:=false;
  11.  
  12.  
  13.    snakepos.left:=random(24);
  14.    snakepos.top:=random(24);
  15.  
  16.  
  17.    timer1.enabled:=true;
  18.    timer2.enabled:=true;
  19.    xdirection:=0;
  20.    ydirection:=0;
  21.    score:=0;
  22.      For i := 0 to (SnakeBody.Count - 1) do
  23.     begin
  24.       SnakeSegment := SnakeBody[i];
  25.       FreeMem(SnakeSegment);
  26.     end;
  27.    SnakeBody.clear;
  28.  
  29.    snakeisgrowing:=false;
  30.    clearworld;            
this is my code

Handoko

  • Hero Member
  • *****
  • Posts: 3653
  • My goal: build my own game engine using Lazarus
Re: how to delete the canvas rectangle
« Reply #153 on: October 09, 2017, 04:39:08 pm »
You made 2 mistakes:
1. Don't put the code in a button, it will have issue with your form's KeyDown event.
2. If you want to replay the game, you need to 'reintroduce' the snake.

So you can try to put the code on FormKeyDown:
Code: Pascal  [Select][+][-]
  1.   if Key = VK_ESCAPE then
  2.     begin
  3.       // Reset the game
  4.       xDirection     := 0;
  5.       yDirection     := 0;
  6.       Score          := 0;
  7.       Timer1.Enabled := True;
  8.       Timer2.Enabled := True;
  9.       SnakeIsGrowing := False;
  10.       For i := 0 to (SnakeBody.Count - 1) do
  11.         begin
  12.           SnakeSegment := SnakeBody[i];
  13.           FreeMem(SnakeSegment);
  14.         end;
  15.       SnakeBody.Clear;
  16.       ClearWorld;
  17.       // Reintroduce the snake
  18.       SnakePos.Left := Random(24);
  19.       SnakePos.Top  := Random(24);
  20.       New(SnakeSegment);
  21.       SnakeSegment^ := SnakePos;
  22.       SnakeBody.Add(SnakeSegment);
  23.   end;

Not critical but important:
You should write your code nicely. See my code above. When your code grow larger, you will be hard to maintain if you do not format the code neatly.
« Last Edit: October 09, 2017, 06:48:42 pm by Handoko »

Handoko

  • Hero Member
  • *****
  • Posts: 3653
  • My goal: build my own game engine using Lazarus
Re: how to delete the canvas rectangle
« Reply #154 on: October 09, 2017, 07:01:02 pm »
Here is the code you're waiting for.

1. Add Varible "KeyBuffer" on The Declaraction Section

Code: Pascal  [Select][+][-]
  1. var
  2.   KeyBuffer: TList;

2. Add The KeyBuffer Code

Code: Pascal  [Select][+][-]
  1. procedure KeyBufferSetSize(NewSize: Integer);
  2. var
  3.   DataSegment: ^Word;
  4.   i: Integer;
  5. begin
  6.   if (NewSize < 1) or (NewSize > 10) then Exit;
  7.   if (NewSize < KeyBuffer.Count) then
  8.     for i := NewSize to (KeyBuffer.Count-1) do // Free the allocated memory
  9.       begin
  10.         DataSegment := KeyBuffer[i];
  11.         Freemem(DataSegment);
  12.       end;
  13.   KeyBuffer.Capacity := NewSize;
  14. end;
  15.  
  16. procedure KeyBufferStore(Key: Word);
  17. var
  18.   DataSegment: ^Word;
  19. begin
  20.   if (KeyBuffer.Count = KeyBuffer.Capacity) then Exit; // The buffer is full
  21.   New(DataSegment);
  22.   DataSegment^ := Key;
  23.   KeyBuffer.Add(DataSegment);
  24. end;
  25.  
  26. function KeyBufferUse: Word;
  27. var
  28.   DataSegment: ^Word;
  29. begin
  30.   Result := VK_UNDEFINED;
  31.   if (KeyBuffer.Count <= 0) then Exit; // The buffer is empty
  32.   DataSegment := KeyBuffer[0];
  33.   Result := DataSegment^;
  34.   Freemem(DataSegment);
  35.   KeyBuffer.Delete(0);
  36. end;
  37.  
  38. function KeyBufferPeek(Index: Integer): Word;
  39. var
  40.   DataSegment: ^Word;
  41. begin
  42.   Result := VK_UNDEFINED;
  43.   if (KeyBuffer.Count <= 0) then Exit; // The buffer is empty
  44.   if (Index < 0) or (Index >= KeyBuffer.Count) then Exit; // Invalid index
  45.   DataSegment := KeyBuffer[Index];
  46. end;

3. Initial The KeyBuffer When The Program Start

Put this on FormCreate:
Code: Pascal  [Select][+][-]
  1.   KeyBuffer := TList.Create;
  2.   KeyBufferSetSize(2);

The size = 2 should be good enough. But you can change it to other values. If you can press the keyboard really fast, you may need to change the value higher (3, 4, or 5).

4. Free The KeyBuffer When Not Needed

Put this on FormClose:
Code: Pascal  [Select][+][-]
  1.   KeyBuffer.Free;

5. Replace The Code of FormKeyDown

Go to your FormKeyDown, remove all the code inside. And replace them with this:
Code: Pascal  [Select][+][-]
  1.   if (KeyBufferPeek(KeyBuffer.Count-1) <> Key) then KeyBufferStore(Key);

I move the direction calculation to Timer1Timer. Because FormKeyDown should only perform key handling not direction decision.

6. Add Some Code To Timer1Timer Code

Go to your Timer1Timer, add this at the beginning of the procedure:
Code: Pascal  [Select][+][-]
  1.   if (score >= 1) then
  2.     case KeyBufferUse of
  3.       vk_left:  if not(direction = 2) then direction := 1;
  4.       vk_right: if not(direction = 1) then direction := 2;
  5.       vk_up:    if not(direction = 4) then direction := 3;
  6.       vk_down:  if not(direction = 3) then direction := 4;
  7.     end;
  8.   if (score = 0) then
  9.     case KeyBufferUse of
  10.       vk_left:  direction := 1;
  11.       vk_right: direction := 2;
  12.       vk_up:    direction := 3;
  13.       vk_down:  direction := 4;
  14.     end;

Well-done it should work now. I tested on my computer, it works as what it should be.
« Last Edit: October 09, 2017, 07:16:34 pm by Handoko »

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #155 on: October 10, 2017, 10:29:35 am »
what does freemem do?

rvk

  • Hero Member
  • *****
  • Posts: 4227
Re: how to delete the canvas rectangle
« Reply #156 on: October 10, 2017, 10:34:06 am »
what does freemem do?
Before you ask such a question, can't you just type freemem lazarus in Google ???

You get here with the first page:
http://lazarus-ccr.sourceforge.net/docs/rtl/system/freemem.html

Handoko

  • Hero Member
  • *****
  • Posts: 3653
  • My goal: build my own game engine using Lazarus
Re: how to delete the canvas rectangle
« Reply #157 on: October 10, 2017, 07:50:41 pm »
Oops, I forgot to do freemem in FormClose. Thanks for reminding me.

Because calling KeyBufferUse will free a single requested memory item, so by repeating it until the TList.Count = 0 will free all the requested memory.

Please replace my previous code for FormClose with this one:
Code: Pascal  [Select][+][-]
  1.   repeat
  2.     KeyBufferUse;
  3.   until (KeyBuffer.Count <= 0);
  4.   KeyBuffer.Free;

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #158 on: October 11, 2017, 11:54:22 am »
@rvk
sorry i will try to search it up next time

@hondoko
thank you so much. But i don't my understanding level for pointer is not that high (it's not your fault you're a great teacher), so i want to practice more by myself. are there any exercises i can practice?

Handoko

  • Hero Member
  • *****
  • Posts: 3653
  • My goal: build my own game engine using Lazarus
Re: how to delete the canvas rectangle
« Reply #159 on: October 11, 2017, 01:17:34 pm »
As I already mentioned, pointer always is the headache thing for beginners. With some more practices you will be proficient in using it.

Here I found some good explanations how to use pointer in Pascal:
http://www.pascal-programming.info/articles/pointers.php
http://www.tutorialspoint.com/pascal/pascal_pointers.htm
http://pjhayward.net/pascal/questions/pointers.php

The most important thing about using pointer is
If you allocated some space for the pointer, you have to free it.

You can think pointers are like the shortcuts/links in your computer, TList is a folder. If you create several shortcuts and store it in a folder. You should manually remove the 'real' files if you delete the shortcuts in the folder. Because if you just delete the shortcuts but forget to delete the 'real' files. The leftovers take up the space in your harddisk, it is bad.

Do you play computer games? You may notice some games will run slower or buggy after hours of playing. But simply restarting the computer and the game, problem solves. That is memory leak issue. Which usually happens because the programmer does not handle the memory (pointers) properly.

And don't forget about array, it is very important. rvk already provided lots of explanations about using array. You should reread his posts and study what he said.

One task for you, if you really want to improve your programming skill:
Rewrite your snake game using arrays only.
I know it will be a bit hard for you, but I believe: you can!
« Last Edit: October 11, 2017, 01:23:41 pm by Handoko »

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #160 on: October 11, 2017, 11:56:26 pm »
hi i managed to delete array if it's bigger than 4 but i can delete them on the screen
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Timer1Timer(Sender: TObject);
  2. begin
  3.   box[0].left:=box[0].left+(xd*scl);
  4.   box[0].top:=box[0].top+(yd*scl);
  5.  
  6.  
  7.   boxlength:=boxlength+1;
  8.   setlength(box,boxlength);
  9.  
  10.   for i:= 1 to boxlength do
  11.   begin
  12.   box[i]:=tshape.create(self);
  13.   box[i].parent:=self;
  14.   box[i].width:=scl;
  15.   box[i].height:=scl;
  16.   box[i].shape:=strectangle;
  17.   box[i].top:=box[0].top;
  18.   box[i].left:=box[0].left;
  19.  
  20.  
  21.   end;
  22.  
  23.   if 4< boxlength then
  24.     begin
  25.     for i:= 1 to boxlength do
  26.     begin
  27.     box[i]:=box[i+1]
  28.     end;                      
  29.  
  30.     setlength(box, boxlength-1);
  31.     boxlength:=boxlength-1;
  32.  
  33.  
  34.     end;        

bytebites

  • Sr. Member
  • ****
  • Posts: 290
Re: how to delete the canvas rectangle
« Reply #161 on: October 12, 2017, 08:00:43 am »
I will produce range check errors. Check your array indexes.

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #162 on: October 16, 2017, 10:00:24 am »
hi i made snake game using array
it works okay but when i get many tails, it gets laggy how can i fix that?

Handoko

  • Hero Member
  • *****
  • Posts: 3653
  • My goal: build my own game engine using Lazarus
Re: how to delete the canvas rectangle
« Reply #163 on: October 16, 2017, 10:29:57 am »
Great job. You managed to create the snake game using array only. I am sure now you have better understanding about using array.

Many things can be done to improve the performance. But in your case, there is a big issue in your code.

I checked your code, you call TShape.Create to do the drawing. I guess you do not know TShape is class, by calling Create, it will create the object and it needs memory to store it. So you created lots of TShape objects but unfortunately you does not free it. It is not okay.

You should free the TShape object. The code should be put on your TForm1.Delete.

For comparison, rvk's code (for the balls) did not call TShape.Free. That because the total of the balls is static. In your snake game, your code creates a new TShape on Timer1Timer. That's the different.

Basically, there are 2 quick solutions for your case:
- Use canvas rectangle instead of TShape
- Free the shape object by calling TShape.Free

Canvas rectangle is a painting command, it does not create new object and you do not need to free it. Read more about canvas rectangle:
http://wiki.freepascal.org/Drawing_with_canvas
« Last Edit: October 16, 2017, 10:41:51 am by Handoko »

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #164 on: October 16, 2017, 10:56:32 am »
so to free the shape object, i just have to do tshpae.free on Tform1.delete?

 

TinyPortal © 2005-2018