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 :

Détection des collisions.


Sujet :

Delphi

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Avril 2011
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 16
    Points : 3
    Points
    3
    Par défaut Détection des collisions.
    Bonjour à tous,

    J'ai un petit soucis, je cherche à détecter les collisions entre un rectangle et plusieurs cercles.

    J'ai pensé à plusieurs solutions que je n'arrive pas à mettre en oeuvre :

    -calculer à un instant t, le périmetre d'un cercle et du rectangle, ainsi si ils sont superposés le périmétre calculé sera inférieur au périmétre du cercle + celui du rectangle séparé.

    -Encadrer mes cercles par des rectangles et utiliser la commande "IntersectRec" mais cela revient à approximer un peu trop mes cercles.

    Si vous connaissez des méthodes pour détecter ces collisions, je vous en remercie !

  2. #2
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 858
    Points : 11 301
    Points
    11 301
    Billets dans le blog
    6
    Par défaut
    N'y a-t-il pas une piste du côté des régions ?
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Avril 2011
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 16
    Points : 3
    Points
    3
    Par défaut
    Je ne connaissais pas les régions, je viens de regarder ça.
    Je peux donc définir des régions pour mes cercles (CreateEllipticRgn) et pour mon rectangle (CreateRectRgn).

    Pour tester si le cercle est en collision avec le rectangle, je pourrai utiliser la fonction PtInRegion pour tester si un point est dans une des régions.

    Il faudrait alors que je teste une dizaine de points du périmétre du cercle pour voir si ils sont dans la région du rectangle. Sachant que j'ai une vingtaine de cercles, ç'est pas un peu long comme méthode ?


    En tout cas, merci de ta réponse rapide!

  4. #4
    Membre chevronné

    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Aveyron (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2009
    Messages : 935
    Points : 1 765
    Points
    1 765
    Par défaut
    Sinon, tu peux calculer toi même :

    Soit :
    Un rectangle X1, Y1, X2, Y2
    Un cercle Xc, Yc, R

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function Dist (Xa, Ya, Xb, Yb : integer) : integer;
    begin
      Result:=Sqrt((Xb-Xa)*(Xb-Xa)+(Yb-Ya)*(Yb-Ya));
    end;
     
    ...
     
    Intersection:=false;
     
    if (Xc in [X1..X2]) and (Yc in [Y1-R..Y2+R]) then Intersection:=true;
     
    if (Yc in [Y1..Y2]) and (Xc in [X1-R..X2+R]) then Intersection:=true;
     
    if (Dist(X1,Y1,Xc,Yc)<=R) or (Dist(X1,Y2,Xc,Yc)<=R) or (Dist(X2,Y1,Xc,Yc)<=R) or (Dist(X2,Y2,Xc,Yc)<=R) then Intersection:=true;

  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 : 54
    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 445
    Points
    28 445
    Par défaut
    2 cas

    1) si le centre du cercle est à l'intérieur du rectangle, il y a de forte chance qu'il y ai collision

    2) si une des distances entre le centre d'un cercle et les 4 lignes du rectangles est inférieure au rayon du cercle, il y a également collision.

    si c'est un problème 2D avec un rectangle sans rotation, c'est assez facile à déterminer

    si le rectangle subis une rotation, j'appliquerais bien une rotation inverse aux centre des cercles pour me replacer dans le cas simple ci-dessus
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  6. #6
    Candidat au Club
    Profil pro
    Inscrit en
    Avril 2011
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 16
    Points : 3
    Points
    3
    Par défaut
    Merci de vos réponses !

    Effectivement dans mon cas le rectangle subit des rotations.
    Je vais essayer d'appliquer vos conseils dans mon programme, en espérant que ça fonctionne !

  7. #7
    Membre confirmé
    Homme Profil pro
    Santé
    Inscrit en
    Septembre 2010
    Messages
    290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Santé
    Secteur : Santé

    Informations forums :
    Inscription : Septembre 2010
    Messages : 290
    Points : 534
    Points
    534
    Par défaut
    Salut,

    Citation Envoyé par Catastrophe Voir le message
    Je ne connaissais pas les régions, je viens de regarder ça.
    Je peux donc définir des régions pour mes cercles (CreateEllipticRgn) et pour mon rectangle (CreateRectRgn).

    Pour tester si le cercle est en collision avec le rectangle, je pourrai utiliser la fonction PtInRegion pour tester si un point est dans une des régions.

    Il faudrait alors que je teste une dizaine de points du périmétre du cercle pour voir si ils sont dans la région du rectangle. Sachant que j'ai une vingtaine de cercles, ç'est pas un peu long comme méthode ?
    Non ! Ce n'est pas comme ça qu'il faut faire.

    Un exemple à tester sur une fiche vierge avec 1 bouton :
    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
    procedure TForm1.Button1Click(Sender: TObject);
      var     R1, R2 : HRGN;
      begin
      R1 := CreateRectRgn(10,30,100,55);// Pas de collision
      //R1 := CreateRectRgn(10,30,100,56); // Collision !
      Canvas.Brush.Color := clGreen;
      FillRgn(GetWindowDC(handle), R1, Canvas.Brush.Handle);
     
      R2 := CreateEllipticRgn(50,50,200,200);
      Canvas.Brush.Color := clRed;
      FillRgn(GetWindowDC(handle), R2, Canvas.Brush.Handle);
     
      if not (CombineRgn(R1,R1,R2,RGN_AND)=NULLREGION) then Beep;//Beep qd collision.
     
      DeleteObject(R1);
      DeleteObject(R2);
    end;
    Précision : L'avantage de la méthode est qu'elle fonctionne sur n'importe quelle forme de sprite, même les plus tarabiscotées.

  8. #8
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2011
    Messages
    271
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Italie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2011
    Messages : 271
    Points : 491
    Points
    491
    Par défaut
    Si tu veux faire cette detection a un interval court pour une animation par exemple, Pour gagner en vitesse, il faudrait mieux commencer par approximer tes objects (cercles, triangles..etc) par des rectangles, si l'intersection des deux rectangles est vide, c'est pas la peine d'aller plus loin. pour cela on utilisera IntersectRect et IsRectEmpty.

    Par contre si l'intersection n'est pas vide, il y'a possibilité de collision, pour le confirmer, utilise les regions et la aussi je pense qu'il vaut mieux approximer ton cercle par un polygone.

  9. #9
    Candidat au Club
    Profil pro
    Inscrit en
    Avril 2011
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 16
    Points : 3
    Points
    3
    Par défaut
    Merci pour ton explication Caribensila !

    Je pense que je vais me tourner vers les régions , ça me parait le plus simple pour des futurs améliorations.

    En revanche, peut-tu m'eclairer sur le GetWindowDC ?

    Edit : ça commence bien ! impossible de faire un tableau de HRGN, type inconnu Il faut utiliser quelquechose de spécial pour les utilises ?

  10. #10
    Membre confirmé
    Homme Profil pro
    Santé
    Inscrit en
    Septembre 2010
    Messages
    290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Santé
    Secteur : Santé

    Informations forums :
    Inscription : Septembre 2010
    Messages : 290
    Points : 534
    Points
    534
    Par défaut
    The GetWindowDC function retrieves the device context (DC) for the entire window, including title bar, menus, and scroll bars. A window device context permits painting anywhere in a window, because the origin of the device context is the upper-left corner of the window instead of the client area.
    Regarde le SDK Windows de l'Aide pour plus de précision sur les Regions.

  11. #11
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2011
    Messages
    271
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Italie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2011
    Messages : 271
    Points : 491
    Points
    491
    Par défaut Modification du code de Caribensila pour le cas de rectangle incliné
    Modification du code de Caribensila pour le cas de rectangle incliné
    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
     
    procedure TForm1.Button1Click(Sender: TObject);
    const
        Rectangle1 : array [0..3] of TPoint = ((X: 20; Y: 30), (X:90; Y:40), (X:88; Y:55), (X:18; Y:45)); //Pas de collision
    //  Rectangle1 : array [0..3] of TPoint = ((X: 20; Y: 30), (X:150; Y:40), (X:148; Y:55), (X:18; Y:45)); // Collision !
    var R1, R2 : HRGN;
     
    begin
      //R1 := CreateRectRgn(10,30,100,55);// Pas de collision
      //R1 := CreateRectRgn(10,30,100,56); // Collision !
      R1 := CreatePolygonRgn( Rectangle1[0], Length(Rectangle1),WINDING);
      Canvas.Brush.Color := clGreen;
      FillRgn(GetWindowDC(handle), R1, Canvas.Brush.Handle);
     
      R2 := CreateEllipticRgn(50,50,200,200);
      Canvas.Brush.Color := clRed;
      FillRgn(GetWindowDC(handle), R2, Canvas.Brush.Handle);
     
      if not (CombineRgn(R1,R1,R2,RGN_AND)=NULLREGION) then button1.Caption:='touche' else button1.Caption:='pas touche';//Beep qd collision.
     
      DeleteObject(R1);
      DeleteObject(R2);
     
    end;

  12. #12
    Candidat au Club
    Profil pro
    Inscrit en
    Avril 2011
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 16
    Points : 3
    Points
    3
    Par défaut
    Re-bonsoir à tous,

    Après avoir tenté les régions (sans succès), je suis retourné à la solution de mick605, mais maintenant j'ai un problème. Je pars pour l'instant du principe que mon rectangle n'a pas de rotation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function Collision(X1,Y1,X2,Y2,X3,Y3,Xr,Yr,R:integer):boolean;
    begin
      Result:=false;
     
      if (Xr in [X1..X2]) and (Yr in [Y1-R..Y2+R]) then Result:=true;
     
      if (Yr in [Y1..Y2]) and (Xr in [X1-R..X2+R]) then Result:=true;
     
      if (Dist(X1,Y1,Xr,Yr)<=R) or (Dist(X1,Y2,Xr,Yr)<=R) or (Dist(X2,Y1,Xr,Yr)<=R) or (Dist(X2,Y2,Xr,Yr)<=R) or (Dist(X3,Y3,Xr,Yr)<=R) then Result:=true;
    end;
    J'ai rajouté un point qui correspond au "pic" de mon rectangle qui est plutot un polygone (imaginez un rectangle surmonté par un triangle).

    Et je test avec mes cercles :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Rep:= Collision(x-20,y,x+20,y-50,x,y+20,fcentrex[i],fcentrey[i],fray[i]);
    Pour l'instant mon rectangle est fixe. Mon problème est que ma variable Rep ne passe jamais à True même quand le rectangle est en plein sur un cercle !

  13. #13
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 693
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    Je rejoinds Caribensila sur le principe

  14. #14
    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 : 54
    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 445
    Points
    28 445
    Par défaut
    une autre idée très simple à mettre en oeuvre

    tu prends un bitmap monochrome (ou pas, c'est juste pour gagner en mémoire et réduire la taille des blocs mémoire à comparer) à fond noir tu dessines dessus ton rectangle chapeauté, en blanc

    tu fais une copie de ce bitmap

    tu dessines maintenant tes disques en noir sur le premier bitmap

    si les deux bitmaps sont identiques, pas de collision, sinon collision

    et pour comparer les bitmaps, ceci devrait fonctionner
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CompareMem(Bitmap1.ScanLine[Bitmap1.Height -1], Bitmap2.ScanLine[Bitmap2.Height -1], Bitmap1.Width * Bitmap1.Height div 8)
    , note que chaque octet représente 8 pixel d'un coup attention au bord droit du bitmap, pour bien faire il faut une largeur divisible par 8 (ou ajuster la largeur dans le calcul de la taille du DIB)
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  15. #15
    Membre chevronné

    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Aveyron (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2009
    Messages : 935
    Points : 1 765
    Points
    1 765
    Par défaut
    Citation Envoyé par Catastrophe Voir le message
    Re-bonsoir à tous,

    Après avoir tenté les régions (sans succès), je suis retourné à la solution de mick605, mais maintenant j'ai un problème. Je pars pour l'instant du principe que mon rectangle n'a pas de rotation :

    ...

    Et je test avec mes cercles :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Rep:= Collision(x-20,y,x+20,y-50,x,y+20,fcentrex[i],fcentrey[i],fray[i]);
    Pour l'instant mon rectangle est fixe. Mon problème est que ma variable Rep ne passe jamais à True même quand le rectangle est en plein sur un cercle !
    Ma solution était pour un rectangle simple sans rotation ... Il est vrai que pour travailler avec des formes plus complexes, je pense qu'il te faut passer par l'utilisation des régions ...

    La solution de Paul peut être bien aussi, mais peut être un peu lente je pense ...

    Pour info, je viens de tester mon code, et le problème vient des 'in'. En remplacant par (Xc>=X1) and (Xc<=X2), ca marche !

    Bonne chance

  16. #16
    Candidat au Club
    Profil pro
    Inscrit en
    Avril 2011
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 16
    Points : 3
    Points
    3
    Par défaut
    Merci pour toutes vos réponses !

    Je viens de repasser à la solution des régions, mon programme doit pouvoir être compilé sous linux, je vais devoir repasser sur Lazarus

    Néanmoins, j'ai testé une solution avec des régions, et ça ne fonctionne pas comme je voudrais

    J'ai défini une classe "Obstacle"

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Constructor Cobstacle.createRandom(width,height:integer);
     begin
      fcentrex := Random(width);
      fcentrey := Random(height div 2);
      fray :=40+Random(30);
      R:= CreateEllipticRgn(fcentrex,fcentrey,fray,fray);
    end;
    Ensuite dans mon interface :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    begin
     Randomize;
    For i:=1 to 8 do
    begin
    Obnord[i]:=Cobstacle.createrandom(TEdForcevent.Left-70,height);
    end;
    Et ensuite dans le timer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    begin
    R1:=CreateRectRgn(1, 1, TEdForcevent.Left-5, height); //région de la "map" (inutile)
    R2 := CreateRectRgn(x-20,y,x+20,y-50); //région du rectangle (pour l'instant fixe)
    for j:=1 to 8 do
        begin
        if not (CombineRgn(R3,R2,Obsud[j].R,RGN_AND)=NULLREGION) then beep;
        end;
    end;
    Malheuresement, ça bippe de façon très aléatoire ! Je ne comprends vraiment pas le problème...

  17. #17
    Membre confirmé
    Homme Profil pro
    Santé
    Inscrit en
    Septembre 2010
    Messages
    290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Santé
    Secteur : Santé

    Informations forums :
    Inscription : Septembre 2010
    Messages : 290
    Points : 534
    Points
    534
    Par défaut
    R3 ?
    - Tu ne nous l'as pas présenté, celui-là.

    Sinon, évite le "Beep" dans ce cas, car la boucle est trop rapide et les "Beeps" se marchent sur les pieds.

    Crée plutôt une variable "CollisionsNbr" que tu incrémentes et affiche à la fin du test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if not (CombineRgn(R3,R2,Obsud[j].R,RGN_AND)=NULLREGION) then Inc(CollisionsNbr);

  18. #18
    Candidat au Club
    Profil pro
    Inscrit en
    Avril 2011
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 16
    Points : 3
    Points
    3
    Par défaut
    Je n'avais pas très bien compris l'intérêt de R3, mais c'est le résultat de l'intersection des deux régions, j'ai donc remis R2, malheuresement ça reste toujours aléatoire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    begin
    self.canvas.Brush.Color:=$9C0000;
    R1:=CreateRectRgn(1, 1, TEdForcevent.Left-5, height);
    self.canvas.FillRect(1,1,TEdForcevent.Left-5,height);
    R2 := CreateRectRgn(x-20,y,x+20,y-50);
    NbrCollision:=0;
    for j:=1 to 8 do
        begin
        if not(CombineRgn(R2,R2,Obsud[j].R,RGN_AND)=NULLREGION) then Inc(NbrCollision);
        if not(CombineRgn(R2,R2,Obnord[j].R,RGN_AND)=NULLREGION) then Inc(NbrCollision);
        end;
     
    TedVitesse.Text:=InttoStr(Nbrcollision);
    end;
    Dans la plupart des cas, c'est bon, mais parfois ça m'affiche "1" alors qu'il n'y a pas de collisions !

  19. #19
    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 : 54
    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 445
    Points
    28 445
    Par défaut
    voici un code qui fonctionne à merveille ... sur mon i5 en tout cas

    le resize recalcule tout, ce qui n'est pas du plus bel effet, mais ça permet de tester la rapidité de la chose en différentes résolution...c'est instantané chez moi.

    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
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    unit Unit1;
     
    interface
    {
      Démonstration de collision par Paul TOTH <tothpaul@free.fr>
      le 1er mai 2011 pour le forum Developpez.com
    }
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;
     
    type
      TForm1 = class(TForm)
        procedure FormCreate(Sender: TObject);
        procedure FormPaint(Sender: TObject);
        procedure FormKeyDown(Sender: TObject; var Key: Word;
          Shift: TShiftState);
        procedure FormResize(Sender: TObject);
      private
        { Déclarations privées }
        FBitmap : TBitmap;
        FCollide: TBitmap;
        FTest   : TBitmap;
        FPos    : TPoint;
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
     // Image de fond
      FBitmap := TBitmap.Create;
     
     // Masque de collision
      FCollide := TBitmap.Create;
      FCollide.PixelFormat := pf1bit;
      FCollide.Canvas.Brush.Color := clBlack;
     
     // Utilisé pour tester les collisions
      FTest := TBitmap.Create;
      FTest.Canvas.Pen.Color := clWhite;
    end;
     
    procedure TForm1.FormResize(Sender: TObject);
    var
      i, x, y, r: Integer;
    begin
      // force un clear du Bitmap
      FBitmap.Height := 0;
      // en blanc
      FBitmap.Canvas.Brush.Color := clWhite;
      // à la taille de l'écran
      FBitmap.Width := ClientWidth;
      FBitmap.Height := ClientHeight;
     
      // idem pour le masque
      FCollide.Height := 0;
      FCollide.Canvas.Brush.Color := clWhite;
      FCollide.Width := ClientWidth;
      FCollide.Height := ClientHeight;
      FCollide.Canvas.Brush.Color := clBlack;
     
      // ajout de disques aléatoires
      Randomize;
      for i := 0 to 5 do
      begin
        x := Random(ClientWidth);
        y := Random(ClientHeight div 2);
        r := 40 + Random(30);
       // en couleur pour l'écran
        FBitmap.Canvas.Brush.Color := RGB(127 + Random(127), 127 + Random(127), 127 + Random(127));
        FBitmap.Canvas.Ellipse(x - r, y - r, x + r, y + r);
       // en noir pour le masque
        FCollide.Canvas.Ellipse(x - r, y - r, x + r, y + r);
      end;
     
      // position initiale
      FPos.X := ClientWidth div 2;
      FPos.Y := ClientHeight div 2;
     
      Invalidate;
    end;
     
     
    procedure TForm1.FormPaint(Sender: TObject);
    var
      Test: Boolean;
    begin
      // copie du masque
      FTest.Assign(FCollide);
      // y dessiner le rectangle en blanc
      FTest.Canvas.Rectangle(FPos.X - 20, FPos.Y - 25, FPos.X + 20, FPos.Y + 25);
      // comparer les deux images
      Test := CompareMem(
        FCollide.ScanLine[FCollide.Height - 1],
        FTest.ScanLine[FTest.Height - 1],
        FTest.Height * ((FTest.Width + 7) div 8)
      );
     
      // afficher l'image de fond
      Canvas.Draw(0, 0, FBitmap);
      // choix de la couleur du rectangle selon la collission
      if Test then
        Canvas.Brush.Color := clGreen
      else
        Canvas.Brush.Color := clRed;
      // dessin du rectangle
      Canvas.Rectangle(FPos.X - 20, FPos.Y - 25, FPos.X + 20, FPos.Y + 25);
    end;
     
    procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    const
      K = 10;
    begin
     // déplacement au clavier, de 10 pixels sinon ça se traine
      case Key of
        VK_LEFT : Dec(FPos.X, K);
        VK_RIGHT: Inc(FPos.X, K);
        VK_UP   : Dec(FPos.Y, K);
        VK_DOWN : Inc(FPos.Y, K);
        else exit;
      end;
      InvalidateRect(Handle, nil, False);
    end;
     
    end.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  20. #20
    Candidat au Club
    Profil pro
    Inscrit en
    Avril 2011
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 16
    Points : 3
    Points
    3
    Par défaut
    Merci Paul, effectivement ça compile bien sous Delphi et c'est rapide !
    Mais le passage sous Lazarus est critique, le scanline n'existe pas

    Je vais continuer avec les régions, ça me parait le meilleur choix

Discussions similaires

  1. Réponses: 3
    Dernier message: 28/05/2010, 13h41
  2. Réponses: 2
    Dernier message: 05/07/2007, 17h35
  3. [FLASH MX PRO] Détection des collisions
    Par Invité dans le forum Flash
    Réponses: 10
    Dernier message: 07/03/2006, 18h20
  4. Gestion des collisions - terrains
    Par Dranor dans le forum DirectX
    Réponses: 1
    Dernier message: 26/06/2003, 18h50

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