Sprite : animation et interpolation

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Sprite : animation et interpolation

Message par blendman »

Salut

Hier, j'ai essayé de créer de l'animation de sprite avec interpolation :
- je crée un sprite
- je lui ajoute des clefs d'animation.
- A chaque clef, je peux modifier certains paramètres : position X,/Y, rotation, taille, alpha.
- puis, je calcule la transformation entre chaque clef pour arriver à la transformation prochaine.

Paramètres à animer, on pourrait ajouter d'autres choses (c'est assez facile à implémenter) :
- changement d'image (sans fade)
- changement de blendmode (sans fade)
- transformation
- clipsprite
- uvscale (?)
etc...

Intérêt et utilisation
Je pense utiliser ça pour créer un utilitaire permettant de concevoir des petites animations de type vectorielle, mais avec les sprites car c'est super rapide :).
J'aimerai par la suite ajouter un petit système de bone ou lien (parent/enfant) entre sprite (j'ai déjà fait la liaison avec la position), pour la taille ça devrait aller, mais c'est la rotation qui risque de me poser le plus de soucis ^^.

L'objectif final étant donc de concevoir un petit outil permettant :
- d'animer facilement des images (sprites) : translation, position, rotation
- de créer facilement des animations avec liens, comme des personnages qui marchent ou des explosions.

Bon, j'avoue que si on pouvait définir soi-même le centre des rotations ou du zoom (le même centre par exemple), ça m'arrangeait ^^. J'ai déjà réussi à le faire, mais ça ne fonctionne qu'avec dx9 (pas openGl, ni dx11).



Pour le moment, voici donc l'interpolation d'animation (simple, sans parent) avec les sprites.
(le code est assez simple je pense).

Code : Tout sélectionner


; animation de sprite avec interpolation (transformation : rotation, scale, position, alpha)
; Purebasic : 5.42
; By blendman 13/03/2016


Structure sKeyFrame
    
    Image.i
    Frame.i
    
    ; les paramètres qu'on change, j'ai besoin d'utiliser des double (ou float) à cause du ratio qui peut être un float/double
    X.d
    y.d
    Angle.d
    Size.d    
    Alpha.d
    
EndStructure   

Structure sSprite
    
    ; taille de l'image de base
    w.i
    h.i
    
    ; les clefs d'animation (keframes) 
    Array KeyFrame.sKeyFrame(0)
    
    
    CurrentKeyFrame.i ; la frame courante de l'animation du sprite
    NextKeyFrame.i    ; pour connaitre la clef suivante
    
    ; pour modifier la position, size et rotation du sprite
    CurrentAngle.d
    CurrentSize.d
    CurrentX.d
    CurrentY.d
    CurrentAlpha.d
    
    ; puis, pour définir le ratio, c'est à dire ce qui reste pour arriver à la prochaine transformation du sprite
    CurrentAngleRatio.d
    CurrentSizeRatio.d
    CurrentXRatio.d
    CurrentYRatio.d
    CurrentAlphaRatio.d
    
    
EndStructure


Global sprite.sSprite ; notre sprite et ses paramètres pour l'animation avec interpolation
Global TotalAnimationFrame = 300 ; on a 300 frame maximum pour notre animation
Global CurrentFrame.i            ; la frame courante d ela timeline


