Easy Animated Sprites

Share your advanced PureBasic knowledge/code with the community.
citystate
Enthusiast
Enthusiast
Posts: 638
Joined: Sun Feb 12, 2006 10:06 pm

Easy Animated Sprites

Post by citystate »

I've always loved the way different animations are grouped within 3D meshes, and can be actioned with a simple command. So I thought I'd bring similar functionality to the 2D world - hope you find it as useful as I do

Code: Select all

;------------------------------------------------------  
;  
;- Animated Sprites
;  author:  citystate (novaseer@hotmail.com)
;
;  create an animated sprite: *sprite.spr=newSprite(SpriteNumber,Default_Action$)
;  and then add frames:       *sprite\AddSprite(SpriteNumber,Action$)
;  create additional actions: *sprite\NewAction(New_Action$)
;  display the sprite:        *sprite\DisplaySprite(x,y)  
;  and add frames to it as above.
;  each time you display the animated sprite, it will show the next frame; 
;  until it reaches the last one, where the sprite will freeze, 
;  unless it is set to repeat: *sprite\Repeating(#True)
;
;  change the current action: *sprite\SetAction(Action$)
;
;  I've included a simple demo in the code, left and right click change the animation, and Alt-F4 
;  quits the program - enjoy
; 
;------------------------------------------------------  
  Global NewMap map_()
;-Structures
  Structure sp_1
    List Sprite.i()
  EndStructure
  Structure sp
    vt.i
    Map action.sp_1()
    rep.b
    def.s
    cur.s
    w.w
    h.w
  EndStructure
;-Interfaces
  Interface Spr
    AddSprite(SpriteID,action$)
    Collision(spriteID,x,y,my_x,my_y)
    CurrentSprite()
    DisplaySprite(x,y,intensity=0,color=0)
    NewAction(action$)
    Repeating(yes)
    SetAction(action$)
    Stopped()
    ToString.s()
  EndInterface

;-Declares
  Declare NewSprite(SpriteNo,defaultAction$="default")
  Declare sp_AddSprite(*o.sp,SpriteID,action$)
  Declare sp_Collision(*o.sp,spriteID,x,y,my_x,my_y)
  Declare sp_CurrentSprite(*o.sp)
  Declare sp_DisplaySprite(*o.sp,x,y,intensity=0,color=0)
  Declare sp_NewAction(*o.sp,action$)
  Declare sp_Repeating(*o.sp,yes)
  Declare sp_SetAction(*o.sp,action$)
  Declare sp_Stopped(*o.sp)
  Declare.s sp_ToString(*o.sp)
;-Datasection  
  DataSection
    sp_vt:
    Data.i @sp_AddSprite()
    Data.i @sp_Collision()
    Data.i @sp_CurrentSprite()
    Data.i @sp_DisplaySprite()
    Data.i @sp_NewAction()
    Data.i @sp_Repeating()
    Data.i @sp_SetAction()
    Data.i @sp_Stopped()
    Data.i @sp_ToString()
  EndDataSection
  
  Procedure sp_AddSprite(*o.sp,SpriteID,action$)
    *mi.sp_1=FindMapElement(*o\action(),action$)
    If *mi=0 And action$
      *mi=AddMapElement(*o\action(),action$)
    EndIf
    If *mi And IsSprite(SpriteID)
      AddElement(*mi\Sprite())
      *mi\Sprite()=SpriteID
    EndIf
  EndProcedure
  
  Procedure sp_Collision(*o.sp,spriteID,x,y,my_x,my_y)
    sp=sp_CurrentSprite(*o)
    If IsSprite(sp) And IsSprite(SpriteID)
      ProcedureReturn SpritePixelCollision(SpriteID,x,y,sp,my_x,my_y)
    EndIf
  EndProcedure
  
  Procedure sp_CurrentSprite(*o.sp)
    ProcedureReturn *o\action(*o\cur)\Sprite()
  EndProcedure
  
  Procedure sp_DisplaySprite(*o.sp,x,y,intensity=0,color=0)
    ne=NextElement(*o\action(*o\cur)\Sprite())
    If ne=0
      If *o\rep=1
        ne=FirstElement(*o\action(*o\cur)\Sprite())
      Else
        ne=LastElement(*o\action(*o\cur)\Sprite())
        *o\rep=2
      EndIf
    EndIf
    If ne:sp=sp_CurrentSprite(*o):EndIf
    If IsSprite(sp)
      If intensity
        If color
          DisplayTransparentSprite(sp,x,y,intensity,color)
        Else
          DisplayTransparentSprite(sp,x,y,intensity)
        EndIf
      Else
        DisplayTransparentSprite(sp,x,y)
      EndIf
    EndIf
  EndProcedure
  
  Procedure sp_NewAction(*o.sp,action$)
    If action$ And FindMapElement(*o\action(),action$)=0
      AddMapElement(*o\action(),action$)
    EndIf
  EndProcedure
  
  Procedure sp_Repeating(*o.sp,yes)
    *o\rep=Bool(yes)
  EndProcedure
  
  Procedure sp_SetAction(*o.sp,action$)
    If FindMapElement(*o\action(),action$)
      *o\cur=action$
      FirstElement(*o\action(action$)\Sprite())
    EndIf
  EndProcedure
  
  Procedure sp_Stopped(*o.sp)
    ProcedureReturn Bool(*o\rep=2)
  EndProcedure
  
  Procedure.S sp_ToString(*o.sp)
    a$="[Spr:"+Str(*o)+"]"+#CRLF$+"ACTION"+#TAB$+"FRAMES"+#CRLF$
    ForEach *o\action()
      a$+MapKey(*o\action())+#TAB$+Str(ListSize(*o\action()\Sprite()))+#CRLF$
    Next
    ProcedureReturn a$
  EndProcedure

  Procedure NewSprite(SpriteNo,defaultAction$="default")
    If defaultAction$ And IsSprite(SpriteNo)
      *i.sp=AllocateMemory(SizeOf(sp))
      InitializeStructure(*i,sp)
      *i\vt=?sp_vt
      *i\w=SpriteWidth(SpriteNo)
      *i\h=SpriteHeight(SpriteNo)
      *i\def=defaultAction$
      *i\cur=defaultAction$
      sp_AddSprite(*i,SpriteNo,defaultAction$)
      AddMapElement(map_(),Str(*i))
    EndIf
    ProcedureReturn *i
  EndProcedure
  
;------------------------------------------------------  
  
Procedure newCursor(col)
  im=CreateSprite(-1,21,21)
  StartDrawing(SpriteOutput(im))
  LineXY(0,0,20,15,#White)
  LineXY(20,15,15,20,#White)
  LineXY(0,0,15,20,#White)
  FillArea(10,10,#White,col)
  StopDrawing()
  TransparentSpriteColor(im,0)
  ProcedureReturn im
EndProcedure

CompilerIf #PB_Compiler_IsMainFile
  Procedure newCursorBusy(col,ang)
    im=CreateSprite(-1,21,21,#PB_Sprite_AlphaBlending)
    r=Red(col)
    g=Green(col)
    b=Blue(col)
    c0=RGBA(r,g,b,0)
    c5=RGBA(r,g,b,255)
    StartDrawing(SpriteOutput(im))
    DrawingMode(#PB_2DDrawing_AllChannels)
    Box(0,0,21,21,0)
    DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_Gradient)
    GradientColor(0,c0)
    GradientColor(1,c5)
    ConicalGradient(10,10,0)
    Circle(10,10,10,1)
    DrawingMode(#PB_2DDrawing_AllChannels)
    Circle(10,10,6,0)
    StopDrawing()
    RotateSprite(im,ang,#PB_Absolute)
    ProcedureReturn im
  EndProcedure

  InitSprite()
  InitMouse()
  OpenWindow(0,0,0,300,600,"")
  OpenWindowedScreen(WindowID(0),0,0,300,600)
  *mouseSpr.Spr=NewSprite(newCursor(#Blue/2))
  *mouseSpr\Repeating(1)
  For i=1 To 360 Step 9
    im=newCursorBusy(#White,i)
    *mouseSpr\AddSprite(im,"busy")
  Next
  Debug *mouseSpr\ToString()
  Repeat
    ExamineMouse()
    x=MouseX()
    y=MouseY()
    m1=MouseButton(1)
    m2=MouseButton(2)
    If m1 And om=0
      *mouseSpr\SetAction("busy")
      om=1
    EndIf
    If m2 And om=1
      *mouseSpr\SetAction("default")
      om=0
    EndIf
    ClearScreen(#Blue)
    *mouseSpr\DisplaySprite(x,y)
    Delay(0)
    FlipBuffers()
  Until WindowEvent()=#PB_Event_CloseWindow
CompilerEndIf  
Last edited by citystate on Thu Jun 15, 2017 5:05 am, edited 1 time in total.
there is no sig, only zuul (and the following disclaimer)

WARNING: may be talking out of his hat
kvitaliy
Enthusiast
Enthusiast
Posts: 162
Joined: Mon May 10, 2010 4:02 pm

Re: Easy Animated Sprites

Post by kvitaliy »

Execution error!
DisplayTransparentSprite(im,x,y) -> DisplayTransparentSprite(sp,x,y)
citystate
Enthusiast
Enthusiast
Posts: 638
Joined: Sun Feb 12, 2006 10:06 pm

Re: Easy Animated Sprites

Post by citystate »

oooh, thanks for the find, I've updated the code
there is no sig, only zuul (and the following disclaimer)

WARNING: may be talking out of his hat
Post Reply