Recent

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

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: how to delete the canvas rectangle
« Reply #180 on: October 18, 2017, 11:21:51 am »
Quote from: pascal
draw to an off-screen bitmap to prevent flickering,
how can i do that?
That quote was actually mine  :)

Given your canvas.rar example you
a) create a global bitmap (don't forget to assign it the proper dimensions)
b) whenever you need to draw your graphics you do that on the bitmap.canvas instead.
c) Whenever you want your graphics displayed on the Form you then copy the contents of that bitmap to your forms's canvas.
d) when your app is done, don't forget to free the bitmap again   :)

Seems' i'm unable to find a good example that resembles your exact situation but if i would have to choose one then it would be this small snippet. But, don't let yourself confused by the separate class. I only pointed to it for you to see how to create and destroy a bitmap, draw to it and how to copy the contents of the bitmap to somewhere else.

But if you want you could take that example almost literally and implement your own 'game-screen' component in a similar fashion (if you are new to bitmaps i would advise against that right now and advise to just play around with bitmaps first for the experience).
« Last Edit: October 18, 2017, 11:47:14 am by molly »

Handoko

  • Hero Member
  • *****
  • Posts: 5376
  • My goal: build my own game engine using Lazarus
Re: how to delete the canvas rectangle
« Reply #181 on: October 18, 2017, 01:44:13 pm »
I wrote 2 codes to show the flickering effect and the solution to solve it following what molly said:

a) create a global bitmap (don't forget to assign it the proper dimensions)
b) whenever you need to draw your graphics you do that on the bitmap.canvas instead.
c) Whenever you want your graphics displayed on the Form you then copy the contents of that bitmap to your forms's canvas.
d) when your app is done, don't forget to free the bitmap again

Flickering and performance are the most basic things a game programmer need to pay attention about. Flickering issue can be solved easily.

For simple games (like snake), flickering rarely happens. It will become noticeable when lots of objects needed to paint on the screen. Below is the common things that may happen when running a game:
  repeat
     clear the screen
     paint object #1
     paint object #2
     ...
     paint object #1000
  end


If only few objects needed to paint on the screen (for example only 10 objects), flickering issue almost never happen. The time between clearing the screen and painting the last object is the key factor, the longer it is the more noticeable flickering effect. It is because the monitor need time to perform the update/refresh.

The solution is simple: "don't paint every single object on the screen directly".

We paint all the objects on a memory buffer, and then we update the screen using a single command to show (or copy) the memory buffer to the screen. TBitmap is good to use as the memory buffer for this case.

My Demo1 shows flickering on my Core2 Quad GeForce 430 Dell monitor if I set the TotalParticles >= 1000. On different hardware, the value may be lower or higher.

The code of Demo2 is basically the same as Demo1, but it does not paint the screen directly so there will no noticeable flickering (I tried to set TotalParticles = 5000).

The differences between the 2 codes are:
- The declaration of variable "TempOutput: TBitmap;"
- Preparing TempOutput on FormCreate
- Freeing TempOutput on FormDestroy
- The procedure DrawGameWorld

Code: Pascal  [Select][+][-]
  1. procedure TForm1.DrawGameWorld;
  2. const
  3.   Padding = 2;
  4. var
  5.   X, Y: Integer;
  6.   ScreenX, ScreenY: Integer;
  7. begin
  8.  
  9.   // Clear the temporary output
  10.   TempOutput.Canvas.Brush.Color := clWhite;
  11.   TempOutput.Canvas.FillRect(0, 0, Width, Height);
  12.  
  13.   // Draw on the canvas of the temporary output
  14.   for X := 1 to WorldWidth do
  15.     for Y := 1 to WorldHeight do
  16.       begin
  17.         ScreenX := (X-1) * Scale;
  18.         ScreenY := (Y-1) * Scale;
  19.         TempOutput.Canvas.Brush.Color := GameWorld[X,Y].Color;
  20.         case GameWorld[X, Y].Item of
  21.           Empty: ; // do nothing
  22.           Box: TempOutput.Canvas.Rectangle(ScreenX, ScreenY, ScreenX+Scale-Padding, ScreenY+Scale-Padding);
  23.           Circle: TempOutput.Canvas.Ellipse(ScreenX, ScreenY, ScreenX+Scale-Padding, ScreenY+Scale-Padding);
  24.           end;
  25.       end;
  26.  
  27.   // Draw the temporary output to the active form's canvas
  28.   Canvas.Draw(0, 0, TempOutput);
  29. end;

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #182 on: October 18, 2017, 02:01:13 pm »
so do i have to put drawgame procedure or can i do it without it?
because i didn't put that in my snake game coding

Handoko

  • Hero Member
  • *****
  • Posts: 5376
  • My goal: build my own game engine using Lazarus
Re: how to delete the canvas rectangle
« Reply #183 on: October 18, 2017, 02:07:16 pm »
Drawgame procedure? Did you mean DrawGameWorld?

For simple games, you do not need it. For complex games, it is a good practice to put all the drawing commands into a single procedure for easier maintaining reason. You can see, I can change the Demo1 to Demo2 to solve the flickering effect easily because I already put all the drawing commands into DrawGameWorld.

shs

  • Sr. Member
  • ****
  • Posts: 310
Re: how to delete the canvas rectangle
« Reply #184 on: October 18, 2017, 02:49:33 pm »
so i just have to put tempout before canvas right?

for example tempout.canvas.rectangle(box) like that?

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: how to delete the canvas rectangle
« Reply #185 on: October 18, 2017, 02:54:41 pm »
for example tempout.canvas.rectangle(box) like that?
Yes.

But, with regards to your canvas.rar example you have something else to consider. Your example draws to the canvas on separate locations inside your code (e.g. you draw and delete at exactly the same time that your game-logic adds or deletes items). You should not do that. Instead you should make one routine that draw everything in one go to the canvas (whatever that canvas might belong to, form or bitmap).

But hold on for a moment. I lost track. Do you already have a working snake-game that works with drawing rectangles to the canvas ? Or is your current working solution only working with TShapes that are placed on the form ?
« Last Edit: October 18, 2017, 03:00:42 pm by molly »

rvk

  • Hero Member
  • *****
  • Posts: 6575
Re: how to delete the canvas rectangle
« Reply #186 on: October 18, 2017, 03:07:11 pm »
But hold on for a moment. I lost track. Do you already have a working snake-game that works with drawing rectangles to the canvas ? Or is your current working solution only working with TShapes that are placed on the form ?
TS already had a working canvas-version.
See here http://forum.lazarus.freepascal.org/index.php/topic,38136.msg262927.html#msg262927

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: how to delete the canvas rectangle
« Reply #187 on: October 18, 2017, 03:15:34 pm »
Thank you very much rvk !

Ok, in that case, the following still stands:
...
But, with regards to your canvas.rar example you have something else to consider. Your example draws to the canvas on separate locations inside your code (e.g. you draw and delete at exactly the same time that your game-logic adds or deletes items). You should not do that. Instead you should make one routine that draw everything in one go to the canvas (whatever that canvas might belong to, form or bitmap).
...

First try to rewrite things so that everything gets drawn to the form canvas (inside event .FormPaint() ) in one go. So try to 'remove' the drawing command from methods .adding() and .delete(). If you are able to accomplish that then updating that code to use a off-screen bitmap becomes much easier.

 

TinyPortal © 2005-2018