← Back to list

Building Google Dino Game with Pygame

How I engineered a fully functional endless runner using OOP, game loop architecture, procedural spawning, and real-time physics in Python.

Ghazal Mohammadi · 2026-05-26 09:59 · 0 claps · 2.9 min read
#python #pygame #gamedev #programming
Open on Medium ↗
Wiki topics: 💻 · Programming ⚛️ · Physics 🏛️ · Architecture

Building Google Dino Game with Pygame

How I engineered a fully functional endless runner using OOP, game loop architecture, procedural spawning, and real-time physics in Python.

Introduction

Most people see the Chrome Dino game as a simple offline mini-game.But when you rebuild it from scratch, it becomes a surprisingly rich systems problem:

  • Real-time game loop synchronization
  • Entity lifecycle management
  • Procedural obstacle generation
  • Frame-based animation systems
  • Collision detection at runtime scale
  • State transitions (play → game over → reset)

This project is a reconstruction of that system using Python + Pygame, focusing less on “making a game” and more on designing a game engine architecture.

1. Game Loop as the Core Execution Model

At the heart of every real-time game lies a deterministic loop:

EVENTS → UPDATE → RENDER

This is not just structure — it is the execution contract of the entire system.

Responsibilities:

  • EVENTS → Input abstraction layer (keyboard, quit, restart)
  • UPDATE → Simulation layer (physics, AI, spawning, scoring)
  • RENDER → Presentation layer (drawing state to screen)

The separation of these concerns is what makes the system scalable.

2. Entity-Centric Design (OOP Architecture)

Instead of procedural logic, the game is built around entities:

  • Player (Dino)
  • Obstacles (Cactus, Bird)
  • World (Ground, Background)

Each entity encapsulates:

  • State
  • Behavior
  • Rendering logic

This creates a lightweight ECS-like structure (Entity Component System inspired).

3. Player System: Physics-Driven Character Controller

The Player class is not just a sprite — it is a physics simulation unit.

Core State Variables:

self.x, self.y
self.velocity_y
self.gravity
self.jump_force

Jump Physics Model

Jumping is implemented as a velocity-based system, not positional teleportation.

velocity_y = jump_force
velocity_y += gravity
y += velocity_y

Interpretation:

  • Jump initializes negative velocity (upward force)
  • Gravity continuously modifies velocity
  • Position integrates velocity over time

This creates a parabolic motion curve, not a linear jump.

Ground Constraint System

if y >= ground_y:py
    y = ground_y
    velocity_y = 0

This enforces a hard boundary condition:

  • Prevents infinite fall
  • Resets physics state cleanly

Animation Pipeline

Player animation is frame-driven:

frame_index → toggles between sprites
animation_timer → controls switching frequency

This decouples:

  • Physics update rate
  • Visual update rate

A key principle in real-time rendering systems.

4. Procedural Obstacle Generation

Obstacles are not pre-defined — they are runtime-generated events.

Spawn Logic:

if cactus_timer >= spawn_delay:
    spawn(Cactus)
    spawn_delay = random_range()

Key Design Decision:

Instead of fixed intervals, spawn timing is:

stochastic (randomized within bounds)

This prevents pattern exploitation and increases replayability.

5. Bird System: Multi-Dimensional Threat Model

Birds introduce complexity beyond ground obstacles:

Differences from Cactus:

  • Variable Y-axis positioning
  • Higher movement speed
  • Animated wing cycle

Vertical Randomization

y = random.choice([220, 250, 270])

This introduces a multi-lane aerial system, forcing dynamic player decision-making.

Animation System

frame = (frame + 1) % len(frames)

This creates a cyclic animation state machine.

6. Dynamic Environment System (Day/Night Cycle)

Instead of static visuals, the environment transitions dynamically.

State Model:

  • background_value → current state
  • target_background → desired state

Transition:

background_value += (target - current) * fade_speed

Result:

A smooth interpolation system similar to:

linear interpolation (LERP)

This avoids abrupt visual transitions and improves UX consistency.

7. Collision Detection System

Collision is handled via bounding boxes:

rect.colliderect(other.rect)

Why Rect-based?

Because:

  • Low computational cost (O(1))
  • Sufficient accuracy for simple geometry
  • Ideal for real-time systems

Collision Pipeline:

  1. Iterate obstacles
  2. Check intersection
  3. Trigger game state transition

8. Persistent Scoring System

The game implements a local persistence layer:

highscore.txt

Logic:

  • Compare runtime score
  • If greater → overwrite file
  • Persist across sessions

This introduces a primitive form of:

state persistence layer

9. System Design Overview

The architecture can be summarized as:

Game Loop
 ├── Input Layer
 ├── Simulation Layer
 │     ├── Player Physics
 │     ├── Enemy Spawning
 │     ├── Collision System
 │     └── World State
 └── Render Layer

This mirrors real-time engine architecture at a simplified scale.

Key Engineering Insights

This project demonstrates:

  • Separation of concerns in real-time systems
  • Deterministic game loop design
  • Physics simulation via velocity integration
  • Procedural content generation
  • Lightweight entity modeling
  • State-driven rendering pipeline

Source Code

GitHub Repository:

https://github.com/GhazalMDI/pygame-dino

Final Thoughts

Rebuilding something as simple as Dino reveals a deeper truth:

Even the simplest games are real-time simulation systems disguised as entertainment.

What looks like a “small project” is actually a complete miniature engine architecture.


메타데이터
post_id
1d2e6d9dab2d
slug
building-google-dino-game-with-pygame-1d2e6d9dab2d
url
https://medium.com/@ghazal.mohammadi.developer/building-google-dino-game-with-pygame-1d2e6d9dab2d
canonical_url
https://medium.com/@ghazal.mohammadi.developer/building-google-dino-game-with-pygame-1d2e6d9dab2d
author_url
https://medium.com/@ghazal.mohammadi.developer
status
ok
fetched_at
2026-07-13 06:23:13