Request: Frames for Images and Sprites

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
hagibaba
Enthusiast
Enthusiast
Posts: 170
Joined: Fri Mar 05, 2004 2:55 am
Location: UK
Contact:

Request: Frames for Images and Sprites

Post by hagibaba »

I wonder why PureBasic doesn't have a frames parameter for images and sprites. How are you supposed to handle animations? Do you have to code your own frames system for animations? Why can't we just have this:

Syntax:
DrawImage(ImageID, x, y [, frame, Width, Height])
DisplaySprite(#Sprite, x, y [, frame])
Result = CreateImage(#Image, Width, Height [, frames, Depth])
Result = CreateSprite(#Sprite, Width, Height [, frames, Mode])
etc...

And then new functions where you can load multiple images/sprites in a left-to-right, top-to-bottom order.
Syntax:
LoadAnimImage(#Image,FileName$,width,height,firstframe,frames [, Flags])
LoadAnimSprite(#Sprite,FileName$,width,height,firstframe,frames [, Mode])
User avatar
Hroudtwolf
Addict
Addict
Posts: 803
Joined: Sat Feb 12, 2005 3:35 am
Location: Germany(Hessen)
Contact:

Post by Hroudtwolf »

There is already a way to create simple animations.
Create a frameset like that....
Image
... use ClipSprite to iterate from tile to tile with the speed you want.

Best regards
Wolf
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

Post by Fluid Byte »

I must admit these BlitzBasic functions wouldn't be bad but you can live witout it. Here's a brief example:

Code: Select all

InitSprite() : InitKeyboard()

OpenWindow(0,0,0,640,480,"void",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)	
OpenWindowedScreen(WindowID(0),0,0,640,480,0,0,0)

CreateSprite(0,512,64)

StartDrawing(SpriteOutput(0))
For i=0 To 7
	Box(64*i,0,64,64,50 + i*28)
Next
StopDrawing()

Repeat
	EventID = WindowEvent()
	
	ClearScreen($804020)
	
	ExamineKeyboard()
		
	AnimDelay + 1
	
	If AnimDelay = 8
		AnimDelay = 0		
		If AnimMode : AnimFrame - 1 : Else : AnimFrame + 1 : EndIf
		If AnimFrame = 7 Or AnimFrame = 0 : AnimMode = 1-AnimMode : EndIf
	EndIf	
	
	ClipSprite(0,AnimFrame * 64,0,64,64)
	For x=0 To 3
		For y=0 To 3
			DisplaySprite(0,130 + x * 100,50 + y * 100)
		Next
	Next
	FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape) Or EventID = #PB_Event_CloseWindow
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
hagibaba
Enthusiast
Enthusiast
Posts: 170
Joined: Fri Mar 05, 2004 2:55 am
Location: UK
Contact:

Post by hagibaba »

Thanks, and extra thanks for the code example.

I didn't know about ClipSprite. I suppose it's enough but I would still prefer built in frame support, I think there is a limit to the size of an image, 8192x8192, it doesn't say if there is a limit for sprites but it's probably the same. This means there is a limit to how many frames you have eg. a 256x256 image has a max of 32 frames. So the only way around that if you need it is to code your own frame system I guess.
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

for sprites there is a limit in the screensize.
it's not that good idea to try to clip sprites bigger than the screen.

but you can also load the frames into single sprites following each other by number.

I wrote an Include some time ago that uses a matrix of frames to clip from, think it is for 3.94

perhaps you can use it, sorry for the german comments

Code: Select all

; *******************************************************************

Declare FreeAnim()      ; muss vordeklariert werden,
                        ; weil auch von InitAnim benutzt

; *******************************************************************

Procedure InitAnim(No_of_Anims.l)

    ;*************************** Beginn Fehler-Pufferung
Static AnimReInit
    If AnimReInit = 1           ; erneuter Aufruf?
        FreeAnim()              ; Speicherplatz freigeben.
    Else                        ; erster Aufruf?
    ;*************************** Ende Fehler-Pufferung

        Structure Animat        ; Struktur definieren
            PosX.l              ; X-Position im Screen
            Posy.l              ; Y-Position im Screen
            FraW.l              ; Breite eines Einzelframes
            FraH.l              ; Höhe eines Einzelframes.
            SetW.l              ; Anzahl Frames in einer Reihe des Sets
            SetH.l              ; Anzahl Reihen im Set
            Fram.l              ; Aktueller Frame
            NoFr.l              ; Anzahl Frames gesamt
            Mode.l              ; Verzögerungs-Modus
            Dely.l              ; Aktuelle Verzögerung
            msBf.l              ; Millisekunden-Buffer
            cont.l              ; counter für frame-verzögerung
        EndStructure
       
        Global AnimErrorTxt.s   ; FehlerNummer
        Global AnimErrorNr.l    ; FehlerText
        Global AnimCount.l      ; Anzahl Anims
        Global SetOffset.l         ; Erste Sprite-Nr.

    ;*************************** Beginn Fehler-Pufferung
    EndIf
    AnimReInit = 1
    ;*************************** Ende Fehler-Pufferung

    AnimCount = No_of_Anims

    SetOffset = 7000        ; hier verändern, wenn gewünscht

    Dim Anim.Animat(No_of_Anims)
     
EndProcedure

; *******************************************************************

Procedure.l FreeAnim()

    ;*************************** Beginn Fehler-Pufferung
    If AnimCount > 0    ; sind Anims vorhanden?
    ;*************************** Ende Fehler-Pufferung

    For n=1 To AnimCount
        If IsSprite(SetOffset+n)     ; alle benutzten sprites
            FreeSprite(SetOffset+n)  ; werden freigegeben
        EndIf
    Next
    Dim Anim.Animat(0)          ; Array-Speicher freigeben
    AnimCount = 0

    ;*************************** Beginn Fehler-Pufferung
        ProcedureReturn 1   ; FreeAnim erfolgreich
    Else
        ProcedureReturn 0   ; FreeAnim fehlgeschlagen
    EndIf
    ;*************************** Ende Fehler-Pufferung

EndProcedure

; *******************************************************************

Procedure.l CreateAnim(Nr.l, File.s, Mode.l, Width.l, Height.l, TRed.l, TGrn.l, TBlu.l)

    SetNr = SetOffset+Nr

    ;*************************** Beginn Fehler-Pufferung
    AnimErrorNr = 0 : AnimErrorTxt = ""

    If AnimCount = 0
        AnimErrorNr = 1 : AnimErrorTxt = "Nicht initialsiert"
    EndIf

    If LoadSprite(SetNr, File, 0) = 0
        AnimErrorNr = 2 : AnimErrorTxt = "Ladefehler"
    EndIf

    If Height = 0 Or Width = 0
        AnimErrorNr = 3 : AnimErrorTxt = "Null-Größe"
    EndIf

    If Nr > AnimCount Or Nr < 1
        AnimErrorNr = 4 : AnimErrorTxt = "Ungültige Anim"
    EndIf

    If TRed<0 Or TRed>255 Or TGrn<0 Or TGrn>255 Or TBlu<0 Or TBlu>255
        AnimErrorNr = 6 : AnimErrorTxt = "Ungültiger Farbwert"
    EndIf

    If AnimErrorNr = 0  ; nur ausführen, wenn kein Fehler aufgetreten ist
    ;*************************** Ende Fehler-Pufferung

        SetWi = SpriteWidth(SetNr)
        SetHe = SpriteHeight(SetNr)

        If Mode = 0
            Anim(Nr)\FraW = Width           ; Sprite-Größe ist angegeben
            Anim(Nr)\FraH = Height
            Anim(Nr)\SetW = SetWi/Width     ; Set-Größe wird ermittelt
            Anim(Nr)\SetH = SetHe/Height
        Else
            Anim(Nr)\FraW = SetWi/Width     ; Sprite-Größe wird ermittelt
            Anim(Nr)\FraH = SetHe/Height
            Anim(Nr)\SetW = Width           ; Set-Größe ist angegeben
            Anim(Nr)\SetH = Height
        EndIf

        Anim(Nr)\NoFr = Anim(Nr)\SetW * Anim(Nr)\SetH
       
        TransparentSpriteColor(SetNr, TRed, TGrn, TBlu)

    ;*************************** Beginn Fehler-Pufferung
        ProcedureReturn 1   ; fehlerfrei
    Else
        ProcedureReturn 0   ; fehlgeschlagen
    EndIf
    ;*************************** Ende Fehler-Pufferung

EndProcedure

; *******************************************************************

Procedure SetAnimTransparence(Nr.l, TRed.l, TGrn.l, TBlu.l)

    SetNr = SetOffset+Nr

    ;*************************** Beginn Fehler-Pufferung
    AnimErrorNr = 0 : AnimErrorTxt = ""

    If AnimCount = 0
        AnimErrorNr = 1 : AnimErrorTxt = "Nicht initialsiert"
    EndIf

    If Nr > AnimCount Or Nr < 1 Or IsSprite(SetNr)=0
        AnimErrorNr = 4 : AnimErrorTxt = "Ungültige Anim"
    EndIf

    If TRed<0 Or TRed>255 Or TGrn<0 Or TGrn>255 Or TBlu<0 Or TBlu>255
        AnimErrorNr = 6 : AnimErrorTxt = "Ungültiger Farbwert"
    EndIf

    If AnimErrorNr = 0  ; nur ausführen, wenn kein Fehler aufgetreten ist
    ;*************************** Ende Fehler-Pufferung

        TransparentSpriteColor(SetNr, TRed, TGrn, TBlu)

    ;*************************** Beginn Fehler-Pufferung
        ProcedureReturn 1   ; fehlerfrei
    Else
        ProcedureReturn 0   ; fehlgeschlagen
    EndIf
    ;*************************** Ende Fehler-Pufferung

EndProcedure

; *******************************************************************

Procedure.l SetAnimDelay(Nr.l, Mode.l, Value.l)

    SetNr = SetOffset+Nr

    ;*************************** Beginn Fehler-Pufferung
    AnimErrorNr = 0 : AnimErrorTxt = ""

    If AnimCount = 0
        AnimErrorNr = 1 : AnimErrorTxt = "Nicht initialsiert"
    EndIf

    If Nr > AnimCount Or Nr < 1 Or IsSprite(SetNr)=0
        AnimErrorNr = 4 : AnimErrorTxt = "Ungültige Anim"
    EndIf

    If Value < 0
        AnimErrorNr = 5 : AnimErrorTxt = "Ungültiges Delay"
    EndIf

    If AnimErrorNr = 0  ; nur ausführen, wenn kein Fehler aufgetreten ist
    ;*************************** Ende Fehler-Pufferung

        Anim(Nr)\Mode = Mode
        Anim(Nr)\Dely = Value

    ;*************************** Beginn Fehler-Pufferung
        ProcedureReturn 1   ; fehlerfrei
    Else
        ProcedureReturn 0   ; fehlgeschlagen
    EndIf
    ;*************************** Ende Fehler-Pufferung

EndProcedure

; *******************************************************************

Procedure.l ShowAnim(Nr.l, AX.l, AY.l)

    SetNr = SetOffset+Nr

    ;*************************** Beginn Fehler-Pufferung
    AnimErrorNr = 0 : AnimErrorTxt = ""

    If AnimCount = 0
        AnimErrorNr = 1 : AnimErrorTxt = "Nicht initialsiert"
    EndIf

    If Nr > AnimCount Or Nr < 1 Or IsSprite(SetNr)=0
        AnimErrorNr = 4 : AnimErrorTxt = "Ungültige Anim"
    EndIf

    If AnimErrorNr = 0  ; nur ausführen, wenn kein Fehler aufgetreten ist
    ;*************************** Ende Fehler-Pufferung

    If Anim(Nr)\Mode = 1                            ; nach Millisekunden
        ActTim = ElapsedMilliseconds()
        If ActTim<0 And Anim(Nr)\msBf > 0           ; dies dient zum vermeiden
            Anim(Nr)\msBf = ActTim+Anim(Nr)\Dely    ; eines Hängenbleibens, falls
        EndIf                                       ; der Rechner 14 Tage läuft
       
        If ActTim >= Anim(Nr)\msBf                  ; wenn die zeit verstrichen,
            Anim(Nr)\msBf = ActTim+Anim(Nr)\Dely    ; timer aktualisieren
            Animate = 1                             ; animieren erlauben
        EndIf
    Else                                            ; nach Frames
        Anim(Nr)\cont +1
        If Anim(Nr)\cont > Anim(Nr)\Dely            ; wenn anzahl frames vorbei,
            Anim(Nr)\cont = 0                       ; counter auf null
            Animate = 1                             ; animieren erlauben
        EndIf
    EndIf

    If Animate = 1                                  ; wenn animieren
        Anim(Nr)\Fram +1                            ; nächstes Bild
        If Anim(Nr)\Fram >= Anim(Nr)\NoFr           ; nach letztem?
            Anim(Nr)\Fram = 0                       ; also erstes
        EndIf
    EndIf

    FrOfY = Anim(Nr)\Fram/Anim(Nr)\SetW
    FrOfX = Anim(Nr)\Fram-Anim(Nr)\SetW*FrOfY
    ClipSprite(SetNr,FrOfX*Anim(Nr)\FraW,FrOfY*Anim(Nr)\FraH,Anim(Nr)\FraW,Anim(Nr)\FraH)
    Anim(Nr)\PosX = AX
    Anim(Nr)\PosY = AY
    DisplayTransparentSprite(SetNr, AX, AY)

    ;*************************** Beginn Fehler-Pufferung
        ProcedureReturn 1   ; fehlerfrei
    Else
        ProcedureReturn 0   ; fehlgeschlagen
    EndIf
    ;*************************** Ende Fehler-Pufferung

EndProcedure

; *******************************************************************

Procedure.l MoveAnim(Nr.l, XM.l, YM.l)

    SetNr = SetOffset+Nr

    ;*************************** Beginn Fehler-Pufferung
    AnimErrorNr = 0 : AnimErrorTxt = ""

    If AnimCount = 0
        AnimErrorNr = 1 : AnimErrorTxt = "Nicht initialsiert"
    EndIf

    If Nr > AnimCount Or Nr < 1 Or IsSprite(SetNr)=0
        AnimErrorNr = 4 : AnimErrorTxt = "Ungültige Anim"
    EndIf

    If AnimErrorNr = 0  ; nur ausführen, wenn kein Fehler aufgetreten ist
    ;*************************** Ende Fehler-Pufferung

    If Anim(Nr)\Mode = 1                            ; nach Millisekunden
        ActTim = ElapsedMilliseconds()
        If ActTim<0 And Anim(Nr)\msBf > 0           ; dies dient zum vermeiden
            Anim(Nr)\msBf = ActTim+Anim(Nr)\Dely    ; eines Hängenbleibens, falls
        EndIf                                       ; der Rechner 14 Tage läuft
       
        If ActTim >= Anim(Nr)\msBf                  ; wenn die zeit verstrichen,
            Anim(Nr)\msBf = ActTim+Anim(Nr)\Dely    ; timer aktualisieren
            Animate = 1                             ; animieren erlauben
        EndIf
    Else                                            ; nach Frames
        Anim(Nr)\cont +1
        If Anim(Nr)\cont > Anim(Nr)\Dely            ; wenn anzahl frames vorbei,
            Anim(Nr)\cont = 0                       ; counter auf null
            Animate = 1                             ; animieren erlauben
        EndIf
    EndIf

    If Animate = 1                                  ; wenn animieren
        Anim(Nr)\Fram +1                            ; nächstes Bild
        If Anim(Nr)\Fram >= Anim(Nr)\NoFr           ; nach letztem?
            Anim(Nr)\Fram = 0                       ; also erstes
        EndIf
    EndIf

    FrOfY = Anim(Nr)\Fram/Anim(Nr)\SetW
    FrOfX = Anim(Nr)\Fram-Anim(Nr)\SetW*FrOfY
    ClipSprite(SetNr,FrOfX*Anim(Nr)\FraW,FrOfY*Anim(Nr)\FraH,Anim(Nr)\FraW,Anim(Nr)\FraH)
    AX = Anim(Nr)\PosX + XM
    AY = Anim(Nr)\PosY + YM
    DisplayTransparentSprite(SetNr, AX, AY)

    ;*************************** Beginn Fehler-Pufferung
        ProcedureReturn 1   ; fehlerfrei
    Else
        ProcedureReturn 0   ; fehlgeschlagen
    EndIf
    ;*************************** Ende Fehler-Pufferung

EndProcedure

; *******************************************************************
oh... and have a nice day.
hagibaba
Enthusiast
Enthusiast
Posts: 170
Joined: Fri Mar 05, 2004 2:55 am
Location: UK
Contact:

Post by hagibaba »

Thanks Kaeru, but I have decided to go with this sort of thing. I like it's simplicity.

1. store the separate image IDs in a memory block and return that.
2. pass the memory block to functions like this:
DrawImageFrame(ImageIDList, x, y [, frame, Width, Height])
and ImageFrame(ImageIDList,frame) so you can use it like this
DrawImage(ImageFrame(ImageIDList,frame), x, y [, Width, Height])
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

ok, as you like...
just one hint: drawing images to a screen is way less performant than using sprites.
oh... and have a nice day.
User avatar
Hroudtwolf
Addict
Addict
Posts: 803
Joined: Sat Feb 12, 2005 3:35 am
Location: Germany(Hessen)
Contact:

Post by Hroudtwolf »

@Kaeru

I've framesets larger than 2 or 3 screensizes in use and I couldn't detect any problems with that at any time.
Maybe, this fact isn't up to date?

Best regards

Wolf
hagibaba
Enthusiast
Enthusiast
Posts: 170
Joined: Fri Mar 05, 2004 2:55 am
Location: UK
Contact:

Post by hagibaba »

Kaeru, yes I understand that but I am converting some B3D code to PB for loading animated gifs either as images or sprites depending on the need and then I'll post it in Tips n Tricks.
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

@hagibaba
oh yes.. I've seen your other topic.. ok

@Wolf
maybe that is a quite old information, aslike that you could only use (2^n)² images for textures...

newer grafix cards are possibly able to deal with clipping from larger sprites,
but I would not count on it, especially when writing games with low system requirements.
perhaps you WANT to write a game for older computers, that really everyone could play it.
then you have to take care of such issues like (2^n)² textures and small enough clippings....
oh... and have a nice day.
Post Reply