Chapter 16: Is It Soup Yet?

Example Assets Needed:
This chapter builds a complete game! You'll need:

Sprites:

  • player.png — 32x32 character spritesheet (4 frames for animation)
  • coin.png — 16x16 collectible spritesheet (4 frames for spin animation)

Sound Effects (.wav):

  • coin.wav — Collect sound
  • miss.wav — Miss/fail sound
  • gameover.wav — Game over jingle

Music (.mp3):

  • music.mp3 — Loopable background music

If you've been following along, you already have most of these from earlier chapters!

You've learned variables, loops, conditionals, graphics, sprites, sound, saving, behaviors, collisions... that's a LOT of ingredients!

But here's the thing about soup: having all the ingredients doesn't mean you have soup. You need to combine them, let them simmer, taste-test, adjust the seasoning...

Is YOUR game soup yet?

This chapter is about putting it all together. We'll build a complete game from scratch, and along the way, I'll share the secrets to making your game feel FINISHED—not just functional.


The Game Development Recipe

Every good game follows a recipe. Here's mine:

1. Start With the Core Loop

What does the player DO? Over and over? That's your core loop.

  • Platformer: Jump, avoid obstacles, reach the goal
  • Shooter: Move, shoot, dodge
  • Puzzle: Think, move pieces, solve

Get this working FIRST. No fancy graphics, no sound, no menus. Just the core loop with rectangles and placeholder art.

2. Add Juice (Feedback)

"Juice" is game developer slang for all the little things that make actions feel GOOD:

  • Screen shake when you get hit
  • Particles when you collect coins
  • Sound effects for EVERYTHING
  • Brief pauses on big impacts
  • Sprite scaling/flashing on damage

3. Add Structure

  • Title screen
  • Game over screen
  • Score/lives display
  • Maybe levels or progression

4. Polish and Test

  • Fix bugs
  • Balance difficulty
  • Add final art and sound
  • Test on friends!

5. Ship It

Done is better than perfect. At some point, you have to call it soup and serve it!


Let's Make Some Soup!

Time to build a complete game using EVERYTHING we've learned. We're making Coin Catcher—a simple but polished arcade game.

The concept: Coins fall from the sky. Catch them to score points. Miss too many and it's game over. As you play, coins fall faster!

Step 1: Project Setup

' ================================================
' COIN CATCHER
' A complete game example
' ================================================

SCREEN 13    ' 320x200, 256 colors

' ================================================
' LOAD ALL RESOURCES UPFRONT
' ================================================
LOADPNG "player.png", "player" AS SPRITESHEET(32, 32)
LOADPNG "coin.png", "coin" AS SPRITESHEET(16, 16)
LOADWAV "coin.wav", "coinSound"
LOADWAV "miss.wav", "missSound"
LOADWAV "gameover.wav", "gameoverSound"
LOADMP3 "music.mp3", "bgm"

Lesson from Chapter 12: Load ALL resources at the start. No stuttering mid-game!

Step 2: Define Behaviors

' ================================================
' DEFINE BEHAVIORS (Chapter 14)
' ================================================

BEHAVIOR "playerIdle"
    ANIMATE "player", 0, 1 FRAMERATE 5
END BEHAVIOR

BEHAVIOR "playerLeft"
    ANIMATE "player", 2, 3 FRAMERATE 10
    BFLIPX ON
END BEHAVIOR

BEHAVIOR "playerRight"
    ANIMATE "player", 2, 3 FRAMERATE 10
    BFLIPX OFF
END BEHAVIOR

BEHAVIOR "coinFall"
    ANIMATE "coin", 0, 1, 2, 3 FRAMERATE 8
    BOSCILLATE AMPLITUDE 3, 0    ' Wobble side to side
END BEHAVIOR

BEHAVIOR "coinCollected"
    BSCALE 1, 1 TO 2, 2 DURATION 10
    BALPHA 1 TO 0 DURATION 10
END BEHAVIOR

Lesson from Chapter 14: Define behaviors once, use everywhere!

Step 3: Define Patterns

' ================================================
' DEFINE PATTERNS (Chapter 14)
' ================================================

PATTERN "playerControl" LOOP
    "playerIdle"
    "playerLeft" WHEN KEYDOWN("LEFT")
    "playerRight" WHEN KEYDOWN("RIGHT")
END PATTERN

PATTERN "coinDeath"
    "coinCollected"
    DISABLE
END PATTERN

Step 4: Game State (Using Custom Types!)

' ================================================
' GAME STATE (Chapter 11 - Custom Types)
' ================================================

TYPE GameState
    score AS INTEGER
    lives AS INTEGER
    level AS INTEGER
    coinsSpawned AS INTEGER
    coinSpeed AS SINGLE
    gameOver AS INTEGER
    paused AS INTEGER
END TYPE

DIM game AS GameState

Step 5: Initialize Game

' ================================================
' INITIALIZE GAME
' ================================================

SUB InitGame()
    game.score = 0
    game.lives = 3
    game.level = 1
    game.coinsSpawned = 0
    game.coinSpeed = 2
    game.gameOver = FALSE
    game.paused = FALSE

    ' Clear any existing sprites
    FOR i = 0 TO 99
        DISABLE SPRITE i
    NEXT i

    ' Create player (sprite 0)
    ENABLE SPRITE 0
    SET SPRITE 0, 160, 170, "player" TAG "player"
    SET SPRITE 0 PATTERN "playerControl"

    ' Set up boundaries (Chapter 14)
    BOUNDARY CLEAR
    BOUNDARY ADD "left", (0, 0)-(10, 200) SOLID
    BOUNDARY ADD "right", (310, 0)-(320, 200) SOLID
    BOUNDARY ADD "floor", (0, 190)-(320, 200)    ' Not solid - coins pass through

    ' Start music
    PLAYMP3 "bgm", 1
END SUB

Step 6: Spawn Coins

' ================================================
' SPAWN COINS
' ================================================

SUB SpawnCoin()
    s = NEXTFREESPRITE()
    IF s > 0 AND s < 50 THEN    ' Reserve sprites 50+ for effects
        ENABLE SPRITE s
        SET SPRITE s, INT(RND * 280) + 20, -20, "coin" TAG "coin"
        SET SPRITE s BEHAVIOR "coinFall"

        ' Speed increases with level
        SET SPRITE s SPEED game.coinSpeed

        game.coinsSpawned = game.coinsSpawned + 1
    END IF
END SUB

Step 7: Update Game Logic

' ================================================
' UPDATE GAME
' ================================================

SUB UpdateGame()
    IF game.paused OR game.gameOver THEN EXIT SUB

    ' Move player with keyboard
    px = SPRITEX(0)
    IF KEYDOWN("LEFT") AND px > 20 THEN
        MOVE SPRITE 0, px - 4, SPRITEY(0)
    END IF
    IF KEYDOWN("RIGHT") AND px < 300 THEN
        MOVE SPRITE 0, px + 4, SPRITEY(0)
    END IF

    ' Move coins down
    FOR SPRITES s, "coin"
        MOVE SPRITE s, SPRITEX(s), SPRITEY(s) + game.coinSpeed
    NEXT SPRITE

    ' Check for coins that fell off screen
    FOR SPRITES s, "coin"
        IF SPRITEY(s) > 200 THEN
            DISABLE SPRITE s
            game.lives = game.lives - 1
            PLAYWAV "missSound"

            IF game.lives <= 0 THEN
                game.gameOver = TRUE
                STOPMP3 "bgm"
                PLAYWAV "gameoverSound"
            END IF
        END IF
    NEXT SPRITE

    ' Collision detection
    FOR COLLISIONS a, b
        tagA$ = SPRITETAG$(a)
        tagB$ = SPRITETAG$(b)

        IF (tagA$ = "player" AND tagB$ = "coin") OR (tagB$ = "player" AND tagA$ = "coin") THEN
            ' Find which one is the coin
            IF tagA$ = "coin" THEN
                coinSprite = a
            ELSE
                coinSprite = b
            END IF

            ' Collect it!
            SET SPRITE coinSprite PATTERN "coinDeath"
            SET SPRITE coinSprite TAG "collected"    ' Prevent double-collection
            game.score = game.score + 10
            PLAYWAV "coinSound"

            ' Level up every 100 points
            IF game.score MOD 100 = 0 THEN
                game.level = game.level + 1
                game.coinSpeed = game.coinSpeed + 0.5
            END IF
        END IF
    NEXT COLLISION

    ' Spawn new coins periodically
    IF TIMER MOD 30 = 0 THEN
        SpawnCoin
    END IF
