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
cSprites.cls (which aggregates the Sprites in a Collection and offers an Add-method)
cSprite.cls (which offers StateProperties for a single Sprite-Instance and Draw- and Animate-Methods)
And finally the Form-Code, which ensures the Loading and animated rendering of the Sprites:
Here's a ScreenShot:
![]()
And here the Zip-Archive for the Project:
PngSprites.zip
Have fun,
Olaf
(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
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
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
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

And here the Zip-Archive for the Project:
PngSprites.zip
Have fun,
Olaf