Recent

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

Handoko

  • Hero Member
  • *****
  • Posts: 5130
  • My goal: build my own game engine using Lazarus
Re: how to delete the canvas rectangle
« Reply #165 on: October 16, 2017, 10:58:44 am »
Yes, right after you set its color to game.brush.color.

Code: Pascal  [Select][+][-]
  1. box[index].Free;

edit:
Actually, you do not need to set the color. Because TShape is object, by freeing it, it will also remove what it already painted and set it to the background. So, you can simple remove these lines too:
Code: Pascal  [Select][+][-]
  1.     box[index].brush.color:=game.brush.color;
  2.     box[index].pen.color:=game.brush.color;
« Last Edit: October 16, 2017, 11:03:01 am by Handoko »

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #166 on: October 16, 2017, 11:38:14 am »
oh wow thank you i didn't know that

also how can use array for canvas ?

Handoko

  • Hero Member
  • *****
  • Posts: 5130
  • My goal: build my own game engine using Lazarus
Re: how to delete the canvas rectangle
« Reply #167 on: October 16, 2017, 01:11:46 pm »
No need to use array of canvas, but you should use array of TRect to store the coordinates.

Your mainform already provide you a canvas. The canvas is an object too, but you do not need to free it manually because the canvas is created automatically by the the form, it will also be freed automatically when you exit the program.

Because it is created by the mainform (or active form), you use the form's name to refer to it, for example:
Form1.canvas.rectangle (10, 10, 20, 20);

Usually, we use self to refer to the active form (without need to know what is the form's name):
self.canvas.rectangle (10, 10, 20, 20);

But on most cases, you do not need to use form's name or self because it will automatically refer to the active form. So your code should become:

procedure TForm1.add;
var
  index: Integer;
begin
    setlength(box, length(box)+1);

    index:=length(box)-1;
    box[index]:=
TRect.Create(self);
    box[index].width:=scl;
    box[index].height:=scl;

    case direction of
      1: begin //right
           box[index].top:=box[index-1].Top;
           box[index].left:=box[index-1].left+scl;
         end;
      2: begin //left
           box[index].top:=box[index-1].Top;
           box[index].left:=box[index-1].left-scl;
         end;
      3: begin //up
           box[index].top:=box[index-1].Top-scl;
           box[index].left:=box[index-1].left;
         end;
      4: begin //down
           box[index].top:=box[index-1].Top+scl;
           box[index].left:=box[index-1].left;
         end;
    end;

   
    Canvas.Pen.Color := game.Brush.Color;
    if index < 2 then
Canvas.Brush.Color := clred
      else if (2 <= index)and (index < 4) then Canvas.Brush.Color := clyellow
      else if (4 <= index)and (index < 6) then Canvas.Brush.Color := clblue;
    Canvas.Rectangle(box[index]);

    ....

« Last Edit: October 16, 2017, 01:38:14 pm by Handoko »

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #168 on: October 16, 2017, 01:20:06 pm »
i got error for this line
Code: Pascal  [Select][+][-]
  1.     box[index]:=TRect.Create(self);
unit1.pas(44,34) Error: Incompatible type for arg no. 1: Got "TForm1", expected "TRect"

Handoko

  • Hero Member
  • *****
  • Posts: 5130
  • My goal: build my own game engine using Lazarus
Re: how to delete the canvas rectangle
« Reply #169 on: October 16, 2017, 01:31:27 pm »
Sorry my fault. TRect is an advanced record, no need to call Create. So you can simply delete that line.

You still need to modify the declaration section for the variable "box". You may also need to modify all things related with the "box". On your IDE you can use shortcut "CTRL" + "F" and type "box" to find the text in your source code.

Note:
TShape is a class that will create an object so you should free it manually. But TRect is an advanced record (which looks like class), you do not call Create and you do not need to free it.
« Last Edit: October 16, 2017, 01:35:06 pm by Handoko »

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #170 on: October 17, 2017, 02:35:12 am »
so what do i have to to delete the array?

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #171 on: October 17, 2017, 10:11:03 am »
the snake is working good but food isn't
Code: Pascal  [Select][+][-]
  1. if (box[length(box)-1].left = food.left) and  (box[length(box)-1].top = food.top) then
  2.   begin
  3.  
  4.    food.topleft:=point(rx,ry);
  5.    food.bottomright:=point(rx+20,ry+20);
  6.  
  7.    boxlength:=boxlength+1;
  8.  
  9.   end;                    

i think this part is wrong but i don't know how i can fix it please find the attachment

Handoko

  • Hero Member
  • *****
  • Posts: 5130
  • My goal: build my own game engine using Lazarus
Re: how to delete the canvas rectangle
« Reply #172 on: October 17, 2017, 12:04:10 pm »
Your code has several issues.

1. Put Your Data Initialization Code In FormCreate

I saw you put that code in FormPaint, it is not good. You can put that code in FormPaint and make it works correctly, but that code will be complicated and hard to maintain.

Your FormCreate now should be like this:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. var
  3.   index: Integer;
  4. begin
  5.   // Prepare snake
  6.   setlength(box, 1);
  7.   index:=length(box)-1;
  8.   box[index].width:=scl;
  9.   box[index].height:=scl;
  10.   box[index].left:=0;
  11.   box[index].top:=0;
  12.   // Prepare food
  13.   randomize;
  14.   rx:=random((width-scl)div scl)*scl;
  15.   ry:=random((height-scl)div scl)*scl;
  16.   food.topleft:=point(rx,ry);
  17.   food.bottomright:=point(rx+20,ry+20);
  18. end;

2. Don't Use FormPaint

You used FormPaint to draw the food, it is not a good thing to do. There is a thing you need to know about FormPaint. When you draw something on FormPaint, it will not update the screen immediately. It sounds weird, isn't it? But this is how they design OnPaint (including FormPaint). You need to force it to update/refresh/repaint. And this is the issue that causes the food won't show up.

I won't explain much about FormPaint. You now can simply remove the code in FormPaint because we will merge the code to Timer1Timer.

3. Do The Painting On Timer1Timer

I think I do not need to explain, because the code below is easy to understand:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Timer1Timer(Sender: TObject);
  2. var
  3.   index: Integer;
  4. begin
  5.  
  6.   // Paint the snake
  7.   index:=length(box)-1;
  8.   canvas.brush.color:=clwhite;
  9.   canvas.pen.color:=form1.color;
  10.   canvas.rectangle(box[index]);
  11.  
  12.   // Paint the food
  13.   food.topleft:=point(rx,ry);
  14.   food.bottomright:=point(rx+20,ry+20);
  15.   canvas.brush.color:=clred;
  16.   canvas.pen.color:=form1.color;
  17.   canvas.rectangle(food);
  18.  
  19.   // Move the snake
  20.   adding();
  21.   if length(box) = boxlength then delete();
  22.  
  23.   // Collision Test
  24.   if (box[length(box)-1].left = food.left) and  (box[length(box)-1].top = food.top) then
  25.   begin
  26.     // Show new food
  27.     randomize;
  28.     rx:=random((width-scl)div scl)*scl;
  29.     ry:=random((height-scl)div scl)*scl;
  30.     food.topleft:=point(rx,ry);
  31.     food.bottomright:=point(rx+20,ry+20);
  32.     // Increase snake's length
  33.     boxlength:=boxlength+1;
  34.   end;
  35. end;

So far the code should work now. Although there still many things can be done to improve the code's quality.

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #173 on: October 17, 2017, 01:42:00 pm »
what should i do to improve code's quality?

Handoko

  • Hero Member
  • *****
  • Posts: 5130
  • My goal: build my own game engine using Lazarus
Re: how to delete the canvas rectangle
« Reply #174 on: October 17, 2017, 03:08:10 pm »
1. No Need To Use "(" and ")"

If the procedure doesn't have any parameter, you can remove that brackets:
Code: Pascal  [Select][+][-]
  1.     procedure Adding;
  2.     procedure Delete;

You don't have to, but I personally will move the Adding and Delete declaration to private section. I left the auto generated by IDE on the top (like FormCreate, FormKeyDown, Timer1Timer). See point #2 below.

2. Put Things On The Lowest Scope

There are 3 visibilities (actually there are 6) in class:
- Private
- Protected
- Public

It is good to put your variables, functions or procedures on the lowest visibility scope unless you really need to put them on the higher visibility levels.

So your "box" and "food" declaration should be in private section:
Code: Pascal  [Select][+][-]
  1.   private
  2.     Box:  array of TRect;
  3.     Food: TRect;
  4.   end;
I personally will put my procedures and functions on this section too (Adding, Delete).

3. BoxLength Should Be Started With 1

Do you not think it is strange, your BoxLength started with the value of 2? So, change the declaration of BoxLength with this:
Code: Pascal  [Select][+][-]
  1.   BoxLength: Integer = 1;

And you also need to change the code of BoxLength in Timer1Timer to become:
Code: Pascal  [Select][+][-]
  1.   if Length(Box) > BoxLength then Delete;

4. Use Better Names

Code: Pascal  [Select][+][-]
  1.   rx, ry : Integer;
  2.   scl = 20;

If you ever tried to the read codes written by professionals, you will notice they always use meaningful names. It will make the code easier to understand especially when the code grows to thousands of lines. Except for i, j, k ..., which are used for looping.

5. Use Space To Make It More Readable

This code below will look nicer:
Code: Pascal  [Select][+][-]
  1.   case Key of
  2.     vk_Right: Direction := 1;
  3.     vk_Left:  Direction := 2;
  4.     vk_Down:  Direction := 3;
  5.     vk_Up:    Direction := 4;
  6.   end;

6. No Need To Use Begin-End For Single Line For-Loop

You can simplify the for-loop statement by removing the begin-end if it only contains 1 command. So the for-loop in your Delete procedure will become:
Code: Pascal  [Select][+][-]
  1.   for i:= 1 to Length(Box)-1 do Box[i-1] := Box[i];

Alternatively, some programmers will prefer to write it in 2 lines:
Code: Pascal  [Select][+][-]
  1.   for i:= 1 to Length(Box)-1 do
  2.     Box[i-1] := Box[i];

7. Use Camel Case

Except for reserved keywords, using camel case will make the code looks better.
https://en.wikipedia.org/wiki/Camel_case
« Last Edit: October 17, 2017, 03:11:54 pm by Handoko »

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: how to delete the canvas rectangle
« Reply #175 on: October 17, 2017, 03:21:45 pm »
@Handoko:
you're in your element it seems, and you seem to be more in line with TS  8-)

additionally to your otherwise excellent suggestions i would personally a) add a separate snake class as that makes more sense to have things "tucked away" in there, b) draw to an off-screen bitmap to prevent flickering, c) at least rename the box array into something like snake or bodyparts (after all it is a snake game).

