Better code readability master
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Fri, 29 Aug 2025 22:55:52 +0000 (01:55 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Fri, 29 Aug 2025 22:55:52 +0000 (01:55 +0300)
Games/Pomppu Paavo/Pomppu Paavo.bas

index 75dc932..d83ae6d 100755 (executable)
@@ -1,4 +1,3 @@
-DECLARE SUB RenderSpriteFromFile (x%, y%, spriteID%, animationFrame%)\r
 ' Pomppu Paavo\r
 '\r
 ' This program is free software: released under Creative Commons Zero (CC0) license\r
@@ -10,15 +9,16 @@ DECLARE SUB RenderSpriteFromFile (x%, y%, spriteID%, animationFrame%)
 ' 1998, Initial version\r
 ' 2025, Improved program readability\r
 \r
-\r
 DECLARE SUB DisplayGameStatistics ()\r
-DECLARE SUB LoadCurrentLevel (y%)\r
+DECLARE SUB LoadCurrentLevel (levelNumber%)\r
+DECLARE SUB RenderSpriteFromFile (xPosition%, yPosition%, spriteID%, animationFrame%)\r
 \r
 DEFINT A-Z\r
 DIM SHARED AsciiLevelData(1 TO 20) AS STRING * 31\r
-DIM SHARED Companion1PositionY%, Companion1PositionX%, Companion2PositionY%, Companion2PositionX%\r
+DIM SHARED Companion1VerticalPosition%, Companion1HorizontalPosition%, Companion2VerticalPosition%, Companion2HorizontalPosition%\r
 DIM SHARED LivesRemaining%, CoinsCollected%\r
-DIM SHARED DoorEntryX%, DoorEntryY%, DoorExitX%, DoorExitY%\r
+DIM SHARED DoorEntryX%, DoorEntryY%\r
+DIM SHARED DoorExitX%, DoorExitY%\r
 DIM SHARED CurrentLevelNumber%\r
 DIM SHARED TerrainGrid(0 TO 34, -10 TO 20) AS STRING * 1\r
 DIM SHARED ObjectGrid(0 TO 34, -10 TO 20) AS STRING * 1\r
@@ -49,7 +49,7 @@ DIM SHARED PlayerRunLeft2Sprite(51)
 DIM SHARED PlayerJumpingSprite(51)\r
 DIM SHARED DoorSprite(120)\r
 \r
-' Define keyboard control sequences\r
+' Define keyboard control sequences using special arrow key codes\r
 leftArrowKey$ = CHR$(0) + "K"\r
 rightArrowKey$ = CHR$(0) + "M"\r
 upArrowKey$ = CHR$(0) + "H"\r
@@ -61,7 +61,7 @@ SCREEN 1
 CurrentLevelNumber% = 1\r
 \r
 ' Capture sprite images from screen drawing operations.\r
-' This technique uses GET command to save drawn graphics into arrays.\r
+' This technique uses GET command to save drawn graphics directly into arrays.\r
 GET (1, 1)-(20, 20), EmptySpaceSprite\r
 RenderSpriteFromFile 0, 0, 1, 1\r
 GET (1, 1)-(20, 20), SolidTerrainSprite\r
@@ -119,308 +119,369 @@ RenderSpriteFromFile 0, 0, 16, 1
 GET (1, 1)-(20, 20), PlayerJumpingSprite\r
 CLS\r
 \r
-\r
+' Capture the introductory screen image\r
 RenderSpriteFromFile -1, -1, 10, 4\r
 GET (1, 1)-(318, 124), IntroScreen\r
 \r
 key$ = INPUT$(1)\r
 \r
 LoadCurrentLevel 1\r
-a = 50\r
-b = 50\r
-Companion1HorizontalVelocity = 1\r
-Companion2HorizontalVelocity = 1\r
+PlayerXPosition% = 50\r
+PlayerYPosition% = 50\r
+Companion1HorizontalSpeed% = 1\r
+Companion2HorizontalSpeed% = 1\r
 MainGameLoop:\r
 keyboardInput$ = INKEY$\r
-IF b > 0 THEN GET (a, b)-(a + 20, b + 20), PlayerSpriteBuffer\r
-IF b > 0 THEN IF PlayerAnimationState = 1 THEN PUT (a, b), PlayerRunRight1Sprite, OR\r
-IF b > 0 THEN IF PlayerAnimationState = 2 THEN PUT (a, b), PlayerRunRight2Sprite, OR\r
-IF b > 0 THEN IF PlayerAnimationState = 10 THEN PUT (a, b), PlayerRunLeft1Sprite, OR\r
-IF b > 0 THEN IF PlayerAnimationState = 20 THEN PUT (a, b), PlayerRunLeft2Sprite, OR\r
-IF b > 0 THEN IF PlayerAnimationState = 3 THEN PUT (a, b), PlayerJumpingSprite, OR\r
-\r
-' Draw first companion hedgehog\r
-GET (Companion1PositionX%, Companion1PositionY%)-(Companion1PositionX% + 10, Companion1PositionY% + 10), HedgehogSprite1\r
-PUT (Companion1PositionX%, Companion1PositionY%), HedgehogSprite, OR\r
-\r
-' Draw second companion hedgehog\r
-GET (Companion2PositionX%, Companion2PositionY%)-(Companion2PositionX% + 10, Companion2PositionY% + 10), HedgehogSprite2\r
-PUT (Companion2PositionX%, Companion2PositionY%), HedgehogSprite, OR\r
-\r
-' Create short delay using sound command (workaround since QBasic lacks built-in sub-second delay)\r
-' SOUND 0,0.8 creates an inaudible tone that takes approximately 8 milliseconds to process\r
+IF PlayerYPosition% > 0 THEN GET (PlayerXPosition%, PlayerYPosition%)-(PlayerXPosition% + 20, PlayerYPosition% + 20), PlayerSpriteBuffer\r
+\r
+' Display appropriate player animation frame based on current movement state\r
+IF PlayerYPosition% > 0 THEN IF PlayerAnimationState% = 1 THEN PUT (PlayerXPosition%, PlayerYPosition%), PlayerRunRight1Sprite, OR\r
+IF PlayerYPosition% > 0 THEN IF PlayerAnimationState% = 2 THEN PUT (PlayerXPosition%, PlayerYPosition%), PlayerRunRight2Sprite, OR\r
+IF PlayerYPosition% > 0 THEN IF PlayerAnimationState% = 10 THEN PUT (PlayerXPosition%, PlayerYPosition%), PlayerRunLeft1Sprite, OR\r
+IF PlayerYPosition% > 0 THEN IF PlayerAnimationState% = 20 THEN PUT (PlayerXPosition%, PlayerYPosition%), PlayerRunLeft2Sprite, OR\r
+IF PlayerYPosition% > 0 THEN IF PlayerAnimationState% = 3 THEN PUT (PlayerXPosition%, PlayerYPosition%), PlayerJumpingSprite, OR\r
+\r
+' Draw first companion hedgehog to screen\r
+GET (Companion1HorizontalPosition%, Companion1VerticalPosition%)-(Companion1HorizontalPosition% + 10, Companion1VerticalPosition% + 10), HedgehogSprite1\r
+PUT (Companion1HorizontalPosition%, Companion1VerticalPosition%), HedgehogSprite, OR\r
+\r
+' Draw second companion hedgehog to screen\r
+GET (Companion2HorizontalPosition%, Companion2VerticalPosition%)-(Companion2HorizontalPosition% + 10, Companion2VerticalPosition% + 10), HedgehogSprite2\r
+PUT (Companion2HorizontalPosition%, Companion2VerticalPosition%), HedgehogSprite, OR\r
+\r
+' Create short delay using sound command (workaround for lack of built-in sub-second delay in QBasic)\r
+' SOUND 0,0.8 produces an inaudible tone that takes approximately 0.8 milliseconds to process\r
 SOUND 0, .8\r
 \r
-' Check collisions with terrain (z = solid block)\r
-' Right side collision checks\r
-IF TerrainGrid((a + 38) \ 20, (b + 37) \ 20) = "z" THEN eda = -1: r = 9: lke = 0\r
-IF TerrainGrid((a + 38) \ 20, (b + 22) \ 20) = "z" THEN eda = -1: r = 9: lke = 0\r
+' Check collisions with solid terrain ("z" character in grid)\r
+' Right side collision detection - checks two points along right edge of player hitbox\r
+' Player hitbox is slightly smaller than sprite (38 instead of full 40 width)\r
+IF TerrainGrid((PlayerXPosition% + 38) \ 20, (PlayerYPosition% + 37) \ 20) = "z" THEN PlayerHorizontalSpeed% = -1: HorizontalAnimationCounter% = 9: GroundContactTime% = 0\r
+IF TerrainGrid((PlayerXPosition% + 38) \ 20, (PlayerYPosition% + 22) \ 20) = "z" THEN PlayerHorizontalSpeed% = -1: HorizontalAnimationCounter% = 9: GroundContactTime% = 0\r
 \r
-' Left side collision checks\r
-IF TerrainGrid((a + 21) \ 20, (b + 22) \ 20) = "z" THEN eda = 1: r = 9: lke = 0\r
-IF TerrainGrid((a + 21) \ 20, (b + 37) \ 20) = "z" THEN eda = 1: r = 9: lke = 0\r
+' Left side collision detection - checks two points along left edge of player hitbox\r
+IF TerrainGrid((PlayerXPosition% + 21) \ 20, (PlayerYPosition% + 22) \ 20) = "z" THEN PlayerHorizontalSpeed% = 1: HorizontalAnimationCounter% = 9: GroundContactTime% = 0\r
+IF TerrainGrid((PlayerXPosition% + 21) \ 20, (PlayerYPosition% + 37) \ 20) = "z" THEN PlayerHorizontalSpeed% = 1: HorizontalAnimationCounter% = 9: GroundContactTime% = 0\r
 \r
-' Top collision checks\r
-IF TerrainGrid((a + 22) \ 20, (b + 21) \ 20) = "z" THEN all = 0: cd = 10: lke = 0\r
-IF TerrainGrid((a + 37) \ 20, (b + 21) \ 20) = "z" THEN all = 0: cd = 10: lke = 0\r
+' Top collision detection - checks if player hits ceiling ("z" block above)\r
+IF TerrainGrid((PlayerXPosition% + 22) \ 20, (PlayerYPosition% + 21) \ 20) = "z" THEN PlayerVerticalSpeed% = 0: CeilingContactCooldown% = 10: GroundContactTime% = 0\r
+IF TerrainGrid((PlayerXPosition% + 37) \ 20, (PlayerYPosition% + 21) \ 20) = "z" THEN PlayerVerticalSpeed% = 0: CeilingContactCooldown% = 10: GroundContactTime% = 0\r
 \r
-' Bottom collision checks (landing on ground)\r
-IF TerrainGrid((a + 22) \ 20, (b + 38) \ 20) = "z" THEN all = -1: r1 = 2: lk = 1: lke = 0\r
-IF TerrainGrid((a + 37) \ 20, (b + 38) \ 20) = "z" THEN all = -1: r1 = 2: lk = 1: lke = 0\r
+' Bottom collision detection (landing on ground) - checks if player lands on solid terrain\r
+' When landing, sets vertical speed to negative (bounce effect), resets jump ability\r
+IF TerrainGrid((PlayerXPosition% + 22) \ 20, (PlayerYPosition% + 38) \ 20) = "z" THEN PlayerVerticalSpeed% = -1: VerticalAnimationCounter% = 2: JumpReadinessCounter% = 1: GroundContactTime% = 0\r
+IF TerrainGrid((PlayerXPosition% + 37) \ 20, (PlayerYPosition% + 38) \ 20) = "z" THEN PlayerVerticalSpeed% = -1: VerticalAnimationCounter% = 2: JumpReadinessCounter% = 1: GroundContactTime% = 0\r
 \r
-qwer = qwer + 1: IF ObjectGrid((a + 30) \ 20, (b + 30) \ 20) = "q" AND qwer > 20 THEN qwer = 1: LivesRemaining% = LivesRemaining% - 1: eda = -10: all = -5: DisplayGameStatistics\r
-IF qwer > 100 THEN qwer = 50\r
+HazardExposureTimer% = HazardExposureTimer% + 1: IF ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 30) \ 20) = "q" AND HazardExposureTimer% > 20 THEN HazardExposureTimer% = 1: LivesRemaining% = LivesRemaining% - 1:    _\r
+PlayerHorizontalSpeed% = -10: PlayerVerticalSpeed% = -5: DisplayGameStatistics\r
+IF HazardExposureTimer% > 100 THEN HazardExposureTimer% = 50\r
 \r
-' Coin collection logic\r
-IF TerrainGrid((a + 30) \ 20, (b + 30) \ 20) = "1" THEN CoinsCollected% = CoinsCollected% + 1: kustuta1 = 1: DisplayGameStatistics: TerrainGrid((a + 30) \ 20, (b + 30) \ 20) = ""\r
+' Coin collection logic - when player overlaps coin position ("1" in grid)\r
+IF TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 30) \ 20) = "1" THEN CoinsCollected% = CoinsCollected% + 1: CoinCollectedFlag% = 1: DisplayGameStatistics: TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 30) \ 20) = ""\r
 \r
-' Trampoline effect\r
-IF TerrainGrid((a + 30) \ 20, (b + 30) \ 20) = "v" THEN all = -8: PlayerAnimationState = 3\r
+' Trampoline effect - when player lands on trampoline ("v" marker), gives strong upward boost\r
+IF TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 30) \ 20) = "v" THEN PlayerVerticalSpeed% = -8: PlayerAnimationState% = 3\r
 \r
-' Conveyor belt movement triggers\r
-IF ObjectGrid((a + 30) \ 20, (b + 38) \ 20) = ">" THEN eda = 3\r
-IF ObjectGrid((a + 30) \ 20, (b + 38) \ 20) = "<" THEN eda = -3\r
+' Conveyor belt movement - ">" and "<" markers in object grid push player horizontally\r
+IF ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 38) \ 20) = ">" THEN PlayerHorizontalSpeed% = 3\r
+IF ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 38) \ 20) = "<" THEN PlayerHorizontalSpeed% = -3\r
 \r
-lke = lke + 1\r
-r = r + 1: IF r > 10 THEN r = 0: IF eda > 0 THEN eda = eda - 1:  ELSE IF eda < 0 THEN eda = eda + 1\r
-r1 = r1 + 1: IF r1 > 3 THEN r1 = 0: all = all + 1\r
-lk = lk + 1: cd = cd - 1\r
+GroundContactTime% = GroundContactTime% + 1\r
+HorizontalAnimationCounter% = HorizontalAnimationCounter% + 1: IF HorizontalAnimationCounter% > 10 THEN HorizontalAnimationCounter% = 0: IF PlayerHorizontalSpeed% > 0 THEN PlayerHorizontalSpeed% = PlayerHorizontalSpeed% - 1 ELSE IF  _\r
+PlayerHorizontalSpeed% < 0 THEN PlayerHorizontalSpeed% = PlayerHorizontalSpeed% + 1\r
+VerticalAnimationCounter% = VerticalAnimationCounter% + 1: IF VerticalAnimationCounter% > 3 THEN VerticalAnimationCounter% = 0: PlayerVerticalSpeed% = PlayerVerticalSpeed% + 1\r
+JumpReadinessCounter% = JumpReadinessCounter% + 1: CeilingContactCooldown% = CeilingContactCooldown% - 1\r
 \r
-' Breakable block interaction\r
-IF ObjectGrid((a + 30) \ 20, (b + 21) \ 20) = "o" THEN TerrainGrid((a + 30) \ 20, (b + 21) \ 20) = "": ObjectGrid((a + 30) \ 20, (b + 21) \ 20) = "": kustuta = 1\r
+' Breakable block interaction - hitting block from below ("o" character) destroys it\r
+IF ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 21) \ 20) = "o" THEN TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 21) \ 20) = "": ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 21) \ 20) = "":    _\r
+TopBreakableBlockClearedFlag% = 1\r
 \r
-IF ObjectGrid((a + 30) \ 20, (b + 38) \ 20) = "a" THEN TerrainGrid((a + 30) \ 20, (b + 38) \ 20) = "": ObjectGrid((a + 30) \ 20, (b + 38) \ 20) = "": kustuta2 = 1\r
+' Bottom breakable block interaction - similar to above but from top side\r
+IF ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 38) \ 20) = "a" THEN TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 38) \ 20) = "": ObjectGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 38) \ 20) = "":    _\r
+BottomBreakableBlockClearedFlag% = 1\r
 \r
 ' First companion hedgehog terrain collision checks\r
-IF TerrainGrid((Companion1PositionX% + 25) \ 20, (Companion1PositionY% + 25) \ 20) = "z" THEN Companion1VerticalVelocity = -1\r
-IF TerrainGrid((Companion1PositionX% + 30) \ 20, (Companion1PositionY% + 10) \ 20) = "z" THEN Companion1HorizontalVelocity = -1\r
-IF TerrainGrid((Companion1PositionX% + 20) \ 20, (Companion1PositionY% + 10) \ 20) = "z" THEN Companion1HorizontalVelocity = 1\r
+IF TerrainGrid((Companion1HorizontalPosition% + 25) \ 20, (Companion1VerticalPosition% + 25) \ 20) = "z" THEN Companion1VerticalSpeed% = -1\r
+IF TerrainGrid((Companion1HorizontalPosition% + 30) \ 20, (Companion1VerticalPosition% + 10) \ 20) = "z" THEN Companion1HorizontalSpeed% = -1\r
+IF TerrainGrid((Companion1HorizontalPosition% + 20) \ 20, (Companion1VerticalPosition% + 10) \ 20) = "z" THEN Companion1HorizontalSpeed% = 1\r
 \r
 ' Second companion hedgehog terrain collision checks\r
-IF TerrainGrid((Companion2PositionX% + 25) \ 20, (Companion2PositionY% + 25) \ 20) = "z" THEN Companion2VerticalVelocity = -1\r
-IF TerrainGrid((Companion2PositionX% + 30) \ 20, (Companion2PositionY% + 10) \ 20) = "z" THEN Companion2HorizontalVelocity = -1\r
-IF TerrainGrid((Companion2PositionX% + 20) \ 20, (Companion2PositionY% + 10) \ 20) = "z" THEN Companion2HorizontalVelocity = 1\r
-\r
-' Screen boundary checks for companions\r
-IF Companion1PositionX% > 300 THEN Companion1HorizontalVelocity = -1\r
-IF Companion1PositionX% < 3 THEN Companion1HorizontalVelocity = 1\r
-IF Companion2PositionX% > 300 THEN Companion2HorizontalVelocity = -1\r
-IF Companion2PositionX% < 3 THEN Companion2HorizontalVelocity = 1\r
-\r
-' Restore previous companion positions\r
-PUT (Companion2PositionX%, Companion2PositionY%), HedgehogSprite2, PSET\r
-PUT (Companion1PositionX%, Companion1PositionY%), HedgehogSprite1, PSET\r
-\r
-' Restore previous player position\r
-IF b > 0 THEN PUT (a, b), PlayerSpriteBuffer, PSET\r
-\r
-' Handle sprite clearing after coin collection\r
-IF kustuta = 1 THEN kustuta = 0: PUT (((a + 10) \ 20) * 20, (b \ 20) * 20), EmptySpaceSprite, PSET\r
-IF kustuta1 = 1 THEN kustuta1 = 0: PUT (((a + 10) \ 20) * 20, ((b + 10) \ 20) * 20), EmptySpaceSprite, PSET\r
-IF kustuta2 = 1 THEN kustuta2 = 0: PUT (((a + 10) \ 20) * 20, ((b + 28) \ 20) * 20), EmptySpaceSprite, PSET\r
-\r
-IF makk = 1 THEN makk = 0: a = a - 20\r
-\r
-ObjectGrid((Companion2PositionX% + 25) \ 20, (Companion2PositionY% + 8) \ 20) = "": ObjectGrid((Companion1PositionX% + 25) \ 20, (Companion1PositionY% + 8) \ 20) = ""\r
-\r
-' Update companion positions\r
-Companion1PositionX% = Companion1PositionX% + Companion1HorizontalVelocity\r
-Companion1PositionY% = Companion1PositionY% + Companion1VerticalVelocity\r
-Companion2PositionX% = Companion2PositionX% + Companion2HorizontalVelocity\r
-Companion2PositionY% = Companion2PositionY% + Companion2VerticalVelocity\r
-\r
-' Mark new companion positions in object grid\r
-ObjectGrid((Companion2PositionX% + 25) \ 20, (Companion2PositionY% + 8) \ 20) = "q": ObjectGrid((Companion1PositionX% + 25) \ 20, (Companion1PositionY% + 8) \ 20) = "q"\r
-\r
-' Apply gravity to companions (max downward velocity = 2)\r
-Companion1VerticalVelocity = Companion1VerticalVelocity + 1: IF Companion1VerticalVelocity > 2 THEN Companion1VerticalVelocity = 2\r
-Companion2VerticalVelocity = Companion2VerticalVelocity + 1: IF Companion2VerticalVelocity > 2 THEN Companion2VerticalVelocity = 2\r
-\r
-' Update player position based on velocity\r
-a = a + eda\r
-b = b + all\r
-\r
-' Level transition when reaching right edge\r
-IF a > 297 THEN a = 2: CurrentLevelNumber% = CurrentLevelNumber% + 1: LoadCurrentLevel CurrentLevelNumber%: Companion1HorizontalVelocity = 1: Companion2HorizontalVelocity = 1\r
-\r
-' Level transition when reaching left edge\r
-IF a < 1 THEN a = 296: IF CurrentLevelNumber% = 1 THEN LoadCurrentLevel CurrentLevelNumber%:  ELSE CurrentLevelNumber% = CurrentLevelNumber% - 1: LoadCurrentLevel CurrentLevelNumber%: IF GraphicsDisplayMode = 2 THEN a = 594\r
-\r
-' Player falls off bottom of screen\r
-IF b > 179 THEN LivesRemaining% = LivesRemaining% - 1: DisplayGameStatistics: CurrentLevelNumber% = CurrentLevelNumber% - 1: LoadCurrentLevel CurrentLevelNumber%: b = 100: a = 2: DisplayGameStatistics\r
-\r
-' Teleportation triggers ("u" and "U" markers in level data)\r
-IF TerrainGrid((a + 30) \ 20, (b + 30) \ 20) = "u" THEN a = DoorExitX% + 10: b = DoorExitY%: eda = 0\r
-IF TerrainGrid((a + 30) \ 20, (b + 30) \ 20) = "U" THEN a = DoorEntryX% + 10: b = DoorEntryY%: eda = 0\r
-\r
-IF keyboardInput$ = rightArrowKey$ THEN eda = eda + 1: IF eda > 3 THEN eda = 3: r = 0 ELSE IF lke > 10 THEN eda = 5\r
-IF keyboardInput$ = rightArrowKey$ THEN IF sipa = 1 THEN PlayerAnimationState = 1:  ELSE PlayerAnimationState = 2\r
-IF keyboardInput$ = leftArrowKey$ THEN IF sipa = 1 THEN PlayerAnimationState = 10:  ELSE PlayerAnimationState = 20\r
-IF keyboardInput$ = leftArrowKey$ THEN eda = eda - 1: IF eda < -3 THEN eda = -3: r = 0 ELSE IF lke > 10 THEN eda = -5\r
-IF keyboardInput$ = upArrowKey$ AND lk < 10 THEN all = all - 5: lk = 20: r1 = 0: PlayerAnimationState = 3\r
-IF keyboardInput$ = downArrowKey$ THEN all = all + 1\r
-IF keyboardInput$ = "/" THEN a = 2: b = 50: CurrentLevelNumber% = CurrentLevelNumber% + 1: LoadCurrentLevel CurrentLevelNumber%: Companion1HorizontalVelocity = 1: Companion2HorizontalVelocity = 1\r
-IF keyboardInput$ = "+" THEN a = 2: b = 50: CurrentLevelNumber% = CurrentLevelNumber% + 5: LoadCurrentLevel CurrentLevelNumber%: Companion1HorizontalVelocity = 1: Companion2HorizontalVelocity = 1\r
+IF TerrainGrid((Companion2HorizontalPosition% + 25) \ 20, (Companion2VerticalPosition% + 25) \ 20) = "z" THEN Companion2VerticalSpeed% = -1\r
+IF TerrainGrid((Companion2HorizontalPosition% + 30) \ 20, (Companion2VerticalPosition% + 10) \ 20) = "z" THEN Companion2HorizontalSpeed% = -1\r
+IF TerrainGrid((Companion2HorizontalPosition% + 20) \ 20, (Companion2VerticalPosition% + 10) \ 20) = "z" THEN Companion2HorizontalSpeed% = 1\r
+\r
+' Screen boundary checks for companions to keep them within play area\r
+IF Companion1HorizontalPosition% > 300 THEN Companion1HorizontalSpeed% = -1\r
+IF Companion1HorizontalPosition% < 3 THEN Companion1HorizontalSpeed% = 1\r
+IF Companion2HorizontalPosition% > 300 THEN Companion2HorizontalSpeed% = -1\r
+IF Companion2HorizontalPosition% < 3 THEN Companion2HorizontalSpeed% = 1\r
+\r
+' Restore previous companion positions before moving them (erases old sprite)\r
+PUT (Companion2HorizontalPosition%, Companion2VerticalPosition%), HedgehogSprite2, PSET\r
+PUT (Companion1HorizontalPosition%, Companion1VerticalPosition%), HedgehogSprite1, PSET\r
+\r
+' Restore previous player position (erases old sprite)\r
+IF PlayerYPosition% > 0 THEN PUT (PlayerXPosition%, PlayerYPosition%), PlayerSpriteBuffer, PSET\r
+\r
+' Handle sprite clearing after collecting coins or breaking blocks\r
+IF TopBreakableBlockClearedFlag% = 1 THEN TopBreakableBlockClearedFlag% = 0: PUT (((PlayerXPosition% + 10) \ 20) * 20, (PlayerYPosition% \ 20) * 20), EmptySpaceSprite, PSET\r
+IF CoinCollectedFlag% = 1 THEN CoinCollectedFlag% = 0: PUT (((PlayerXPosition% + 10) \ 20) * 20, ((PlayerYPosition% + 10) \ 20) * 20), EmptySpaceSprite, PSET\r
+IF BottomBreakableBlockClearedFlag% = 1 THEN BottomBreakableBlockClearedFlag% = 0: PUT (((PlayerXPosition% + 10) \ 20) * 20, ((PlayerYPosition% + 28) \ 20) * 20), EmptySpaceSprite, PSET\r
+\r
+IF PullBackwardFlag% = 1 THEN PullBackwardFlag% = 0: PlayerXPosition% = PlayerXPosition% - 20\r
+\r
+ObjectGrid((Companion2HorizontalPosition% + 25) \ 20, (Companion2VerticalPosition% + 8) \ 20) = "": ObjectGrid((Companion1HorizontalPosition% + 25) \ 20, (Companion1VerticalPosition% + 8) \ 20) = ""\r
+\r
+' Update companion positions based on their current velocities\r
+Companion1HorizontalPosition% = Companion1HorizontalPosition% + Companion1HorizontalSpeed%\r
+Companion1VerticalPosition% = Companion1VerticalPosition% + Companion1VerticalSpeed%\r
+Companion2HorizontalPosition% = Companion2HorizontalPosition% + Companion2HorizontalSpeed%\r
+Companion2VerticalPosition% = Companion2VerticalPosition% + Companion2VerticalSpeed%\r
+\r
+' Mark new companion positions in object grid for collision detection\r
+ObjectGrid((Companion2HorizontalPosition% + 25) \ 20, (Companion2VerticalPosition% + 8) \ 20) = "q": ObjectGrid((Companion1HorizontalPosition% + 25) \ 20, (Companion1VerticalPosition% + 8) \ 20) = "q"\r
+\r
+' Apply gravity to companions (max downward speed capped at 2 pixels/frame)\r
+Companion1VerticalSpeed% = Companion1VerticalSpeed% + 1: IF Companion1VerticalSpeed% > 2 THEN Companion1VerticalSpeed% = 2\r
+Companion2VerticalSpeed% = Companion2VerticalSpeed% + 1: IF Companion2VerticalSpeed% > 2 THEN Companion2VerticalSpeed% = 2\r
+\r
+' Update player position based on calculated velocities\r
+PlayerXPosition% = PlayerXPosition% + PlayerHorizontalSpeed%\r
+PlayerYPosition% = PlayerYPosition% + PlayerVerticalSpeed%\r
+\r
+' Level transition when reaching right edge of screen\r
+IF PlayerXPosition% > 297 THEN PlayerXPosition% = 2: CurrentLevelNumber% = CurrentLevelNumber% + 1: LoadCurrentLevel CurrentLevelNumber%: Companion1HorizontalSpeed% = 1: Companion2HorizontalSpeed% = 1\r
+\r
+' Level transition when reaching left edge of screen\r
+IF PlayerXPosition% < 1 THEN PlayerXPosition% = 296: IF CurrentLevelNumber% = 1 THEN LoadCurrentLevel CurrentLevelNumber% ELSE CurrentLevelNumber% = CurrentLevelNumber% - 1: LoadCurrentLevel CurrentLevelNumber%: IF GraphicsDisplayMode% = 2 THEN  _\r
+PlayerXPosition% = 594\r
+\r
+' Player falls off bottom of screen - lose life and restart level\r
+IF PlayerYPosition% > 179 THEN LivesRemaining% = LivesRemaining% - 1: DisplayGameStatistics: CurrentLevelNumber% = CurrentLevelNumber% - 1: LoadCurrentLevel CurrentLevelNumber%: PlayerYPosition% = 100: PlayerXPosition% = 2: DisplayGameStatistics\r
+\r
+' Teleportation triggers ("u" and "U" markers in level data create door pairs)\r
+IF TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 30) \ 20) = "u" THEN PlayerXPosition% = DoorExitX% + 10: PlayerYPosition% = DoorExitY%: PlayerHorizontalSpeed% = 0\r
+IF TerrainGrid((PlayerXPosition% + 30) \ 20, (PlayerYPosition% + 30) \ 20) = "U" THEN PlayerXPosition% = DoorEntryX% + 10: PlayerYPosition% = DoorEntryY%: PlayerHorizontalSpeed% = 0\r
+\r
+' Handle keyboard input for movement controls\r
+IF keyboardInput$ = rightArrowKey$ THEN PlayerHorizontalSpeed% = PlayerHorizontalSpeed% + 1: IF PlayerHorizontalSpeed% > 3 THEN PlayerHorizontalSpeed% = 3: HorizontalAnimationCounter% = 0 ELSE IF GroundContactTime% > 10 THEN PlayerHorizontalSpeed% = 5\r
+IF keyboardInput$ = rightArrowKey$ THEN IF RunningAnimationStage% = 1 THEN PlayerAnimationState% = 1 ELSE PlayerAnimationState% = 2\r
+IF keyboardInput$ = leftArrowKey$ THEN IF RunningAnimationStage% = 1 THEN PlayerAnimationState% = 10 ELSE PlayerAnimationState% = 20\r
+IF keyboardInput$ = leftArrowKey$ THEN PlayerHorizontalSpeed% = PlayerHorizontalSpeed% - 1: IF PlayerHorizontalSpeed% < -3 THEN PlayerHorizontalSpeed% = -3: HorizontalAnimationCounter% = 0 ELSE IF GroundContactTime% > 10 THEN PlayerHorizontalSpeed% = -5\r
+IF keyboardInput$ = upArrowKey$ AND JumpReadinessCounter% < 10 THEN PlayerVerticalSpeed% = PlayerVerticalSpeed% - 5: JumpReadinessCounter% = 20: VerticalAnimationCounter% = 0: PlayerAnimationState% = 3\r
+IF keyboardInput$ = downArrowKey$ THEN PlayerVerticalSpeed% = PlayerVerticalSpeed% + 1\r
+IF keyboardInput$ = "/" THEN PlayerXPosition% = 2: PlayerYPosition% = 50: CurrentLevelNumber% = CurrentLevelNumber% + 1: LoadCurrentLevel CurrentLevelNumber%: Companion1HorizontalSpeed% = 1: Companion2HorizontalSpeed% = 1\r
+IF keyboardInput$ = "+" THEN PlayerXPosition% = 2: PlayerYPosition% = 50: CurrentLevelNumber% = CurrentLevelNumber% + 5: LoadCurrentLevel CurrentLevelNumber%: Companion1HorizontalSpeed% = 1: Companion2HorizontalSpeed% = 1\r
 IF keyboardInput$ = "q" THEN END\r
-sipa = sipa + 1\r
-IF sipa = 3 THEN sipa = 1\r
+\r
+' Cycle through running animation frames (alternates between two states)\r
+RunningAnimationStage% = RunningAnimationStage% + 1\r
+IF RunningAnimationStage% = 3 THEN RunningAnimationStage% = 1\r
 GOTO MainGameLoop\r
 \r
 SUB DisplayGameStatistics\r
 '\r
-' Updates and displays the game's status information (coins, lives)\r
-' Handles game over condition when lives reach zero.\r
+' Updates and displays the game's status information on screen (coins collected, remaining lives)\r
+' Handles game over condition when player runs out of lives.\r
 '\r
-' This subroutine is called whenever:\r
-' - A coin is collected\r
-' - The player loses a life (from hazards or falling)\r
-' - Periodically during gameplay for live updates\r
+' This subroutine is triggered whenever:\r
+' - A coin is collected (incrementing coins counter)\r
+' - The player loses a life due to hazards or falling off-screen\r
+' - Periodically during gameplay for live status updates\r
 \r
 LOCATE 1, 1\r
 IF GraphicsDisplayMode% = 2 THEN GOTO SkipTextDisplay\r
 \r
-' Clear previous stats display to prevent text overlap\r
+' Clear previous statistics display to prevent overlapping text\r
 PRINT "                "\r
 \r
-' Award extra life every 10 coins collected\r
-IF CoinsCollected% > 9 THEN CoinsCollected% = 0: LivesRemaining% = LivesRemaining% + 1\r
+' Award extra life every 10 coins collected as bonus\r
+IF CoinsCollected% > 9 THEN\r
+    CoinsCollected% = 0\r
+    LivesRemaining% = LivesRemaining% + 1\r
+END IF\r
 \r
-' Display current game statistics\r
+' Display current game statistics in top-left corner of screen\r
 LOCATE 1, 1\r
-PRINT "o "; CoinsCollected%; "  Lives "; LivesRemaining%\r
+PRINT "Coins: "; CoinsCollected%; "  Lives: "; LivesRemaining%\r
 \r
 SkipTextDisplay:\r
-' Check if player has run out of lives\r
+' Check if player has completely run out of lives (game over condition)\r
 IF LivesRemaining% < 0 THEN END\r
 END SUB\r
 \r
-SUB LoadCurrentLevel (y)\r
+SUB LoadCurrentLevel (levelNumber%)\r
 125\r
-Companion1PositionX% = 0\r
-Companion1PositionY% = 0\r
-aiia1 = 0\r
-Companion2PositionY% = 0\r
-FOR a1 = 1 TO 32\r
-  FOR b1 = 1 TO 20\r
-    TerrainGrid(a1, b1) = ""\r
-    ObjectGrid(a1, b1) = ""\r
-  NEXT b1\r
-NEXT a1\r
-\r
-FOR a = 1 TO 20\r
-  AsciiLevelData(a) = ""\r
-NEXT a\r
+Companion1HorizontalPosition% = 0\r
+Companion1VerticalPosition% = 0\r
+Companion2HorizontalPosition = 0\r
+Companion2VerticalPosition% = 0\r
+\r
+' Clear terrain and object grids before loading new level data\r
+FOR xIndex% = 1 TO 32\r
+  FOR yIndex% = 1 TO 20\r
+    TerrainGrid(xIndex%, yIndex%) = ""\r
+    ObjectGrid(xIndex%, yIndex%) = ""\r
+  NEXT yIndex%\r
+NEXT xIndex%\r
+\r
+' Initialize ASCII level data array\r
+FOR lineCounter% = 1 TO 20\r
+  AsciiLevelData(lineCounter%) = ""\r
+NEXT lineCounter%\r
 \r
 CLS\r
 LOCATE 3, 10\r
 \r
-IF y >= 1 AND y <= 18 THEN\r
-  fileName$ = "lvl/" + LTRIM$(STR$(y)) + ".lvl"\r
+' Determine which level file to load based on requested level number\r
+IF levelNumber% >= 1 AND levelNumber% <= 18 THEN\r
+  fileName$ = "lvl/" + LTRIM$(STR$(levelNumber%)) + ".lvl"\r
   OPEN fileName$ FOR INPUT AS #1\r
-  INPUT #1, increment\r
-  i% = 1\r
+  INPUT #1, LevelNumberAdjustment%\r
+  rowIndex% = 1\r
   WHILE NOT EOF(1)\r
-    LINE INPUT #1, AsciiLevelData(i%)\r
-    i% = i% + 1\r
+    LINE INPUT #1, AsciiLevelData(rowIndex%)\r
+    rowIndex% = rowIndex% + 1\r
   WEND\r
   CLOSE #1\r
-  CurrentLevelNumber% = CurrentLevelNumber% + increment\r
+  CurrentLevelNumber% = CurrentLevelNumber% + LevelNumberAdjustment%\r
 ELSE\r
-  SELECT CASE y\r
+  ' Special handling for non-standard levels (intro screen, test levels)\r
+  SELECT CASE levelNumber%\r
   CASE 19\r
     CLS\r
     RenderSpriteFromFile 1, 1, 10, 3\r
     LOCATE 20, 1\r
     PRINT "end"\r
-    ' Wait for 50 frames before accepting input\r
-    FOR frameCount% = 1 TO 50\r
+    ' Wait for 50 frames before continuing (creates brief pause)\r
+    FOR frameCounter% = 1 TO 50\r
       inputBuffer$ = INKEY$\r
-    NEXT frameCount%\r
+    NEXT frameCounter%\r
     inputBuffer$ = INPUT$(1)\r
     CLS\r
     SCREEN 2\r
     END\r
   CASE 100\r
+    ' Create empty level with 10 blank lines\r
     FOR lineIndex% = 1 TO 10\r
       AsciiLevelData(lineIndex%) = "                "\r
     NEXT lineIndex%\r
   CASE 101\r
+    ' Create larger empty level with 19 blank lines\r
     FOR lineIndex% = 1 TO 19\r
       AsciiLevelData(lineIndex%) = "                               "\r
     NEXT lineIndex%\r
     GraphicsDisplayMode% = 2\r
   END SELECT\r
 END IF\r
-FOR e = 0 TO 9\r
-FOR D = 0 TO 15\r
-q$ = RIGHT$(LEFT$(AsciiLevelData(e + 1), D + 1), 1)\r
-IF q$ = "m" THEN PUT (D * 20, e * 20), SolidTerrainSprite, PSET: TerrainGrid(D + 1, e + 1) = "z"\r
-IF q$ = "o" THEN PUT (D * 20, e * 20), BoxSprite, PSET: TerrainGrid(D + 1, e + 1) = "z": ObjectGrid(D + 1, e + 1) = "o"\r
-IF q$ = "." THEN PUT (D * 20, e * 20), StarSprite, PSET\r
-IF q$ = "-" THEN PUT (D * 20, e * 20), CloudSprite, PSET\r
-IF q$ = "x" THEN Companion1PositionX% = D * 20: Companion1PositionY% = (e + 1) * 20\r
-IF q$ = "y" THEN Companion2PositionX% = D * 20: Companion2PositionY% = (e + 1) * 20\r
-IF q$ = "1" THEN PUT (D * 20, e * 20), CoinSprite, PSET: TerrainGrid(D + 1, e + 1) = "1"\r
-IF q$ = "p" THEN PUT (D * 20, (e * 20) + 10), BushSprite, PSET\r
-IF q$ = "h" THEN PUT (D * 20, e * 20), WindowSprite, PSET\r
-IF q$ = "v" THEN PUT (D * 20, (e * 20) + 10), TrampolineSprite, PSET: TerrainGrid(D + 1, e + 1) = "v"\r
-IF q$ = "t" THEN PUT (D * 20, e * 20), TreeSprite, PSET\r
-IF q$ = ">" THEN PUT (D * 20, e * 20), RightArrowSprite, PSET: TerrainGrid(D + 1, e + 1) = "z": ObjectGrid(D + 1, e + 1) = ">"\r
-IF q$ = "<" THEN PUT (D * 20, e * 20), LeftArrowSprite, PSET: TerrainGrid(D + 1, e + 1) = "z": ObjectGrid(D + 1, e + 1) = "<"\r
-IF q$ = "a" THEN PUT (D * 20, e * 20), HoleSprite, PSET: TerrainGrid(D + 1, e + 1) = "z": ObjectGrid(D + 1, e + 1) = "a"\r
-IF q$ = "u" THEN PUT (D * 20, e * 20), DoorSprite, PSET: TerrainGrid(D + 1, e + 1) = "u": DoorEntryX% = D * 20: DoorEntryY% = e * 20\r
-IF q$ = "U" THEN PUT (D * 20, e * 20), DoorSprite, PSET: TerrainGrid(D + 1, e + 1) = "U": DoorExitX% = D * 20: DoorExitY% = e * 20\r
-NEXT D\r
-NEXT e\r
+\r
+' Parse ASCII level representation into game world\r
+FOR rowIndex% = 0 TO 9\r
+  FOR columnIndex% = 0 TO 15\r
+    ' Extract single character from level data at current position\r
+    currentCharacter$ = RIGHT$(LEFT$(AsciiLevelData(rowIndex% + 1), columnIndex% + 1), 1)\r
+\r
+    ' Interpret character codes to build terrain and place objects:\r
+    ' "m" = solid block (terrain)\r
+    IF currentCharacter$ = "m" THEN PUT (columnIndex% * 20, rowIndex% * 20), SolidTerrainSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "z"\r
+\r
+    ' "o" = breakable box (both terrain and object properties)\r
+    IF currentCharacter$ = "o" THEN PUT (columnIndex% * 20, rowIndex% * 20), BoxSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "z": ObjectGrid(columnIndex% + 1, rowIndex% + 1) = "o"\r
+\r
+    ' "." = star decoration (cosmetic only)\r
+    IF currentCharacter$ = "." THEN PUT (columnIndex% * 20, rowIndex% * 20), StarSprite, PSET\r
+\r
+    ' "-" = cloud decoration (cosmetic only)\r
+    IF currentCharacter$ = "-" THEN PUT (columnIndex% * 20, rowIndex% * 20), CloudSprite, PSET\r
+\r
+    ' "x" = starting position for first companion hedgehog\r
+    IF currentCharacter$ = "x" THEN Companion1HorizontalPosition% = columnIndex% * 20: Companion1VerticalPosition% = (rowIndex% + 1) * 20\r
+\r
+    ' "y" = starting position for second companion hedgehog\r
+    IF currentCharacter$ = "y" THEN Companion2HorizontalPosition% = columnIndex% * 20: Companion2VerticalPosition% = (rowIndex% + 1) * 20\r
+\r
+    ' "1" = collectible coin\r
+    IF currentCharacter$ = "1" THEN PUT (columnIndex% * 20, rowIndex% * 20), CoinSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "1"\r
+\r
+    ' "p" = decorative bush (rendered slightly lower)\r
+    IF currentCharacter$ = "p" THEN PUT (columnIndex% * 20, (rowIndex% * 20) + 10), BushSprite, PSET\r
+\r
+    ' "h" = window decoration\r
+    IF currentCharacter$ = "h" THEN PUT (columnIndex% * 20, rowIndex% * 20), WindowSprite, PSET\r
+\r
+    ' "v" = trampoline that boosts player upward when landed on\r
+    IF currentCharacter$ = "v" THEN PUT (columnIndex% * 20, (rowIndex% * 20) + 10), TrampolineSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "v"\r
+\r
+    ' "t" = tree decoration\r
+    IF currentCharacter$ = "t" THEN PUT (columnIndex% * 20, rowIndex% * 20), TreeSprite, PSET\r
+\r
+    ' ">" = right-moving conveyor belt (overrides normal movement)\r
+    IF currentCharacter$ = ">" THEN PUT (columnIndex% * 20, rowIndex% * 20), RightArrowSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "z": ObjectGrid(columnIndex% + 1, rowIndex% + 1) = ">"\r
+\r
+    ' "<" = left-moving conveyor belt (overrides normal movement)\r
+    IF currentCharacter$ = "<" THEN PUT (columnIndex% * 20, rowIndex% * 20), LeftArrowSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "z": ObjectGrid(columnIndex% + 1, rowIndex% + 1) = "<"\r
+\r
+    ' "a" = bottom breakable block (similar to "o" but different behavior)\r
+    IF currentCharacter$ = "a" THEN PUT (columnIndex% * 20, rowIndex% * 20), HoleSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "z": ObjectGrid(columnIndex% + 1, rowIndex% + 1) = "a"\r
+\r
+    ' "u" = entry door for teleportation system\r
+    IF currentCharacter$ = "u" THEN PUT (columnIndex% * 20, rowIndex% * 20), DoorSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "u": DoorEntryX% = columnIndex% * 20: DoorEntryY% = rowIndex% * 20\r
+\r
+    ' "U" = exit door for teleportation system (pairs with "u")\r
+    IF currentCharacter$ = "U" THEN PUT (columnIndex% * 20, rowIndex% * 20), DoorSprite, PSET: TerrainGrid(columnIndex% + 1, rowIndex% + 1) = "U": DoorExitX% = columnIndex% * 20: DoorExitY% = rowIndex% * 20\r
+  NEXT columnIndex%\r
+NEXT rowIndex%\r
 END SUB\r
 \r
 SUB RenderSpriteFromFile (x%, y%, spriteID%, animationFrame%)\r
