🏛️ Object-Oriented Programming (OOP) Evidence Portfolio

Course: CS111
Student: Anika Seksaria
Term: Spring 2026


🔹 Writing Classes

  • 📌 Requirement: Create minimum 2 custom character classes extending base classes.
  • 📝 Assessment Method: Code review of Bullet.js, RedRidingMusic.js, and SplineBarrier.

🧠 Program Design & Implementation

  • Class Definition: A class acts as a blueprint or template. Instead of managing separate, loose variables for individual components, a class bundles all related data and behaviors into a single organized package.
  • Application: A custom Bullet class consolidates properties such as velocity and direction, enabling the game loop to generate multiple active projectiles smoothly. Independent operations are also established through distinct music management and collision barrier classes.
  • Optimization: This structural choice enhances code clarity. Because each object independently tracks its own variables and state updates, the reliance on global variables is eliminated, preventing unintended side effects across different game states.
class Bullet {
    constructor(data) {
        this.x = data.x;
        this.y = data.y;
        this.velocity = data.velocity || { x: 0, y: 0 };
        this.gameEnv = data.gameEnv;
        this.shooter = data.shooter;
        this.direction = data.direction || 'down';
        this.width = 20;
        this.height = 20;
        this.lifetime = 3000;
        this.creationTime = Date.now();
        this.destroyed = false;
    }
}

class RedRidingMusic {
    constructor() {
        this.audio = null;
        this.started = false;
        this.isPlaying = false;
        this.endpoint = 'https://itunes.apple.com/search?term=little+red+riding+hood&entity=song&limit=5';
        this.userActivated = false;
        this.createToggleButton();
    }
}

class SplineBarrier {
    constructor(leftPoints, rightPoints, gameEnv) {
        this.leftControlPoints = leftPoints;
        this.rightControlPoints = rightPoints;
        this.gameEnv = gameEnv;
        this.ctx = gameEnv.ctx;

        const leftSamples = this.sampleSpline(this.leftControlPoints, 1000);
        const rightSamples = this.sampleSpline(this.rightControlPoints, 1000);
        this.polygon = [...leftSamples, ...rightSamples.reverse()];
    }
}

🔹 Methods with Parameters

  • 📌 Requirement: Implement methods with parameters (e.g., collision handlers tracking multiple entities).
  • 📝 Assessment Method: Code review of method signatures requiring 2+ parameters.

🧠 Program Design & Implementation

  • Method Parameters: Parameters function as input variables inside a method. They allow a function to receive external data dynamically when called, instead of relying on fixed, unchangeable values.
  • Application: Inside the level control class, functions like checkInZone(player, zone) and checkPlayerWolfCollision(player, wolf) accept two specific game objects simultaneously to process relative coordinates and bounding box overlapping logic.
  • Optimization: Using parameterized inputs dramatically increases reusability. The same collision calculations can be run flexibly against different positions, characters, or level zones without rewriting redundant block algorithms.
// EVIDENCE: METHODS WITH PARAMETERS
class GameLevelRedRidingHood2 {

    checkInZone(player, zone) {
        if (!player?.position) return false;

        return (
            player.position.x + player.width > zone.x &&
            player.position.x < zone.x + zone.width &&
            player.position.y + player.height > zone.y &&
            player.position.y < zone.y + zone.height
        );
    }

    checkPlayerWolfCollision(player, wolf) {
        if (!player?.position || !wolf?.position) return false;

        const wolfPadding = 60;
        const playerPadding = 10;

        return (
            player.position.x + playerPadding < wolf.position.x + wolf.width - wolfPadding &&
            player.position.x + player.width - playerPadding > wolf.position.x + wolfPadding &&
            player.position.y + playerPadding < wolf.position.y + wolf.height - wolfPadding &&
            player.position.y + player.height - playerPadding > wolf.position.y + wolfPadding
        );
    }
}

🔹 Object Instantiation

  • 📌 Requirement: Instantiate game objects dynamically within a GameLevel configuration.
  • 📝 Assessment Method: Code review of the level setup routine generating concrete instances.

🧠 Program Design & Implementation

  • Instantiation Concept: Instantiation is the process of creating a concrete, usable object from an abstract class blueprint. This is achieved by utilizing the new keyword, which allocates memory and runs the class constructor function.
  • Application: Inside the level configuration constructor, distinct visual elements and actors are actively instantiated during runtime. The environment layout creates a background entity using new GameEnvBackground(...) and builds the playable actor using new ShooterPlayer(...).
  • Optimization: Separating class logic from execution allows data arrays to dynamically generate entirely unique object sets per scene. This architecture prevents hardcoded properties, allowing the engine to scale asset generation seamlessly.
