Page 1 sur 2

Scrolling d'un sprite

Publié : jeu. 06/juil./2017 10:57
par Fig
J'en ai eu besoin pour mon projet et je trouve cela élégant.
Ca ajoute une petite animation à peu de frais sur un sprite statique sur un écran.
Pas essayé sur de large sprites mais il n'y a pas de raison que ça ne fonctionne pas sur un gros parallaxe.

Code : Tout sélectionner

If InitSprite() = 0 Or InitKeyboard() = 0:MessageRequester("Error", "Can't open the sprite system", 0):End:EndIf
If OpenWindow(0, 0, 0,800,600, "Scroll Sprite", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)=0:MessageRequester("Error", "Can't open windowed screen!", 0):EndIf
If OpenWindowedScreen(WindowID(0), 0, 0, 800, 600, 0, 0, 0)=0:MessageRequester("Error", "Can't open windowed screen!", 0):EndIf    
;}

LoadSprite(0, #PB_Compiler_Home + "examples/sources/Data/PureBasic.bmp")
Procedure Scroll(sprite.i,StepX.i,StepY.i)
   If StartDrawing(SpriteOutput(sprite))
      Buffer.i= DrawingBuffer()
      Pitch.i= DrawingBufferPitch()
      If StepX>0
         StepX<<2
         *Dest=AllocateMemory(StepX)
         For y = 0 To SpriteHeight(sprite)-1
            *debut = Buffer+Pitch*y
            CopyMemory(*debut,*Dest,StepX)
            CopyMemory(*debut+StepX,*debut,pitch-StepX)
            CopyMemory(*Dest,*debut+Pitch-StepX,StepX)
         Next y
         FreeMemory(*dest)
      ElseIf StepX<0
         StepX=Abs(StepX)
         StepX<<2
         *Dest=AllocateMemory(StepX)
         For y = 0 To SpriteHeight(sprite)-1
            *debut = Buffer+Pitch*y
            CopyMemory(*debut+pitch-StepX,*Dest,StepX)
            CopyMemory(*debut,*debut+StepX,pitch-StepX)
            CopyMemory(*Dest,*debut,StepX)
         Next y
         FreeMemory(*dest)
      EndIf
      If StepY>0
         *Dest=AllocateMemory(pitch*StepY)
         *debut = Buffer
         CopyMemory(*debut,*Dest,pitch*StepY)
         CopyMemory(*debut+pitch*StepY,*debut,pitch*(SpriteHeight(sprite)-StepY))
         CopyMemory(*Dest,*debut+pitch*(SpriteHeight(sprite)-StepY),pitch*StepY)
         FreeMemory(*dest)
      ElseIf StepY<0
         StepY=Abs(StepY)
         *debut = Buffer
         *Dest=AllocateMemory(pitch*StepY)
         CopyMemory(*debut+pitch*(SpriteHeight(sprite)-StepY),*Dest,pitch*StepY)
         CopyMemory(*debut,*debut+pitch*StepY,pitch*(SpriteHeight(sprite)-StepY))
         CopyMemory(*Dest,*debut,pitch*StepY)
         FreeMemory(*dest)
      EndIf 
      StopDrawing()     
   EndIf
EndProcedure

Repeat
   WindowEvent()
   ExamineKeyboard()
   FlipBuffers()
   ClearScreen(#Black)
   DisplaySprite(0,0,0)
   Scroll(0,-6,3)
Until KeyboardPushed(#PB_Key_Escape)

Re: Scrolling d'un sprite

Publié : jeu. 06/juil./2017 14:15
par falsam
Merci fig. Ca répond en plus partiellement à une question que j'ai posé ici http://www.purebasic.fr/french/viewtopi ... =2&t=16198

L'idéal serait d'avoir une procédure ScrollSprite(Sprite, StepX, StepY) permettant de scroller un sprite verticalement et/ou horizontalement en précisant le pas vertical et horizontal.

Si c'est possible, merci de ce plus.

Re: Scrolling d'un sprite

Publié : jeu. 06/juil./2017 15:16
par djes
Il faut dire pour la petite histoire (même si on ne peut pas grand chose aux choix de microsoft qui traîne de biens gros boulets depuis le début) qu'avant le passage à dx9, polux faisait ça avec des copysprite() ou des grabs ou des clips, et c'était facile et hyper rapide (plusieurs parallaxes superposés...) ; maintenant, c'est une autre histoire, il faut penser complètement différemment. Mais bon, les bécanes sont suffisamment puissantes pour ne pas avoir trop à se fatiguer...

Re: Scrolling d'un sprite

Publié : jeu. 06/juil./2017 16:24
par comtois
Je n'ai pas testé, ta méthode est plus rapide qu'avec ClipSprite() ?

Code : Tout sélectionner

If InitSprite() = 0 Or InitKeyboard() = 0:MessageRequester("Error", "Can't open the sprite system", 0):End:EndIf
If OpenWindow(0, 0, 0,800,600, "Scroll Sprite", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)=0:MessageRequester("Error", "Can't open windowed screen!", 0):EndIf
If OpenWindowedScreen(WindowID(0), 0, 0, 800, 600, 0, 0, 0)=0:MessageRequester("Error", "Can't open windowed screen!", 0):EndIf   
;}
LoadSprite(0, #PB_Compiler_Home + "examples/sources/Data/PureBasic.bmp")

Width = SpriteWidth(0)
Procedure Clamp(*x.integer, limite)
  If *x\i > limite
    *x\i = 0
  EndIf  
EndProcedure

x=0
Repeat
   WindowEvent()
   ExamineKeyboard()
   FlipBuffers()
   ClearScreen(#Black)
   ClipSprite(0,x,0,Width-x,SpriteHeight(0))
   DisplayTransparentSprite(0,0,0)
   ClipSprite(0,0,0,x,SpriteHeight(0))
   DisplayTransparentSprite(0,Width-x,0)
   Clamp(@x, Width)
   x + 1
Until KeyboardPushed(#PB_Key_Escape)

Re: Scrolling d'un sprite

Publié : jeu. 06/juil./2017 16:32
par Fig
Je ne sais pas si c'est plus rapide, mais pour la procedure clamp() on peut la remplacer avantageusement par un modulo, je pense.

Code : Tout sélectionner

x%width
Pour ma part, je préfère que le sprite entier soit modifié plutôt que de l'afficher en deux fois, mais c'est chacun qui voit ce qu'il préfère, en l’occurrence je ne suis pas sectaire. :D

Re: Scrolling d'un sprite

Publié : jeu. 06/juil./2017 16:44
par comtois
Fig a écrit :Je ne sais pas si c'est plus rapide, mais pour la procedure clamp() on peut la remplacer avantageusement par un modulo, je pense.

Code : Tout sélectionner

x%width
Entièrement d'accord, bon c'est du vite fait.
Pour ma part, je préfère que le sprite entier soit modifié plutôt que de l'afficher en deux fois, mais c'est chacun qui voit ce qu'il préfère, en l’occurrence je ne suis pas sectaire. :D
Moi non plus, c'était histoire de montrer une autre façon de faire, à chacun de choisir la méthode qui lui convient :)

Re: Scrolling d'un sprite

Publié : jeu. 06/juil./2017 18:00
par Fig
falsam a écrit :Merci fig. Ca répond en plus partiellement à une question que j'ai posé ici http://www.purebasic.fr/french/viewtopi ... =2&t=16198
L'idéal serait d'avoir une procédure ScrollSprite(Sprite, StepX, StepY) permettant de scroller un sprite verticalement et/ou horizontalement en précisant le pas vertical et horizontal.
Si c'est possible, merci de ce plus.
Voila, tu as la fonction ScrollSprite(Sprite, StepX, StepY), j'ai modifié le premier code. Ca fonctionne pas mal je trouve. :wink:
0 pour pas de scroll dans la direction en question. Positif ou négatif pour un sens ou l'autre verticalement et/ou horizontalement.

Re: Scrolling d'un sprite

Publié : jeu. 06/juil./2017 20:15
par falsam
Hey mais c'est pas mal du tout cette procédure. Elle est bien plus stable que la mienne. Je teste ça avec un code plus concret .....

Re: Scrolling d'un sprite

Publié : jeu. 06/juil./2017 22:02
par Fig
Le comportement est intéressant avec transformsprite: ça fonctionne.
Avec rotatedSprite aussi.

Par contre avec zoomsprite, il faut effectuer la translation alors que le sprite a sa dimension d'origine.

Re: Scrolling d'un sprite

Publié : ven. 07/juil./2017 16:37
par Tonio
Merci du partage Fig

Re: Scrolling d'un sprite

Publié : sam. 08/juil./2017 9:56
par Fig
Bulletproof and shorter by Demivec.

Code : Tout sélectionner

Procedure Scroll(sprite.i, StepX.i, StepY.i)
  Protected SpriteW, SpriteH, y, Buffer, Pitch, PixelFormat, *Dest, *debut
  If StartDrawing(SpriteOutput(sprite))
    SpriteW = OutputWidth(): SpriteH = OutputHeight()
    StepX = (StepX + SpriteW) % SpriteW
    StepY = (StepY + SpriteH) % SpriteH
    If StepX = 0 And StepY = 0: StopDrawing(): ProcedureReturn: EndIf
    Buffer = DrawingBuffer()
    Pitch = DrawingBufferPitch()
    If StepX <> 0
    PixelFormat = DrawingBufferPixelFormat() & ~#PB_PixelFormat_ReversedY
    If PixelFormat >= #PB_PixelFormat_32Bits_RGB
       StepX <<2
    ElseIf PixelFormat >= #PB_PixelFormat_24Bits_RGB
       StepX * 3
    ElseIf PixelFormat >= #PB_PixelFormat_15Bits
       StepX <<1
    EndIf
      *Dest = AllocateMemory(StepX)
      For y = 0 To SpriteH - 1
        *debut = Buffer + Pitch * y
        CopyMemory(*debut, *Dest, StepX)
        CopyMemory(*debut + StepX, *debut, Pitch - StepX)
        CopyMemory(*Dest, *debut + Pitch - StepX, StepX)
      Next y
      FreeMemory(*dest)
    EndIf
    If StepY <> 0
      If DrawingBufferPixelFormat() & #PB_PixelFormat_ReversedY
        StepY = SpriteH - StepY ;reverse the Y value
     EndIf
      *Dest = AllocateMemory(Pitch * StepY)
      *debut = Buffer
      CopyMemory(*debut, *Dest, Pitch * StepY)
      CopyMemory(*debut + Pitch * StepY, *debut, Pitch * (SpriteH - StepY))
      CopyMemory(*Dest, *debut + Pitch * (SpriteH - StepY), Pitch * StepY)
      FreeMemory(*Dest)
    EndIf  
    StopDrawing()    
  EndIf
EndProcedure


CompilerIf  #PB_Compiler_IsMainFile
  If InitSprite() = 0 Or InitKeyboard() = 0: MessageRequester("Error", "Can't open the sprite system", 0): End: EndIf
  If OpenWindow(0, 0, 0, 800, 600, "Scroll Sprite", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) = 0: MessageRequester("Error", "Can't open windowed screen!", 0): EndIf
  If OpenWindowedScreen(WindowID(0), 0, 0, 800, 600, 0, 0, 0) = 0: MessageRequester("Error", "Can't open windowed screen!", 0): EndIf    
  ;}
  
  LoadSprite(0, #PB_Compiler_Home + "examples/sources/Data/PureBasic.bmp")
  Define sw = SpriteWidth(0), sh = SpriteHeight(0) ;save original sprite size values for random selection later
  Define time.d, stepx, stepy
  
  Repeat
    WindowEvent()
    ExamineKeyboard()
    FlipBuffers()
    ClearScreen(#Black)
    
    RotateSprite(0, 0.1, #PB_Relative)
    If time.d < ElapsedMilliseconds()
       ZoomSprite(0, Random(sw * 3, 2), Random(sh * 3, 2))
       stepx = Random(4) - 2: stepy = Random(4) - 2: time = ElapsedMilliseconds() + 3000
    EndIf

    Scroll(0, stepx, stepy)
    DisplaySprite(0, ScreenWidth() / 2 - SpriteWidth(sprite) / 2,ScreenHeight() / 2)
    
  Until KeyboardPushed(#PB_Key_Escape)
CompilerEndIf

Re: Scrolling d'un sprite

Publié : sam. 08/juil./2017 10:39
par Mindphazer
Et là ça fonctionne nickel sur Mac ! :P
(la première version du premier code ne fonctionnait pas, je crois que tu l'as modifiée suite à ce que t'avait dit Wilbert sur le forum anglais :) )

Re: Scrolling d'un sprite

Publié : sam. 08/juil./2017 22:20
par falsam
J'ai suivit les débats sur ce forum ainsi que sur le forum Anglophone. Fig et Demivec bravo c'est du beau travail.

J'ai quand même un souci avec la vitesse de défilement qui même réglée à 1 reste encore trop rapide dans le cadre d'une application utilisant un system de paralax comme vous allez avec cet exemple mettant en jeu 3 scroll-layer.

http://falsam.com/download/purebasic/ScrollSprite.zip

J'espére que vous aurez une solution à me proposer. Merci.

Re: Scrolling d'un sprite

Publié : dim. 09/juil./2017 8:51
par Fig
Bein tu update pas à chaque tour de boucle dans ce cas là... Mais je suis sûr que tu y aS pensé, non ?
Comme de toute façon un écran n'affichera pas les déplacements de fraction de pixels, hein... :mrgreen:

Waw c'est beau en tout cas !! Elles sont de qui ces images ? (je les piquerai bien moi...)

Re: Scrolling d'un sprite

Publié : dim. 09/juil./2017 9:42
par djes
Fig a écrit :Comme de toute façon un écran n'affichera pas les déplacements de fraction de pixels, hein... :mrgreen:
À ta place, je ne serais pas aussi sûr de moi ! :mrgreen: