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 :

Affichage "sympa" de cartes à jouer


Sujet :

Delphi

  1. #41
    Modérateur

    Re-salut,

    Paul TOTH: note que tu peux aussi réduire la taille d'affichage de l'image
    ...
    en prenant un rapport de 2/3 de l'image on évite les trous mais l'image est plus petite évidemment ... sauf à agrandir l'image source.
    Oui, mais ça oblige à faire plusieurs manips superflues, alors qu'avec l'astuce de la transformée inverse on ne crée aucun trou, et ça en une seule passe.

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  2. #42
    Modérateur

    Bonjour,

    Pour en finir, j'ai utilisé l'astuce de la transformée inverse qui ne crée aucun trou dans le résultat, et comme il n'y a plus de trous à boucher on gagne des lignes de code et du coup celui-ci n'en compte plus que 170.
    Par contre j'ai laissé tomber toutes les complications qui ne sont pas indispensables vu que l'objectif visé est seulement de détecter le n° de la carte survolée par la souris.
    Et pour ce qui est de la vitesse d'exécution elle me semble correcte lorsque par exemple on élargit la fiche (ce qui force à re-dessiner le tout) la fluidité est bonne et sans scintillements.
    (... et puis comme il s'agit d'un jeu de cartes Coussati risque d'en faire occuper tout l'écran sans possibilité de redimensionner, avec simplement une carte qui disparaît lorsqu'elle est jouée).

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  3. #43
    Modérateur

    Bonjour,

    Voici pour le fun un nouveau ZIP qui utilise de simples TImage standards à la place des TRotateImage pour afficher les cartes avec en plus des ombres "sympas".

    A+.

    EDIT : le ZIP ci-joint est remplacé par celui de mon message suivant suite à simplification.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  4. #44
    Modérateur

    Bonjour,

    Comme cette nuit j'ai pris conscience d'une lourdeur dans le code du ZIP d'hier, en voici une nouvelle version simplifiée qui n'utilise plus ni le composant TRotateImage ni des TImage mais uniquement des BitMap's et toujours avec les ombres portées.

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  5. #45
    Rédacteur/Modérateur

    Tout de même une sacré usine à gaz

    Un petit exemple en GDI à l'aide de SetWorldTransform pour la rotation d'image et ExtCreateRegion pour la rotation de région. Le rendu n'est pas parfait (j'ai repris tes images ) mais le principe est là, y compris la détection.


  6. #46
    Expert éminent sénior
    Excellent Andnotor

    moi je vous propose la version Flash avec FlashPascal

    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
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
     
    program Cartes;
     
    uses
      Flash8;
     
    {$FRAME_WIDTH 800}
    {$FRAME_HEIGHT 600}
     
    // les images doivents être en 32Bits avec un canal Alpha
    {$BITMAP back 'back.bmp'}
    {$BITMAP c0 'bg0_32.bmp'}
    {$BITMAP c1 'bg1_32.bmp'}
    {$BITMAP c2 'bg2_32.bmp'}
    {$BITMAP c3 'bg3_32.bmp'}
    {$BITMAP c4 'bg4_32.bmp'}
    {$BITMAP c5 'bg5_32.bmp'}
    {$BITMAP c6 'bg6_32.bmp'}
    {$BITMAP c7 'bg7_32.bmp'}
    {$BITMAP c8 'bg8_32.bmp'}
     
    type
    // TInside reprend l'image de la carte à l'intérieur de TCarte
    // c'est lui qui prend les évènements souris pour que l'ombre ne soit pas sensible à la souris
      TInside = class(MovieClip)
        procedure onPress; override;
        procedure onRelease; override;
        procedure onReleaseOutside; override;
      end;
     
      TCarte = class(MovieClip)
        constructor Create(const bitmapName: string; angle: Number);
      end;
     
    var
      fond: BitmapData;
     
    constructor TCarte.Create(const bitmapName: string; angle: Number);
    var
      shadow: MovieClip;
      inside: MovieClip;
    begin
      inherited Create(_root, bitmapName, _root.getNextHighestDepth());
     
      shadow := MovieClip.Create(Self, '', 1);
      shadow.attachBitmap(fond, 1, '', true);
      shadow._x := -fond.width/2 - 10;
      shadow._y := -fond.height - Stage.Height/4 + 10;
      shadow._alpha := 50;
     
      inside := TInside.Create(Self, '', 2);
      inside.attachBitmap(loadBitmap(bitmapName), 1, '', true);
      inside._x := -fond.width/2;
      inside._y := -fond.height - Stage.Height/4;
     
      _x := Stage.width / 2;
      _y := Stage.Height;
     
      _rotation := angle;
    end;
     
    procedure TInside.onPress;
    begin
      _parent.swapDepths(_parent._parent.getNextHighestDepth());
      _parent.startDrag(False, -_width, -_height, Stage.Width + _width, Stage.Height + _height);
    end;
     
    procedure TInside.onRelease;
    begin
      _parent.stopDrag();
    end;
     
    procedure TInside.onReleaseOutside;
    begin
      _parent.stopDrag();
    end;
     
    begin
      _root.beginBitmapFill(loadBitmap('back'));
      _root.moveto(0,0);
      _root.lineto(Stage.width, 0);
      _root.lineto(Stage.width,Stage.height);
      _root.lineto(0, Stage.Height);
      _root.lineto(0,0);
      _root.EndFill();
     
      fond := loadBitmap('c0');
      TCarte.Create('c1', -40);
      TCarte.Create('c2', -30);
      TCarte.Create('c3', -20);
      TCarte.Create('c4', -10);
      TCarte.Create('c5',   0);
      TCarte.Create('c6', +10);
      TCarte.Create('c7', +20);
      TCarte.Create('c8', +30);
    end.


    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  7. #47
    Modérateur

    Bonjour,


    Andnotor : Tout de même une sacré usine à gaz
    Bin, à force de transformer un code tout en voulant éviter de trop modifier l'existant on arrive souvent à compliquer.

    Un petit exemple en GDI à l'aide de SetWorldTransform pour la rotation d'image et ExtCreateRegion pour la rotation de région. Le rendu n'est pas parfait (j'ai repris tes images ) mais le principe est là, y compris la détection.
    J'ai essayé de tester ton Zip mais sous Delphi 6 j'ai seulement obtenu :
    [Erreur] Project1.dpr(4): ',' ou ';' attendu(e) mais '.' trouvé(e)
    [Erreur fatale] Project1.dpr(5): Fichier non trouvé : 'Vcl.dcu'
    Pour le faire fonctionner sous D6, on fait comment ???

    Paul TOTH : moi je vous propose la version Flash avec FlashPascal
    Pour essayer de le tester j'ai voulu installer Adobe Flash Player et l'installation m'a placé airappinstaller.exe dans le sous-dossier Adobe\Flash Player\AddIns et il ne se passe rien quand je double-clique dessus !!!???
    Pas de chance aujourd'hui ...

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  8. #48
    Expert éminent sénior
    Citation Envoyé par Gilbert Geyer Voir le message
    Bonjour,



    Bin, à force de transformer un code tout en voulant éviter de trop modifier l'existant on arrive souvent à compliquer.


    J'ai essayé de tester ton Zip mais sous Delphi 6 j'ai seulement obtenu :

    Pour le faire fonctionner sous D6, on fait comment ???


    Pour essayer de le tester j'ai voulu installer Adobe Flash Player et l'installation m'a placé airappinstaller.exe dans le sous-dossier Adobe\Flash Player\AddIns et il ne se passe rien quand je double-clique dessus !!!???
    Pas de chance aujourd'hui ...

    A+.
    les corrections pour Delphi 6:
    remplacer Vlc.Forms par Forms
    supprimer Application.MainFormOnTaskbar := True;

    c'est tout !

    Pour Flash, Google Chrome sait afficher un SWF sans aucun plugin, il suffit de drag&droper le fichier dans une fenêtre du navigateur. ça fonctionne aussi sous IE (quand le plugin est installé) en autorisant le contenu bloqué.

    Sinon Adobe propose un FlashPlayer autonome (le Projector)
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  9. #49
    Rédacteur/Modérateur

    Citation Envoyé par Gilbert Geyer Voir le message
    Pour le faire fonctionner sous D6, on fait comment ???
    Namespace XE3. Dans la source, modifie VCL.Forms en Forms

  10. #50
    Modérateur

    Re-salut,

    Andnotor: Dans la source, modifie VCL.Forms en Forms
    Ok, merci et pour faire fonctionner sous D6 il a aussi fallu virer Application.MainFormOnTaskbar := True;
    En tous cas ça marche avec seulement 137 lignes contre mes 574 ... donc même si l'ajout des ombres et de la disparition d'une carte qui a été jouée en cliquant dessus nécessitait elle aussi 137 lignes ça porterait ton code à 274 lignes soit 2 fois moins que mon usine à gaz.

    En ajoutant dans le FormCreate :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    Cards[i].Image.Transparent:=True;
    Cards[i].Image.TransparentColor:=clAqua;

    ... le rendu s'améliore.
    Pour le reste il faut piger l'utilisation des trucs comme SetWorldTransform et j'en passe...

    A+.

    EDIT : Oups, je n'avais pas remarqué la réponse de Paul TOTH
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  11. #51
    Modérateur

    Re-salut,

    Paul TOTH : Pour Flash, Google Chrome sait afficher un SWF sans aucun plugin, il suffit de drag&droper le fichier dans une fenêtre du navigateur. ça fonctionne aussi sous IE (quand le plugin est installé) en autorisant le contenu bloqué.

    Sinon Adobe propose un FlashPlayer autonome (le Projector)
    Comme j'utilise Firefox je vais essayer le Projector d'Adobe...

    A+ .
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  12. #52
    Modérateur

    Re-salut,

    J'ai installé le FlashPlayer avec le lien de Paul TOTH et ça m'installe des fichiers dans des répertoires introuvables autrement qu'en recherchant *Flash*.* sur C:
    et quand je double-clique sur les *.exe les uns me proposent de désinstaller Adobe et au double-click sur FlashPlayerPlugin_13_0_0_182.exe il ne se passe rien: ???
    Pas de chance aujourd'hui...

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  13. #53
    Expert éminent sénior
    Citation Envoyé par Gilbert Geyer Voir le message
    Re-salut,

    J'ai installé le FlashPlayer avec le lien de Paul TOTH et ça m'installe des fichiers dans des répertoires introuvables autrement qu'en recherchant *Flash*.* sur C:
    et quand je double-clique sur les *.exe les uns me proposent de désinstaller Adobe et au double-click sur FlashPlayerPlugin_13_0_0_182.exe il ne se passe rien: ???
    Pas de chance aujourd'hui...

    A+.
    il faut prendre le Projector, c'est un executable autonome et non un plugin comme dans FlashPlayerPlugin_13_0_0_182.exe !
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  14. #54
    Rédacteur/Modérateur

    Citation Envoyé par Gilbert Geyer Voir le message
    ...ça porterait ton code à 274 lignes...
    Pas autant que ça



    Pour l'ombre, il suffit en fait :
    • de créer une image entièrement noir (ou d'une autre couleur d'ailleurs). Une image de un pixel suffit ;
    • de décaler la région de la carte de la portée de l'ombre ;
    • de l'ajouter à une nouvelle région Shadow puis d'y soustraire la région originale de la carte ;
    • d'appliquer un clipping sur cette région Shadow et de dessiner l'image noir sur toute la fiche en spécifiant un taux de transparence par AlphaBlend (AlphaBlend se charge de faire un stretch de notre mini image).


    Remplace FormPaint par ceci :
    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
    procedure TForm1.FormPaint(Sender: TObject);
    const
      Blend :TBlendFunction = (BlendOp:AC_SRC_OVER; BlendFlags:0; SourceConstantAlpha:50; AlphaFormat:0);
     
    var
      i         :integer;
      Shadow    :TBitmap;
      ShadowRgn :hRgn;
     
    begin
      Shadow    := TBitmap.Create;
      ShadowRgn := CreateRectRgn(0,0,0,0);
     
      try
        Shadow.Width  := 1;
        Shadow.Height := 1;
        Shadow.Canvas.Pixels[0,0] := clBlack;
     
        for i := Low(Cards) to High(Cards) do
        begin
          //Dessin image
          SetBrushOrgEx(Canvas.Handle, Cards[i].Origin.X, Cards[i].Origin.Y, nil);
          Canvas.Brush.Bitmap := Cards[i].Image;
          PaintRgn(Canvas.Handle, Cards[i].Region);
     
          //Ombre (Région décalée -région originale)
          OffsetRgn(Cards[i].Region, -10, 10);
          CombineRgn(ShadowRgn, ShadowRgn, Cards[i].Region, RGN_OR);
          OffsetRgn(Cards[i].Region, 10, -10);
          CombineRgn(ShadowRgn, ShadowRgn, Cards[i].Region, RGN_DIFF);
        end;
     
        //Dessin ombre
        OffsetRgn(ShadowRgn, 1, -1);
        SelectClipRgn(Canvas.Handle, ShadowRgn);
        Windows.AlphaBlend(Canvas.Handle, 0, 0, ClientWidth, ClientHeight, Shadow.Canvas.Handle, 0, 0, Shadow.Width, Shadow.Height, Blend);
     
      finally
        Shadow.Free;
        DeleteObject(ShadowRgn);
      end;
    end;


    Supprimer une carte ne prendrait pas beaucoup plus de ligne. Il faudrait uniquement appliquer la rotation avant la peinture plutôt qu'à la création. Pour le clique, toujours PtInRegion

  15. #55
    Modérateur

    Re-bonjour,

    1 )Andnotor Pour l'ombre, il suffit en fait :
    ...
    ... en spécifiant un taux de transparence par AlphaBlend (AlphaBlend se charge de faire un stretch de notre mini image).
    Ok, ça marche mais pour voir les ombres portées d'une carte sur sa voisine il faut augmenter le taux en remplaçant SourceConstantAlpha:30 par SourceConstantAlpha:50 dans Blend.

    Supprimer une carte ne prendrait pas beaucoup plus de ligne. Il faudrait uniquement appliquer la rotation avant la peinture plutôt qu'à la création. Pour le clique, toujours PtInRegion
    Pour supprimer une carte jouée je m'en suis sorti simplement en ajoutant :
    - dans TCard le boolean Jouee : initialisée à False au départ,
    - la FormMouseDown ci-après
    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
    procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; 
      Shift: TShiftState; X, Y: Integer);
    var i: integer;
    begin
      for i := High(Cards) downto Low(Cards) do
        if PtInRegion(Cards[i].Region, X, Y) and (not Cards[i].Jouee) then
        begin
          Cards[i].Image.Free;
          DeleteObject(Cards[i].Region);
          Cards[i].Jouee:=True;
          FormPaint(Sender);
          Caption := Format('Carte Jouée N°%d', [i]);
          EXIT;
        end;
    end;

    - un if PtInRegion(Cards[i].Region, X, Y) and (not Cards[i].Jouee) then ... dans TForm1.FormMouseMove,
    - un BitMap d'arrière plan (BmpAP) créé au départ et de taille égale à celle de lafiche,
    - et dans le début de la FormPaint je fais un canvas.Draw(0, 0, BmpAP) pour effacer l'ancien tracé suivi du nouveau avec for i := Low(Cards) to High(Cards) do if (not Cards[i].Jouee) then
    begin
    //Dessin image,
    - j'ai aussi ajouté un if not Cards[i].Jouee then ... dans TForm1.FormDestroy pour quitter proprement.

    2) Petite question :
    Si je souhaite placer le centre du jeu en éventail en bas en hors de la fiche lorsque WindowSate:=wsMaximized et obtenir un éventail tel que l'angle supérieur gauche de chaque carte se trouve sur un arc de cercle de Rayon R
    je fais comment ???
    ... car en remplaçant dans FormCreate, Cards[i].Origin := Point(30 * i, 10) par Cards[i].Origin := Point(100 * i, 250) j'obtiens ceci :

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  16. #56
    Modérateur

    Re-salut,

    Paul TOTH : il faut prendre le Projector, c'est un executable autonome et non un plugin comme dans FlashPlayerPlugin_13_0_0_182.exe !
    OK, merci beaucoup, avec flashplayer_13_sa.exe ça marche enfin.
    Et non seulement ça marche, mais en prime on obtient un rendu hyper-excellent (voir l'image ci-après) : les bords des cartes inclinées sont hyper-nets et sans aucune rognure comme c'est le cas des autres solutions .
    ... et en plus on peut riper les cartes avec la souris ...
    Mais ça me pose un Big-Problème : pour personnaliser le code il faut s'initier au Flash Pascal :
    En tous cas c'est super.

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  17. #57
    Rédacteur/Modérateur

    Il faut calculer Origin à l'aide de la matrice dans la rotation.

    Un point après rotation se retrouve ainsi
    x' = x *eM11 +y *eM21 +eDX
    y' = x *eM12 +y *eM22 +eDY
    eDX, eDY correspond au coin supérieur gauche de la carte après rotation.

    Pour le centre de la carte
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    X := Round((Image.Width div 2) *eM11 +(Image.Height div 2) *eM21 +eDX);
    Y := Round((Image.Width div 2) *eM12 +(Image.Height div 2) *eM22 +eDY);


    et le calcul de l'origine (par rapport au centre) pour un rayon de 300 et un décalage pour que le tout soit visible à l'écran (il faudra peut-être corriger aussi l'angle de départ)
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    Origin.X := 400 +Round(300 *eM12 -X);
    Origin.Y := 500 -Round(300 *eM11 +Y);


    Maintenant comme je l'ai dit, pour que tout soit dynamique sur le Resize, il faudra déplacer l'appel à Rotate

  18. #58
    Modérateur

    Bonjour,

    Andnotor : Il faut calculer Origin à l'aide de la matrice dans la rotation.
    ...
    et un décalage pour que le tout soit visible à l'écran (il faudra peut-être corriger aussi l'angle de départ) ":
    Ok, merci beaucoup. Dans mon usine à gaz j'utilisais un angle de départ de -16° et un Delta de +4° ça devrait convenir.

    Maintenant comme je l'ai dit, pour que tout soit dynamique sur le Resize, il faudra déplacer l'appel à Rotate
    Vu que le jeu de cartes est destiné à être distribué par un serveur il est probable que le jeu s'effectue en plein écran avec WindowState=wsMaximized et sans possibilité de Resize.
    Faudrait que Coussati nous confirme ceci...

    Par contre ce qui serait intéressant c'est d'ajouter une petite routine qui effectue un traitement anti-alias pour estomper les rognures sur les bords des cartes inclinées pour obtenir un rendu équivalent à celui obtenu par Paul ToTH sous FlashPascal. Je vais essayer ceci ce matin ...

    A+.
    .
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  19. #59
    Rédacteur/Modérateur

    C'était un exemple en GDI. Pour un meilleur rendu, utiliser des images 32 bits et GDI+ le fera beaucoup mieux.
    A noter que Paul a un peu triché, l'ombre fait partie de l'image 32 et... tourne avec elle

  20. #60
    Expert éminent sénior
    Citation Envoyé par Andnotor Voir le message
    C'était un exemple en GDI. Pour un meilleur rendu, utiliser des images 32 bits et GDI+ le fera beaucoup mieux.
    A noter que Paul a un peu triché, l'ombre fait partie de l'image 32 et... tourne avec elle
    non, non, l'ombre est une carte noire sous la carte de jeu avec un alpha à 50%, certes les deux éléments sont placés dans un troisième qui subit la rotation mais ça c'est juste parce que Flash le permet

    d'ailleurs on peut faire la même chose en FMX sans une seule ligne de code
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store