How much of that would be feasible for TS i have no idea.

edit: Oh, and i just noticed: you might already noticed i'm an advocate of using Low()/High() and Succ()/Pred() instead of length-1 and hard-coded start-index-values  :)
« Last Edit: October 17, 2017, 03:49:34 pm by molly »

munair

  • Hero Member
  • *****
  • Posts: 798
  • compiler developer @SharpBASIC
    • SharpBASIC
Re: how to delete the canvas rectangle
« Reply #176 on: October 17, 2017, 03:33:27 pm »
Except for i, j, k ..., which are used for looping.
Most programmers start the first for-loop with variable 'i'. This is common practice and goes back to the 1960s if I remember correctly. i stands for 'iteration'. Nested loops then follow with 'j', 'k', etc to keep some 'logic' to the variable naming. ;)
keep it simple

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #177 on: October 17, 2017, 11:21:49 pm »
@hondoko
 Thank you :)
Code: Pascal  [Select][+][-]
  1. draw to an off-screen bitmap to prevent flickering,
how can i do that?

J-G

  • Hero Member
  • *****
  • Posts: 953
Re: how to delete the canvas rectangle
« Reply #178 on: October 18, 2017, 10:47:21 am »
Most programmers start the first for-loop with variable 'i'.  i stands for 'iteration'.
Not in my mind - i = 'Index'  indicating the [index] of the array. It could just as easily be 'x' which from antiquity is the 'Unknown quantity' or even 'c' for Count.
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

munair

  • Hero Member
  • *****
  • Posts: 798
  • compiler developer @SharpBASIC
    • SharpBASIC
Re: how to delete the canvas rectangle
« Reply #179 on: October 18, 2017, 11:21:07 am »
Most programmers start the first for-loop with variable 'i'.  i stands for 'iteration'.
Not in my mind - i = 'Index'  indicating the [index] of the array. It could just as easily be 'x' which from antiquity is the 'Unknown quantity' or even 'c' for Count.
If you follow back the naming convention then 'x' wasn't a candidate. It seems to have its roots in Fortran where i,j,k were implicitely declared as integer, while x,y,z were of type real.

According to Wikipedia and other sources the naming convention dates back further to mathematical notation:

"This style is generally agreed to have originated from the early programming of FORTRAN, where these variable names beginning with these letters were implicitly declared as having an integer type, and so were obvious choices for loop counters that were only temporarily required. The practice dates back further to mathematical notation where indices for sums and multiplications are often i, j, etc."

So yes, index may have been the original meaning coming from the world of mathematics. However, in programming, loops are not always used to go through indices of arrays. Often calculations are done using the iterator.

Anyway, I picked it up long ago in a programming book where it was explained that i means iterator. I guess we'll never know the original reason why the Fortran developer(s) chose i. It may have been Integer, Index, Iterator or even Item. You will find them all if you search the internet.
keep it simple

 

TinyPortal © 2005-2018