Build a Space Game Part 1: Introduction
Just like NASA's mission control coordinates multiple systems during a space launch, we're going to build a space game that demonstrates how different parts of a program can work together seamlessly. While creating something you can actually play, you'll learn essential programming concepts that apply to any software project. We'll explore two fundamental approaches to organizing code: inheritance and composition. These aren't just academic concepts – they're the same patterns that power everything from video games to banking systems. We'll also implement a communication system called pub/sub that works like the communication networks used in spacecraft, allowing different components to share information without creating dependencies. By the end of this series, you'll understand how to build applications that can scale and evolve – whether you're developing games, web applications, or any other software system. ## Pre-Lecture Quiz Pre-lecture quiz ## Inheritance and Composition in Game Development As projects grow in complexity, code organization becomes critical. What begins as a simple script can become difficult to maintain without proper structure – much like how the Apollo missions required careful coordination between thousands of components. We'll explore two fundamental approaches for organizing code: inheritance and composition. Each has distinct advantages, and understanding both helps you choose the right approach for different situations. We'll demonstrate these concepts through our space game, where heroes, enemies, power-ups, and other objects must interact efficiently. ✅ One of the most famous programming books ever written has to do with design patterns. In any game, you have game objects – the interactive elements that populate your game world. Heroes, enemies, power-ups, and visual effects are all game objects. Each exists at specific screen coordinates using x and y values, similar to plotting points on a coordinate plane. Despite their visual differences, these objects often share fundamental behaviors: - They exist somewhere – Every object has x and y coordinates so the game knows where to draw it - Many can move around – Heroes run, enemies chase, bullets fly across the screen - They have a lifespan – Some stick around forever, others (like explosions) appear briefly and vanish - They react to stuff – When things collide, power-ups get collected, health bars update ✅ Think about a game like Pac-Man. Can you identify the four object types listed above in this game? ### Expressing Behavior Through Code Now that you understand the common behaviors game objects share, let's explore how to implement these behaviors in JavaScript. You can express object behavior through methods attached to either classes or individual objects, and there are several approaches to choose from. The Class-Based Approach Classes and inheritance provide a structured approach to organizing game objects. Like the taxonomic classification system developed by Carl Linnaeus, you start with a base class containing common properties, then create specialized classes that inherit these fundamentals while adding specific capabilities. ✅ Inheritance is an important concept to understand. Learn more on MDN's article about inheritance. Here's how you can implement game objects using classes and inheritance: Let's break this down step by step: - We're creating a basic template that every game object can use - The constructor saves where the object is (x, y) and what kind of thing it is - This becomes the foundation that all your game objects will build on In the above, we've: - Extended the GameObject class to add movement functionality - Called the parent constructor using super() to initialize inherited properties - Added a moveTo() method that updates the object's position Understanding these concepts: - Creates specialized object types that inherit appropriate behaviors - Demonstrates how inheritance allows selective feature inclusion - Shows that heroes can move while trees remain stationary - Illustrates how the class hierarchy prevents inappropriate actions ✅ Take a few minutes to re-envision a Pac-Man hero (Inky, Pinky or Blinky, for example) and how it would be written in JavaScript. The Composition Approach Composition follows a modular design philosophy, similar to how engineers design spacecraft with interchangeable components. Instead of inheriting from a parent class, you combine specific behaviors to create objects with exactly the functionality they need. This approach offers flexibility without rigid hierarchical constraints. Here's what this code does: - Defines a base gameObject with position and type properties - Creates a separate movable behavior object with movement functionality - Separates concerns by keeping position data and movement logic independent In the above, we've: - Combined base object properties with movement behavior using spread syntax - Created factory functions that return customized objects - Enabled flexible object creation without rigid class hierarchies - Allowed objects to have exactly the behaviors they need Key points to remember: - Composes objects by mixing behaviors rather than inheriting them - Provides more flexibility than rigid inheritance hierarchies - Allows objects to have exactly the features they need - Uses modern JavaScript spread syntax for clean object combination quadrantChart title Code Organization Patterns x-axis Simple --> Complex y-axis Rigid --> Flexible quadrant-1 Advanced Composition quadrant-2 Hybrid Approaches quadrant-3 Basic Inheritance quadrant-4 Modern Composition Class Inheritance: [0.3, 0.2] Interface Implementation: [0.6, 0.4] Mixin Patterns: [0.7, 0.7] Pure Composition: [0.8, 0.9] Factory Functions: [0.5, 0.8] Prototype Chain: [0.4, 0.3] flowchart TD A[Hero Takes Damage] --> B[Publish: HERO_DAMAGED] B --> C[Event System] C --> D[Health Bar Subscriber] C --> E[Sound System Subscriber] C --> F[Visual Effects Subscriber] C --> G[Achievement System Subscriber] D --> H[Update Health Display] E --> I[Play Damage Sound] F --> J[Show Red Flash] G --> K[Check Survival Achievements] style A fill:#ffebee style B fill:#e1f5fe style C fill:#e8f5e8 style H fill:#fff3e0 style I fill:#fff3e0 style J fill:#fff3e0 style K fill:#fff3e0 // Step 1: Create the EventEmitter class class EventEmitter { constructor() { this.listeners = {}; // Store all event listeners // Register a listener for a specific message type on(message, listener) { if (!this.listeners[message]) { this.listeners[message] = []; this.listeners[message].push(listener); // Send a message to all registered listeners emit(message, payload = null) { if (this.listeners[message]) { this.listeners[message].forEach(listener => { listener(message, payload); }); // Step 1: Define your message types const Messages = { HERO_MOVE_LEFT: 'HERO_MOVE_LEFT', HERO_MOVE_RIGHT: 'HERO_MOVE_RIGHT', ENEMY_SPOTTED: 'ENEMY_SPOTTED' // Step 2: Create your event system and game objects const eventEmitter = new EventEmitter(); const hero = createHero(0, 0); // Step 3: Set up event listeners (subscribers) eventEmitter.on(Messages.HERO_MOVE_LEFT, () => { hero.moveTo(hero.x - 5, hero.y); console.log(Hero moved to position: ${hero.x}, ${hero.y}); }); eventEmitter.on(Messages.HERO_MOVE_RIGHT, () => { hero.moveTo(hero.x + 5, hero.y); console.log(Hero moved to position: ${hero.x}, ${hero.y}); }); // Step 4: Connect keyboard input to events (publishers) window.addEventListener('keydown', (event) => { switch(event.key) { case 'ArrowLeft': eventEmitter.emit(Messages.HERO_MOVE_LEFT); break; case 'ArrowRight': eventEmitter.emit(Messages.HERO_MOVE_RIGHT); break; }); sequenceDiagram participant User participant Keyboard participant EventEmitter participant Hero participant SoundSystem participant Camera User->>Keyboard: Presses ArrowLeft Keyboard->>EventEmitter: emit('HERO_MOVE_LEFT') EventEmitter->>Hero: Move left 5 pixels EventEmitter->>SoundSystem: Play footstep sound EventEmitter->>Camera: Follow hero Hero->>Hero: Update position SoundSystem->>SoundSystem: Play audio Camera->>Camera: Adjust viewport timeline title Game Architecture Learning Progression section Object Patterns (20 minutes) Code Organization: Class inheritance : Composition patterns : Factory functions : Behavior mixing section Communication Systems (25 minutes) Event Architecture: Pub/Sub implementation : Message design : Event emitters : Loose coupling section Game Object Design (30 minutes) Entity Systems: Property management : Behavior composition : State handling : Lifecycle management section Architecture Patterns (35 minutes) System Design: Component systems : Observer pattern : Command pattern : State machines section Advanced Concepts (45 minutes) Scalable Architecture: Performance optimization : Memory management : Modular design : Testing strategies section Game Engine Concepts (1 week) Professional Development: Scene graphs : Asset management : Rendering pipelines : Physics integration section Framework Mastery (2 weeks) Modern Game Development: React game patterns : Canvas optimization : WebGL basics : PWA games section Industry Practices (1 month) Professional Skills: Team collaboration : Code reviews : Game design patterns : Performance profiling
journey title Your Game Development Journey section Foundation Learn game architecture: 3: Student Understand inheritance: 4: Student Explore composition: 4: Student section Communication Build pub/sub system: 4: Student Design event flow: 5: Student Connect components: 5: Student section Application Create game objects: 5: Student Implement patterns: 5: Student Plan game structure: 5: Student
Follow the lesson from Microsoft Web-Dev-For-Beginners course