Object Oriented Programming
Writing Classes
What is writing classes?
Writing classes are a big part of OOP (Object Oriented Programming). A class is an organized, repeatable way to make multiple functions for an object that share similar properties.
Benefits of writing classes?
- Code reusability - write once, use many times
- Efficiency - multiple functions in one class
- Organization - organize related properties and methods together
- Scalability - easy to manage multiple objects
- Maintainability - changes in one place affect all instances
// Example class defining a game level with characters
class GameLevelPatrollingGuard {
constructor(data) {
this.level = data.level || 1;
this.background = new Background(data.bg);
this.player = new Player(data.player);
this.npc = new PatrollingGuard(data.npc);
this.gameObjects = [this.background, this.player, this.npc];
}
configureGameArea(canvas, ctx) {
// Render all game objects
this.gameObjects.forEach(obj => obj.draw(ctx));
}
}
// Usage
const levelData = { level: 1, bg: {...}, player: {...}, npc: {...} };
const gameLevel = new GameLevelPatrollingGuard(levelData);
What does this code do?
- Defines a
GameLevelPatrollingGuardclass with a constructor - Constructor accepts data and creates game objects
- Stores background, player, and NPC in
gameObjectsarray configureGameArea()method renders all game objects- Shows how a single class organizes multiple related functions
- Demonstrates constructor patterns and instance creation
// Child class extending parent class
class ExampleEnemy extends Enemy {
constructor(data, gameEnv) {
super(data, gameEnv);
this.enemyType = 'Example';
}
handleCollisionEvent(projectile) {
// Override: detect collision with player
if (this.collidesWith(projectile)) {
console.log("Enemy hit! Destroying player...");
projectile.destroy();
}
}
}
What does this code do?
- Extends
Enemyparent class to create child class - Calls
super()to initialize parent properties - Adds
enemyTypeproperty specific to this enemy - Overrides
handleCollisionEvent()method - Shows collision detection and object destruction
- Demonstrates inheritance and method overriding together
Methods & Parameters
What are methods and parameters?
Methods are reusable blocks of code that perform specific tasks. Parameters are inputs to methods that let you pass data and customize behavior.
Benefits of methods and parameters?
- Reusability - write code once, call many times
- Flexibility - customize behavior through parameters
- Maintainability - easier to update and debug
- Clarity - descriptive names make code readable
- Organization - group related functionality
// Class with multiple methods and parameters
class Guard {
constructor(data, gameEnv) {
this.x = data.x;
this.y = data.y;
this.health = 50;
this.vx = 2;
this.vy = 0;
}
// Method with parameters
update(canvas) {
this.stayWithinCanvas(canvas);
}
// Method to keep guard within canvas boundaries
stayWithinCanvas(canvas) {
if (this.x < 0 || this.x + 50 > canvas.width) {
this.vx *= -1;
}
this.x += this.vx;
}
// Collision detection method
handleCollisionEvent(projectile) {
if (this.collidesWith(projectile)) {
console.log("Guard hit!");
projectile.destroy();
}
}
}
What does this code do?
- Constructor takes
dataandgameEnvparameters to customize each instance update()method takes canvas parameter for boundary checkingstayWithinCanvas()keeps guard bouncing within boundshandleCollisionEvent()detects collisions with projectiles- Shows methods with different parameters and purposes
- Demonstrates how parameters customize behavior
Instantiation & Objects
What is instantiation?
Instantiation means creating a new instance (copy) of an object from a class blueprint. Each instance has its own properties and data.
Benefits of instantiation?
- Create multiple objects from one template
- Reusability - same class for many objects
- Organization - cleaner code structure
- Easy management - change instances independently
- Scalability - quickly add more objects
const enemyData = {
id: `waveEnemy_${this.currentWave}_${i}`,
src: sprite_src,
SCALE_FACTOR: 5,
STEP_FACTOR: 0,
ANIMATION_RATE: 8,
INIT_POSITION: { x: xPos, y: yPos },
pixels: { height: 1000, width: 3000 }, // full spritesheet dimensions
orientation: { rows: 2, columns: 6 },
left: { row: 0, start: 0, columns: 6 }, // top row = ghost leaning left
right: { row: 1, start: 0, columns: 6 }, // bottom row = ghost leaning right
up: { row: 0, start: 0, columns: 6 },
down: { row: 1, start: 0, columns: 6 },
hitbox: { widthPercentage: 0.4, heightPercentage: 0.5 },
healthPoints: 1,
speed: speed
};
const enemy = new WaveEnemy(enemyData, this.gameEnv);
this.waveEnemies.push(enemy);
this.gameEnv.gameObjects.push(enemy);
}
}
In this code from our game level:
- We make a class called
enemyData - We use the keyword
newto instantiate the enemy using the enemy class
Inheritence
What is inheritance?
Inheritance allows classes to acquire properties and methods from parent classes. Child classes can reuse parent code and add their own specialized behavior.
Benefits of inheritance?
- Reuse code - write once in parent, use in all children
- Create specialized versions - customize child behavior
- Reduce duplication - avoid repeating code
- Organize hierarchies - create logical class relationships
- Share functionality - common methods in one place
// Parent class with common properties and methods
class Character {
constructor(name, health) {
this.name = name;
this.health = health;
this.isDead = false;
}
takeDamage(damage) {
this.health -= damage;
if (this.health <= 0) {
this.isDead = true;
console.log(this.name + " is dead!");
}
}
}
// Child class extends parent
class Guard extends Character {
constructor(name, health) {
super(name, health);
this.patrolRadius = 100;
}
patrol() {
console.log(this.name + " is patrolling...");
}
}
// Usage
const guard = new Guard("Guard1", 50);
guard.takeDamage(10); // Uses parent method
guard.patrol(); // Uses child method
What does this code do?
Characterparent class defines common properties (name, health)takeDamage()is shared by all childrenGuardchild class callssuper()to initialize parent- Guard adds specialized property
patrolRadius - Guard adds specialized method
patrol() - Shows how child reuses parent code while adding own features
// Another inheritance example
class Entity {
constructor(x, y) {
this.x = x;
this.y = y;
this.vx = 0;
this.vy = 0;
}
move() {
this.x += this.vx;
this.y += this.vy;
}
}
// Player adds score tracking to Entity
class Player extends Entity {
constructor(x, y) {
super(x, y);
this.score = 0;
}
addScore(points) {
this.score += points;
}
}
// Usage
const player = new Player(100, 300);
player.move(); // From parent
player.addScore(10); // From child
What does this code do?
Entityparent class provides position and movementPlayerchild class callssuper(x, y)for position- Player adds score-tracking functionality
- Child inherits
move()from parent - Child adds
addScore()method - Shows inheritance creating specialized versions of common class
Method Overriding
What is method overriding?
Method overriding means creating a new version of a parent class’s method in a child class. Instead of using the parent’s method, the child uses its own customized version.
Benefits of method overriding?
- Customization - each child class behaves differently
- Polymorphism - call method on any child, correct behavior runs
- Flexibility - change behavior without changing parent
- Code reuse with differences - keep common code, change specifics
- Cleaner code - no need for conditional logic
// Parent class with methods
class Enemy {
constructor(data, gameEnv) {
this.x = data.x;
this.y = data.y;
this.health = 100;
this.vx = 2;
}
handleCollisionEvent(projectile) {
console.log("Generic enemy hit");
}
stayWithinCanvas(canvas) {
if (this.x < 0 || this.x + 50 > canvas.width) {
this.vx *= -1;
}
}
}
// Guard child overrides both methods
class Guard extends Enemy {
handleCollisionEvent(projectile) {
// Override: destroy player instead
console.log("Guard hit! Destroying player...");
projectile.destroy();
this.health -= 10;
}
stayWithinCanvas(canvas) {
// Override: bounce at edges
if (this.x < 0 || this.x + 50 > canvas.width) {
this.vx *= -1;
this.x += this.vx;
}
}
}
// ExampleEnemy overrides only collision
class ExampleEnemy extends Enemy {
handleCollisionEvent(projectile) {
// Override collision behavior
console.log("Example enemy explodes!");
projectile.destroy();
}
// Keeps parent stayWithinCanvas
}
What does this code do?
- Parent
Enemyclass defines default methods Guardchild overrides bothhandleCollisionEvent()andstayWithinCanvas()ExampleEnemychild only overrideshandleCollisionEvent()- Each child can have completely different behavior
- Shows flexibility of method overriding
- Demonstrates partial override - some methods from parent, some custom
Constructor Chaining
What is constructor chaining?
Constructor chaining means one constructor calls another constructor so you can reuse setup code. This happens in classes with extends and super().
Benefits of constructor chaining?
- Avoid repeating initialization code
- Parent code runs first, then child code
- Clean initialization of inheritance hierarchies
- Automatic parent property setup
- Maintainable inheritance relationships
// Parent class with constructor
class Enemy {
constructor(data, gameEnv) {
this.name = data.name;
this.x = data.x;
this.y = data.y;
this.health = data.health || 50;
this.vx = 0;
this.vy = 0;
console.log(this.name + " created");
}
}
// Child class calls parent constructor with super()
class Guard extends Enemy {
constructor(data, gameEnv) {
super(data, gameEnv); // Calls parent constructor first
// Child-specific initialization
this.velocity = 2;
this.patrolRadius = 100;
console.log(this.name + " is guarding with velocity " + this.velocity);
}
}
// Usage
const guardData = { name: "Guard1", x: 100, y: 300, health: 75 };
const guard = new Guard(guardData, gameEnv);
What does this code do?
super(data, gameEnv)calls parent constructor first- Parent constructor initializes name, x, y, health, velocities
- After parent setup complete, child code runs
- Child adds Guard-specific properties (velocity, patrolRadius)
- Console shows parent initialization first, then child
- Demonstrates proper constructor chaining pattern