Sprite stacking - 3d effect
Posted: Thu Jan 08, 2026 2:25 pm
A belated happy new year to you all 
Below is some code which demonstrates the use of 2d Sprite stacking to create a pseudo 3d effect, might be useful for someone...

Below is some code which demonstrates the use of 2d Sprite stacking to create a pseudo 3d effect, might be useful for someone...
Code: Select all
; Create pseudo 3d from stacked 2d sprites - pjay 05/24 (updated 01/26) - Written & tested on Win PB 6.11 x64.
; Inspired by Jon Topielskis' video here: https://www.youtube.com/watch?v=_Z5eg9UvLRw
; Sprite resource from: https://github.com/jontopielski/sprite-stacking-tutorial/blob/master/
EnableExplicit
#Width = 1024 : #Height = 768 : #sprWidth = 15 : #sprHeight = 32 : #sprNum = 11 : #sprScale = 2 : UsePNGImageDecoder()
If Not InitSprite() : End : EndIf
OpenWindow(0, 0, 0, #width, #height, "Sprite stacking (Faux 3d) demo - Phil James 2024", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
Define scrScale.f = DesktopResolutionX(), w = WindowWidth(0) * scrScale, h = WindowHeight(0) * scrScale, event, x, y, ptime.f, t.f, car, ems.q
Define.f scale, x1, y1, x2, y2, angle
If Not OpenWindowedScreen(WindowID(0), 0, 0, w, h) : End : EndIf
CatchSprite(0, ?CarSlices, #PB_Sprite_AlphaBlending) ;: SpriteQuality(#PB_Sprite_BilinearFiltering)
Repeat
Repeat
event = WindowEvent()
If event = #PB_Event_CloseWindow : End : EndIf
Until event = 0
ClearScreen(RGBA(170,180,190,255))
; example movement & rotation (using lemniscate shape)
ems = ElapsedMilliseconds() : ptime = ems / 1000.0
For car = 0 To 7
t = ptime + (car * 0.35)
scale = 2.0 / (3.0 - Cos(2.0 * t)) : x1.f = scale * Cos(t) : y1.f = scale * Sin(2.0 * t) / 2.0 : x1 * (w * 0.4) : y1 * (h * 0.5)
t + 0.01 ; increase to ~0.9 to make it appear to skid through corners.
scale = 2.0 / (3.0 - Cos(2.0 * t)) : x2.f = scale * Cos(t) : y2.f = scale * Sin(2.0 * t) / 2.0 : x2 * (w * 0.4) : y2 * (h * 0.5)
Angle.f = Degree(ACos((x2 - x1) / Sqr((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)))) : If y1 < y2 : Angle = 360.0 - Angle : EndIf
RotateSprite(0, -angle - 90, #PB_Absolute)
For y = 0 To 10 ; 11 slices in sheet...
ClipSprite(0, y * 15, 0, 15, 31)
ZoomSprite(0, #sprWidth * #sprScale * scrScale, #sprHeight * #sprScale * scrScale)
DisplayTransparentSprite(0, (w * 0.45) + x1, (h * 0.4) + y1 - (y * (#sprScale * scrScale)))
Next
Next
; bottom 3: larger size & split middle to show slices
RotateSprite(0, ems * 0.05, #PB_Absolute)
t = Sin((ElapsedMilliseconds() ) / 2000) * 5 : If t < 1 : t = 1 : EndIf
For y = 0 To 10 ; 11 slices...
ClipSprite(0, y * 15, 0, 15, 31)
ZoomSprite(0, #sprWidth * #sprScale * scrScale * 2, #sprHeight * #sprScale * scrScale * 2)
DisplayTransparentSprite(0, (w * 0.15), (h * 0.75) - (y * (#sprScale * scrScale * 2)))
DisplayTransparentSprite(0, (w * 0.45), (h * 0.75) - (t * y * (#sprScale * scrScale * 2)))
DisplayTransparentSprite(0, (w * 0.75), (h * 0.75) - (y * (#sprScale * scrScale * 2)))
Next
; display spritesheet that makes up the stacked car parts
t = Sin((ElapsedMilliseconds() - 2000) / 2000) * 2
If t > 0 : If t > 1 : t = 1 : EndIf
RotateSprite(0, 0, #PB_Absolute) : ClipSprite(0, #PB_Default, #PB_Default, #PB_Default, #PB_Default)
ZoomSprite(0, (#sprWidth * #sprNum) * 2 * scrScale, #sprHeight * 2.0 * scrScale)
DisplayTransparentSprite(0, (w * 0.5) - ( (#sprWidth * #sprNum) * 2 * scrScale) * 0.5, 32, t * 255)
EndIf
FlipBuffers()
ForEver
DataSection ; carslices.png included
CarSlices: : Data.q $0A1A0A0D474E5089,$524448490D000000,$20000000A5000000,$B856730000000608,$47527301000000B1,$0000E91CCEAE0042,$9C78544144493F03,$851430A395BD9CED,$C1C02A06C05C732F,$0401702825013016,$0102501005C0E014,$81C0280E01404C05, $C10050130170204A,$463F32BCB606C074,$0325F7E33A46790F,$ACFBF5AE70C0BBD6,$DF71F7ACB2C89E08,$D9EC65F71F232CB2,$4A51AC9294B9BCF8,$451400073CF20001,$EFE7D32C326E7771,$DF1F7E2217FDCD1F,$04710F9E9DDF39A8,$AB5AC68FCBD01D00, $BC257DACE004310E,$EE5B5C89D3A7C3FE,$5B254B18B808BB76,$8A3B64A80005BAC8,$32358CDEDD64CB35,$5E197C25A2DF05A5,$100058C5D29AE709,$67D19A69AEB5B1C7,$32C1E55380DA70DA,$BB01EBAEBA23E030,$410A221093DFA5F7,$76F9A53D1108414B, $1B81015359801635,$2FAC61E3BCA087EB,$8E2596594D9C5AED,$4FA4BC787E2923C7,$35A473A899F474D3,$213F5856958525D0,$A57B2948000D9BE3,$560EA78CC5DF7594,$DB12948AC1B794A4,$0001EFDFB82D72ED,$2B5D17C5B48EDB6D,$8E3AD0C967C0CBEA, $0CC3003F7CDE59F9,$04525D3A14253AF1,$E1C07138BEEA5B53,$EE9A50000D96BB55,$6A5A44D6EA52BC61,$E6AAAA805D4BC747,$B375694F04D0B3AF,$195BAC83535007AD,$ED23F974F157D7AE,$5CE02BED1AC08CC2,$EA86D78E46596653,$B24207AD646AC292, $6B1922D5B0E66F6E,$FCB8710A62EA7A35,$8D2BED69FC979B9D,$CB52FD24494FB9BE,$1009929B0CF10E41,$1814DA1FE3912536,$A6C2013253619E35,$9B0704C94D838264,$36B3A2B15F8E0992,$54DAEE6AB526C8C3,$4A9D6AD148EF39AD,$F9FDB7592C6CE4B6, $8AE6B590D34D4710,$D729857E5AED5ACE,$710F9ED5426AB2E2,$57C13A76EB260DA4,$A93D5F24EA59E463,$21F593478C698B6E,$B4B4A9EF9BDE3569,$CD174D34B8A998A9,$6D29BBC5C265A731,$8B9C64FDFBF7CDD6,$093079D442D126D6,$10CC32537784AF19, $6A78D4E4999A5367,$79B09968BBC6642D,$BF199114E4992E03,$1B2D4A9E3CDCF326,$569A7AAAAA155552,$44C97039D662F9D4,$FA3EF055F2A7290A,$E9AED0D30F6969D6,$5C2DB4A5DE134367,$929F70184CC0C6DF,$DAD0CFE799EF0E09,$7E5BA6A9DA9AFB24, $853F7BFAA545FFFE,$3EF9984128C525D4,$D0CFE79935CA6B9C,$3F8CF1A84D09F4DA,$618060DB9CA7D29E,$0A160B734A6CE0D6,$272EB5A1AA35D77A,$ACCF8A2D92A19AEE,$9B3BEE5D76BAED1F,$AB6D2EAB5AF4EC23,$90000E7C3854B962,$D7A63C7EE6A2160F, $8E84C4D9DF2D1FCC,$FE399900ADE707B7,$210BF569D421EF01,$4E454900000000B5, $44AE426082000000
EndDataSection