Well, this small Demo shows, how to properly handle a Sprite-based "Game-Scenario"
(using a 64x64 tiled Map of "plain-Grass") - as well as a few other "static Sprites"
(as unmoving Trees, and two unmoving, but animated "Coins") - as well as four moving
(and animated) "Person-Sprites".

There's no vbRichClient5-Reference needed for this Demo - instead the transparent
(Alpha)Sprite-Rendering is ensured with a small Helper-Class cPngCacheGDIP,
which supports Alpha-Pngs, but also all kind of other Image-Resources.
I'd say, it's quite easy to either make or find nice PNG-Images for your Sprites...,
and thus good old "masked Bitmap-Handling" is "banned for good" here.

The Demo handles the Sprites in 2 small and simple Classes (no Picture- or Image-Controls are needed)
and shows, how to use a normal VB-PictureBox as the Game-Canvas in Double-Buffered-Mode properly.
So there's no flickering, since any Sprites are rendered onto the (AutoRedraw-)BackBuffer,
before the Buffer is flipped back onto the Screen per PicCanvas.Refresh.

The "Game-Loop" is ensured over a fast ticking Timer here (for simplicitys sake) - and
refreshes the Screen with a new Scene (constantly redrawing 95 Sprites) any 15msec or so
(that's roughly 60Hz) - and it causes only 0.3% CPU-Load whilst doing so, because the
Systems AlphaBlend-Call is done in Hardware on most Systems these days.

The CodeBase is really quite small ...
When we leave out the unchanging Helper-Class cPngCacheGDIP, we have only:

modMain.bas
Code:
Option Explicit

Public PngCache As New cPngCacheGDIP 'let's declare it here for global usage
 
Sub Main()
  'add true Alpha-Channel-Png-resources (once, at App-Startup)
  PngCache.AddImage "Grass", App.Path & "\Res\Grass.jpg"
  PngCache.AddImage "Tree", App.Path & "\Res\Tree.png"
  PngCache.AddImage "AnimCoin", App.Path & "\Res\AnimCoin.png"
  PngCache.AddImage "Person", App.Path & "\Res\Person.png"

  fTest.Show 'load and show the Main-Form
End Sub
cSprites.cls (which aggregates the Sprites in a Collection and offers an Add-method)
Code:
Option Explicit

Public Col As New Collection

Public Sub AddAndInit(Sprite As cSprite, Key, ImgKey, x, y, Optional aShiftX, Optional aShiftY)
  Sprite.Key = Key
  Sprite.ImgKey = ImgKey
  Sprite.dX = PngCache.Width(ImgKey)
  Sprite.dY = PngCache.Height(ImgKey)
  Sprite.x = x
  Sprite.y = y
  If Not IsMissing(aShiftX) Then Sprite.aShiftX = aShiftX
  If Not IsMissing(aShiftY) Then Sprite.aShiftY = aShiftY
  
  Col.Add Sprite, Key
End Sub
cSprite.cls (which offers StateProperties for a single Sprite-Instance and Draw- and Animate-Methods)
Code:
Option Explicit
 
Public Key, ImgKey, x, y, dX, dY 'standard Properties
Public aShiftX, aShiftY, aX, aY  'additional Props for (optional) animation
 
Public Sub Draw(ByVal hDC As Long)
  PngCache.AlphaRenderTo hDC, ImgKey, x, y, IIf(aShiftX, aShiftX, dX), IIf(aShiftY, aShiftY, dY), aX, aY
End Sub

Public Sub MoveRel(xRel, yRel)
  x = x + xRel
  y = y + yRel
End Sub

Public Sub Animate()
  aX = aX + aShiftX: If aX >= dX - 1 Then aX = 0
  aY = aY + aShiftY: If aY >= dY - 1 Then aY = 0
End Sub
And finally the Form-Code, which ensures the Loading and animated rendering of the Sprites:
Code:
Option Explicit 'shows, how to make use of the two small Classes: cSprites and cSprite

Private x, y, Statics As New cSprites, Movers As New cSprites, Sprite As cSprite

Private Sub Form_Load()
  'add a static BackGround-Image onto our Canvas
  Set picCanvas.Picture = LoadPicture(App.Path & "\Res\Checker.jpg")
  
  'add the "Map"-Content (grass only in this demo)
  For y = 0 To 480 Step 64: For x = 0 To 640 Step 64
    Statics.AddAndInit New cSprite, "Grass_" & x & "_" & y, "Grass", x, y
  Next x, y
  Statics.Col.Remove "Grass_0_0" 'just to show, that "removing by key" works of course
  Statics.Col.Remove "Grass_128_128" 'and another one (leaving the BackGround-Image shine through)
  
  'add a few more static Sprites into the same (static) Collection as the Map-Content above
  Statics.AddAndInit New cSprite, "Tree1", "Tree", 40, 40
  Statics.AddAndInit New cSprite, "Tree2", "Tree", 300, 200
  Statics.AddAndInit New cSprite, "Tree3", "Tree", 540, 320
  Statics.AddAndInit New cSprite, "AnimCoin1", "AnimCoin", 580, 80, 44
  Statics.AddAndInit New cSprite, "AnimCoin2", "AnimCoin", 60, 420, 44
  
  'now the "PlayerSprites" which are to be moved (we add them to the Movers-Collection)
  Movers.AddAndInit New cSprite, "Person1", "Person", 120, 120, 45
  Movers.AddAndInit New cSprite, "Person2", "Person", 500, 120, 45
  Movers.AddAndInit New cSprite, "Person3", "Person", 500, 320, 45
  Movers.AddAndInit New cSprite, "Person4", "Person", 120, 320, 45
  
  Caption = Statics.Col.Count + Movers.Col.Count & " Sprites handled in a 60Hz-Refresh-Loop"
End Sub
 
Private Sub Redraw() 'our central scene-drawing-routine
  picCanvas.Cls 'clear anything on the backbuffer (leaving only the background-picture)
    DrawAllSpritesIn Statics 'all statics first
    DrawAllSpritesIn Movers 'movers are drawn on top of statics
  picCanvas.Refresh 'flip the DoubleBuffer to the Screen
End Sub

Private Sub DrawAllSpritesIn(Sprites As cSprites)
  For Each Sprite In Sprites.Col
    Sprite.Draw picCanvas.hDC
  Next
End Sub
  
Private Sub tmrRefresh_Timer() 'we handle the Sprites-State in a timer
Static Cnt&: Cnt = (Cnt + 1) Mod 72
Static Fac&: If Cnt = 0 Then Fac = IIf(Fac, -Fac, 1)
  
  For Each Sprite In Statics.Col
    Select Case Sprite.Key
      Case "AnimCoin1", "AnimCoin2": If Cnt Mod 4 = 0 Then Sprite.Animate
    End Select
  Next
  
  For Each Sprite In Movers.Col
    Select Case Sprite.Key
      Case "Person1": Sprite.MoveRel 1 * Fac, 1 * Fac
      Case "Person2": Sprite.MoveRel -1 * Fac, 1 * Fac
      Case "Person3": Sprite.MoveRel -1 * Fac, -1 * Fac
      Case "Person4": Sprite.MoveRel 1 * Fac, -1 * Fac
    End Select
    If Cnt Mod 3 = 0 Then Sprite.Animate
  Next
  
  Redraw
End Sub
Here's a ScreenShot:




And here the Zip-Archive for the Project:
PngSprites.zip

Have fun,

Olaf