Page 2 sur 2

Re: Sprite selection (ou collision)

Publié : lun. 25/avr./2016 9:26
par Fig
J'avais une erreur, je testais le coté opposé du sprite (360° au lieu de 180°).
Je peux adapter la procedure à une transformation si cette transformation est un zoom ou une déformation uniforme.
Par contre si tu compte étirer juste un angle du sprite, il faudra procéder autrement et utiliser une enveloppe en mémoire pour chaque sprite...
Tu me dis si ca vaut la peine que je modifie la procedure pour l'étirement/zoom.
Si ca ne correspond pas à tes besoins, don't act...

Ps: code édité, un point vert visualise le test...

Code : Tout sélectionner

; Fig pixeltest de sprite en rotation
If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 Or OpenWindow(0,0,0,1024,768,"test")=0 Or OpenWindowedScreen(WindowID(0),0,0,1024,768)=0 
  MessageRequester("Error", "Can't open the sprite system", 0)
  End
EndIf
Enumeration
  #logo
  #souris
  #pixel
EndEnumeration
Global xxx,yyy
;Sprite du logo Pb
UsePNGImageDecoder()
file$ = OpenFileRequester("Image",GetCurrentDirectory()+"\","png|*.png",0)
If file$ =""
    End
EndIf
LoadSprite(#logo,file$,#PB_Sprite_AlphaBlending|#PB_Sprite_PixelCollision)
;Sprite de souris rouge
CreateSprite(#souris,5,5)
StartDrawing(SpriteOutput(#souris)):Box(0,0,5,5,#Red):Box(1,1,5,5,#Black):StopDrawing()
;Sprite pour tester la collision sur 1 pixel
CreateSprite(#pixel,1,1,#PB_Sprite_PixelCollision):StartDrawing(SpriteOutput(#pixel)):Box(0,0,1,1,#White):StopDrawing()

;renvoie 0 si pas de collision sinon il y a une collision    
Procedure Test_rotation(sprite1,sprite1X,sprite1Y,sprite2,sprite2X,sprite2Y,PivotX,PivotY,angle.f)
  angle=Radian(180-angle)
  X=sprite2X-PivotX
  Y=sprite2Y-PivotY
  R.f=Sqr((X*X)+(Y*Y))
  Anglem.f=ACos(X/R)
  If Y>0:anglem=2*#PI-anglem:EndIf
  sprite2X=R*Cos(Anglem-angle)+PivotX
  sprite2Y=R*Sin(Anglem-angle)+PivotY
  xxx=sprite2x:yyy=sprite2y
  ProcedureReturn SpritePixelCollision(sprite1,sprite1X,sprite1Y,sprite2,sprite2X,sprite2Y)
EndProcedure

Repeat
  ExamineKeyboard()
  ExamineMouse():X=MouseX():y=MouseY()
  Repeat:Delay(3):Until WindowEvent()=0
  FlipBuffers():ClearScreen(#Black)
  angle+1
  RotateSprite(#logo,0,#PB_Absolute)
  DisplayTransparentSprite(#logo,150,200,120)
  RotateSprite(#logo,angle,#PB_Absolute)
  DisplayTransparentSprite(#logo,150,200)
  DisplayTransparentSprite(#souris,X,Y)
  
  StartDrawing(ScreenOutput())
  If Test_rotation(#logo,150,200,#pixel,X,Y,150+(SpriteWidth(0)/2),200+(SpriteHeight(0)/2),angle)
    DrawText(20,20,"Collision détecté !!!")
  EndIf
  If xxx>0 And xxx<1024 And yyy>0 And yyy<768:Plot(xxx,yyy,#Green):EndIf
  StopDrawing()
Until KeyboardReleased(#PB_Key_Escape)

Re: Sprite selection (ou collision)

Publié : lun. 25/avr./2016 9:43
par blendman
salut

En fait, je n'utilise pas du tout RotateSprite() ni zoomsprite() dans mon éditeur d'animation de sprite, mais uniquement SpriteTransformation() pour les rotations et les zooms :

Code : Tout sélectionner

Procedure SpriteTransformation(Sprite.i, X.f, Y.f, Width.f, Height.f, Angle.f)
    ; by stargate    
    Protected Cos.f = Cos(Radian(Angle))
    Protected Sin.f = Sin(Radian(Angle))    
    TransformSprite(Sprite, X*Cos-Y*Sin, X*Sin+Y*Cos, (X+Width)*Cos-Y*Sin, (X+Width)*Sin+Y*Cos, (X+Width)*Cos-(Y+Height)*Sin,
                    (X+Width)*Sin+(Y+Height)*Cos, X*Cos-(Y+Height)*Sin, X*Sin+(Y+Height)*Cos)
EndProcedure
Car ça me permet de faire des rotations/zoom en fonction d'un offset que je définis par moi-même :).


Donc, s'il y a moyen d'adapter le code pour que ça fonctionne avec cette fonction-ci, c'est certain que je l'utiliserai dans mon éditeur.

Par la suite, il est possible que je déforme un sprite en "tirant" sur un des sommets, mais pour le moment ce n'est pas le cas ^^.

Re: Sprite selection (ou collision)

Publié : lun. 25/avr./2016 11:21
par Fig
Voila sur un nouveau principe, très stupide, je l'avoue... (on affiche 2 fois les sprites testés, une fois dans une couleur qui leur est propre, on les teste alors, puis une seconde fois avec leur couleur normale)
ce principe était utilisé dans certains jeux isometriques pour détecter les clics sur les zones inclinées des tiles.

Il y a des inconvénients, certes, mais aussi le gros avantage que ça fonctionnera même si tu tire sur un angle seulement...
Principe que tu peux adapter, tu peux aussi accélérer la chose en affichant toutes les silouettes colorées d'un coup et en testant une seule fois la couleur pour savoir quel sprite est pointé.
Bref sur ce principe tu as l'embarra du choix pour adapter, en réduisant le nombre de sprites testés aussi, en fonction de la zone de ton ecran (j'ai vu que ton ecran est partitionné)
En plus tu n'as à t'en servir que lorsque le clic souris est activé je suppose (??)

Si ca ne va pas, il faudra utiliser la technique du test de triangle de Comtois, en faisant épouser tes bones les limites de tes sprites et en testant le double triangle du sprite.

Code : Tout sélectionner

; Fig pixeltest de sprites transformés
If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 Or OpenWindow(0,0,0,1024,768,"test")=0 Or OpenWindowedScreen(WindowID(0),0,0,1024,768)=0 
  MessageRequester("Error", "Can't open the sprite system", 0)
  End
EndIf
Enumeration
  #test
  #logo
  #souris
  #pixel
EndEnumeration

;Sprite du logo Pb
UsePNGImageDecoder()
file$ = OpenFileRequester("Image",GetCurrentDirectory()+"\","png|*.png",0)
If file$ =""
    End
EndIf
LoadSprite(#logo,file$,#PB_Sprite_AlphaBlending|#PB_Sprite_PixelCollision)
;Sprite de souris rouge
CreateSprite(#souris,5,5)
StartDrawing(SpriteOutput(#souris)):Box(0,0,5,5,#Red):Box(1,1,5,5,#Black):StopDrawing()
Procedure SpriteTransformation(Sprite.i, X.f, Y.f, Width.f, Height.f, Angle.f)
    ; by stargate    
    Protected Cos.f = Cos(Radian(Angle))
    Protected Sin.f = Sin(Radian(Angle))    
    TransformSprite(Sprite, X*Cos-Y*Sin, X*Sin+Y*Cos, (X+Width)*Cos-Y*Sin, (X+Width)*Sin+Y*Cos, (X+Width)*Cos-(Y+Height)*Sin,
                    (X+Width)*Sin+(Y+Height)*Cos, X*Cos-(Y+Height)*Sin, X*Sin+(Y+Height)*Cos)
  EndProcedure
  
;affiche directement le numero du sprite survolé  
Procedure Test_and_display(sprite1,sprite1X,sprite1Y,X,Y)
  DisplayTransparentSprite(sprite1,sprite1X,sprite1Y,255,sprite1)
  StartDrawing(ScreenOutput())
  test=Point(x,y)
  StopDrawing()
  DisplayTransparentSprite(#logo,150,200,255)
    ProcedureReturn test
EndProcedure

Repeat
  ExamineKeyboard()
  ExamineMouse():X=MouseX():y=MouseY()
  Repeat:Delay(3):Until WindowEvent()=0
  FlipBuffers():ClearScreen(#Black)
  angle+1
  SpriteTransformation(#logo,20,100,50,48,angle)
  Spritedetection=Test_and_display(#logo,150,200,X,Y)  
  If spritedetection
    StartDrawing(ScreenOutput())
      DrawText(20,20,"Collision detecté")
    StopDrawing()
  EndIf
    DisplayTransparentSprite(#souris,X,Y)

Until KeyboardReleased(#PB_Key_Escape)

Re: Sprite selection (ou collision)

Publié : lun. 25/avr./2016 12:10
par blendman
Salut Fig :)

Et bien écoute, ton dernier exemple est carrément bien et ça me convient parfaitement ;).

Je l'ai légèrement modifié pour qu'on puisse avoir des sprites transparents et que ça ne fonctionne qu'au clic souris (bon, le #wm_ c'est windows surtout, mais il doit y avoir l'équivalent pour linux et mac j'imagine ^^).

Code : Tout sélectionner

; Fig pixeltest de sprite en rotation

If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 Or OpenWindow(0,0,0,1024,768,"test")=0 Or OpenWindowedScreen(WindowID(0),0,0,1024,768)=0
    MessageRequester("Error", "Can't open the sprite system", 0)
    End
EndIf

Enumeration
    #test
    #logo
    #logo1
    #souris
EndEnumeration

;Sprite du logo Pb
UsePNGImageDecoder()
file$ = OpenFileRequester("Image",GetCurrentDirectory()+"\","png|*.png",0)
If file$ =""
    End
EndIf

LoadSprite(#logo,file$,#PB_Sprite_AlphaBlending|#PB_Sprite_PixelCollision)

CopySprite(#logo,#logo1,#PB_Sprite_AlphaBlending|#PB_Sprite_PixelCollision)

w = SpriteWidth(#logo)
h = SpriteHeight(#logo)
r.d = 0.5

;Sprite de souris rouge
CreateSprite(#souris,5,5)
StartDrawing(SpriteOutput(#souris)):Box(0,0,5,5,#Red):Box(1,1,5,5,#Black):StopDrawing()


Procedure SpriteTransformation(Sprite.i, X.f, Y.f, Width.f, Height.f, Angle.f)
    ; by stargate   
    Protected Cos.f = Cos(Radian(Angle))
    Protected Sin.f = Sin(Radian(Angle))   
    TransformSprite(Sprite, X*Cos-Y*Sin, X*Sin+Y*Cos, (X+Width)*Cos-Y*Sin, (X+Width)*Sin+Y*Cos, (X+Width)*Cos-(Y+Height)*Sin,(X+Width)*Sin+(Y+Height)*Cos, X*Cos-(Y+Height)*Sin, X*Sin+(Y+Height)*Cos)
EndProcedure

;affiche directement le numero du sprite survolé 
Procedure TestCollision(sprite1,sprite1X,sprite1Y,X,Y)
    
    Static NewMap Sprite2Color.i()
    Static NewMap Color2Sprite.i()
    
    If FindMapElement(sprite2color(),Str(sprite1))=0
        Repeat
            newcolor.i=Random(483647)
        Until FindMapElement(color2sprite(),Str(newcolor))=0
        Color2Sprite(Str(newcolor))=sprite1
        sprite2color(Str(sprite1))=newcolor
    Else
        newcolor=sprite2color(Str(sprite1))
    EndIf
    
    DisplayTransparentSprite(sprite1,sprite1X,sprite1Y,255,newcolor)
    
    If StartDrawing(ScreenOutput())
        If x >=0 And x<OutputWidth() And y>=0 And y < OutputHeight()
            TEST=Point(x,y)
            ;TEST=RGBA(Red(TEST),Green(TEST),Blue(TEST),255)
        EndIf  
        StopDrawing()
    EndIf
    
    If FindMapElement(color2sprite(),Str(TEST))
        ProcedureReturn color2sprite()
    EndIf
EndProcedure

angle = 60

Repeat
        
    ExamineKeyboard()
    
    X=WindowMouseX(0):y=WindowMouseY(0)
    
    Repeat
        event = WaitWindowEvent(1)
        
        If event = #WM_LBUTTONDOWN
            ClearScreen(#Black)    
            spritedetection = TestCollision(#logo,150,200,X,Y) 
            spritedetection = TestCollision(#logo1,350,200,X,Y) 

        EndIf
                
    Until event =0 Or event =#PB_Event_CloseWindow
    
    ClearScreen(#Black) 

    SpriteTransformation(#logo,-(w*r)/2,-10,w*r,h*r,angle)    
    DisplayTransparentSprite(#logo,150,200,255)
        
    SpriteTransformation(#logo1,-(w*r)/2,-10,w*r,h*r,90)    
    DisplayTransparentSprite(#logo1,350,200,150)
      
    DisplayTransparentSprite(#souris,X,Y)
        
    If spritedetection
        StartDrawing(ScreenOutput())
        DrawText(20,20,"Collision detecté, sprite : "+Str(spritedetection))
        StopDrawing()
    EndIf
    
    FlipBuffers()
    
Until KeyboardReleased(#PB_Key_Escape) Or event =#PB_Event_CloseWindow
Je vais voir à optimiser en fonction des remarques que tu as faites(ne tester qu'une seule fois, avec la couleur, ou si les sprites sont visibles dans l'écran, etc...) ;).
Encore un immense merci, je vais intégrer ça dans mon éditeur d'animation de sprite :).

Re: Sprite selection (ou collision)

Publié : lun. 25/avr./2016 12:25
par Fig
Content d'avoir trouvé une astuce qui convienne à ton utilisation.
Repeat
newcolor.i=Random(483647)
Until FindMapElement(color2sprite(),Str(newcolor))=0
On peut sans doute remplacer ça, en donnant comme numero de couleur le numero du sprite directement, ca évite les tables de hashage du coup. :mrgreen:
(j'ai fait la modification dans le listing du haut, ça marche bien, s'assurer juste que le sprite ne vaut pas 0)
Une autre idée, c'est peut être possible de mettre ces couleurs en transparent ? Je ne sais pas si "point" est capable de lire juste un canal alpha. Tu sais mieux que moi, j'en suis sûr.

Bonne continuation.

Re: Sprite selection (ou collision)

Publié : lun. 25/avr./2016 16:47
par Mesa
Il existe un algo spécifique pour savoir si un point est dans un polygone, qu'il soit convexe ou concave.
Fait une recherche avec "algorithm inside polygon"

Dans ma collection de code recueilli dans les forums, j'ai ça:

Code : Tout sélectionner

Structure point_f
  x.f
  y.f
EndStructure
Procedure inpoly(*p.point_f, List poly.point_f())
  Protected.point_f new, old, lp, rp
  Protected inside
  If ListSize(poly()) < 3: ProcedureReturn 0: EndIf 
  LastElement(poly()): old = poly()
  ForEach poly()
    ;find leftmost endpoint 'lp' and the rightmost endpoint 'rp' based on x value
    If poly()\x > old\x 
      lp = old
      rp = poly()
    Else
      lp = poly()
      rp = old
    EndIf 
    If lp\x < *p\x And *p\x <= rp\x And (*p\y - lp\y) * (rp\x - lp\x) < (rp\y - lp\y) * (*p\x - lp\x)
      inside = ~inside
    EndIf 
    old = poly()
  Next 
  ProcedureReturn inside & 1
EndProcedure
 
If InitSprite()
  If InitKeyboard() And InitMouse()
    OpenWindow(0, 0, 0, 800, 600, "Press [Esc] to close, [Left mouse button] Add Point, [Right mouse button] Clear All Points.", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
    OpenWindowedScreen(WindowID(0), 0, 0, 800, 600, 1, 0, 0)
    SetFrameRate(60)
  EndIf
Else
  MessageRequester("", "Unable to initsprite"): End
EndIf
 
NewList v.point_f()
Define.point_f pvp, mp
Define Col, EventID, mode.b, modetxt.s
Repeat
  Delay(1)
  EventID = WindowEvent()
  ExamineKeyboard()
  ExamineMouse()
  ClearScreen(Col)
 
  mp\x = MouseX()
  mp\y = MouseY()
  If MouseButton(#PB_MouseButton_Left)
    AddElement(v())
    v()\x = mp\x
    v()\y = mp\y
    Delay(100)
  EndIf
 
  If MouseButton(#PB_MouseButton_Right)
    ClearList(v())
    Delay(100)
  EndIf
 
  StartDrawing(ScreenOutput())
    If LastElement(v())
      pvp = v()
      ForEach v()
        LineXY(pvp\x, pvp\y, v()\x, v()\y, RGB(0, $FF, 0)) ;Green
        Circle(pvp\x, pvp\y, 5, RGB($FF, 0, 0)) ;Red
        pvp = v()
      Next
    EndIf 
    Circle(MouseX(), MouseY(), 5, RGB($C0, $C0, $FF)) ;LightBlue 
 
    If inpoly(mp, v())
      modetxt = "You are in the polygon."
      Col = RGB(0, 0, 0)
    Else
      modetxt = "You are not in the polygon."
      Col = RGB($50, $50, $50)
    EndIf
    DrawText((800 - TextWidth(modetxt)) / 2, 0, modetxt) 
  StopDrawing()
 
  FlipBuffers()
Until KeyboardReleased(#PB_Key_Escape) Or EventID = #PB_Event_CloseWindow
Avec rotation:

Code : Tout sélectionner

; Author : comtois
; Date :   20/04/2007


; Code de collision avec un rectangle en rotation... d'apres un code de comtois
; http://www.purebasic.fr/french/viewtopic.php?t = 1960


Structure Rectangle
  X.l ; Coordonée Central X
  Y.l ; Coordonée Central Y
  R.l ; Demi Diagonal du Rectangle
  Angle.l ; Angle de Rotation
  X1.l
  Y1.l
  X2.l
  Y2.l
  X3.l
  Y3.l
  X4.l
  Y4.l
EndStructure

Global Rect.Rectangle

Rect\X = 400
Rect\Y = 300
Rect\R = 150


If InitSprite() = 0 Or InitKeyboard()= 0 Or InitMouse()= 0  Or InitSound()= 0
  MessageRequester("Error", "DirectX 7+ is needed.", 0)
  End
EndIf

OpenWindow(0, 0, 0, 800, 600, "Planete Alien ", #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, 800, 600, 0, 0, 0)

Procedure Drawrect()
   LineXY(Rect\X1, Rect\Y1, Rect\X2, Rect\Y2, RGB(255, 255, 255))
   LineXY(Rect\X2, Rect\Y2, Rect\X3, Rect\Y3, RGB(255, 255, 255))
   LineXY(Rect\X3, Rect\Y3, Rect\X4, Rect\Y4, RGB(255, 255, 255))
   LineXY(Rect\X4, Rect\Y4, Rect\X1, Rect\Y1, RGB(255, 255, 255))
  Circle(Rect\X1, Rect\Y1, 10, RGB(255, 0, 0))
  Circle(Rect\X2, Rect\Y2, 10, RGB(255, 0, 0))
  Circle(Rect\X3, Rect\Y3, 10, RGB(255, 0, 0))
  Circle(Rect\X4, Rect\Y4, 10, RGB(255, 0, 0))
EndProcedure

Procedure Signe(a.l)
  If a>0
    ProcedureReturn 1
  ElseIf a = 0
    ProcedureReturn 0
  Else
    ProcedureReturn - 1
  EndIf
EndProcedure


Procedure Coli()
; Test la collision du point avec le triangle
  ; pour en savoir plus  http://tanopah.jo.free.fr/seconde/region.html
  ; Plan 1
  mx = MouseX() : my = MouseY()
  xu1 = Rect\X2 - Rect\X1: yu1 = Rect\Y2 - Rect\Y1
  c1 = Rect\Y1*xu1 - Rect\X1*yu1
  P1 = Rect\X3*yu1 - Rect\Y3*xu1 + c1
  AX1 = Mx*yu1 - My*xu1 + c1
  ; Plan 2
  xu2 = Rect\X3 - Rect\X2: yu2 = Rect\Y3 - Rect\Y2
  c2 = Rect\Y2*xu2 - Rect\X2*yu2
  P2 = Rect\X1*yu2 - Rect\Y1*xu2 + c2
  AX2 = Mx*yu2 - My*xu2 + c2
  ; Plan 3
  xu3 = Rect\X4 - Rect\X3: yu3 = Rect\Y4 - Rect\Y3
  c3 = Rect\Y3*xu3 - Rect\X3*yu3
  P3 = Rect\X1*yu3 - Rect\Y1*xu3 + c3
  AX3 = Mx*yu3 - My*xu3 + c3
  ; Plan 4
  xu4 = Rect\X1 - Rect\X4: yu4 = Rect\Y1 - Rect\Y4
  c4 = Rect\Y4*xu4 - Rect\X4*yu4
  P4 = Rect\X3*yu4 - Rect\Y3*xu4 + c4
  AX4 = Mx*yu4 - My*xu4 + c4

  If  Signe(AX1)= Signe(P1) And Signe(AX2)= Signe(P2) And Signe(AX3)= Signe(P3) And Signe(AX4)= Signe(P4)
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure
  #DEG=#PI/180
Repeat
  ExamineMouse()
  ExamineKeyboard()
 
  Rect\X = 400 + 100*Sin(Rect\Angle*#DEG)
  Rect\Y = 300 + 100*Cos(Rect\Angle*#DEG)
 

  Rect\Angle + 1
  If Rect\Angle>360: Rect\Angle = 0: EndIf
 
    Rect\X1 = Rect\X + Rect\R*Cos((Rect\Angle - 25)*#DEG)
    Rect\Y1 = Rect\Y + Rect\R*Sin((Rect\Angle - 25)*#DEG)
 
    Rect\X2 = Rect\X + Rect\R*Cos((Rect\Angle + 25)*#DEG)
    Rect\Y2 = Rect\Y + Rect\R*Sin((Rect\Angle + 25)*#DEG)
   
    Rect\X3 = Rect\X + Rect\R*Cos((Rect\Angle + 180 - 25)*#DEG)
    Rect\Y3 = Rect\Y + Rect\R*Sin((Rect\Angle + 180 - 25)*#DEG)
   
    Rect\X4 = Rect\X + Rect\R*Cos((Rect\Angle - 180 + 25)*#DEG)
    Rect\Y4 = Rect\Y + Rect\R*Sin((Rect\Angle - 180 + 25)*#DEG)
   
  ; Si ma souris passe dans le rectangle
  If Coli()
    ClearScreen(#Blue)
  Else
    ClearScreen(0)
  EndIf
 
  StartDrawing(ScreenOutput())
    Drawrect()
    Circle(MouseX(), MouseY(), 10, RGB(0, 255, 0))
   
  StopDrawing()
 
 
 
  Delay(1)
 
  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)

Rapide avec 2 cercles

Code : Tout sélectionner

Procedure Circles_Faster_Collision(cx1.f, cy1.f, radius1.f, cx2.f, cy2.f, radius2.f)
  dCenter.f =(cx2 - cx1) *(cx2 - cx1) +(cy2 - cy1) *(cy2 - cy1)
  dRadius.f =(radius1 + radius2) *(radius1 + radius2)
  If dCenter <= dRadius
      ProcedureReturn #True
    Else
      ProcedureReturn #False
  EndIf
EndProcedure


Procedure Circles_Fast_Collision(cx1.f, cy1.f, radius1.f, cx2.f, cy2.f, radius2.f)
  d.f = Sqr((cx2 - cx1) *(cx2 - cx1) +(cy2 - cy1) *(cy2 - cy1))
  If d <= radius1 + radius2
      ProcedureReturn #True
    Else
      ProcedureReturn #False
  EndIf
EndProcedure


Procedure Circles_Collision(x1.f, y1.f, r1.f, x2.f, y2.f, r2.f)
  dx.f =(x1 - x2)
  dy.f =(y1 - y2)
  If Abs(dx) <= r1 And Abs(dy) <= r1
      ProcedureReturn #True
  EndIf
  If dx = 0 And dy = 0
      ProcedureReturn #True
    Else
      dxdy.f = dx / dy
      N.f =(r2 * r2 - r1 * r1 - x2 * x2 + x1 * x1 - y2 * y2 + y1 * y1) /(2 *(y1 - y2))
      A.f = dxdy * dxdy + 1
      B.f = 2 * y1 * dxdy - 2 * N * dxdy - 2 * x1
      C.f =(x1 * x1 + y1 * y1 + N * N - r1 * r1 - 2 * y1 * N)
      Delta.f = B * B - 4 * A * C
      If Delta < 0
          ProcedureReturn #False
        Else
          ProcedureReturn #True
      EndIf
  EndIf
EndProcedure



  ScreenWidth = GetSystemMetrics_(#SM_CXSCREEN)
  ScreenHeight = GetSystemMetrics_(#SM_CYSCREEN)
  ScreenDepth = 32
  If InitSprite() And InitMouse() And InitKeyboard()
      If OpenScreen(ScreenWidth, ScreenHeight, ScreenDepth, "")
          Quit = #False
          Repeat
            FlipBuffers()
            ClearScreen($000000)
            ExamineKeyboard()
            ExamineMouse()
            MouseX = MouseX()
            MouseY = MouseY()
            If KeyboardPushed(#PB_Key_Escape) : Quit = #True : EndIf
            StartDrawing(ScreenOutput())
              DrawingMode(4)
              If Circles_Faster_Collision(ScreenWidth / 2, ScreenHeight / 2, 200, MouseX, MouseY, 200)
                  Color = #Red
                Else
                  Color = #White
              EndIf
              Circle(ScreenWidth / 2, ScreenHeight / 2, 200, Color)
              Circle(MouseX, MouseY, 200, Color)
            StopDrawing()
          Until Quit
      EndIf
  EndIf
End

Avec des ellipses:

Code : Tout sélectionner

Procedure SpriteCollisionLocation(Sprite1.l, x1.l, y1.l, Sprite2.l, x2.l, y2.l, *location.POINTS)
  Protected w1.l, h1.l, w2.l, h2.l
  Protected xl.l, xr.l, yt.l, yb.l
  Protected x.l, y.l, u.l, v.l, yy.l, vv.l
  Protected i.l, j.l, cx.l, cy.l, nb.l, collision.l
 
  w1 = SpriteWidth(Sprite1)
  h1 = SpriteHeight(Sprite1)
  w2 = SpriteWidth(Sprite2)
  h2 = SpriteHeight(Sprite2)
 
  collision = #True
 
  If x1 < x2
    If(x1 + w1) > x2
      xl = x2
      u  =  0
      x  = xl - x1
    Else
      collision = #False
    EndIf
  Else
    If(x2 + w2) > x1
      xl = x1
      x  =  0
      u  = xl - x2
    Else
      collision = #False
    EndIf
  EndIf
 
  If y1 < y2
    If(y1 + h1) > y2
      yt = y2
      v  =  0
      y  = yt - y1
    Else
      collision = #False
    EndIf
  Else
    If(y2 + h2) > y1
      yt = y1
      y  =  0
      v  = yt - y2
    Else
      collision = #False
    EndIf
  EndIf
 
  If collision = #True
   
    If(x1 + w1) <(x2 + w2)
      xr = x1 + w1
    Else
      xr = x2 + w2
    EndIf
   
    If(y1 + h1) <(y2 + h2)
      yb = y1 + h1
    Else
      yb = y2 + h2
    EndIf
   
    xr - 1
    yb - 1
    w1 - 1
    h1 - 1
    w2 - 1
    h2 - 1
  EndIf
 
  If collision = #True
    Dim pt1.l(w1, h1)
    If StartDrawing( SpriteOutput(Sprite1) )
      For i = xl To xr
        For j = yt To yb
          pt1(i - xl + x, j - yt + y) = Point(i - xl + x, j - yt + y)
        Next j
      Next i
      StopDrawing()
    Else
      collision = #False
    EndIf
  EndIf
 
  If collision = #True
    Dim pt2.l(w2, h2)
    If StartDrawing( SpriteOutput(Sprite2) )
      For i = xl To xr
        For j = yt To yb
          pt2(i - xl + u, j - yt + v) = Point(i - xl + u, j - yt + v)
        Next j
      Next i
      StopDrawing()
    Else
      collision = #False
    EndIf
  EndIf
 
  If collision = #True
    yy = y
    vv = v
   
    For i = xl To xr
      y = yy
      v = vv
      For j = yt To yb
       
        If pt1(x, y) And pt2(u, v)
          cx + i
          cy + j
          nb + 1
        EndIf
       
        y + 1
        v + 1
      Next j
      x + 1
      u + 1
    Next i
   
    If nb > 0 And *location
      *location\x = cx / nb
      *location\y = cy / nb
    EndIf
   
  EndIf
 
  ProcedureReturn nb
EndProcedure

InitSprite()
InitMouse()
InitKeyboard()

x = 500
y = 500

If OpenScreen(1024, 768, 16, "")
 
  TransparentSpriteColor(#PB_Default, $000000)
 
  CreateSprite(0, 320, 240)
  CreateSprite(1,  60,  60)
  CreateSprite(2,   3,   3)

  If StartDrawing( SpriteOutput(0) )
    Ellipse(160, 120, 160, 120, $0000FF)
    Ellipse(160, 120,  80,  60, $000000)
    StopDrawing()
  EndIf

  If StartDrawing( SpriteOutput(1) )
    Circle( 0, 30, 30, $00FF00)
    Circle(60, 30, 30, $00FF00)
    Circle(30, 30, 20, $000000)
    StopDrawing()
  EndIf

  If StartDrawing( SpriteOutput(2) )
    Box(0, 0, 3, 3, $FF0000)
    StopDrawing()
  EndIf
 
  Repeat
    ExamineMouse()
    ExamineKeyboard()
    ClearScreen($000000)
   
    x + MouseDeltaX()
    y + MouseDeltaY()
   
    DisplayTransparentSprite(0, 80, 80)
    DisplayTransparentSprite(1,  x,  y)
   
    If SpriteCollisionLocation(0, 80, 80, 1, x, y, @Location.POINTS)
      DisplaySprite(2, Location\x - 1, Location\y - 1)
    EndIf
   
    FlipBuffers()
  Until KeyboardPushed(#PB_Key_Escape)
 
  CloseScreen()
EndIf

Dans un triangle:

Code : Tout sélectionner

; Comtois 05/02/05
; Détection d'un point dans un triangle

;-Initialisation
Global ScreenHeight.l, ScreenWidth.l
Declare Erreur(Message$)
If ExamineDesktops()
  ScreenWidth = DesktopWidth(0)
  ScreenHeight = DesktopHeight(0)
Else
  Erreur("Euh ?")
EndIf
If InitSprite() = 0 Or InitMouse() = 0 Or InitKeyboard()= 0
  Erreur("Impossible d'initialiser DirectX 7 Ou plus")
ElseIf OpenWindow(0, 0, 0, ScreenWidth, ScreenHeight, "", #PB_Window_BorderLess) = 0
  Erreur("Impossible de créer la fenêtre")
EndIf
;{/ouvre un écran
If OpenWindowedScreen( WindowID(0), 0, 0, ScreenWidth , ScreenHeight, 0, 0, 0 ) = 0
  Erreur("Impossible d'ouvrir l'écran ")
EndIf

Structure Triangle
  X1.l
  Y1.l
  X2.l
  Y2.l
  X3.l
  Y3.l
EndStructure
Procedure Erreur(Message$)
  MessageRequester( "Erreur" , Message$ , 0 )
  End
EndProcedure
Procedure Signe(a.l)
  If a>0
    ProcedureReturn 1
  ElseIf a = 0
    ProcedureReturn 0
  Else
    ProcedureReturn - 1
  EndIf
EndProcedure

Procedure CollisionTriangle(*T.Triangle, *P.point)
  ; Test la collision du point avec le triangle
  ; pour en savoir plus  http://tanopah.jo.free.fr/seconde/region.html
  ; Plan 1
  xu1 =*T\X2 -*T\X1: yu1 =*T\Y2 -*T\Y1
  c1 =*T\Y1*xu1 -*T\X1*yu1
  P1 =*T\X3*yu1 -*T\Y3*xu1 + c1
  AX1 =*P\x*yu1 -*P\y*xu1 + c1
  ; Plan 2
  xu2 =*T\X3 -*T\X2: yu2 =*T\Y3 -*T\Y2
  c2 =*T\Y2*xu2 -*T\X2*yu2
  P2 =*T\X1*yu2 -*T\Y1*xu2 + c2
  AX2 =*P\x*yu2 -*P\y*xu2 + c2
  ; Plan 3
  xu3 =*T\X1 -*T\X3: yu3 =*T\Y1 -*T\Y3
  c3 =*T\Y3*xu3 -*T\X3*yu3
  P3 =*T\X2*yu3 -*T\Y2*xu3 + c3
  AX3 =*P\x*yu3 -*P\y*xu3 + c3
  
  If  Signe(AX1)= Signe(P1) And Signe(AX2)= Signe(P2) And Signe(AX3)= Signe(P3)
    Resultat =#True
  EndIf
  ProcedureReturn Resultat
EndProcedure

Procedure AffPoints(*T.Triangle, *P.point, mem)
  StartDrawing(ScreenOutput())
    ;/Affiche le triangle
    Circle(*T\X1, *T\Y1, 4, RGB(255, 0, 0))
    Circle(*T\X2, *T\Y2, 4, RGB(255, 0, 0))
    Circle(*T\X3, *T\Y3, 4, RGB(255, 0, 0))
    LineXY(*T\X1, *T\Y1, *T\X2, *T\Y2, RGB(255, 0, 0))
    LineXY(*T\X2, *T\Y2, *T\X3, *T\Y3, RGB(255, 0, 0))
    LineXY(*T\X1, *T\Y1, *T\X3, *T\Y3, RGB(255, 0, 0))
    ;/Affiche le point
    If mem
      DrawingMode(4)
      Circle(*P\x, *P\y, 6, RGB(255, 255, 255))
    Else
      DrawingMode(0)
      Circle(*P\x, *P\y, 4, RGB(255, 255, 255))
    EndIf
    ;/Affiche une croix pour mieux suivre le déplacement du point
    LineXY(*P\x, 0, *P\x, ScreenHeight - 1, RGB(255, 255, 255))
    LineXY(0, *P\y, ScreenWidth - 1, *P\y, RGB(255, 255, 255))
    If CollisionTriangle(*T, *P)
      FrontColor(RGB(255, 255, 0))
      BackColor(RGB(255, 0, 0))
      texte$ = "  IN "
    Else
      FrontColor(RGB(155, 155, 155))
      BackColor(RGB(0, 255, 0))
      texte$ = " OUT "
    EndIf
    DrawText(0, 0, texte$)
  StopDrawing()
EndProcedure
Procedure TestPoint(X1, Y1, X2, Y2, d)
  If X1>X2 - d And X1 And Y1>Y2 - d And Y1
    ProcedureReturn #True
  EndIf
  ProcedureReturn Resultat
EndProcedure

Triangle.Triangle
Point.point
; Triangle modifiable à la souris
Triangle\X1 = 50
Triangle\Y1 = 50
Triangle\X2 = 200
Triangle\Y2 = 400
Triangle\X3 = 730
Triangle\Y3 = 150
; Point à tester
Point\x = 340
Point\y = 100
DiametreSelection = 6

Repeat
  While WindowEvent(): Wend
  ClearScreen(0)
  ExamineKeyboard()
  ExamineMouse()
  ; Le triangle est modifiable à la souris en cliquant sur un point
  If MouseButton(1)
    If MemPoint = 1
      Triangle\X1 = MouseX()
      Triangle\Y1 = MouseY()
    ElseIf MemPoint = 2
      Triangle\X2 = MouseX()
      Triangle\Y2 = MouseY()
    ElseIf MemPoint = 3
      Triangle\X3 = MouseX()
      Triangle\Y3 = MouseY()
    EndIf
  Else
    MemPoint = 0
  EndIf
  If TestPoint(MouseX(), MouseY(), Triangle\X1, Triangle\Y1, DiametreSelection)
    MemPoint = 1
  ElseIf TestPoint(MouseX(), MouseY(), Triangle\X2, Triangle\Y2, DiametreSelection)
    MemPoint = 2
  ElseIf TestPoint(MouseX(), MouseY(), Triangle\X3, Triangle\Y3, DiametreSelection)
    MemPoint = 3
  EndIf
  ; Place le point à tester sous la souris
  Point\x = MouseX()
  Point\y = MouseY()
  ; Affiche le tout
  AffPoints(@Triangle, @Point, MemPoint)
  FlipBuffers()
  Delay(1)
Until KeyboardPushed(#PB_Key_Escape)

M.

Re: Sprite selection (ou collision)

Publié : lun. 25/avr./2016 16:59
par falsam
Merci pour ces codes Mesa. C'est archivé dans mes exemples types.

Re: [ok] Sprite selection (ou collision)

Publié : jeu. 28/avr./2016 12:06
par blendman
@Fig : en testant, je viens de remarquer que ça ne marche pas avec les sprites dont la couleur est transparente, ça ne marche que pour les pixels dont l'alpha est = 255.

Tu aurais une idée pour résoudre ça, j'ai beau chercher je n'ai pas trouvé de solution ^^.

@Mesa : merci pour les exemples , ça peut toujours servir ;)

Re: [ok] Sprite selection (ou collision)

Publié : ven. 29/avr./2016 10:42
par Fig
blendman a écrit :@Fig : en testant, je viens de remarquer que ça ne marche pas avec les sprites dont la couleur est transparente, ça ne marche que pour les pixels dont l'alpha est = 255.

Tu aurais une idée pour résoudre ça, j'ai beau chercher je n'ai pas trouvé de solution ^^.
Ta boucle peut avoir l'air de ça:

flipbuffer
efface l'ecran.
Tu affiche tous les sprites à tester en dur (255)
Tu fais ton test à la position de la souris pour determiner le sprite
tu efface l'ecran (ou mieux tu affiche ton fond d'ecran tout simplement.)
tu affiche tous tes elements de maniere normale

Code : Tout sélectionner

; Fig pixeltest de sprites transformés
If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 Or OpenWindow(0,0,0,1024,768,"test")=0 Or OpenWindowedScreen(WindowID(0),0,0,1024,768)=0 
  MessageRequester("Error", "Can't open the sprite system", 0)
  End
EndIf
Enumeration
  #fond
  #logo
  #souris
EndEnumeration

;Sprite du logo Pb
UsePNGImageDecoder()
file$ = OpenFileRequester("Image",GetCurrentDirectory()+"\","png|*.png",0)
If file$ =""
  End
EndIf
LoadSprite(#logo,file$,#PB_Sprite_AlphaBlending|#PB_Sprite_PixelCollision)
;Sprite de souris rouge
CreateSprite(#souris,15,15)
StartDrawing(SpriteOutput(#souris)):Box(0,0,15,15,#Red):Box(3,3,15,15,#Black):StopDrawing()
CreateSprite(#fond,32,32,#PB_Sprite_AlphaBlending|#PB_Sprite_PixelCollision)
StartDrawing(SpriteOutput(#fond)):Box(0,0,32,32,RGB(125,125,125)):StopDrawing()

Procedure SpriteTransformation(Sprite.i, X.f, Y.f, Width.f, Height.f, Angle.f)
  ; by stargate    
  Protected Cos.f = Cos(Radian(Angle))
  Protected Sin.f = Sin(Radian(Angle))    
  TransformSprite(Sprite, X*Cos-Y*Sin, X*Sin+Y*Cos, (X+Width)*Cos-Y*Sin, (X+Width)*Sin+Y*Cos, (X+Width)*Cos-(Y+Height)*Sin,
                  (X+Width)*Sin+(Y+Height)*Cos, X*Cos-(Y+Height)*Sin, X*Sin+(Y+Height)*Cos)
EndProcedure


Repeat
  ExamineKeyboard()
  ExamineMouse():X=MouseX():y=MouseY()
  Repeat:Delay(3):Until WindowEvent()=0
  FlipBuffers():ClearScreen(#Black)
  angle+1
  
  ;affiche ici tous tes sprites à tester
  SpriteTransformation(#logo,20,100,50,48,angle)
  DisplayTransparentSprite(#logo,150,200,255,#logo)
  ;...
  ;...
  ;effectue le test
  StartDrawing(ScreenOutput())
  spritedetection=Point(X,Y)
  StopDrawing()
  ;efface l'ecran...   ;ou mieux si tu as un fond d'ecran affiche le, il effacera tout
  ;ClearScreen(#Black)
  
  ;affiche normalement tous tes éléments
  ;fond d'ecran
  gris=0
  For i=0 To 1024 Step 32
    For j=0 To 768 Step 32
      gris=~gris
      DisplayTransparentSprite(#fond,i,j,255,gris)
    Next j
  Next i
  ;sprites
  ;alpha 150 par exemple...
  DisplayTransparentSprite(#logo,150,200,150)
  ;...etc...
  
  DisplayTransparentSprite(#souris,X,Y)
  If spritedetection
    StartDrawing(ScreenOutput())
    DrawText(20,20,"Sprite "+Str(spritedetection)+" détecté")
    StopDrawing()
  EndIf
Until KeyboardReleased(#PB_Key_Escape)

Re: [ok] Sprite selection (ou collision)

Publié : ven. 29/avr./2016 12:08
par blendman
En fait, je me suis mal exprimé, je voulais un sprite transparent à l'origine, comme celui-ci :

Image

Si tu testes avec celui-ci, tu verras que ça ne fonctionne pas ;)

Re: [ok] Sprite selection (ou collision)

Publié : ven. 29/avr./2016 12:33
par Fig
Pas trouvé d'autre solution que de doubler le sprite et avec une procedure ad-hoc de forcer le canal alpha du sprite à 255.

Code : Tout sélectionner

; Fig pixeltest de sprites transformés
If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 Or OpenWindow(0,0,0,1024,768,"test")=0 Or OpenWindowedScreen(WindowID(0),0,0,1024,768)=0 
  MessageRequester("Error", "Can't open the sprite system", 0)
  End
EndIf
Enumeration
  #fond
  #logo
  #logo2
  #souris
EndEnumeration
Structure Pixel
  Pixel.l
EndStructure

Procedure ForceAlpha(sprite)
StartDrawing(SpriteOutput(sprite))
Memsprite=DrawingBuffer()
Pitch=DrawingBufferPitch()
StopDrawing()
      For y = 0 To SpriteHeight(sprite)-1
        *Line.Pixel = memsprite+Pitch*y
        For x = 0 To SpriteWidth(sprite)-1
          If Alpha(*line\pixel)<>0
            *Line\Pixel = RGBA(0,0,0,255)
          EndIf
          *Line+4
        Next x
      Next y
EndProcedure

Procedure SpriteTransformation(Sprite.i, X.f, Y.f, Width.f, Height.f, Angle.f)
  ; by stargate    
  Protected Cos.f = Cos(Radian(Angle))
  Protected Sin.f = Sin(Radian(Angle))    
  TransformSprite(Sprite, X*Cos-Y*Sin, X*Sin+Y*Cos, (X+Width)*Cos-Y*Sin, (X+Width)*Sin+Y*Cos, (X+Width)*Cos-(Y+Height)*Sin,
                  (X+Width)*Sin+(Y+Height)*Cos, X*Cos-(Y+Height)*Sin, X*Sin+(Y+Height)*Cos)
EndProcedure

;Sprite du logo Pb
UsePNGImageDecoder()
file$ = OpenFileRequester("Image",GetCurrentDirectory()+"\","png|*.png",0)
If file$ =""
  End
EndIf
LoadSprite(#logo,file$,#PB_Sprite_AlphaBlending)
CopySprite(#logo,#logo2)
ForceAlpha(#logo2)
;Sprite de souris rouge
CreateSprite(#souris,15,15)
StartDrawing(SpriteOutput(#souris)):Box(0,0,15,15,#Red):Box(3,3,15,15,#Black):StopDrawing()
CreateSprite(#fond,32,32,#PB_Sprite_AlphaBlending)
StartDrawing(SpriteOutput(#fond)):Box(0,0,32,32,RGB(125,125,125)):StopDrawing()

Repeat
  ExamineKeyboard()
  ExamineMouse():X=MouseX():y=MouseY()
  Repeat:Delay(3):Until WindowEvent()=0
  FlipBuffers():ClearScreen(#Black)
  angle+1
  
  ;affiche ici tous tes sprites à tester
  SpriteTransformation(#logo2,20,100,50,48,angle)
  DisplayTransparentSprite(#logo2,120,200,255,#logo)
  ;...
  ;...
  ;effectue le test
  StartDrawing(ScreenOutput())
  spritedetection.q=Point(X,Y)
  StopDrawing()
  ;efface l'ecran...   ;ou mieux si tu as un fond d'ecran affiche le, il effacera tout
  ;ClearScreen(#Black)
  
  ;affiche normalement tous tes éléments
  ;fond d'ecran
  gris=0
  For i=0 To 1024 Step 32
    For j=0 To 768 Step 32
      gris=~gris
      DisplayTransparentSprite(#fond,i,j,255,gris)
    Next j
  Next i
  ;sprites
  SpriteTransformation(#logo,20,100,50,48,angle)
  DisplayTransparentSprite(#logo,120,200,150)

  
  ;...etc...
  
  DisplayTransparentSprite(#souris,X,Y)
  If spritedetection
  StartDrawing(ScreenOutput())
    DrawText(20,20,"Sprite "+Str(spritedetection)+" détecté")
 StopDrawing()
  EndIf
    
Until KeyboardReleased(#PB_Key_Escape)

Re: [ok] Sprite selection (ou collision)

Publié : ven. 29/avr./2016 16:39
par Fig
je pensais qu'en utilise un mode de fusion ca serait faisable mais je n'ai pas trouvé :(
Dommage que Pb ne permette pas l'affichage des sprites PNG en ignorant le canal alpha.

Re: [ok] Sprite selection (ou collision)

Publié : sam. 30/avr./2016 8:37
par Mesa
@Blendman: Pourquoi tu n'utilises pas l'algo inpoly() du 1er exemple :|
Il est indépendant de la transparence mais peux-tu vérifier si ça marche quand même stp ?

Et je peux savoir pourquoi tu veux tester la collision avec de la transparence, car dans un jeu, on veux justement que la transparence ne "collisionne" pas...

Code : Tout sélectionner

#Window_main = 0

Structure point_f
  x.f
  y.f
EndStructure
Procedure inpoly(*p.point_f, List poly.point_f())
  Protected.point_f new, old, lp, rp
  Protected inside
  ;If ListSize(poly()) < 3: ProcedureReturn 0: EndIf 
  LastElement(poly()): old = poly()
  ForEach poly()
    ;find leftmost endpoint 'lp' and the rightmost endpoint 'rp' based on x value
    If poly()\x > old\x 
      lp = old
      rp = poly()
    Else
      lp = poly()
      rp = old
    EndIf 
    If lp\x < *p\x And *p\x <= rp\x And (*p\y - lp\y) * (rp\x - lp\x) < (rp\y - lp\y) * (*p\x - lp\x)
      inside = ~inside
    EndIf 
    old = poly()
  Next 
  ProcedureReturn inside & 1
EndProcedure
Global NewList v.point_f() 

If InitSprite() =0 Or InitKeyboard()  =0
  End
EndIf

Procedure SpriteTransformation(Sprite.i, X.f, Y.f, Width.f, Height.f, Angle.f, x0.f,y0.f)
  
  ; by stargate
  
  Protected Cos.f = Cos(Radian(Angle))
  Protected Sin.f = Sin(Radian(Angle))
  
  TransformSprite(Sprite, X*Cos-Y*Sin, X*Sin+Y*Cos, (X+Width)*Cos-Y*Sin, (X+Width)*Sin+Y*Cos, (X+Width)*Cos-(Y+Height)*Sin,
                  (X+Width)*Sin+(Y+Height)*Cos, X*Cos-(Y+Height)*Sin, X*Sin+(Y+Height)*Cos)
  AddElement(v()) 
  v()\x =   X*Cos-Y*Sin+x0
  v()\y = X*Sin+Y*Cos+y0
  AddElement(v()) 
  v()\x = (X+Width)*Cos-Y*Sin +x0
  v()\y = (X+Width)*Sin+Y*Cos+y0
  AddElement(v()) 
  v()\x =  (X+Width)*Cos-(Y+Height)*Sin+x0
  v()\y = (X+Width)*Sin+(Y+Height)*Cos+y0
  AddElement(v()) 
  v()\x =  X*Cos-(Y+Height)*Sin+x0
  v()\y = X*Sin+(Y+Height)*Cos+y0
EndProcedure
Define.point_f  mp

flag = #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget
WinW =1024
WinH =768

If OpenWindow(#Window_main,0,0,WinW,WinH, "Sprite selection", Flag) = 0
  End
EndIf
If OpenWindowedScreen(WindowID(0), 0,0,WinW,WinH) = 0
  End
EndIf

UsePNGImageDecoder()
LoadSprite(0,#PB_Compiler_Home+"Examples\Sources\Data\PurebasicLogo.bmp",#PB_Sprite_PixelCollision)
;LoadSprite(1,"c:\shado.png" )
CopySprite(0,1,#PB_Sprite_PixelCollision)
W =SpriteWidth(0)
H =SpriteHeight(0)
r.d = 1
x = 150
y = 150
x1.f = 450.0
y1.f = 400.0

CreateSprite(2,200,40,#PB_Sprite_PixelCollision)

cursor = 3
CreateSprite(cursor,4,4,#PB_Sprite_PixelCollision)

If StartDrawing(SpriteOutput(3))
  Box(0,0,OutputWidth(),OutputHeight(),RGBA(255,255,255,255))        
  StopDrawing()
EndIf
SpriteTransformation(1, -10,-(h*r)/2, w*r, h*r ,60, x1, y1)	; mis en dehors de la boucle pour ne pas remplir la liste inutilement: A OPTIMISER

Repeat
  
  Repeat       
    EventID  = WindowEvent()
    
    Select EventID               
      Case #PB_Event_CloseWindow
        End               
    EndSelect       
  Until event = 0
  
  ClearScreen(RGB(50,50,50))
  
  mx = WindowMouseX(0)
  my = WindowMouseY(0)
  mp\x = mx
  mp\y = my
  
  DisplayTransparentSprite(cursor,mx,my,255,RGBA(255,255,255,255))
  
  txt$ = ""
  
  If SpritePixelCollision(0,x,y,cursor,mx,my) <> 0
    txt$ = "mouse over sprite0"
  EndIf
  
  
  DisplayTransparentSprite(0,x,y,255,#Red)
  ; 		SpriteTransformation(1, -10,-(h*r)/2, w*r, h*r ,60, x1, y1);	; mis en dehors de la boucle pour ne pas remplir la liste inutilement: A OPTIMISER
  DisplaySprite(1,x1,y1)
  
  If inpoly(mp, v())
    txt1$ = "mouse over sprite1"
  Else
    txt1$=""
  EndIf
  
  If StartDrawing(SpriteOutput(2))
    Box(0,0,OutputWidth(),OutputHeight(),0)
    DrawText(0,0,txt$+" | " +txt1$)
    StopDrawing()
  EndIf
  
  DisplaySprite(2,0,0) 
  
  FlipBuffers()
  
Until Quit = 1
M.

Re: [ok] Sprite selection (ou collision)

Publié : sam. 30/avr./2016 9:58
par Fig
Quand il parle de transparence il parle de canal alpha.
Le canal alpha à 0 n'est pas détecté. C'est totalement transparent. Au dessus, c'est semi-transparent donc, ça doit être détecté.

En lisant le fil attentivement tu verras que le probleme de Blendman est de detecter une collision avec un sprite qui a été transformé.
Ta méthode est très bonne, mais impliquerait qu'on modifie l'enveloppe mathématique en même temps qu'on transforme le sprite, ce qui est hypercompliqué. (le sprite étant un carré composé de 2 triangle, dont les triangles sont deformés. Mais ce qu'on souhaite détecter n'épouse pas les limites des deux triangles, malheureusement)

Re: [ok] Sprite selection (ou collision)

Publié : sam. 30/avr./2016 17:03
par blendman
@Mesa : Fig a très bien répondu, mais la sélection recherchée doit être fonctionnelle sur les sprites transformés (pas juste des rotations et/ou scale, mais aussi des skeeze, et des transformations en bougeant les sommets des sprites), ce qui peut être vite complexe à mettre en place. D'autant, que je ne veux justement pas détecter la transparence complète (alpha= 0), mais les niveaux de transparence oui (alpha >0) ;).

@Fig : merci pour ton dernier code, je vais utiliser cette technique ;).