Back to Blog

Building Flappy Bird as a lightweight arcade clone

Emmanouil Athanasopoulos2 min read420 words
React NativeGame EnginePhysicsMobile

The Motivation Behind the Project

Flappy Bird is deceptively small as a game, which makes it a useful project for exploring how tiny changes in timing and feedback affect the whole experience. I built this clone to keep the controls simple while still making the gameplay feel tight.

Core Features and Design Goals

  • Tap-to-fly controls: one gesture drives the whole game loop.
  • Obstacle rhythm: the spacing and timing need to stay consistent enough for the game to feel fair.
  • Score chasing: a clear reward loop that makes replaying worthwhile.

Technical Implementation

  • Built a custom ECS (Entity-Component-System) architecture using React Native Game Engine with three distinct systems: Physics (gravity + flap velocity clamping at 60fps-normalized delta time), MovePipes (pipe recycling with randomized gap positioning), and CollisionDetection (AABB-vs-circle checks against four pipe surfaces and the floor).
  • Implemented level-specific gameplay modifiers including configurable gravity constants, adjustable pipe gaps, speed burst specials that randomly accelerate pipes by 1.5x, and moving pipe specials where gap positions oscillate sinusoidally by ±40px.
  • Designed a SoundManager singleton with Expo Audio that pre-loads flap, hit, score, and die sound effects, with method-level error isolation so a failed audio load never crashes the game loop.

Challenges I Faced Along the Way

The hardest part was tuning the physics constants. Gravity, flap velocity, pipe speed, and gap size all interact with each other, and changing one requires adjusting the others. I spent more time tweaking these values than writing the actual game logic. The other challenge was collision detection accuracy — AABB (axis-aligned bounding box) checks work well for rectangular pipes, but the bird sprite is roughly circular, which led to unfair-feeling deaths where the visual sprite clearly missed the pipe but the bounding box clipped it. I ended up using a circle-vs-rectangle check with a slightly smaller collision radius than the visual radius to make the game feel fair.

The Technology Stack

Built with Expo and React Native. The game loop runs on React Native Game Engine with a custom physics system (not Matter.js at runtime — gravity and velocity are manually computed per frame). Expo Audio handles sound effects, and the entity/system pattern cleanly separates rendering from game logic across Physics, MovePipes, and CollisionDetection systems.

Final Reflections

A small game can still be a serious exercise in timing, feedback, and control feel. The most surprising lesson was how much the perceived quality of a game depends on constants that have nothing to do with code quality — gravity values, gap sizes, and audio timing make or break the experience.