-'\r
-' Renders a sprite on screen by loading pixel data from external file\r
+' Renders a sprite on screen by loading pixel data directly from external file\r
 ' File format explanation:\r
-' - First line contains height (number of rows)\r
-' - Subsequent lines contain strings of digit characters:\r
-'     '0' = transparent/background\r
-'     '1'-'3' = color indexes (mapped to current palette)\r
-' Example file for 3x2 sprite:\r
+' - First line contains height (number of pixel rows in sprite)\r
+' - Subsequent lines contain strings of digit characters where:\r
+'     '0' = transparent/background (no drawing)\r
+'     '1'-'3' = color values (mapped to current palette)\r
+' Example file for simple 3x2 sprite:\r
 '     2\r
 '     123\r
 '     010\r
 '\r
 ' Parameters:\r
-' x%, y%        = Top-left drawing position\r
-' spriteID%     = Which sprite file to load (img/<id>.i01)\r
-' animationFrame% = Special handling:\r
-'                   1 = normal rendering\r
-'                   50 = horizontally flipped\r
-'                   Other values = scaled rendering (value = scale factor)\r
+' xPosition%, yPosition%   = Top-left drawing coordinates on screen\r
+' spriteID%                = Which sprite file to load (references img/<id>.i01)\r
+' animationFrame%          = Special rendering mode selector:\r
+'                            1 = normal rendering\r
+'                            50 = horizontally flipped version\r
+'                            Other values = scaled rendering (value indicates scale factor)\r
 \r
 DIM rowText AS STRING\r
 fileName$ = "img/" + LTRIM$(STR$(spriteID%)) + ".i01"\r
 OPEN fileName$ FOR INPUT AS #1\r
-INPUT #1, height%\r
-DIM spritePixelRows(1 TO 100)  AS STRING\r
-FOR rowIndex% = 1 TO height%\r
+INPUT #1, spriteHeight%\r
+DIM spritePixelRows(1 TO 100)    AS STRING\r
+FOR rowIndex% = 1 TO spriteHeight%\r
     LINE INPUT #1, spritePixelRows(rowIndex%)\r
 NEXT rowIndex%\r
 CLOSE #1\r
 \r
-' Handle special rendering modes based on animationFrame parameter\r
+' Handle special rendering modes based on animation frame parameter\r
 IF animationFrame% = 50 THEN GOTO DrawFlippedSprite\r
 \r
+' Normal rendering - draw pixels from top to bottom, left to right\r
 FOR rowIndex% = 1 TO 100\r
     IF spritePixelRows(rowIndex%) = "" THEN GOTO FinishDrawing\r
-    FOR columnIndex% = 1 TO LEN(spritePixelRows(rowIndex%))\r
-        ' Convert character digit to numeric color value (0-3)\r
-        pixelColor% = ASC(RIGHT$(LEFT$(spritePixelRows(rowIndex%), columnIndex%), 1)) - 48\r
-        ' Calculate actual screen position considering scaleFactor\r
-        PSET ((x% + columnIndex%), (y% + rowIndex%)), pixelColor%\r
-    NEXT columnIndex%\r
+    FOR pixelColumn% = 1 TO LEN(spritePixelRows(rowIndex%))\r
+        ' Convert character digit to numeric color value\r
+        ' ASCII '0'=48, so subtracting 48 gives 0-9 numeric value\r
+        pixelColor% = ASC(RIGHT$(LEFT$(spritePixelRows(rowIndex%), pixelColumn%), 1)) - 48\r
+\r
+        ' Only draw non-zero pixels (0 is treated as transparent)\r
+        IF pixelColor% > 0 THEN PSET ((xPosition% + pixelColumn%), (yPosition% + rowIndex%)), pixelColor%\r
+    NEXT pixelColumn%\r
 NEXT rowIndex%\r
 GOTO FinishDrawing\r
 \r
 DrawFlippedSprite:\r
-' Horizontally flipped rendering\r
+' Horizontally flipped rendering - mirror image for left-facing sprites\r
 FOR rowIndex% = 1 TO 100\r
     IF spritePixelRows(rowIndex%) = "" THEN GOTO FinishDrawing\r
     FOR columnIndex% = 1 TO LEN(spritePixelRows(rowIndex%))\r