How I created a fully functional Flappy Bird game and learned valuable lessons about game development, debugging, and problem-solving along the way pair with AmazonQ CLI
๐ฎ The Challenge
Ever wondered what it takes to recreate one of the most addictive mobile games of all time? I recently embarked on a journey to build Flappy Bird from scratch using modern web technologies, and let me tell you - it was quite an adventure!
Tech Stack:
- ๐ฏ Phaser 3 - Game engine
- ๐ TypeScript - Type safety and better DX
- ๐ฆ Rollup - Module bundling
- ๐จ HTML5 Canvas - Rendering
- ๐ Web Audio API - Sound effects
๐ The Development Journey
Phase 1: Setting Up the Foundation
The project started with a clean architecture approach:
flappy-bird-game/
โโโ src/
โ โโโ scenes/ # Game scenes (Menu, Game, GameOver)
โ โโโ objects/ # Game entities (Bird, PipeManager, Background)
โ โโโ config/ # Game configuration
โ โโโ assets/ # Images and sounds
Key decisions:
- TypeScript for better code maintainability
- Scene-based architecture for clean separation of concerns
- Component-based game objects for reusability
Phase 2: The Physics and Animation
Creating the bird was surprisingly fun! Here's what made it special:
export class Bird {
private sprite: Phaser.Physics.Arcade.Sprite;
flap(): void {
this.sprite.setVelocityY(GameConfig.bird.flapStrength); // -350 px/s
this.flapSound.play();
}
update(): void {
// Realistic rotation based on velocity
if (this.sprite.body.velocity.y < 0) {
this.sprite.setRotation(-0.5); // Upward tilt
} else {
this.sprite.setRotation(Math.min(0.5, this.sprite.rotation + 0.05));
}
}
}
The magic details:
- โจ Smooth rotation that follows physics
- ๐ต Sound feedback on every flap
- ๐ญ 3-frame animation for wing flapping
Phase 3: The Great Scoring System Debugging Saga ๐
This is where things got really interesting. What seemed like a simple feature turned into a fascinating debugging adventure!
The Problem: Score Wasn't Working! ๐ฑ
// โ This approach FAILED miserably
this.physics.add.overlap(bird, pipes, (bird, object) => {
if (object.getData('isScoreTrigger')) {
score++; // Never executed!
}
});
The symptoms:
- Game loaded perfectly โ
- Bird physics worked โ
- Pipes generated correctly โ
- Score remained stubbornly at 0 โ
The Investigation ๐
Through extensive console logging, I discovered:
- Overlap detection wasn't firing for invisible score triggers
- Mixed object types in physics groups caused conflicts
- Phaser's collision system was more complex than expected
// Debug logs revealed the truth:
console.log('Bird position:', birdX, birdY); // โ
Working
console.log('Score trigger created:', triggerX); // โ
Working
console.log('Overlap detected:', object); // โ Never appeared!
The Breakthrough: Manual Position Tracking ๐ก
Instead of fighting with Phaser's physics system, I implemented a custom scoring algorithm:
private checkScoreManually(): void {
const birdX = 50; // Bird stays at fixed X position
this.scoreTriggers.forEach(trigger => {
// Pipes move left: X(t) = Xโ + velocity ร deltaTime
trigger.x += GameConfig.pipes.speed * deltaTime; // -200 px/s
// Score when pipe passes bird (left movement)
if (!trigger.scored && trigger.x <= birdX && trigger.x > birdX - 50) {
trigger.scored = true;
this.passedPipes++;
this.scene.events.emit('score-updated', this.passedPipes);
}
});
}
The key insight: In Flappy Bird, the bird doesn't move horizontally - the pipes move toward the bird! ๐คฏ
๐ฏ Technical Highlights
1. Smart Asset Management
// Automated asset copying during build
const copyAssets = () => {
copyDir('./src/assets', './dist/src/assets');
console.log('Assets copied successfully!');
};
2. Persistent High Score System
// Simple but effective localStorage implementation
const highScore = localStorage.getItem('flappyHighScore') || 0;
if (currentScore > highScore) {
localStorage.setItem('flappyHighScore', String(currentScore));
showNewRecordAnimation(); // โจ Visual feedback
}
3. Performance Optimizations
- Object pooling for pipes
- Manual cleanup of off-screen objects
- Efficient collision detection only where needed
- Optimized sprite animations
๐ The Final Result
After solving the scoring system puzzle, everything clicked into place:
Game Features:
- โ Smooth 60fps gameplay
- โ Accurate collision detection
- โ Persistent high scores
- โ Sound effects and animations
- โ Responsive controls (mouse + keyboard)
- โ Mobile-friendly design
๐ Lessons Learned
1. Sometimes Simple Solutions Win
Complex framework features aren't always the answer. My manual position tracking turned out to be more reliable than Phaser's built-in collision system.
2. Debug Logging is Your Best Friend
console.log('๐ฏ Manual score detection! Pipe passed bird at X:', triggerX);
console.log('โ
New score:', this.passedPipes);
Those emoji-filled logs made debugging actually enjoyable!
3. Understanding Game Mechanics Matters
I initially misunderstood how Flappy Bird works. The bird doesn't move horizontally - this insight was crucial for fixing the scoring system.
4. TypeScript + Game Development = โค๏ธ
Type safety caught numerous bugs before runtime and made refactoring much safer.
๐ง The Architecture That Worked
graph TB
A[GameScene] --> B[Bird]
A --> C[PipeManager]
A --> D[Background]
C --> E[Manual Score Detection]
B --> F[Physics & Animation]
A --> G[Collision System]
H[GameConfig] --> A
Key Components:
- GameScene: Orchestrates everything
- Bird: Physics-based player character
- PipeManager: Obstacle generation + custom scoring
- Background: Scrolling environment
- GameConfig: Centralized configuration
๐ Try It Yourself!
Want to build your own version? Here's the quick start:
# Clone and setup
git clone <your-repo>
cd flappy-bird-game
npm install
# Build and run
npm run build
npm run serve
# Open http://localhost:8080
Pro tips for aspiring game developers:
- Start with a simple game loop
- Add one feature at a time
- Debug with extensive logging
- Don't be afraid to try different approaches
- Test frequently on different devices
๐ฎ What's Next?
The game is fully playable, but there's always room for improvement:
- ๐ฑ Mobile touch controls
- ๐จ Particle effects for enhanced visuals
- ๐ Online leaderboards
- ๐ต Background music
- ๐ง Level editor
๐ญ Final Thoughts
Building Flappy Bird taught me that game development is as much about problem-solving as it is about coding. The scoring system bug that initially frustrated me became the most educational part of the entire project.
The real victory wasn't just creating a working game - it was learning to debug systematically, think creatively about solutions, and persist through challenging problems.
Whether you're a seasoned developer or just starting out, I encourage you to try building a simple game. You'll be surprised by how much you learn about programming, problem-solving, and the satisfaction of creating something interactive and fun!
๐ Resources & Links
- ๐ฎ Play the Game
- ๐ป Source Code
- ๐ AmazonQ CLI Docs
- โจ AmazonQ CLI Challenges and T-shirts
- ๐ Phaser 3 Documentation
- ๐ฏ TypeScript Handbook
What's your experience with game development? Have you faced similar debugging challenges? Share your stories in the comments below! ๐
Happy coding, and may your birds always flap smoothly! ๐ฆโจ
Tags: #AmazonQCLI #gamedev #typescript #phaser #javascript #webdev #debugging #flappybird #html5games


Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.