OOP

Table of Contents

Core Topics

Core Building Blocks

  • Classes:Blueprints or templates that define the data and behavior (methods) for a specific type of object.
  • Objects: Specific instances created from a class. For example, if “Car” is the class, “My Toyota” is a specific object.
  • Attributes: The data or state of an object (e.g., a car’s color or model).
  • Methods: Functions defined within a class that describe the actions an object can perform (e.g., “drive” or “brake”).

Writing Classes

Writing Classes, involves creating reusable blueprints that define the unique properties and behaviors of game entities.

//Enemy Example

class Enemy extends Character {
    constructor(data = null, gameEnv = null) {
        super(data, gameEnv);
        this.playerDestroyed = false; // Tracks if the player has been "killed"
    }
//Npc example
class Npc extends Character {
    constructor(data = null, gameEnv = null) {
        super(data, gameEnv);
        this.interact = data?.interact; // Interact function
        this.currentQuestionIndex = 0;
        this.alertTimeout = null;
        this.isInteracting = false; // Flag to track if currently interacting
        this.handleKeyDownBound = this.handleKeyDown.bind(this);
        this.handleKeyUpBound = this.handleKeyUp.bind(this);
        this.bindInteractKeyListeners();

Methods and Parameters

Methods and parameters allow you to define specific actions for your objects and pass in unique data to customize how those actions are performed.

Example - In this example, the handleCollision method uses parameters (other and direction) to determine if the NPC should start an interaction based on which game object it touched.

// A method within the Npc class
handleCollision(other, direction) {

    if (this.interact && direction === "side") {
        this.isInteracting = true; 
        this.interact(other);      
        console.log("NPC interaction started with: " + other.id);
    }
}

Instantiation

instantiation is the process of creating a concrete, usable instance (an object) from an abstract template called a class.

for (let gameObjectClass of this.gameObjectClasses) {
    if (!gameObjectClass.data) gameObjectClass.data = {}
    // THIS IS INSTANTIATION
    let gameObject = new gameObjectClass.class(gameObjectClass.data, this.gameEnv)
    this.gameEnv.gameObjects.push(gameObject)
}

Explanation - This loop is how the game creates real objects from class blueprints. Each item in the list tells the game what kind of object to make and what data to give it. The new keyword makes the object, and then the game stores it so it can move, draw, and update it during gameplay.

Inheritence

Inheritance is the mechanism where a child class (like Npc or Enemy) automatically gains all the logic and attributes of a parent class (like Character). By using the extends keyword, you ensure that every specialized character in your game starts with the same foundational physics and movement rules without needing to rewrite that code for every new file.

Code Runner Challenge

Inheritance

View IPYNB Source
%%js 

// CODE_RUNNER: Inheritance

class Character {
    constructor(data, gameEnv) {
        this.x = data.x;
        this.y = data.y;
        this.velocity = { x: 0, y: 0 };
        this.gameEnv = gameEnv;
    }
}

class Player extends Character {
    constructor(data, gameEnv) {
        super(data, gameEnv); // Variables are passed from Parent to Child here
        
        // This log proves 'x', 'y', and 'velocity' exist in the Player instance
        console.log("Variables preserved from Parent:", this.x, this.y, this.velocity);
        
        this.health = 100;
    }
}

// Testing the preservation
const data = { x: 100, y: 200 };
const myPlayer = new Player(data, "Game Environment");
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Explanation - This shows inheritance in a simple way. Player starts with everything that Character already has, like shared movement or gravity. Then Player can add its own details, like health. This keeps shared code in one place instead of copying it into every character.

Method Overiding

Method Overriding is when a child class changes or adds to a behavior it inherited from its parent. While inheritance gives the child the parent’s “tools,” overriding allows the child to use those tools in a custom way.

Code Runner Challenge

Method Overidinga

View IPYNB Source
%%js

//CODE_RUNNER: Method Overidinga

// Classes with unique overrides
class Player extends Character {
    update() {
        console.log("Running Player input logic...");
    }
}

class Enemy extends Character {
    update() {
        console.log("Running Enemy AI logic...");
    }
}

// Polymorphic implementation
const gameObjects = [new Player(), new Enemy()];

gameObjects.forEach(obj => {
    obj.update(); 
});
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...
  1. The list: The player and enemy are stored together in one gameObjects list.

  2. The same command: The game runs .update() on each object in the list.

  3. The result: The same command does different things depending on the object. The player runs player movement code, and the enemy runs enemy behavior code.

Constrctor Chaining

Constructor Chaining is the process of calling one constructor from another within a hierarchy of classes.

class Character {
    constructor(data, gameEnv) {
        this.x = data.x;
        this.y = data.y;
        this.gameEnv = gameEnv;
    }
}

class Player extends Character {
    constructor(data, gameEnv) {
        super(data, gameEnv); 
        this.health = 100;
    }
}

super() sends the basic setup data from Player to Character.

Character sets up the shared things first, like position and game environment. After that, Player adds its own details, like health.

This matters because JavaScript needs the parent setup to finish before the child class can use this for its own values.