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