// EVIDENCE: OBJECT INSTANTIATION
class GameLevelRedRidingHood3 {
    constructor(gameEnv) {
        this.gameEnv = gameEnv;

        let width = gameEnv.innerWidth;
        let height = gameEnv.innerHeight;

        const image_data_forest = {
            name: 'forest',
            src: gameEnv.path + "/images/projects/red-riding/lrrh-lvl3-bg-clipped.png",
            pixels: { height: 580, width: 1038 }
        };

        this.background = new GameEnvBackground(image_data_forest, gameEnv);

        const sprite_data_red = {
            id: 'RedRidingHood',
            src: gameEnv.path + "/images/projects/red-riding/Finalred.png",
            SCALE_FACTOR: 6,
            STEP_FACTOR: 800,
            INIT_POSITION: { x: width / 2 - 50, y: height - 100 },
            pixels: { height: 144, width: 192 },
            orientation: { rows: 3, columns: 4 }
        };

        this.player = new ShooterPlayer(sprite_data_red, gameEnv);
    }
}

🔹 Class Hierarchy & Inheritance

  • 📌 Requirement: Establish a clear class hierarchy containing multiple structural tiers.
  • 📝 Assessment Method: Code review of structural implementation leveraging the inheritance chain.

🧠 Program Design & Implementation

  • Inheritance Structure: Inheritance allows a child class to automatically adopt properties and methods from a parent class using the extends keyword. This sets up a vertical relationship where specific variations share a common baseline.
  • Application: The specific specialized character class ShooterPlayer explicitly inherits from the base Player class. This design grants the specialized class immediate access to default engine movement and animation state processing without duplicate logic blocks.
  • Optimization: Code redundancy is significantly lowered by utilizing shared inheritance patterns. General logic remains secured in parent files, while child files remain lightweight and focused strictly on custom extension mechanics like ammunition updates and localized cooldown tracking.
// EVIDENCE: CLASS HIERARCHY AND INHERITANCE
import Player from '@assets/js/GameEnginev1.1/essentials/Player.js';

class ShooterPlayer extends Player {
    constructor(data, gameEnv) {
        super(data, gameEnv);

        this.bullets = [];
        this.shootCooldown = data.shootCooldown || 500;
        this.lastShotTime = 0;
        this.facing = 'up';
    }
}

🔹 Polymorphism & Method Overriding

  • 📌 Requirement: Override inherited methods to implement specialized subclass behaviors.
  • 📝 Assessment Method: Code review of the custom lifecycle loop updates within extended classes.

🧠 Program Design & Implementation

  • Polymorphism & Overriding: Method overriding occurs when a child class rewrites a function that it already inherited from its parent class. This allows the child class to execute unique actions while keeping the exact same function name.
  • Application: The ShooterPlayer class overrides the standard game loop update() method. By invoking super.update(), it preserves the parent's base movement mechanics while adding a custom sequence to track projectile cleanup and active bullets.
  • Optimization: This design pattern streamlines game operations. The main engine wrapper can call update() uniformly across an array of diverse entity types without needing to know or manage their unique inner runtime modifications.
// EVIDENCE: POLYMORPHISM AND METHOD OVERRIDING
class ShooterPlayer extends Player {

    // Overriding the parent class update method
    update() {
        // Call the parent class update to handle basic movement and animation
        super.update();

        // Add specialized custom behavior for checking and cleaning up active bullets
        this.bullets = this.bullets.filter(bullet => {
            const age = Date.now() - bullet.creationTime;
            if (age > bullet.lifetime) {
                bullet.destroyed = true;
                return false;
            }
            return true;
        });
    }
}

🔹 Encapsulation & Access Modifiers

  • 📌 Requirement: Protect object states using scope controls and encapsulation design patterns.
  • 📝 Assessment Method: Code review of getter/setter methods or local execution scopes.

🧠 Program Design & Implementation

  • Encapsulation Mechanism: Encapsulation restricts direct external access to an object's internal components. This ensures that internal states cannot be modified randomly by external scripts, protecting the stability of the program.
  • Application: Instead of allowing other classes to change coordinates arbitrarily, proper architectural flow utilizes standardized functions like setX() and setY(). This pattern filters incoming coordinates through boundary checks before overwriting memory.
  • Optimization: Restricting variable scope isolates bugs effectively. Malformed assignments or out-of-bounds positions are caught immediately inside the specific class methods, rather than corrupting the wider engine framework.
// EVIDENCE: ENCAPSULATION AND ACCESS CONTROL
class GameCharacter {
    constructor(x, y, gameEnv) {
        // Internal variables bundled inside the class object
        this.x = x;
        this.y = y;
        this.gameEnv = gameEnv;
    }

    // Encapsulated setter method controlling modifications to the X coordinate
    setX(newX) {
        // Data verification: prevents character from moving past the left edge of the screen
        if (newX >= 0 && newX <= this.gameEnv.innerWidth) {
            this.x = newX;
        }
    }

    // Encapsulated setter method controlling modifications to the Y coordinate
    setY(newY) {
        // Data verification: prevents character from moving past the top edge of the screen
        if (newY >= 0 && newY <= this.gameEnv.innerHeight) {
            this.y = newY;
        }
    }
}