Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Gráficos (https://www.clubdelphi.com/foros/forumdisplay.php?f=8)
-   -   Dibujando con Canvas (https://www.clubdelphi.com/foros/showthread.php?t=60523)

ivanloco 04-10-2008 18:09:50

Dibujando con Canvas
 
Hola: estoy realizando el juego del tetris en 3D, lo hago por medio de ir pintando triangulos con la funcion Canvas.Polygon().
El problema que tengo es que cada vez que muevo la ficha que va cayendo tengo que redibujar todo y esto hace que la imagen completa del juego parpadee lo cual es muy molesto.
Si alguien sabe como puedo solucionar esto le agradezco me informe como.

Saludos

coso 04-10-2008 21:52:48

Hola, en principio poniendo a la form doublebuffered := true (por codigo) solucionarias algo. Ahora bien, si se tienen q mover muchos graficos como parece q es el caso, te recomiendo q uses o bien OpenGL o alguna libreria como GLScene. Saludos.

coso 05-10-2008 09:33:47

Hola de nuevo. Otra manera sencilla seria borrar tansolo (pintando con el fondo) el lugar anterior de la pieza donde esta ya no es visible. Saludos.

ivanloco 05-10-2008 21:07:19

Implemente la segunda opcion y funciona bien. Gracias

ivanloco 05-10-2008 21:11:53

Ahora tengo otra duda, si quiero que el fondo sea una imagen cargada en un componente Image, como hago para que este se vea cuando borro la posicion anterior de la ficha?

coso 05-10-2008 21:16:36

Pues para 'borrar' la imagen debes copiar el mismo trozo que habia antes en ese lugar. Esto lo puedes conseguir teniendo un TImage no visible con todo el fondo cargado y ir copiando de ella segun necesites. Para eso puedes usar el metodo copyrect de TCanvas. Saludos.

PD : De todas maneras, el doublebuffered a true (tanto del form como de donde muevas) te optimizara el parpadeo.

ivanloco 05-10-2008 23:04:16

Gracias por la pronta respuesta, pero podrias poner aunque sea un pseudocodigo de como seria ya que mire la funcion pero no entiendo como funciona. Lleva tres parametros: rectangulo destino, un canvas y el rectangulo origen.

Gracias

coso 06-10-2008 10:15:17

Hola, te pongo el mismo ejemplo que en la ayuda de delphi

Código Delphi [-]
var
  Bitmap: TBitmap;
  MyRect, MyOther: TRect;
begin
  MyRect := Rect(10,10,100,100);
  MyOther := Rect(10,111,100, 201);
  Bitmap := TBitmap.Create;
  Bitmap.LoadFromFile('c:\windows\tartan.bmp');
  Form1.Canvas.BrushCopy(MyRect, Bitmap, MyRect, clBlack);
  Form1.Canvas.CopyRect(MyOther,Bitmap.Canvas,MyRect);
  Bitmap.Free;
end;

MyRect es la zona de Form1 donde se va a copiar, bitmap.canvas es el canvas origen, y MyOther es el 'trozo' que se coje de bitmap.canvas.
saludos

ivanloco 06-10-2008 23:13:03

Perdon por seguir insistiendo, pero finalmente decidi tratar de implementar el doble buffer porq me ayudaria en varias cosas.
Encontre en un articulo (http://delphi.about.com/library/bluc/text/uc052102g.htm) esta solucion :

Código:

Bmp := TBitmap.Create;
try
  Bmp.Width := ClientWidth;
  Bmp.Height := ClientHeight;

  // Draw lines onto the **bitmap's** canvas
  for i := 0 to 20000 do
  begin
    Bmp.Canvas.MoveTo(Random(ClientWidth), Random(ClientHeight));
    Bmp.Canvas.LineTo(Random(ClientWidth), Random(ClientHeight));
  end;

  Canvas.Draw(0,0, Bmp); // draw the bitmap to screen now
finally 
  Bmp.Free;
end;

Lo que esto trata de hacer es, primero dibujar todo al canvas del componente TBitmap y luego pasarselo al Canvas del form.
Parece ser una buena solucion para dibujar todo de una y que no se vea como se va dibujando paso a paso.
El problema que tengo es que uso un componente timer y cada vez que ejecuta llama a este codigo de manera que la imagen vuelve a parpadear.
Active la propiedad Doublebuffer del form a true pero no cambia en nada el resultado, ya no se que hacer.
Si alguien se da cuenta de mi error por favor digame como solucionarlo. Gracias

gatosoft 07-10-2008 02:19:12

Bueno, la tecnica del Doble Buffer evita el parpadeo... no tendría por que fallarte.... a menos que el tiempo de tu ttimer fuera inferior al tiempo que tarda en dibujarse la figura... Por otro lado, activar la propiedad Doublebuffer del form es como redundar...

Practica aumentando el tiempo de tu ttimer, por ejemplo a 5 segundos, o mas (dependiendo de como lo tengas) y verifica si te sigue pasando... si no pasa quiere decir que el problema es con el ttimer....

Si sigue pasando entonces el problema está en algo de la logica de tu codigo....

coso 07-10-2008 10:18:06

Cita:

activar la propiedad Doublebuffer del form es como redundar...
no bien bien. Asi se creara un solo bitmap para todo en memoria, y al pintar pintaria el bitmap de la form, mientras que de la otra manera pintaria la form directamente a pantalla y luego el bitmap correspondiente a TBitmap, este si, desde memoria mediante el doblebuffered. Se gana poco, si, pero se gana. Saludos.

cHackAll 07-10-2008 19:22:45

Código Delphi [-]
unit Unit1; // Ejemplo de buffer doble programada, no interesa el valor de la propiedad...
 
interface
 
uses Windows, Classes, Graphics, Controls, Forms, ExtCtrls;
 
type
 TForm1 = class(TForm)
  Timer: TTimer;
  procedure FormCreate(Sender: TObject);
  procedure FormPaint(Sender: TObject);
  procedure TimerTimer(Sender: TObject);
  procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  procedure FormDestroy(Sender: TObject);
 end;
 
var Form1: TForm1;
 
implementation
 
{$r *.dfm}
 
var
 Bitmap: TBitmap;
 Value: Integer;
 Flag: Boolean;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
 Bitmap := TBitmap.Create;
 Bitmap.Width := ClientWidth;
 Bitmap.Height := ClientHeight;
 Bitmap.Canvas.Pen.Color := clRed;
 Timer.Interval := 20;
end;
 
procedure TForm1.FormPaint(Sender: TObject);
begin
 BitBlt(Canvas.Handle, 0, 0, ClientWidth, ClientHeight, Bitmap.Canvas.Handle, 0, 0, SRCCOPY); // Double buffered !
end;
 
procedure TForm1.TimerTimer(Sender: TObject);
begin
 if not Flag then
  if Value = 120 then
   Flag := not Flag
  else
   Inc(Value, 6)
 else
  if Value = 0 then
   Flag := not Flag
  else
   Dec(Value, 6);
 FormMouseMove(nil, [], 0, 0);
end;
 
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
 Point: TPoint;
 Size: Integer;
begin
 with Bitmap.Canvas do
  begin
   Lock;
 
   Size := Value - 100;
   GetCursorPos(Point);
   if Size < 0 then Size := 0;
   Y := Point.Y - Top - (66 * 2) + (Value - Size);
   X := Point.X - Left;
 
   Brush.Color := clBlack;
   FillRect(ClientRect);
   Pen.Color := clRed;
   Brush.Color := Pen.Color;
   Ellipse(X - 66, Y - (66 * 2) + Size, X + 66, Y);
   Y := Point.Y - ClientOrigin.Y;
   Pen.Color := 150 + Size * 5;
   Rectangle(X - 66, Y, X + 66, Y + 2);

   FormPaint(nil);
   Unlock;
  end;
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
 Bitmap.Destroy;
end;
 
end.

coso 07-10-2008 19:30:24

Muy chulo :D:D pero si la form tuviese algun componente y no solo un bitmap que se pintase todo en ella...con el doublebuffered de la form se evitaria flickering al pintar todo de un mismo golpe no? me refiero...es redundante o no el uso de doublebuffered en todos los componentes con posible retardo a pintar? Bueno, para el caso, mas o menos lo mismo.

cHackAll 07-10-2008 19:52:00

A que te refieres coso? pues el ejemplo funciona con N componentes "encima" sin ningun efecto "flickering" :rolleyes:

PD; al utilizar la propiedad DoubleBuffered perteneciente a TWinControl se crea en cada proceso de repintado, un nuevo canvas y bitmap internamente y se hace uso de una llamada recursiva a WMPaint con lo que en procesos complejos con GDI se nota una carga extra al procesador.

Tambien me parece que seria un "juego" algo "feo" si tuviese un TButton al centro del formulario (por ejemplo).

Saludos

coso 07-10-2008 22:20:58

no no tu ejemplo perfecto, pero si el bitmap no se copiase a toda la form, entonces todo el resto (si estuviese doublebuffered a false) se dibujaria directamente a pantalla no? entonces, vamos, para una form con un dibujo mejor crear un unico bitmap de toda la form (esto es doublebuffered a true de la form). Me refiero, q si TBitmap esta con dblbuffer y la form no, el trozo de form visible se dibujaria directamente a pantalla mientras q de TBitmap se haria el dibujo a memoria y luego volcado, o sea, dos pasos, mientras q si la form esta a doublebuffer solo se haria un unico bitmap total en memoria de todo lo que se tiene q mostrar y luego, volcado (espero haberme explicado, aqui es tarde :)). Venga saludos.

cHackAll 08-10-2008 01:03:38

Cita:

Empezado por coso (Mensaje 318773)
no no tu ejemplo perfecto, pero si el bitmap no se copiase a toda la form, entonces todo el resto (si estuviese doublebuffered a false) se dibujaria directamente a pantalla no? entonces, vamos, para una form con un dibujo mejor crear un unico bitmap de toda la form (esto es doublebuffered a true de la form). Me refiero, q si TBitmap esta con dblbuffer y la form no, el trozo de form visible se dibujaria directamente a pantalla mientras q de TBitmap se haria el dibujo a memoria y luego volcado, o sea, dos pasos, mientras q si la form esta a doublebuffer solo se haria un unico bitmap total en memoria de todo lo que se tiene q mostrar y luego, volcado (espero haberme explicado, aqui es tarde :)). Venga saludos.

Entonces dejando de lado el ejemplo que puse; explicame lo que quieres decir una vez mas... te prometo que ahora si lo entendere :o

coso 08-10-2008 09:57:42

1.- Form1.doublebuffered := true; TBitmap.doublebuffered := true -> 1 unico bitmap creado en memoria (de toda la form + TBitmap) y volcado a pantalla.

2.- Form1.doublebuffered := false;TBitmap.doublebuffered := true; -> TBitmap se dibuja en memoria y se vuelca a su zona correspondiente de pantalla, Form1 (excepto el trozo de TBitmap) se dibuja directamente en pantalla. Hay posibilidad de flickering segun como sea Form1 (si tarda mucho en dibujarse, habra retardo entre repintados)

(1) es mejor; los dos doublebuffered, no son redundantes (como mucho, el de TBitmap). ;) saludos.

coso 08-10-2008 10:06:03

(*) donde pone TBitmap, lee TImage. Es la TImage donde se mueven las fichas del principio...saludos.

ivanloco 09-10-2008 03:08:40

MUCHAS GRACIAS A TODOS!!! finalmente pude lograr implementar el double buffer y que las cosas funcionen corractamente. Nuevamente GRACIAS!


La franja horaria es GMT +2. Ahora son las 19:33:21.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi