IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 Delphi Discussion :

DoubleBuffered et scintillement


Sujet :

Delphi

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 130
    Points : 46
    Points
    46
    Par défaut DoubleBuffered et scintillement
    Bonjour,
    J'essaye toujours de développer un simili pac man.
    J'ai un gros problème de scintillement lorsque je déplace le personnage (une Timage) au milieu d'une foultitude d'autres Timages (les Tiles constituant le niveau).
    J'ai tout d'abord essayé de mettre le fameux : DoubleBuffered:=True;
    Le résultat est encore pire : Certes, il n'y a plus de scintillement, mais pac man se déplace comme une limace, et tout semble ralentir...
    Que faire?

  2. #2
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    apprendre à programmer

    1) TImage n'est pas le plus efficace pour gérer ce genre de chose

    2) le déplacement devrait être fonction du temps qui passe et non du framerate, or donc le déplacement devrait au pire être saccadé mais jamais ralenti.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 130
    Points : 46
    Points
    46
    Par défaut
    Dans ce cas par quoi remplacer les t.images?

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 130
    Points : 46
    Points
    46
    Par défaut
    Bien, je vais essayer d'être plus précis.
    Voici la fonction TTimer (réglée à 10ms) qui contient le code lié au déplacement de pacman.
    Je dirais qu'en l'état, les déplacements sont très fluides et rapides, notamment grâce à la boucle "for n=1 to 4"
    D'autre part, les phases d'animations (variable anim) sont elles modifiées par un autre TTimer, qui lui est réglé sur 100ms.
    La quantité phénoménale de TImages (plus de 300 car le tableau de jeu contient 300 tiles) est peut-être la raison pour laquelle DoubleBuffered:=True rame de façon monstrueuse au point d'être inutilisable.
    Mon problème reste le scintillement. J'ai un temps pensé à fixer la Timage du pacman sur un panel et forcé le panel en double buffer avec Form1.Panel1.DoubleBuffered:=True;
    Dans ce cas, le pacman se déplaçait de façon fluide et sans scintillement, mais le problème devenait alors le panel gris qui apparaissait derrière le pacman lors des déplacements... Bref, je ne vois pas comment faire. Est-il possible de rendre visible ce qu'il y a sous le TPanel tout en fixant une transparence à l'image posée dessus?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    procedure TForm1.Timer1Timer(Sender: TObject);
    var n:Integer;
        x,y:Integer;
    begin
      Form1.Image302.Left:=Form1.Image301.Left+1;
      if GetKeyState(VK_RIGHT) and $80=$80 then  une_action:='right';
      if GetKeyState(VK_LEFT) and $80=$80 then  une_action:='left';
      if GetKeyState(VK_UP) and $80=$80 then  une_action:='up';
      if GetKeyState(VK_DOWN) and $80=$80 then  une_action:='down';
     
      x:=Round(Form1.Image301.Left/60)+1;
      y:=Round(Form1.Image301.Top/60)+1;
      if level[y][x]=' ' then begin level[y][x]:='-'; (Form1.findcomponent('Image'+IntToStr(x+((y-1)*20))) as TImage).Picture.LoadFromFile(Appdir+'tile2.bmp'); end;
     
      x:=Ceil(Form1.Image301.Left/60)+1;
      if (une_action='left') and (level[y][x-1]<>'1') then
        for n := 1 to 4 do
        begin
          Form1.Image301.Left:=Form1.Image301.Left-1;
          if anim=4 then anim:=0;
          if anim=0 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanleft1.bmp');
          if anim=1 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanleft2.bmp');
          if anim=2 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanleft3.bmp');
          if anim=3 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanleft2.bmp');
        end;
      x:=Trunc(Form1.Image301.Left/60)+1;
      if (une_action='right') and (level[y][x+1]<>'1') then
        for n := 1 to 4 do
        begin
          Form1.Image301.Left:=Form1.Image301.Left+1;
          if anim=4 then anim:=0;
          if anim=0 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanright1.bmp');
          if anim=1 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanright2.bmp');
          if anim=2 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanright3.bmp');
          if anim=3 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanright2.bmp');
        end;
      y:=Ceil(Form1.Image301.Top/60)+1;
      if (une_action='up') and (level[y-1][x]<>'1') then
        for n := 1 to 4 do
        begin
          Form1.Image301.Top:=Form1.Image301.Top-1;
          if anim=4 then anim:=0;
          if anim=0 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanleft1.bmp');
          if anim=1 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanleft2.bmp');
          if anim=2 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanleft3.bmp');
          if anim=3 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanleft2.bmp');
        end;
      y:=trunc(Form1.Image301.Top/60)+1;
      if (une_action='down')and (level[y+1][x]<>'1') then
        for n := 1 to 4 do
        begin
          Form1.Image301.Top:=Form1.Image301.Top+1;
          if anim=4 then anim:=0;
          if anim=0 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanright1.bmp');
          if anim=1 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanright2.bmp');
          if anim=2 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanright3.bmp');
          if anim=3 then Form1.Image301.Picture.LoadFromFile(Appdir+'pacmanright2.bmp');
        end;
    end;

  5. #5
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    alors, pour ne pas me répéter je te propose déjà de consulter ce source qui montre comment gérer les touches, le temps qui passe et le bitmap offline

    pour les TImage, je vois dans ton code que c'est pire que ce que je pensais puisque à chaque animation tu recharges un fichier depuis le disque, opération particulièrement lente.

    le plus simple dans la mesure où tu utilises la transparence est de charger tous tes bitmaps dans un TImageList (dans l'IDE, il n'est donc plus nécessaire de les joindre au jeu), et pour dessiner PacMan :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
      ImageList1.Draw(FBuffer.Canvas, PlayerX,  PlayerY, anim);
    d'autre part, tu parles de 300 tuiles, si mon souvenir est bon, dans PacMan seul PacMan et les 3 fantômes se déplacent, tu dois donc parler des tuiles qui forment le labyrinthe. Et bien celle-ci doivent être dessinées une fois pour toute dans un autre bitmap vierge de personnage, et tu commences ton rendu par copier ce bitmap de fond vers le buffer, puis tu dessines les personnages sur le buffer et finalement le buffer à l'écran

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    procedure Tform1.Paint(sender: TObject);
    begin
    // FFond est le bitmap contenant le décors, il a été crée en début du niveau
    // à partir des tuiles d'un TImageList également
      FBuffer.Assign(FFond); 
    // dessin des personnages
      ImageList1.Draw(FBuffer.Canvas, PlayerX, PlayerY, Anim);
    // les fantomes
      for i := 0 to 2 do
        ImageList1.Draw(FBuffer.Canvas, Fantome[i].X, Fantome[i].Y, Fantome[i].Anim);
    // à l'ecran
      Canvas.Draw(0, 0, FBuffer);
    end;
    les pastilles sont également dans le décors, elles sont simplement effacées au fur et à mesure du passage de PacMan

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 130
    Points : 46
    Points
    46
    Par défaut
    Désolé, je n'arrive pas à comprendre. Le programme Tetris est incompréhensible pour mon niveau vu sa complexité.
    J'essaye de comprendre ton explication, mais je vois pas concrètement par où commencer.

    procedure Tform1.Paint(sender: TObject);?
    Qu'est ce que cette procédure? Un Paintbox qui prend toute la place de la Form?

    FBuffer.Assign(FFond); ?
    Ca signifie que l'on copie FFond dans la variable bitmap fbuffer?
    Comment FFond peut il contenir le bitmap de 300 tuiles?
    FFond:= ?

    Canvas.Draw(0, 0, FBuffer);?
    Dessiner aux coordonnées 0,0 l'image Fbuffer?

    Sinon, j'ai une autre piste, peut-être plus simple :
    Dans un TPanel, copier le sprite et faire un copyrect de l'image cachée sous le tpanel.
    Il y aurait donc 2 images superposées dans le tpanel. L'image 1 serait celle située sous le panel et l'image 2 le sprite, transparent.
    Le but de l'Image 1 est de rendre le panel artificiellement invisible.
    Cette idée vient du fait que j'ai remarqué qu'on pouvait faire Panel1.DoubleBuffered:=True, supprimant les scintillements tout en préservant la rapidité en raison de la petite surface sur laquelle la fonction est appliquée, le Panel ayant exactement la taille du sprite.

  7. #7
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    voici un DonkeyMan inspiré de Donkey
    DonkeyMan.zip

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 130
    Points : 46
    Points
    46
    Par défaut
    Merci pour ta patience, j'ai jeté un coup d'oeil au code, ça m'a l'air cette fois abordable. Je vais étudier tout ça...

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 130
    Points : 46
    Points
    46
    Par défaut
    J'ai tenté d'adapter ton code. J'ai créé 2 imagelist, l'une contenant les tiles du niveau, l'autre les phases d'animation de pacman.
    J'ai mis un TTimer à 10ms et ajouté l'événement OnPaint dans la Form (double click dans les propriétés). Dans le Form.Create, j'ai défini la map comme lors de mon code original.

    1) InvalidateRect(Handle,nil,False); ne fonctionne pas, mais en le remplaçant par refresh; (qui fait donc appel à FormPaint), ça semble revenir au même.

    2) Mon personnage ne se déplace pas tile par tile, mais pixel par pixel, c'est super classe mais ça complique les choses. Tandis que dans donkeyman, il suffit de remplacer une tile par une autre, ici c'est une autre affaire. Les tiles doivent être toutes dessinées en premier, puis le pacman posé par dessus aux coordonnées x,y, avec x et y étant en pixels et non en numéro de colonne/ligne de tiles.

    La conséquence est que lorsque pacman se déplace, il laisse une trace derrière lui, même si le déplacement est fluide et sans scintillement grâce à l'image virtuelle FDessin...

  10. #10
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    Citation Envoyé par sys1 Voir le message
    J'ai tenté d'adapter ton code. J'ai créé 2 imagelist, l'une contenant les tiles du niveau, l'autre les phases d'animation de pacman.
    J'ai mis un TTimer à 10ms et ajouté l'événement OnPaint dans la Form (double click dans les propriétés). Dans le Form.Create, j'ai défini la map comme lors de mon code original.

    1) InvalidateRect(Handle,nil,False); ne fonctionne pas, mais en le remplaçant par refresh; (qui fait donc appel à FormPaint), ça semble revenir au même.

    2) Mon personnage ne se déplace pas tile par tile, mais pixel par pixel, c'est super classe mais ça complique les choses. Tandis que dans donkeyman, il suffit de remplacer une tile par une autre, ici c'est une autre affaire. Les tiles doivent être toutes dessinées en premier, puis le pacman posé par dessus aux coordonnées x,y, avec x et y étant en pixels et non en numéro de colonne/ligne de tiles.

    La conséquence est que lorsque pacman se déplace, il laisse une trace derrière lui, même si le déplacement est fluide et sans scintillement grâce à l'image virtuelle FDessin...
    non, ton code est invalide.

    mon DonkeyMan se déplace par case car je multiplie PlayerX/Y par 30, il suffirait de ne pas le faire pour avoir une position au pixel près.

    si tu as une trace, c'est que tu n'utilises pas correctement les deux bitmaps, FFond ne doit pas contenir Pacman et FDessin est écrasé par FFond à chaque fois.

Discussions similaires

  1. Scintillement malgré DoubleBuffered
    Par NiklosKoda dans le forum Débuter
    Réponses: 1
    Dernier message: 04/05/2009, 12h31
  2. Scintillement des textures
    Par polonain2 dans le forum OpenGL
    Réponses: 18
    Dernier message: 08/06/2004, 10h01
  3. Pb scintillement-stabilité lors réaffichage de JPanel
    Par Pill_S dans le forum Composants
    Réponses: 5
    Dernier message: 28/04/2004, 14h03
  4. Pb affichage avec un PaintBox (pour eviter scintillement)
    Par juan64 dans le forum C++Builder
    Réponses: 7
    Dernier message: 08/04/2004, 09h21
  5. [appli][Java2D]Pb scintillement Animation
    Par ddams dans le forum 2D
    Réponses: 2
    Dernier message: 25/04/2003, 11h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo