# Manage complex game states
class GameState:
def __init__(self):
self.states = {
'MENU': 0,
'PLAYING': 1,
'PAUSED': 2,
'GAME_OVER': 3,
'VICTORY': 4
}
self.current_state = self.states['MENU']
def transition_to(self, state_name):
if state_name in self.states:
self.current_state = self.states[state_name]
print(f"Transitioned to: {state_name}")
def is_state(self, state_name):
return self.current_state == self.states.get(state_name)
# Usage
game_state = GameState()
print(f"Current state: MENU = {game_state.is_state('MENU')}")
game_state.transition_to('PLAYING')
print(f"Now playing: {game_state.is_state('PLAYING')}")Chapter 2.6: Advanced Game Development & Next Steps
Polish, Patterns, and Your Game Dev Journey
๐ฎ PROJECT 2.6 | Difficulty: Intermediate-Advanced | Time: 20 minutes
๐ป Interactive Options:
- ๐ Open in JupyterLite
- ๐ฅ Download Notebook (Challenge) - For use in local Jupyter or Google Colab
- ๐ก Note: Pygame runs best locally with a display, but weโll show examples!
โจ Game Juice: Making Games Feel Good
โGame juiceโ refers to all the small details that make a game feel satisfying:
Screen Shake
# Add to any game for impact!
import random
class ScreenShake:
def __init__(self):
self.shake_amount = 0
self.shake_duration = 0
def trigger(self, amount=10, duration=10):
self.shake_amount = amount
self.shake_duration = duration
def update(self):
if self.shake_duration > 0:
self.shake_duration -= 1
return (random.randint(-self.shake_amount, self.shake_amount),
random.randint(-self.shake_amount, self.shake_amount))
return (0, 0)
# Usage in game loop:
# offset_x, offset_y = screen_shake.update()
# # Apply offset when drawingParticle Effects
# Simple particle system for explosions, trails, etc.
import pygame
import random
import math
class Particle:
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
angle = random.uniform(0, 2 * math.pi)
speed = random.uniform(1, 5)
self.vx = math.cos(angle) * speed
self.vy = math.sin(angle) * speed
self.lifetime = random.randint(20, 40)
self.size = random.randint(2, 4)
def update(self):
self.x += self.vx
self.y += self.vy
self.vy += 0.2 # Gravity
self.lifetime -= 1
self.size = max(1, self.size - 0.1)
def draw(self, surface):
alpha = int(255 * (self.lifetime / 40))
color_with_alpha = (*self.color, alpha)
pygame.draw.circle(surface, self.color, (int(self.x), int(self.y)), int(self.size))
def is_alive(self):
return self.lifetime > 0
# Create explosion effect:
# particles = []
# for _ in range(20):
# particles.append(Particle(explosion_x, explosion_y, RED))Smooth Camera Follow
# For side-scrollers or larger worlds
class Camera:
def __init__(self, width, height):
self.width = width
self.height = height
self.x = 0
self.y = 0
def follow(self, target_x, target_y, lerp_factor=0.1):
"""Smoothly follow a target"""
target_camera_x = target_x - self.width // 2
target_camera_y = target_y - self.height // 2
self.x += (target_camera_x - self.x) * lerp_factor
self.y += (target_camera_y - self.y) * lerp_factor
def apply(self, x, y):
"""Convert world coordinates to screen coordinates"""
return (x - self.x, y - self.y)๐จ Advanced Patterns
State Machine
Object Pooling
# Reuse objects instead of creating/destroying (better performance)
class BulletPool:
def __init__(self, size=50):
self.bullets = []
self.available = []
for i in range(size):
bullet = {'active': False, 'x': 0, 'y': 0, 'vx': 0, 'vy': 0}
self.bullets.append(bullet)
self.available.append(bullet)
def spawn(self, x, y, vx, vy):
if self.available:
bullet = self.available.pop()
bullet['active'] = True
bullet['x'] = x
bullet['y'] = y
bullet['vx'] = vx
bullet['vy'] = vy
return bullet
return None
def recycle(self, bullet):
bullet['active'] = False
self.available.append(bullet)
def update(self):
for bullet in self.bullets:
if bullet['active']:
bullet['x'] += bullet['vx']
bullet['y'] += bullet['vy']
# Check if out of bounds
if bullet['y'] < 0 or bullet['y'] > 600:
self.recycle(bullet)
# Usage
pool = BulletPool(50)
bullet = pool.spawn(100, 100, 5, -10)
print(f"Spawned bullet: {bullet}")Component System
# Build flexible game objects with components
class GameObject:
def __init__(self, x, y):
self.x = x
self.y = y
self.components = {}
def add_component(self, name, component):
self.components[name] = component
component.owner = self
def get_component(self, name):
return self.components.get(name)
def update(self):
for component in self.components.values():
if hasattr(component, 'update'):
component.update()
class HealthComponent:
def __init__(self, max_health):
self.max_health = max_health
self.current_health = max_health
self.owner = None
def take_damage(self, amount):
self.current_health -= amount
if self.current_health <= 0:
print(f"Object at ({self.owner.x}, {self.owner.y}) destroyed!")
return True
return False
class MovementComponent:
def __init__(self, speed):
self.speed = speed
self.vx = 0
self.vy = 0
self.owner = None
def update(self):
self.owner.x += self.vx * self.speed
self.owner.y += self.vy * self.speed
# Create an enemy with components
enemy = GameObject(100, 100)
enemy.add_component('health', HealthComponent(100))
enemy.add_component('movement', MovementComponent(2))
print(f"Enemy created at ({enemy.x}, {enemy.y})")
health = enemy.get_component('health')
health.take_damage(50)
print(f"Enemy health: {health.current_health}")๐ฎ Game Types You Can Build
Now that you know Pygame, you can create:
Platformers
game_ideas = {
"Platformer": {
"Examples": "Super Mario, Celeste",
"Key Features": ["Jumping physics", "Collision with platforms", "Level design"],
"Difficulty": "โญโญโญ"
},
"Puzzle": {
"Examples": "Tetris, Match-3",
"Key Features": ["Grid logic", "Pattern matching", "Scoring systems"],
"Difficulty": "โญโญ"
},
"Top-Down": {
"Examples": "Zelda, Hotline Miami",
"Key Features": ["8-direction movement", "Camera", "Enemy AI"],
"Difficulty": "โญโญโญ"
},
"Tower Defense": {
"Examples": "BTD, Plants vs Zombies",
"Key Features": ["Path finding", "Resource management", "Wave spawning"],
"Difficulty": "โญโญโญโญ"
},
"Roguelike": {
"Examples": "Binding of Isaac, Enter the Gungeon",
"Key Features": ["Procedural generation", "Permadeath", "Random items"],
"Difficulty": "โญโญโญโญโญ"
}
}
print("๐ฎ Games You Can Build:")
for game_type, details in game_ideas.items():
print(f"\n{game_type} {details['Difficulty']}")
print(f" Examples: {details['Examples']}")
print(f" Key Features: {', '.join(details['Key Features'])}")๐ Beyond Pygame
Pygame Zero
- Simpler API for beginners
- Less boilerplate code
- Great for teaching
Arcade Library
- Modern alternative to Pygame
- Better performance
- Built-in physics
Game Engines
engines = {
"Godot": "Free, open-source, great 2D support, Python-like scripting",
"Unity": "Industry standard, C#, massive asset store",
"Unreal": "AAA quality, Blueprint visual scripting or C++",
"GameMaker": "2D focused, drag-and-drop or code",
"Love2D": "Lua-based, simple and fast"
}
print("๐ฎ When to Move to Game Engines:")
for engine, description in engines.items():
print(f" {engine}: {description}")๐ Resources for Game Developers
Learning
- PyGame Documentation: pygame.org
- Real Python Pygame Tutorial: realpython.com
- Game Programming Patterns: gameprogrammingpatterns.com
- YouTube: Brackeys, Sebastian Lague, Code Bullet
Assets
- Graphics: OpenGameArt.org, itch.io, Kenney.nl
- Sound: freesound.org, OpenGameArt.org
- Music: incompetech.com, freemusicarchive.org
Communities
- r/pygame: Reddit community
- PyGame Discord: Active Discord server
- itch.io: Share and play indie games
๐ Final Project Ideas
Portfolio Project Ideas
Build one of these to showcase your skills:
Beginner
- Flappy Bird Clone - Simple mechanics, polish matters
- Memory Match Game - Card flipping with animations
- Brick Breaker - Paddle, ball, bricks
Intermediate
- Dungeon Crawler - Random rooms, monsters, items
- Tower Defense - Path, towers, waves
- Racing Game - Top-down view, laps, time
Advanced
- Procedural Platformer - Random level generation
- Multiplayer Pong - Network play
- Card Game - Deck building, AI opponent
Tips for Great Projects: - Start small, add features incrementally - Polish is more important than features - Get feedback early and often - Version control with Git - Share on itch.io!
๐ฏ Best Practices Recap
best_practices = [
"1. Keep your game loop at 60 FPS",
"2. Separate logic from rendering",
"3. Use deltatime for consistent movement across frame rates",
"4. Comment your code and use meaningful variable names",
"5. Profile performance with pygame.time.Clock.get_fps()",
"6. Test on different computers/resolutions",
"7. Add options menu (volume, fullscreen, controls)",
"8. Include a tutorial or help screen",
"9. Playtest with others - you're too close to your game!",
"10. Have fun and iterate based on what feels good!"
]
print("โจ Game Development Best Practices:")
for practice in best_practices:
print(f" {practice}")๐ Congratulations!
Youโve completed the Pygame chapter! You now know:
โ
Game loop architecture
โ
Event handling and input
โ
Sprite rendering with matrices
โ
Collision detection
โ
Game state management
โ
Building complete games (Snake & Space Invaders)
โ
Advanced patterns and polish
These skills transfer to:
- Mobile game development
- Web games (with Pygame WebAssembly)
- Simulations and visualizations
- Interactive art
- Any real-time interactive application!
๐ Whatโs Next?
Continue your journey with: - Chapter 3: Manim - Create beautiful mathematical animations! - Or dive deeper into game development with more complex projects!
๐ Youโre a Game Developer Now!
Every game starts with a simple idea and grows through iteration. Donโt aim for perfection on your first tryโmake something playable, get feedback, and improve!
The games industry is built by people who started exactly where you are. Keep creating, keep learning, and most importantly, keep having fun!