Advanced Game Tutorial: Space Shooter (MIT App Inventor)
Overview
This tutorial walks you through building an advanced 2D arcade-style Space Shooter using MIT App Inventor. You'll
learn about Canvas and ImageSprite usage, dynamic sprite creation/removal, collision handling, scoring, power-ups,
level progression, boss fights, persistent high scores (TinyDB), sound effects, and basic performance tips.
Learning objectives
• Design a responsive game UI using Canvas & ImageSprites.
• Spawn enemies and bullets dynamically and manage them efficiently.
• Detect collisions (player/enemy/bullet/power-up) and implement consequences.
• Implement scoring, levels, lives, and a boss encounter.
• Persist high scores using TinyDB and optionally use Firebase for leaderboards.
• Add sound, notifications, and polish (pause, restart, UI feedback).
Required components & assets
• Visible components: Screen1, Canvas (full-screen or large area), Labels (Score, Lives, Level), Buttons (Shoot,
Pause), ListView (optional high-score view).
• Sprites: Player ImageSprite, Enemy ImageSprite(s), Bullet ImageSprite(s), PowerUp ImageSprite(s), Boss
ImageSprite, Explosion animation frames (optional).
• Non-visible components: Clock (GameLoop), Sound (Sound effects & music), Notifier, TinyDB (high scores),
AccelerometerSensor (optional for tilt controls), FirebaseDB (optional for online leaderboard).
• Assets: PNG images for player, enemies, bullets, power-ups, background tiles/images (for scrolling), sound files
(shoot, explosion, background music). Recommended sizes: Player ~48x48, Enemies 32–64px, Bullets 16–24px,
Background at least canvas size or tiled for scrolling.
Step-by-step build
Step 1 — Project setup
1. Create a new project: name it SpaceShooter. 2. Set Screen1 Orientation to 'Landscape' for a horizontal playfield.
3. Add a Canvas component (set Width to Fill Parent, Height to Fill Parent or a fixed height). Set BackgroundImage to
a starfield or space image (or plan to tile/scroll a background).
Step 2 — Design the visible UI
On Screen1, add and arrange these visible components: - Canvas1 (the game area). Place Labels on top
(ScoreLabel, LivesLabel, LevelLabel). - Buttons: ButtonShoot (for touch controls), ButtonLeft & ButtonRight (optional),
ButtonPause. - Optional: ListView to show High Scores on Screen2. Position Labels at the top using
HorizontalArrangement and style them (font size, color). For mobile screens, make sure controls do not overlap
Canvas.
Step 3 — Add non-visible components
From Palettes, add: - Clock1: set TimerInterval to 30–50 ms (game loop cadence). Start it enabled = false initially. -
Sound components (or Player) for background music and effects. - TinyDB1: store high scores locally. - Notifier1: to
show messages if needed. - AccelerometerSensor1: optional, if you want tilt controls. If you plan to sync
leaderboards, add FirebaseDB and configure the URL and token.
Step 4 — Variables and data structures
In the Blocks editor initialize the global variables you'll need. Example variables:
• global PlayerSprite = null (will hold the player ImageSprite reference)
• global Bullets = create empty list (store bullet sprite references)
• global Enemies = create empty list (store enemy sprite references)
• global PowerUps = create empty list
• global Score = 0
• global Lives = 3
• global Level = 1
• global SpawnRate = 1000 (milliseconds, used with additional timers)
• global GameRunning = false
Step 5 — Create the Player sprite
Recommended approach: At Screen1.Initialize, create the Player sprite using Canvas1.CreateImageSprite so you can
reference it easily.
1 When Screen1.Initialize:
2 set global GameRunning to false
3 set global Score to 0; set LabelScore.Text to 0
4 call Canvas1.CreateImageSprite(playerImage, x=Canvas1.Width/2, y=Canvas1.Height - 80)
-> returns sprite reference
5 set global PlayerSprite to that sprite
6 set PlayerSprite.Width/Height to desired size
7 set PlayerSprite.Bouncing to false; set PlayerSprite.Visible to true
Step 6 — Player controls (tilt and touch options)
Option A — On-screen buttons: - When ButtonLeft.Pressed: change PlayerSprite.X by -playerSpeed (ensure within
canvas bounds). - When ButtonRight.Pressed: change PlayerSprite.X by +playerSpeed. - When ButtonShoot.Click:
spawn a new bullet. Option B — Accelerometer (tilt): - Use AccelerometerSensor.AccelerationChanged to move the
player's X based on the X acceleration value. Make sure to clamp PlayerSprite.X between 0 and Canvas1.Width -
PlayerSprite.Width.
Step 7 — Shooting: player bullets
Create bullets dynamically so they can be fired rapidly. Use Canvas1.CreateImageSprite for bullets and store
references in global Bullets list.
1 When ButtonShoot.Click (or when touch input triggers shooting):
2 call Canvas1.CreateImageSprite(bulletImage, x=global PlayerSprite.X, y=global
PlayerSprite.Y - offset) -> returns bulletSprite
3 set bulletSprite.Tag to 'playerBullet' (or set a custom property in a parallel list)
4 set bulletSprite.Velocity (or use Y property in Clock loop) to move upward
5 add bulletSprite to global Bullets
Step 8 — Spawning enemies
Enemies can be simple downward-moving sprites. To spawn: - On a secondary Clock (EnemySpawnClock) with
Interval = spawnRate, create enemies at random X positions near the top of the Canvas. - Give enemies a Tag like
'enemy' and set their Speed / Heading (e.g., Heading = 180 to move downwards). - Add them to global Enemies list
for tracking.
Step 9 — Game loop and movement
Use Clock1.Timer as the main game loop. On each tick: - Move bullets upward (decrease their Y). If Y < 0, remove
and delete the sprite from global Bullets. - Move enemies downward (increase their Y). If Y > Canvas1.Height, remove
and delete from global Enemies and decrease lives. - Detect collisions using 'when ImageSprite.CollidedWith' events
for player/enemy/bullet/powerup. - Update ScoreLabel and LivesLabel accordingly.
Step 10 — Collision handling (core logic)
Use these event handlers and logic patterns:
• When bullet.CollidedWith(other): if bullet.Tag = 'playerBullet' and other.Tag = 'enemy' → remove both sprites,
add explosion (optional), increase Score, remove enemy from global Enemies and bullet from global Bullets,
chance to spawn PowerUp.
• When PlayerSprite.CollidedWith(enemy): reduce global Lives by 1, show damage animation and temporary
invincibility, remove enemy (and play explosion). If Lives <= 0 then call GameOver procedure.
• When PlayerSprite.CollidedWith(powerUp): apply effect (e.g., set rapidFire = true for N seconds, or add 1 life),
remove powerup sprite.
Step 11 — Power-ups and special items
On enemy destruction, randomly spawn a power-up (extra life, shield, rapid fire). Implement a timer-based effect
expiration for temporary boosts.
Step 12 — Level progression & boss
Increase difficulty by adjusting spawn rates, enemy speed, and type variety as Score or Level increases. At certain
thresholds (e.g., Score >= 1000), spawn a Boss: - Boss is a bigger ImageSprite with HP (store HP in a parallel list or
use Tag 'bossHP'). - Boss attacks by creating enemy bullets and moving in patterns (left-right oscillation). - Only
remove Boss when HP <= 0 and reward the player with big score/next level.
Step 13 — Game over, pause, and UI flow
Implement procedures: - Procedure StartGame: initialize variables, clear existing sprites, start clocks, set
GameRunning to true. - Procedure PauseGame: set GameRunning to false, stop clocks and music. - Procedure
GameOver: stop clocks, show Game Over screen (can be Screen2), check and store high score in TinyDB.
Step 14 — Saving high scores with TinyDB
When GameOver runs, compare current Score to stored high score: use TinyDB.GetValue tag 'HighScore' and then
TinyDB.StoreValue if current Score is higher. Optionally store a list of top scores with player names (use TinyDB with
tag 'HighScores' containing a list of name-score pairs).
Step 15 — Sound, music, and polish
- Play background music in a loop (Sound.Play) while GameRunning. - Play sound effects on shooting and
explosions. - Add visual feedback like brief sprite flashes on damage, or screen shake by offsetting background
slightly.
Step 16 — Performance tips
Mobile devices have limited CPU for App Inventor games. Tips:
• Reuse sprites when possible instead of creating/destroying many objects each frame (object pooling pattern).
• Keep Clock intervals balanced — too fast wastes CPU, too slow makes game choppy; 30–50 ms is common.
• Limit number of on-screen sprites; hide offscreen sprites and reuse them.
• Minimize heavy computations inside Clock.Timer — precompute values when possible.
Step 17 — Debugging & testing checklist
• Test input methods separately (buttons vs tilt).
• Check collisions at various sprite sizes and speeds.
• Monitor memory by testing long play sessions (look for slowdowns).
• Test under different screen sizes and orientations.
• Verify TinyDB values are stored and retrieved correctly.
Step 18 — Example block pseudocode
1 When Screen1.Initialize:
2 call StartGame()
4 Procedure StartGame:
5 set global Score to 0; update LabelScore
6 set global Lives to 3; update LabelLives
7 clear global Bullets, Enemies, PowerUps (delete sprites if exist)
8 create Player sprite and store in global PlayerSprite
9 enable Clock1 (game loop) and EnemySpawnClock
11 When EnemySpawnClock.Timer:
12 create enemy at random X, Y = -enemyHeight
13 set enemy.Tag = 'enemy'; add to global Enemies
15 When Clock1.Timer:
16 for each bullet in global Bullets: move bullet upward; if offscreen remove
17 for each enemy in global Enemies: move enemy downward; if offscreen remove and
decrement Lives
18 check collisions (handled in ImageSprite.CollidedWith events)
20 When bullet.CollidedWith(other):
21 if bullet.Tag = 'playerBullet' and other.Tag = 'enemy': remove both; set global Score
= global Score + points; update score label
23 When PlayerSprite.CollidedWith(enemy):
24 decrement Lives; if Lives <=0 call GameOver
26 Procedure GameOver:
27 disable clocks; show Game Over screen; store high score in TinyDB
Assets & Recommended Sizes
Asset Recommended size (px) Notes
Player sprite 48 x 48 Clear silhouette, transparent background
Enemy sprites 32–64 px Consistent style; different colors for variants
Bullet sprites 16–24 px Small and fast-moving
Power-up icons 24–32 px Distinct shapes/colors for easy recognition
Background Canvas size or tiling Seamless if scrolling
Extensions & next steps
• Add online leaderboard using FirebaseDB (store a list keyed by 'HighScores').
• Implement power-up shop and in-app purchases (if publishing to stores beyond App Inventor's scope).
• Add achievements and share high scores via SocialSharing (Web component interaction).
• Add more polish: parallax background layers, particle effects (small circles), and animations.
Final notes
This tutorial gives a structured plan—step-by-step logic and block pseudocode—for creating a polished Space
Shooter in MIT App Inventor. Because App Inventor is a visual, event-driven environment, implement the pseudocode
with the corresponding blocks: CreateImageSprite, ImageSprite.CollidedWith, Clock.Timer,
Canvas1.CreateImageSprite, TinyDB.StoreValue/GetValue, etc. If you'd like, I can generate a second PDF containing
exact block-screen screenshots and a ready-to-import asset pack (images + sounds) with suggested file names.