; pour ajouter des keyframes (clefs d'animation) à notre sprite
Procedure AddSpriteKeyFrame(frame,x,y,size,angle,alpha)
    
    ; pour ajouter une nouvelle keyframe
    n = ArraySize(sprite\KeyFrame()) + 1
    
    ReDim Sprite\KeyFrame.sKeyFrame(n)
    
    With sprite
        
        \keyFrame(n)\Angle  = angle
        \keyFrame(n)\x      = x
        \keyFrame(n)\y      = y
        \keyFrame(n)\size   = size
        \keyFrame(n)\frame  = frame
        \keyFrame(n)\Alpha  = alpha
        
    EndWith
    
    ; puis je trie les clefs pour les remettre dans l'ordre
    SortStructuredArray(Sprite\KeyFrame(),#PB_Sort_Ascending, OffsetOf(sKeyFrame\frame), TypeOf(sKeyFrame\frame))
    
    
EndProcedure

Procedure AddFirstKeyFrame(frame,x,y,size,angle,alpha)
    
    ; pour ajouter la première clef d'animation, car un tableau ne peut être négatif, il atoujours au moins un paramètre
    With sprite
        \KeyFrame(0)\Angle  = angle
        \KeyFrame(0)\x      = x
        \KeyFrame(0)\y      = y
        \KeyFrame(0)\size   = size
        \KeyFrame(0)\frame  = frame
        \KeyFrame(0)\Alpha  = alpha
        \CurrentAngle   =  \KeyFrame(0)\Angle
        \CurrentSize    =  \KeyFrame(0)\Size
        \CurrentX       =  \KeyFrame(0)\x
        \CurrentY       =  \KeyFrame(0)\y
        \CurrentAlpha   =  \KeyFrame(0)\Alpha
    EndWith
    
    
EndProcedure

; pour dessiner le sprite, en fonction de son animation
Procedure DrawSprite()
    
    w = sprite\w
    h = sprite\h
    n = ArraySize(sprite\KeyFrame())
    
    ; CurrentFrame c'est la frame (image jouée) actuelle de la timeline. 
    
    If CurrentFrame = sprite\KeyFrame(sprite\NextKeyFrame)\Frame 
        
        ; Notre frame courante est sur une clef d'animation de notre sprite
        ; je définis donc la clef actuelle car elle a changé
        Sprite\CurrentKeyFrame = sprite\NextKeyFrame
        
        Debug "ok "+Str(CurrentFrame)
        
        f = sprite\CurrentKeyFrame ; la clef actuelle
        f1 = f+1                   ; la clef suivante
        If f1 > n                  ; si on dépasse le nombre total de clefs, on revient au début
            f1 =0
            ; pour connaître le nombre de frame entre les deux clefs (actuelle et suivante)
            NbFrame = Abs(TotalAnimationFrame - sprite\KeyFrame(f)\Frame) 
        Else
            ; pour connaître le nombre de frame entre les deux clefs (actuelle et suivante)
            NbFrame = Abs(sprite\KeyFrame(f1)\Frame - sprite\KeyFrame(f)\Frame) 
        EndIf
        
        
        
        ; les paramètres actuels du sprite : position, angle, taille
        sprite\CurrentX        = sprite\KeyFrame(f)\X
        sprite\CurrentY        = sprite\KeyFrame(f)\Y
        sprite\CurrentAngle    = sprite\KeyFrame(f)\Angle
        sprite\CurrentSize     = sprite\KeyFrame(f)\Size
        sprite\CurrentAlpha    = sprite\KeyFrame(f)\Alpha
        
        ; ici, je définis pour chaque paramètre le ratio que je dois ajouter pour arriver au paramètre suivant (lorsqu'on sera à la clefs suivante)
        sprite\CurrentXRatio       = Abs(sprite\KeyFrame(f1)\X - sprite\CurrentX)/NbFrame
        sprite\CurrentYRatio       = Abs(sprite\KeyFrame(f1)\y - sprite\CurrentY)/NbFrame
        sprite\CurrentAngleRatio   = Abs(sprite\KeyFrame(f1)\Angle - sprite\CurrentAngle)/NbFrame
        sprite\CurrentSizeRatio    = Abs(sprite\KeyFrame(f1)\Size - sprite\CurrentSize)/NbFrame
        sprite\CurrentAlphaRatio   = Abs(sprite\KeyFrame(f1)\alpha - sprite\CurrentAlpha)/NbFrame
        
        
        ; puis, on incrémente pour passer à la clef suivante
        sprite\NextKeyFrame +1
        If sprite\NextKeyFrame > n
            sprite\NextKeyFrame = 0
        EndIf
        
        
    EndIf
    
    a = sprite\CurrentKeyFrame
    dir = 0
    If a = n        
        b = 0
        ; à l'envers
        ; dir = -1
    Else
        b = sprite\CurrentKeyFrame+1       
    EndIf  
    
    
    If dir = 0
        NextAngle   = sprite\KeyFrame(b)\Angle
        NextSize    = sprite\KeyFrame(b)\Size
        NextX       = sprite\KeyFrame(b)\X
        NextY       = sprite\KeyFrame(b)\Y
        NextAlpha   = sprite\KeyFrame(b)\Alpha
        
        
        xx = sprite\KeyFrame(a)\X
        yy = sprite\KeyFrame(a)\y   
        rr = sprite\KeyFrame(a)\Angle
        ss = sprite\KeyFrame(a)\Size
        aa = sprite\KeyFrame(a)\Alpha
    Else
        c = b
        b = a
        a = c
        NextAngle   = sprite\KeyFrame(b)\Angle
        NextSize    = sprite\KeyFrame(b)\Size
        NextX       = sprite\KeyFrame(b)\X
        NextY       = sprite\KeyFrame(b)\Y
        NextAlpha   = sprite\KeyFrame(b)\Alpha
        
        xx = sprite\KeyFrame(a)\X
        yy = sprite\KeyFrame(a)\y   
        rr = sprite\KeyFrame(a)\Angle
        ss = sprite\KeyFrame(a)\Size 
        aa = sprite\KeyFrame(a)\Alpha 
    EndIf
    
    If xx < NextX 
        sprite\CurrentX + sprite\CurrentXRatio
    ElseIf xx > NextX 
        sprite\CurrentX - sprite\CurrentXRatio
    EndIf
    
    If yy < Nexty
        sprite\Currenty + sprite\CurrentYRatio
    ElseIf yy > Nexty 
        sprite\Currenty - sprite\CurrentYRatio
    EndIf
    
    If rr < NextAngle
        sprite\CurrentAngle + sprite\CurrentAngleRatio
    ElseIf rr > NextAngle 
        sprite\CurrentAngle - sprite\CurrentAngleRatio
    EndIf
    
    If ss < NextSize
        sprite\CurrentSize + sprite\CurrentSizeRatio
    ElseIf ss > NextSize 
        sprite\CurrentSize - sprite\CurrentSizeRatio
    EndIf
    
    If aa < NextAlpha
        sprite\CurrentAlpha + sprite\CurrentAlphaRatio
    ElseIf aa > NextAlpha
        sprite\CurrentAlpha - sprite\CurrentAlphaRatio
    EndIf
    If sprite\CurrentAlpha>255
        sprite\CurrentAlpha = 255
    ElseIf sprite\CurrentAlpha<0
        sprite\CurrentAlpha = 0
    EndIf
    
    RotateSprite(0,sprite\CurrentAngle ,0)
    ZoomSprite(0,sprite\CurrentSize*0.01*w,sprite\CurrentSize*0.01*h)
    DisplayTransparentSprite(0,sprite\CurrentX,sprite\CurrentY,Sprite\CurrentAlpha)
    
    CurrentFrame+1
    If CurrentFrame > TotalAnimationFrame
        CurrentFrame = 0
    EndIf
    
    
    ProcedureReturn i
EndProcedure 



InitSprite()

OpenWindow(0,0,0,800,600,"Interpolation d'animation de sprite ! ",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,800,600)

LoadSprite(0,#PB_Compiler_Home +"Examples/Sources/Data/PureBasicLogo.bmp")  
SpriteQuality(1)

sprite\w = SpriteWidth(0)
sprite\h = SpriteHeight(0)

AddFirstKeyFrame(0,200,100,100,0,255)

; on ajoute 2 keyframe
AddSpriteKeyFrame(100,180,100,150,0,255) ; ajout d'une keyframe en 100
AddSpriteKeyFrame(200,180,100,120,40,100) ; ajout d'une keyframe en 200
AddSpriteKeyFrame(50,180,100,100,0,100) ; ajout d'une keyframe en 50


; on peut ajouter des clefs d'animation ici.


Repeat
    
    Repeat
        EventID = WaitWindowEvent(1)
        
        Select EventId
            Case #PB_Event_CloseWindow
                Quit = 1
        EndSelect
        
    Until eventId = 0
    
    
    ClearScreen(0)
    DrawSprite()
    ; pour afficher les frames    
    If StartDrawing(ScreenOutput())
        DrawText(0,0,"Frame : "+Str(CurrentFrame))
        StopDrawing()
    EndIf
    
    FlipBuffers()
    
    ; 1 petite pause pour voir le passage entre les keyframes 
    For i = 0 To ArraySize(sprite\KeyFrame())
        If CurrentFrame = sprite\KeyFrame(i)\Frame      
            ; Delay (300)
        EndIf
    Next
    
Until quit = 1
Si vous avez des remarques, des améliorations ou des commentaires, n'hésitez pas ;).
Avatar de l’utilisateur
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Sprite : animation et interpolation

Message par Kwai chang caine »

Ca marche niquel chez moi W7 32bits v5.40
C'est drolement fluide 8O
Merci du partage 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Sprite : animation et interpolation

Message par blendman »

C'est drolement fluide 8O
C'est grâce à Purebasic et surtout grâce au screen et aux sprites ;).
Avatar de l’utilisateur
Ar-S
Messages : 9476
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Sprite : animation et interpolation

Message par Ar-S »

Marche nickel sous W10
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Répondre