END SUB

Step 8: Draw UI

' ================================================
' DRAW UI (Chapters 5 & 9)
' ================================================

SUB DrawUI()
    ' Score
    LOCATE 1, 1
    COLOR 15
    PRINT "Score: "; game.score

    ' Lives (draw hearts)
    LOCATE 1, 30
    FOR i = 1 TO game.lives
        PRINT CHR$(3);    ' Heart character
    NEXT i

    ' Level
    LOCATE 1, 15
    PRINT "Level "; game.level
END SUB

SUB DrawGameOver()
    ' Darken the screen
    LINE (60, 60)-(260, 140), 0, BF
    LINE (60, 60)-(260, 140), 15, B

    WINDOW (70, 70)-(250, 130)
    COLOR 15

    LOCATE 3, 5
    PRINT "GAME OVER"

    LOCATE 5, 3
    PRINT "Final Score: "; game.score

    LOCATE 8, 2
    PRINT "Press SPACE to restart"

    WINDOW    ' Reset window
END SUB

SUB DrawPaused()
    LINE (100, 80)-(220, 120), 0, BF
    LINE (100, 80)-(220, 120), 15, B

    LOCATE 12, 13
    COLOR 15
    PRINT "PAUSED"
END SUB

Step 9: Title Screen

' ================================================
' TITLE SCREEN
' ================================================

SUB ShowTitle()
    CLS 1    ' Dark blue background

    ' Title
    LOCATE 5, 10
    COLOR 14
    PRINT "COIN CATCHER"

    LOCATE 8, 8
    COLOR 7
    PRINT "Catch the coins!"

    LOCATE 10, 6
    PRINT "Miss 3 and it's over!"

    LOCATE 14, 7
    COLOR 15
    PRINT "Press SPACE to start"

    ' Wait for space
    DO
        DELAY 16
    LOOP UNTIL KEYDOWN("SPACE")

    ' Wait for release
    DO
        DELAY 16
    LOOP UNTIL NOT KEYDOWN("SPACE")
END SUB

Step 10: Main Game Loop

' ================================================
' MAIN GAME LOOP
' ================================================

ShowTitle
InitGame

DO
    ' Handle pause
    IF KEYDOWN("P") THEN
        game.paused = NOT game.paused
        DELAY 200    ' Debounce
    END IF

    ' Update
    UpdateGame

    ' Render
    BEGIN FRAME
    CLS 9    ' Light blue sky

    ' Draw ground
    LINE (0, 180)-(319, 199), 2, BF

    ' Draw UI
    DrawUI

    IF game.paused THEN
        DrawPaused
    END IF

    IF game.gameOver THEN
        DrawGameOver
    END IF

    END FRAME
    DELAY 16

    ' Restart?
    IF game.gameOver AND KEYDOWN("SPACE") THEN
        InitGame
    END IF

LOOP UNTIL KEYDOWN("ESCAPE")

STOPMP3 "bgm"
END

The Checklist: Is It Soup Yet?

Before you call your game "done," run through this checklist:

Core Gameplay

  • Can the player DO the main thing? (move, jump, shoot, etc.)
  • Is there a goal or win condition?
  • Is there a fail state or challenge?
  • Does difficulty increase over time?

Feedback & Juice

  • Does every action have a sound?
  • Do important events have visual feedback?
  • Are there animations (not just static sprites)?
  • Does the game "feel" good to play?

Structure

  • Is there a title screen?
  • Is there a game over screen?
  • Can the player restart without closing the game?
  • Is the score/progress visible?

Polish

  • Are there any obvious bugs?
  • Is the difficulty fair (not too hard at the start)?
  • Have you tested it on someone else?
  • Does it run smoothly (no stuttering)?

Technical

  • Are all resources loaded at startup?
  • Are sprites properly disabled when not needed?
  • Is music stopped when it should be?
  • Does the game clean up properly on restart?

