Source:Réaliser un RPG en PureBasic/Combats, fondus enchaînés et coffre/sprite.pb
;** sprite.pb
;**
;** Gestion des sprites
;**
;** Rôle:
;** - initialisation et libération des sprites.
;** - affichage des sprites
;** - Gestion des événements associés au sprites
XIncludeFile "sprite.pbi"
Procedure InitSprites(*libsprite.s_lib_sprite)
*libsprite\n_sprite = 0
*libsprite\sprites = #Null
EndProcedure
Procedure FreeSprites(*libsprite.s_lib_sprite)
Define.l i, anim
Define.s_sprite *Ptsprite
Define.s_anim *Ptanim
Define.s_frame *Ptframe
For i = 0 To *libsprite\n_sprite - 1
*Ptsprite = *libsprite\sprites + i * SizeOf(s_sprite)
If IsSprite(*Ptsprite\surf\Id) : FreeSprite(*Ptsprite\surf\Id) : EndIf
For anim = 0 To *Ptsprite\n_anim - 1
*Ptanim = *Ptsprite\anim + anim * SizeOf(s_anim)
FreeMemory(*Ptanim\frame)
Next anim
FreeMemory(*Ptsprite\anim)
Next i
FreeMemory(*libsprite\sprites)
*libsprite\n_sprite = 0
EndProcedure
Procedure SpriteStaticData(*libsprite.s_lib_sprite)
Define.l MemSprite
Define.s_sprite *Ptsprite
Define.s_anim *Ptanim
Define.s_frame *Ptframe
*libsprite\n_sprite = 2
*libsprite\sprites = AllocateMemory(*libsprite\n_sprite * SizeOf(s_sprite))
;Sprite 0: player
*Ptsprite=*libsprite\sprites
With *Ptsprite
\x = 256
\y = 86
\offsetG = 5
\offsetD = 15
\offsetH = 20
\offsetB = 3
\surf\id = LoadSprite(#PB_Any, "sprites\player.bmp")
TransparentSpriteColor(\surf\Id, #Black)
\width = 24
\height = 32
\n_anim = 4
\cur_anim = #ANIMATION_BAS
\ispaused_anim = 1
\anim = AllocateMemory(\n_anim * SizeOf(s_anim))
EndWith
; anim 0: haut
*Ptanim = *Ptsprite\anim
With *Ptanim
\cur_frame = 0
\n_frame = 3
\delaybetweenframes = 100
\lastfrmupdate = ElapsedMilliseconds()
\frame = AllocateMemory(\n_frame * SizeOf(s_frame))
EndWith
With *Ptframe
*Ptframe = *Ptanim\frame
\x = 144
\y = 0
*Ptframe + SizeOf(s_frame)
\x = 168
\y = 0
*Ptframe + SizeOf(s_frame)
\x = 192
\y = 0
EndWith
; anim 1: droite
*Ptanim + SizeOf(s_anim)
With *Ptanim
\cur_frame = 0
\n_frame = 3
\delaybetweenframes = 100
\lastfrmupdate = ElapsedMilliseconds()
\frame = AllocateMemory(\n_frame * SizeOf(s_frame))
EndWith
With *Ptframe
*Ptframe = *Ptanim\frame
\x = 144
\y = 32
*Ptframe + SizeOf(s_frame)
\x = 168
\y = 32
*Ptframe + SizeOf(s_frame)
\x = 192
\y = 32
EndWith
;anim 2: bas
*Ptanim + SizeOf(s_anim)
With *Ptanim
\cur_frame = 0
\n_frame = 3
\delaybetweenframes = 100
\lastfrmupdate = ElapsedMilliseconds()
\frame = AllocateMemory(\n_frame * SizeOf(s_frame))
EndWith
With *Ptframe
*Ptframe = *Ptanim\frame
\x = 144
\y = 64
*Ptframe + SizeOf(s_frame)
\x = 168
\y = 64
*Ptframe + SizeOf(s_frame)
\x = 192
\y = 64
EndWith
; anim 3: gauche
*Ptanim + SizeOf(s_anim)
With *Ptanim
\cur_frame = 0
\n_frame = 3
\delaybetweenframes = 100
\lastfrmupdate = ElapsedMilliseconds()
\frame = AllocateMemory(\n_frame * SizeOf(s_frame))
EndWith
With *Ptframe
*Ptframe = *Ptanim\frame
\x = 144
\y = 96
*Ptframe + SizeOf(s_frame)
\x = 168
\y = 96
*Ptframe + SizeOf(s_frame)
\x = 192
\y = 96
EndWith
;Sprite 1: pnj
MemSprite = *Ptsprite\surf\id
*Ptsprite + SizeOf(s_sprite)
With *Ptsprite
\x = 100
\y = 128
\offsetG = 5
\offsetD = 15 ; 15
\offsetH = 20
\offsetB = 3 ; 10
\surf\id = MemSprite ; utilise le même sprite que le sprite 0
\width = 24
\height = 32
\n_anim = 4
\cur_anim = #ANIMATION_BAS
\ispaused_anim = 0
\anim = AllocateMemory(\n_anim * SizeOf(s_anim))
EndWith
;anim 0: haut
*Ptanim=*Ptsprite\anim
With *Ptanim
\cur_frame = 0
\n_frame = 3
\delaybetweenframes = 100
\lastfrmupdate = ElapsedMilliseconds()
\frame = AllocateMemory(\n_frame * SizeOf(s_frame))
EndWith
With *Ptframe
*Ptframe=*Ptanim\frame
\x = 0
\y = 0
*Ptframe + SizeOf(s_frame)
\x = 24
\y = 0
*Ptframe + SizeOf(s_frame)
\x = 48
\y = 0
EndWith
;anim 1: droite
*Ptanim + SizeOf(s_anim)
With *Ptanim
\cur_frame = 0
\n_frame = 3
\delaybetweenframes = 100
\lastfrmupdate = ElapsedMilliseconds()
\frame = AllocateMemory(\n_frame * SizeOf(s_frame))
EndWith
With *Ptframe
*Ptframe = *Ptanim\frame
\x = 0
\y = 32
*Ptframe + SizeOf(s_frame)
\x = 24
\y = 32
*Ptframe + SizeOf(s_frame)
\x = 48
\y = 32
EndWith
;anim 2: bas
*Ptanim + SizeOf(s_anim)
With *Ptanim
\cur_frame = 0
\n_frame = 3
\delaybetweenframes = 100
\lastfrmupdate = ElapsedMilliseconds()
\frame = AllocateMemory(\n_frame * SizeOf(s_frame))
EndWith
With *Ptframe
*Ptframe = *Ptanim\frame
\x = 0
\y = 64
*Ptframe + SizeOf(s_frame)
\x = 24
\y = 64
*Ptframe + SizeOf(s_frame)
\x = 48
\y = 64
EndWith
;anim 3: gauche
*Ptanim + SizeOf(s_anim)
With *Ptanim
\cur_frame = 0
\n_frame = 3
\delaybetweenframes = 100
\lastfrmupdate = ElapsedMilliseconds()
\frame = AllocateMemory(\n_frame * SizeOf(s_frame))
EndWith
With *Ptframe
*Ptframe=*Ptanim\frame
\x = 0
\y = 96
*Ptframe + SizeOf(s_frame)
\x = 24
\y = 96
*Ptframe + SizeOf(s_frame)
\x = 48
\y = 96
EndWith
EndProcedure
Procedure SaveSprites(*libsprite.s_lib_sprite, charset.s, filename.s)
Define *buffer
Define.s_sprite *Ptsprite
Define.s_anim *Ptanim
Define.s_frame *Ptframe
Define.l i, anim, frm
*buffer = AllocateMemory(256)
If *libsprite = 0 : ProcedureReturn : EndIf
If OpenFile(0, filename) = 0 : ProcedureReturn : EndIf
WriteLong(0, *libsprite\n_sprite)
For i = 0 To *libsprite\n_sprite - 1
*Ptsprite = *libsprite\sprites + i * SizeOf(s_sprite)
With *Ptsprite
WriteLong(0, \x)
WriteLong(0, \y)
WriteLong(0, \width)
WriteLong(0, \height)
WriteLong(0, \n_anim)
WriteLong(0, \cur_anim)
WriteByte(0, \ispaused_anim)
WriteLong(0, \offsetG)
WriteLong(0, \offsetD)
WriteLong(0, \offsetH)
WriteLong(0, \offsetB)
EndWith
WriteData(0, @charset,Len(charset))
WriteData(0, *buffer, 255 - Len(charset))
For anim = 0 To *Ptsprite\n_anim - 1
*Ptanim=*Ptsprite\anim + anim * SizeOf(s_anim)
With *Ptanim
WriteLong(0, \n_frame)
WriteLong(0, \cur_frame)
WriteLong(0, \lastfrmupdate)
WriteLong(0, \delaybetweenframes)
EndWith
For frm=0 To *Ptanim\n_frame-1
*Ptframe = *Ptanim\frame + frm * SizeOf(s_frame)
WriteLong(0, *Ptframe\x)
WriteLong(0, *Ptframe\y)
Next frm
Next anim
Next i
CloseFile(0)
EndProcedure
Procedure LoadSprites(*libsprite.s_lib_sprite, filename.s)
Define.s FichierCharset
Define.l i, anim, frm
Define.s_sprite *Ptsprite
Define.s_anim *Ptanim
Define.s_frame *Ptframe
If *libsprite = 0 : ProcedureReturn : EndIf
If ReadFile(0, filename) = 0 : ProcedureReturn : EndIf
*libsprite\n_sprite = ReadLong(0)
*libsprite\sprites = AllocateMemory(*libsprite\n_sprite * SizeOf(s_sprite))
For i = 0 To *libsprite\n_sprite - 1
*Ptsprite=*libsprite\sprites + i * SizeOf(s_sprite)
With *Ptsprite
\x = ReadLong(0)
\y = ReadLong(0)
\width = ReadLong(0)
\height = ReadLong(0)
\n_anim = ReadLong(0)
\cur_anim = ReadLong(0)
\ispaused_anim = ReadByte(0)
\offsetG = ReadLong(0)
\offsetD = ReadLong(0)
\offsetH = ReadLong(0)
\offsetB = ReadLong(0)
EndWith
FichierCharset = Space(256)
ReadData(0, @FichierCharset, 255)
*Ptsprite\surf\Id = LoadSprite(#PB_Any, FichierCharset)
If *Ptsprite\surf\Id = 0
MessageRequester("Erreur", "Impossible de charger " + FichierCharset, 0)
End
EndIf
;Change la couleur transparente du sprite
TransparentSpriteColor(*Ptsprite\surf\Id, #Black)
*Ptsprite\anim = AllocateMemory(*Ptsprite\n_anim * SizeOf(s_anim))
For anim = 0 To *Ptsprite\n_anim - 1
*Ptanim = *Ptsprite\anim + anim * SizeOf(s_anim)
With *Ptanim
\n_frame = ReadLong(0)
\cur_frame = ReadLong(0)
\lastfrmupdate = ReadLong(0)
\delaybetweenframes = ReadLong(0)
\frame=AllocateMemory(\n_frame * SizeOf(s_frame))
EndWith
For frm = 0 To *Ptanim\n_frame - 1
*Ptframe = *Ptanim\frame + frm * SizeOf(s_frame)
*Ptframe\x = ReadLong(0)
*Ptframe\y = ReadLong(0)
Next frm
Next anim
Next i
CloseFile(0)
EndProcedure
Procedure HandleSprites(ispaused.l,*libsprite.s_lib_sprite,*map.s_map)
Define.s_sprite *Ptsprite
Define.l i, oldx, oldy, anim
;centre la vue sur le joueur
*Ptsprite = *libsprite\sprites
If (*Ptsprite\x < (800 / 2))
*map\offsetX = 0
Else
*map\offsetX=*Ptsprite\x-(800/2)
If *map\offsetX > *map\width * #TILE_WIDTH - 800
*map\offsetX = *map\width * #TILE_WIDTH - 800
EndIf
EndIf
If *Ptsprite\y < (600 / 2)
*map\offsetY = 0
Else
*map\offsetY = *Ptsprite\y - (600 / 2)
If *map\offsetY > *map\height * #TILE_HEIGHT - 600
*map\offsetY = *map\height * #TILE_HEIGHT - 600
EndIf
EndIf
;gestion du joueur
HandleSprite(*Ptsprite, *map)
;gestion des pnj
For i = 1 To *libsprite\n_sprite - 1
*Ptsprite = *libsprite\sprites + i * SizeOf(s_sprite)
If ispaused = 0 And *Ptsprite\ispaused_anim = 0
oldx = *Ptsprite\x
oldy = *Ptsprite\y
;on fait se déplacer le pnj en continuant dans sa direction...
Select *Ptsprite\cur_anim
Case #ANIMATION_DROITE
SpriteMove(*Ptsprite, *Ptsprite\x + 1, *Ptsprite\y, *map)
Case #ANIMATION_GAUCHE
If *Ptsprite\x>0
SpriteMove(*Ptsprite, *Ptsprite\x - 1, *Ptsprite\y, *map)
EndIf
Case #ANIMATION_HAUT
If *Ptsprite\y>0
SpriteMove(*Ptsprite, *Ptsprite\x, *Ptsprite\y - 1, *map)
EndIf
Case #ANIMATION_BAS
SpriteMove(*Ptsprite, *Ptsprite\x, *Ptsprite\y + 1, *map)
EndSelect
If oldx = *Ptsprite\x And oldy = *Ptsprite\y
anim = *Ptsprite\cur_anim
While anim = *Ptsprite\cur_anim
anim=Random(*Ptsprite\n_anim - 1)
Wend
SpriteChangeAnim(*Ptsprite, anim, 0)
EndIf
EndIf
HandleSprite(*Ptsprite, *map)
Next
EndProcedure
Procedure HandleSprite(*sprite.s_sprite, *map.s_map)
Define.rectangle src, dest
Define.s_sprite *Ptsprite
Define.s_anim *Ptanim
Define.s_frame *Ptframe
*Ptanim = *sprite\anim + *sprite\cur_anim * SizeOf(s_anim)
If *sprite\ispaused_anim = 0
If ElapsedMilliseconds() - *Ptanim\lastfrmupdate > *Ptanim\delaybetweenframes
*Ptanim\cur_frame = (*Ptanim\cur_frame + 1) % *Ptanim\n_frame
*Ptanim\lastfrmupdate = ElapsedMilliseconds()
EndIf
EndIf
*Ptframe = *Ptanim\frame + *Ptanim\cur_frame * SizeOf(s_frame)
src\x = *Ptframe\x
src\y = *Ptframe\y
src\w = *sprite\width
src\h = *sprite\height
dest\x = *sprite\x - *map\offsetX
dest\y = *sprite\y - *map\offsetY
dest\w = *sprite\width
dest\h = *sprite\height
;teste si le sprite est à l'écran... si ce n'est pas le cas, inutile de continuer!
If dest\x < -dest\w : ProcedureReturn : EndIf
If dest\y < -dest\h : ProcedureReturn : EndIf
If dest\x<0
src\x - dest\x
src\w + dest\x
dest\w + dest\x
dest\x = 0
EndIf
If dest\y < 0
src\y - dest\y
src\h + dest\y
dest\h + dest\h
dest\y = 0
EndIf
ClipSprite(*sprite\surf\Id, src\x, src\y,src\w, src\h)
DisplayTransparentSprite(*sprite\surf\Id,dest\x,dest\y)
EndProcedure
Procedure SpriteChangeAnim(*sprite.s_sprite,anim.l,ispaused.b)
Define.s_anim *Ptanim
*sprite\cur_anim = anim
*sprite\ispaused_anim = ispaused
*Ptanim = *sprite\anim + *sprite\cur_anim * SizeOf(s_anim)
*Ptanim\cur_frame = 0
*Ptanim\lastfrmupdate = ElapsedMilliseconds()
EndProcedure
Procedure SpriteMove(*sprite.s_sprite, x, y, *map.s_map)
Define.l hgx,hgy, hdx,hdy, bgx,bgy, bdx,bdy
Define.l T1, T2, T3, T4
; calcul du tile sur lequel est situé chaque bord du sprite
hgx = (x + *sprite\offsetG) / #TILE_WIDTH
hgy = (y + *sprite\offsetH) / #TILE_HEIGHT
hdx = (x + #TILE_WIDTH - *sprite\offsetD) / #TILE_WIDTH
hdy = (y + *sprite\offsetH) / #TILE_HEIGHT
bgx = (x + *sprite\offsetG) / #TILE_WIDTH
bgy = (y + #TILE_HEIGHT - *sprite\offsetB) / #TILE_HEIGHT
bdx = (x + #TILE_WIDTH - *sprite\offsetD) / #TILE_WIDTH
bdy = (y + #TILE_HEIGHT - *sprite\offsetB) / #TILE_HEIGHT
T1 = DataMap(GET_TILE(hgx, hgy, *map))
T2 = DataMap(GET_TILE(hdx, hdy, *map))
T3 = DataMap(GET_TILE(bgx, bgy, *map))
T4 = DataMap(GET_TILE(bdx, bdy, *map))
If chipset(T1)\Collision = 0 And chipset(T2)\Collision = 0 And chipset(T3)\Collision = 0 And chipset(T4)\Collision = 0
If x > *map\width * #TILE_WIDTH - *sprite\width
x = *map\width * #TILE_WIDTH - *sprite\width
EndIf
If y > *map\height * #TILE_HEIGHT - *sprite\height
y = *map\height * #TILE_HEIGHT - *sprite\height
EndIf
*sprite\x = x
*sprite\y = y
EndIf
EndProcedure
Procedure SpriteEvent(*map.s_map,*libsprite.s_lib_sprite)
Define.s_sprite *Ptsprite
*Ptsprite = *libsprite\sprites
*Ptsprite\ispaused_anim = 1
If KeyboardPushed(#PB_Key_Right)
SpriteMove(*Ptsprite, *Ptsprite\x + 1, *Ptsprite\y, *map)
If *Ptsprite\cur_anim <> #ANIMATION_DROITE
SpriteChangeAnim(*Ptsprite, #ANIMATION_DROITE, 0)
Else
*Ptsprite\ispaused_anim = 0
EndIf
ElseIf KeyboardPushed(#PB_Key_Left)
If *Ptsprite\x > 0
SpriteMove(*Ptsprite, *Ptsprite\x - 1, *Ptsprite\y, *map)
EndIf
If *Ptsprite\cur_anim<>#ANIMATION_GAUCHE
SpriteChangeAnim(*Ptsprite, #ANIMATION_GAUCHE, 0)
Else
*Ptsprite\ispaused_anim = 0
EndIf
ElseIf KeyboardPushed(#PB_Key_Down)
SpriteMove(*Ptsprite, *Ptsprite\x, *Ptsprite\y + 1, *map)
If *Ptsprite\cur_anim<>#ANIMATION_BAS
SpriteChangeAnim(*Ptsprite, #ANIMATION_BAS, 0)
Else
*Ptsprite\ispaused_anim = 0
EndIf
ElseIf KeyboardPushed(#PB_Key_Up)
If*Ptsprite\y > 0
SpriteMove(*Ptsprite, *Ptsprite\x, *Ptsprite\y-1, *map)
EndIf
If *Ptsprite\cur_anim <> #ANIMATION_HAUT
SpriteChangeAnim(*Ptsprite, #ANIMATION_HAUT, 0)
Else
*Ptsprite\ispaused_anim = 0
EndIf
EndIf
EndProcedure