Common Bugs and How to Fix Them

"My sprites are disappearing randomly!"

You're probably running out of sprite slots. Use NEXTFREESPRITE() to check for available slots, and make sure you DISABLE SPRITE when sprites are no longer needed.

s = NEXTFREESPRITE()
IF s >= 0 THEN
    ' Safe to use sprite s
ELSE
    ' No sprites available!
END IF

"Collisions are triggering multiple times!"

Re-tag collected items immediately so they don't trigger again:

FOR COLLISIONS a, b
    IF SPRITETAG$(a) = "coin" AND SPRITETAG$(b) = "player" THEN
        SET SPRITE a TAG "collected"    ' Change tag immediately!
        score = score + 10
    END IF
NEXT COLLISION

"My game slows down over time!"

You're probably not cleaning up old sprites. Make sure disabled sprites are really disabled:

' When a coin goes off-screen:
DISABLE SPRITE coinSprite
SET SPRITE coinSprite BEHAVIOR NONE
SET SPRITE coinSprite PATTERN NONE

"Sound effects are overlapping weirdly!"

Limit how often a sound can play:

DIM lastSoundTime AS INTEGER

IF shouldPlaySound AND TIMER - lastSoundTime > 100 THEN
    PLAYWAV "effect"
    lastSoundTime = TIMER
END IF

"My game is too hard/too easy!"

Playtest! Watch someone else play. If they're frustrated in the first 30 seconds, it's too hard. If they're bored after a minute, it's too easy.

Start easy and ramp up gradually:

' Level 1: Slow coins, lots of lives
' Level 5: Medium coins, fewer mistakes allowed
' Level 10: Fast coins, you really need to focus!

coinSpeed = 1 + (level * 0.3)

Sharing Your Game

Once your soup is ready, it's time to serve it! Crash BASIC lets you bundle your game into a single file that others can play.

Creating a Bundle

Your game and all its resources get packaged into a .cbundle file:

  1. Make sure your game runs correctly in the IDE
  2. Use the Bundles widget to create a new bundle
  3. All your code files and resources are included automatically
  4. Give your bundle a name and export it!

What Goes in a Bundle?

mygame.cbundle/
    main.bas           <- Your main program
    helpers.bas        <- Any imported modules
    resources/
        player.png     <- All your images
        coin.png
        music.mp3      <- All your sounds
        coin.wav
    data/
        highscore.sav  <- Saved data (if any)

The Bundle is Self-Contained

When someone opens your .cbundle, they get everything they need. No missing files, no "works on my machine" problems!


Final Tips

Start Small

Your first game should be Pong, not Skyrim. Small games teach you more than unfinished big games.

Finish Things

A finished bad game is better than an unfinished masterpiece. You learn the most from the last 10% of a project.

Steal Like an Artist

Remake classic games! Pong, Breakout, Space Invaders, Snake. Understanding WHY those games work teaches you design.

Show People

Watch someone else play your game. Don't help them. Don't explain. Just watch. You'll learn SO much about what's confusing or unclear.

Have Fun

If you're not having fun making games, something's wrong. Games are about joy—including the joy of making them!


Quick Reference: Complete Game Checklist

Category Check
Resources All loaded at startup?
Behaviors Defined before use?
Sprites Properly enabled/disabled?
Collision Tagged correctly?
Sound Playing at right moments?
Music Starts/stops correctly?
UI Score/lives visible?
Flow Title → Game → Game Over → Restart?
Input Responsive and debounced?
Performance Runs at steady 60 FPS?

You Did It!

Congratulations! You've learned everything you need to make games with Crash BASIC:

  • Variables to store data
  • Conditionals to make decisions
  • Loops to repeat actions
  • Functions to organize code
  • Graphics to draw worlds
  • Sprites to bring characters to life
  • Sound to create atmosphere
  • Saving to preserve progress
  • Behaviors to automate movement
  • Collisions to create interaction

The only thing left is to MAKE GAMES!

Start simple. Finish what you start. Show people. Learn from feedback. Make another one. Get better.

Your soup is ready. Time to serve it!


Thank you for reading "Crash-tan Teaches BASIC!" Now go make something amazing!