Skip to content

Extra opdracht OOP - Doortje Geuze

Voor dit blok heb ik een extra opdracht gekregen om te werken aan object oriented programming, oftewel: OOP.

OOP gaat in het kort over het maken van objecten die zowel gegevens als methods bevatten. OOP creëert voor meer structuur in de code wat de code herbruikbaarder maakt, dit zorgt ervoor dat er tijd bespaart kan worden met het coderen.(w3schools.com)

In OOP bestaan er vier pilaren, deze zijn: abstraction, encapsulation, inheritance en polymorphism. In deze opdracht ga ik deze pilaren uitleggen en ondersteunen met code uit mijn eigen projecten.

Abstraction

Bij abstraction gaat het over het verstoppen van informatie en de code makkelijker te maken door minder belangrijke details weg te laten, hierdoor kan je focussen op de belangrijke code en wordt de code makkelijker leesbaar. (C. Gupta, Datatrained.com)

Er zijn verschillende methods om informatie te verstoppen in programmeren

Abstract classes

Abstract classen in CSharp

In programmeertalen zoals C# en java heb je de abstract keyword voor abstract classes.(learn.microsoft.com) Dit houdt in dat je met het keyword aangeeft dat de class alleen bedoeld is als basis-class van andere klassen en niet op zichzelf wordt geïnstantieerd

Een voorbeeld hoe je dat kan aangeven in C# is door abstract te zetten voor de class zoals aangegeven hieronder:

public abstract class Piece : GameObjectList
Deze Piece class is nu abstract en wordt dus als basis-class beschouwd. Nu kunnen classen van de piece class inheriten om alle methods en properties te krijgen en wel geïnstantieerd worden.

Abstract classes in Javascript

Een voorbeeld van een abstract class in JavaScript is de TileGrid class in het project van blok 2. Deze abstract class is abstract, want de class is niet gemaakt om instanties van te maken. Het is een abstract concept waar op basis van classes gemaakt van kunnen worden. Je zou het dus kunnen beschouwen als een soort ‘blueprint’ om anderen classes op te bouwen.

De TileGrid class is een class waar dit gebeurt. De class heeft properties en methods alleen is deze gemaakt als een blueprint voor de Normal- en SpecialTileGrid class. Deze classes hebben beide de functionaliteit van de TileGrid class, maar ze hebben ook anderen functies die de ander niet hoeft.

class TileGrid {
    //static #instance; // currently incomplete singleton, should be abstract
    #tileSize; // "protected"
    #tiles; // "protected"
    #width; // "protected"
    #height; // "protected"

    constructor(width, height, tileSize) {
        this.#tileSize = tileSize;
        this.#width = width;
        this.#height = height;
    }

    getTileFromGridPosition(gridPosition) {
        if (gridPosition.x < 0 || gridPosition.x >= this.#width || gridPosition.y < 0 || gridPosition.y >= this.#height) {
            return null;
        }
        let tile = this.#tiles[gridPosition.x][gridPosition.y];
        return tile;
    }

    getGridPosition(position) {
        const gridXPosition = Math.floor(position.x / this.#tileSize);
        const gridYPosition = Math.floor(position.y / this.#tileSize);
        const gridPosition = createVector(gridXPosition, gridYPosition);
        return gridPosition;
    }

    getTileFromPosition(position) {
        return this.getTileFromGridPosition(this.getGridPosition(position));
    }


    get _width() {
        return this.#width;
    }

    get _height() {
        return this.#height;
    }

    get _tileSize() {
        return this.#tileSize;
    }

    get _tiles() {
        return this.#tiles;
    }

    set _tiles(value) {
        this.#tiles = value;
    }
}
class NormalTileGrid extends TileGrid {
    #tileTypeArray;
    #scoreMap;
    #nTypes;
    #numberOfMatches;
    #matching;
    #gravity;
    #comboMultiplier;

    constructor(width, height, tileSize, manager) {
        super(width, height, tileSize);
        this.manager = manager;
        this.#tileTypeArray = [
            "taco",
            "ruffle",
            "babloon",
            "dabloon",
            "pringle"
        ];
        this.#scoreMap = {
            3: 10000,
            4: 20000,
            5: 50000,
            "combo!": 50000
        };
        this.#nTypes = this.#tileTypeArray.length;
        this.#numberOfMatches = 0;
        this.#matching = true; // for spawning tiles this needs to be true
        this.#gravity = false;
        this.#comboMultiplier = 0;
        this.#generateTileGrid();
    }

    draw() {
        for (let x = 0; x < this._width; x++) {
            for (let y = 0; y < this._height; y++) {
                if (this._tiles[x][y] !== null) {
                    this._tiles[x][y].draw();
                }
                // this._tiles[x][y].animate();
            }
        }

        if (this.#matching === true) {
            // this.getAndResolve();
        }

        else if (this.#gravity === true) {
            this.moveFloatingTilesDown();
        }
        else {
            // this.spawnNewTiles();
        }

        // draws inputHandler.selectedTile over all tiles so it takes priority
        if (inputHandler.selectedTile !== null) {
            inputHandler.selectedTile.draw();
        }

    }

    #generateTileGrid() {

        //tiles is a 2D array, meaning that it is an array of arrays. 
        //see https://www.freecodecamp.org/news/javascript-2d-arrays/ for more information about 2D arrays.
        this._tiles = new Array();
        //generate tile grid here and place tiles in the 2D #tile array.
        for (let x = 0; x < this._width; x++) {
            this._tiles[x] = new Array();
            for (let y = 0; y < this._height; y++) {
                do {
                    this._tiles[x][y] = new NormalTile(
                        this.#getRandomTileType(),
                        this._tileSize,
                        x,
                        y,
                        this
                    );
                    // } while (true === false);
                } while (this.#findMatch3(x, y) === true);
                // } while (this.#findAndResolveMatches() !== false)
            }
        }

        this.#numberOfMatches = 0;
        this.#matching = false;
        this.#gravity = false;
    }

    #getRandomTileType() {
        return this.#tileTypeArray[Math.round(random(0, this.#nTypes - 1))];
    }

    swapTiles(tile1, tile2) {
        if (moving === false) {
            // moving = true;
            if (tile1 !== null &&
                tile2 !== null &&
                // this.#findAllMoving() === false &&
                tile1 !== tile2) {
                const gridPosition1 = this.getGridPosition(tile1.position);
                const gridPosition2 = this.getGridPosition(tile2.position);
                this._tiles[gridPosition2.x][gridPosition2.y] = tile1;
                this._tiles[gridPosition1.x][gridPosition1.y] = tile2;
                // if (tile1 !== null && tile2 !== null) {
                if (this.getAllMatches().length > 0) {
                    if (betaAnimationMode === true) {
                        tile1.animateToOne(gridPosition2.mult(tile1.size));
                        tile2.animateToTwo(gridPosition1.mult(tile2.size));
                        // this.getAndResolve();
                        // setTimeout(() => {
                        //     this.spawnNewTiles();
                        // }, 2000);
                    }
                    else {
                        tile1.moveTo(gridPosition2.mult(tile1.size));
                        tile2.moveTo(gridPosition1.mult(tile2.size));
                        this.getAndResolve();
                        this.moveFloatingTilesDown();
                        setTimeout(() => {
                            moving = false;
                            this.spawnNewTiles()
                        }, 1000);
                    }
                    console.log("Match!")
                }
                else {
                    console.log("Nah, no match.")
                    this._tiles[gridPosition2.x][gridPosition2.y] = tile2;
                    this._tiles[gridPosition1.x][gridPosition1.y] = tile1;
                }

            }

            else {
                return;
            }
        }
    }

    #handleMove() {
        this.manager.moves.update(1);
        if (this.manager.moves.left < 1 && this.manager.score.currentScore < this.manager.score.goalScore) {
            alert("you lost ):");
            whichScreen = "select screen";
        }
        else {
            console.log(this.manager.moves.left);
        }
    }

    swapGravityTiles(tile1, tile2) {
        if (tile1.normalMoving === false && tile2.normalMoving === false) {
            const gridPosition1 = this.getGridPosition(tile1.position);
            const gridPosition2 = this.getGridPosition(tile2.position);
            this._tiles[gridPosition2.x][gridPosition2.y] = tile1;
            this._tiles[gridPosition1.x][gridPosition1.y] = tile2;

        else {
            return;
        }
    }

    #findMatch3(x, y) {
        // if right two tiles are regular tiles
        // if left two tiles are same type as tile
        if (this.#matching === true) {
            console.log(this.#matching);
            if (x > 1 &&
                this._tiles[x][y] !== null &&
                this._tiles[x - 1][y] !== null &&
                this._tiles[x - 2][y] !== null &&

                this._tiles[x][y].normalMoving === false &&
                this._tiles[x - 1][y].normalMoving === false &&
                this._tiles[x - 2][y].normalMoving === false &&

                this._tiles[x - 1][y].type === this._tiles[x][y].type &&
                this._tiles[x - 2][y].type === this._tiles[x][y].type
            ) {
                console.log("match!");

            }
            // if upper two tiles are regular tiles
            // if upper two tiles are the same type as tile
            if (y > 1 &&
                this._tiles[x][y] !== null &&
                this._tiles[x][y - 1] !== null &&
                this._tiles[x][y - 2] !== null &&

                this._tiles[x][y].normalMoving === false &&
                this._tiles[x][y - 1].normalMoving === false &&
                this._tiles[x][y - 2].normalMoving === false &&

                this._tiles[x][y - 1].type === this._tiles[x][y].type &&
                this._tiles[x][y - 2].type === this._tiles[x][y].type
            ) {
                return true

        }
    }

    #findAllMatch3() {
        for (let x = 0; x < this._width; x++) {
            for (let y = 0; y < this._height; y++) {
                this.#findMatch3(x, y);
            }
        }
    }

    // line solver
    getMatchPerLine(lineArray) {
        let matchArray = [];
        let nMatches = 1;
        // for array length (width/height) - 1 (since it shouldn't have to check on the last tile)
        for (let i = 0; i < lineArray.length - 1; i++) {
            // if tile type is same as next tile type in array
            if (lineArray[i].type === lineArray[i + 1].type) {
                console.log(`type ${i}: ${lineArray[i].type}`);
                console.log(`type ${i + 1}: ${lineArray[i + 1].type}`);
                console.log("they match!");
                nMatches += 1;
                if (nMatches > 2) {
                    console.log("Match > 2!");
                    // for number of matches
                    for (let j = 0; j < nMatches; j++) {
                        console.log(`i - j = ${i - j}`);
                        // if matches array excludes tile that wants to be added
                        // (this is in case of match 4 or 5)
                        if (matchArray.includes(lineArray[i - j + 1]) === true) {
                            // do nothing
                        }
                        else {
                            // add every tile that matches 
                            matchArray.push(lineArray[i - j + 1]);
                        }
                    }

                }
            }
            else {
                console.log(`type ${i}: ${lineArray[i].type}`);
                console.log(`type ${i + 1}: ${lineArray[i + 1].type}`);
                console.log("They do not match!");
                console.log(`last matches streak: ${nMatches}`);
                nMatches = 1;
            }
        }
        return matchArray;
    }

    // all lines match getter
    getAllMatches() {
        // get all vertical matches
        let allMatchesArray = [];
        for (let y = 0; y < this._height; y++) {
            console.log(`checking vertical line array ${y}...`);
            let verticalLineArray = this.tiles[y];
            let matchesFromArray = this.getMatchPerLine(verticalLineArray);
            console.log(`received horizontal array`);
            allMatchesArray = allMatchesArray.concat(matchesFromArray);
        }

        // get all horizontal matches
        for (let x = 0; x < this._width; x++) {
            // create horizontal array from 2d array
            let horizontalLineArray = [];
            for (let x2 = 0; x2 < this._width; x2++) {
                horizontalLineArray.push(this.tiles[x2][x]);
            }
            let matchesFromArray = this.getMatchPerLine(horizontalLineArray);
            console.log(`received horizontal array`);
            allMatchesArray = allMatchesArray.concat(matchesFromArray);
        }
        return allMatchesArray;
    }

    // collects matched cats and replaces the cat position with null
    collectMatches(allMatchesArray) {
        allMatchesArray.forEach((tile) => {
            console.log(tile.x);
            if (this.tiles[tile.x][tile.y] !== null) {
                this.tiles[tile.x][tile.y].collect();
            }
        });
    }

    // gets all matches and resolved them
    getAndResolve() {
        console.log("matching")
        this.collectMatches(this.getAllMatches());
    }


    moveFloatingTilesDown() {
        console.log("gravitating");
        // reversed for loop
        let upperTileObjectArray = [];
        // let upperTileCounter = 0;
        for (
            let y = this._height - 1, y2 = 0;
            y >= 0;
            y--, y2++
        ) {
            for (let x = 0; x < this._width; x++) {
                if (this.tiles[x][y].visible === false) {
                    let voidTile = {
                        name: "void tile",
                        description: "proxy object for tile which is null",
                        x: x,
                        y: y
                    };
                    console.log(`void tile found @(${x}, ${y})`);
                    for (let i = 0; i < y + 1; i++) {
                        console.log(`producing upper tile @ (${x},${y - i})`);
                        let upperTile = this.tiles[x][y - i];
                        if (upperTile.visible === true) {
                            console.log(`upper tile found @(${upperTile.x}, ${upperTile.y})`);
                            let upperTileObject = {
                                tile: upperTile,
                                x: upperTile.x,
                                y: upperTile.y,
                                xDistanceBetweenVoid: x - upperTile.x,
                                yDistanceBetweenVoid: y - upperTile.y,
                                yIteration: i
                            };
                            if (upperTileObject.tile.visble === true) {
                                console.log("upper tile should exist");
                                console.log(upperTileObject.tile);
                            }
                            else {
                                console.log("upper tile somehow doesn't exist");
                            }
                            upperTileObjectArray.push(upperTileObject);
                            console.log("added to upperTileObjectArray");
                            console.log(upperTileObjectArray);

                            // end for loop
                            i = y + 1;
                        }
                    }
                }
            }

            let gravityMap = new Map();
            console.log(upperTileObjectArray);
            upperTileObjectArray.forEach(obj => {
                let upperGridPosition = createVector(
                    obj.x,
                    obj.y
                );
                console.log(`upper grid position: ${upperGridPosition}`)
                console.log(`upper tile:`)
                console.log(obj.tile);
                console.log(`upper grid position: @(${upperGridPosition.x},${upperGridPosition.y})`);
                for (let i = 0; i < upperGridPosition.y + 1; i++) {
                    console.log(i);
                    console.log(upperGridPosition.y - i);
                    let upperUpperGridPosition = createVector(
                        upperGridPosition.x,
                        upperGridPosition.y - i
                    );
                    console.log(`upper upper grid position @(${upperGridPosition.x},${upperUpperGridPosition.y})`);
                    console.log(`uut x: ${this.tiles[upperUpperGridPosition.x]}`);
                    console.log(`uut:`);
                    console.log(this.tiles[upperUpperGridPosition.x][upperUpperGridPosition.y]);
                    let upperUpperTile = this.tiles[upperUpperGridPosition.x][upperUpperGridPosition.y];
                    let newUpperUpperGridPosition = createVector(
                        upperUpperGridPosition.x,
                        upperUpperGridPosition.y + obj.yDistanceBetweenVoid
                    );
                    gravityMap.set(upperUpperTile, newUpperUpperGridPosition);
                }
            });
            gravityMap.forEach((newUpperUpperGridPosition, upperUpperTile) => {
                console.log(`tile: ${upperUpperTile}, endPosition: ${newUpperUpperGridPosition}`);
                let newUpperUpperEndPosition = createVector(
                    newUpperUpperGridPosition.x * this.tileSize,
                    newUpperUpperGridPosition.y * this.tileSize
                );
                let newVoidTile = this.getTileFromGridPosition(
                    newUpperUpperGridPosition,
                    newUpperUpperGridPosition
                );
                this.swapGravityTiles(upperUpperTile, newVoidTile);
                upperUpperTile.animateGravity(newUpperUpperEndPosition);
            });
        }
        this.#gravity = false;
        // this.spawnNewTiles();
    }


    spawnNewTiles() {
        // if (this.#gravity === false) {
        while (this.#findAllMoving() === true) {
            return;
        }
        console.log("spawning new tiles");
        for (let x = 0; x < this._width; x++) {
            for (let y = 0; y < this._height; y++) {
                if (this._tiles[x][y].visible === false || this._tiles[x][y] === null) {
                    this.#numberOfMatches += 1;
                    this._tiles[x][y] = new NormalTile(
                        this.#getRandomTileType(),
                        this._tileSize,
                        x,
                        y,
                        this
                    );
                }
            }
        }
        if (this.getAllMatches.length > 0) {
            this.#handleScore();
            this.#handleMove();
            this.getAndResolve();
            this.moveFloatingTilesDown();
            this.spawnNewTiles();
            return;
        }
        else {
            this.#handleScore();
            this.#handleMove();
            return;
        }

    }

    #handleScore() {
        switch (this.#numberOfMatches) {
            case 3:
                this.manager.score.update(this.#scoreMap[3]);
                break;
            case 4:
                this.manager.score.update(this.#scoreMap[4]);
                break;
            case 5:
                this.manager.score.update(this.#scoreMap[5]);
                break;
            default:
                this.manager.score.update(this.#scoreMap["combo!"])
                break;
        }
        this.#numberOfMatches = 1;

        if (this.manager.score.currentScore >= this.manager.score.goalScore) {
            alert(`You won! \nYour score was: ${this.manager.score.currentScore}`)
            whichScreen = "select screen";
        }
        else {
            console.log(this.manager.score.currentScore);
            console.log(this.manager.score.goalScore);
        }
        return;
    }

    #findAllMoving() {
        for (let x = 0; x < this._width; x++) {
            for (let y = 0; y < this._height; y++) {
                if (this._tiles[x][y].normalMoving === true) {
                    // console.log("something moving");
                    return true;
                }
                else {
                    // console.log("nothing moving");
                    return false;
                }
            }
        }
    }

    get tiles() {
        return this._tiles;
    }

    get tileSize() {
        return this._tileSize;
    }

    get matching() {
        return this.#matching;
    }

    set matching(value) {
        this.#matching = value;
    }

    get gravity() {
        return this.#gravity;
    }

    set gravity(value) {
        this.#gravity = value;
    }

}
class SpecialTileGrid extends TileGrid {
    #dummyCucumber;
    #dummyBanana;
    #realCucumber;
    #realBanana;

    constructor(width, height, tileSize) {
        super(width, height, tileSize);

        this.#dummyCucumber = new SpecialTile("komkommer", this._tileSize, 1, 8, normalTileGrid);
        this.#dummyBanana = new SpecialTile("bananen", this._tileSize, 5, 8, normalTileGrid);

        this.#realCucumber = new SpecialTile("komkommer", this._tileSize, 1, 8, normalTileGrid);
        this.#realBanana = new SpecialTile("bananen", this._tileSize, 5, 8, normalTileGrid);

        this.#generateTileGrid();
    }

    draw() {
        this.#dummyCucumber.draw();
        this.#dummyBanana.draw();

        this._tiles[1][8].draw();
        this._tiles[5][8].draw();

        if (inputHandler.selectedSpecialTile != undefined) {
            inputHandler.selectedSpecialTile.draw();
        }
    }

    #generateTileGrid() {
        this._tiles = new Array();
        for (let x = 0; x < this._width; x++) {
            this._tiles[x] = new Array();
            for (let y = 0; y < this._height; y++) {
                this._tiles[x][y] = null;
            }
        }
        this._tiles[1][8] = this.#realCucumber;
        this._tiles[5][8] = this.#realBanana;
    }

}


Process abstraction

Bij proces abstractie zijn de onderliggende details van een proces verborgen. Al zou je dus een Koffiezetapparaat als voorbeeld nemen, bij een koffiezetapparaat heb je een knop die clean zegt. Deze knop stuurd een command om het apparaat intern schoon te maken. onder de kap, gaat het apparaat nu alerlij dingen schoon maken.

Wij weten één proces maar intern gebeuren er meerdere andere processen die eigenlijk van ons zijn geabstraheerd.(Thorben, Stackify.com)

Process abstraction in CSharp

Als voorbeeld in C# hebben we hier de de class DrawStartingCard Deze method tekende de classen ObstacleCard, NerfCarden BuffCard. Hier zijn dus de onderliggende datails van het proces verborgen, want er gebeurt een process (DrawStartingCards) die anderen methods (ObstacleCard, NerfCarden BuffCard) weer aan roopt die verborgen zijn.

private void DrawStartingCards()
        {
            cards = new GameObjectList();
            Add(cards);
            cards.Add(new ObstacleCard(0, 0, this));
            cards.Add(new ObstacleCard(900, 0, this));
            cards.Add(new ObstacleCard(900, 200, this));
            cards.Add(new NerfCard(0, 200, this));
            cards.Add(new BuffCard(0, 400, this));
        }
public class ObstacleCard : Card
{
    GameState GameState;
    public ObstacleCard(int x, int y, GameState gameState) : base(x, y, gameState)
    {
        InitializeCard("Obstacle");
        card.Position = new Vector2(x, y);
        Add(card);
        this.GameState = gameState;
    }
    public override void CardUsed(int TileX, int TileY, string TileID)
    {
        Console.WriteLine("ObstacleCard used");
        CreateObstacleTiles(TileX, TileY, TileID);
        Remove(card);
        Gamestate.cards.Remove(card);
    }

    public void CreateObstacleTiles(int TileX, int TileY, string TileID)
    {
        Tile tile = new(Tile.TileType.O, TileX, TileY, TileID);
        tile.Position = new Vector2(TileX, TileY);
        GameState.Add(tile);
        Console.WriteLine("Create obstacle tiles was looped through");
    }
}

Encapsulation

Encapsulation betekent het bundelen van gegevens aan de Class. De functies, variabelen en andere stukken code die in deze class zitten kunnen niet beïnvloed worden door anderen classes of buitenstaanders. Dit kan je doen door een class private en protected properties te geven.(knowledgebase.hbo-ict-hva.nl)

Public, private en protected

In C# kan je public, private en protected properties hebben. In Javascript kan je ook public en private properties hebben maar is er geen ingebouwd mechanisme om properties protected te verklaren

Public

Al heb je public properties en methods dan mogen deze gebruikt worden door alles.

In C# toon je dit aan door er public ervoor te zetten.

Protected

Properties en methods mogen alleen gebruikt worden door de class zelf of door subclasses (child-classes van de parent-class)

In C# Toon je dit aan door er protected ervoor te zetten.

Private

Private properties en methods mogen alleen gebruikt worden door de class zelf, dus ook niet door subclassen.

In C# Toon je dit aan door er private ervoor te zetten en in JavaScript met een #

Encapsulation in JavaScript

In dit voorbeeld uit de code van het project van blok 2 hebben we hier een class met private properties, deze worden in JavaScript aangegeven met de # voor de properties, namelijk typeMap, type, image, size en enlarge. Deze properties zijn dus nu private en kunnen alleen door de Tile class gebruikt worden

class Tile 
    #typeMap;
    #type;
    #image;
    #size;
    #enlarged;

Een ander voorbeeld van hetzelfde project is in de class CanvasManager. Hier worden ook private properties gebruikt, namelijk de width en de height. Deze kunnen dus ook aleen gebruikt worden door de CanvasManager class.

class CanvasManager 
    #width;
    #height;

Encapsulation in CSharp

Anderen voorbeelden van encapsulation in C# is de protected methode initializeCard Zoals hier onder te zien is.

public class Card : GameObjectList
    {
        protected SpriteGameObject card;
        public bool IsSelected {get; set;}
        //public bool IsSelected { get => isSelected; set => isSelected = value; }
        public int StartOffsetX {get; set;}
        public int StartOffsetY {get; set;}
        protected readonly GameState Gamestate;
        protected readonly InputHelper inputHelper;

        public Card(int x, int y, GameState gameState) : base()
        {
            //creates a card with an x & y offset, position and image
            StartOffsetX = x;
            StartOffsetY = y + 50;
            Gamestate = gameState;
            inputHelper = new InputHelper();
        }

        protected void InitializeCard(string CardTypeName)
        {
            card = new SpriteGameObject($"Images/Cards/{CardTypeName}", 0, $"{CardTypeName}");
        }
        //checks whether the mouse is inside the collision box (image) of a card
        public bool CardMouseCollision(Vector2 Mouse)
        {
            return card.BoundingBox.Contains(Mouse);
        }

        public virtual void CardUsed(int TileX, int TileY, string TileID)
        {
            Console.WriteLine("Card used");
            Gamestate.cards.Remove(card);
        }
    }
}
protected void InitializeCard(string CardTypeName)
{
card = new SpriteGameObject($"Images/Cards/{CardTypeName}", 0, $"{CardTypeName}");  
}

Inherintance

Inheritance is dat je een klasse uit een andere klasse afleiden voor een hiërarchie van klassen die properties en methods delen.(Thorben, stackify.com)

Inheritance in JavaScript

In JavaScript kan je dit aan tonen met extend. Door extend te gebruiken neemt de child class alle methods over en door super te gebruiken bij de constructor neem je de methods over van de parent class.

class SpecialTile extends Tile {
    #offset
    #defaultCucumberPosition;
    #defaultBananaPosition;
    constructor(type, size, x, y) {
        super(type, size, x, y);
        this.#defaultCucumberPosition = createVector(1, 8).mult(this.size);
        this.#defaultBananaPosition = createVector(5, 8).mult(this.size);
        this.#offset = createVector(
            (size + this._resizeOffset) / 2,
            (size + this._resizeOffset) / 2
class SpecialTile extends Tile
constructor(type, size, x, y) {
        super(type, size, x, y);
}

Inheritance in CSharp

Inheritance in C# kan je aantonen met het : symbool

In het voorbeeld hieronder inherit de class Knight van de class Piece. De class Knight krijgt nu alle properties en methods van de class piece, mits deze public of protected zijn.

class Knight : Piece

Polymorphism

Polymorphism betekent dat de geinherited class methods overwrite die de main class aan hem doorgeeft.(.w3schools.com)

In het voorbeeld hier onder uit C# staat een class genaamd Pawn, deze Pawn class heeft geinherit van de class Piece.

Door middel van de override keyword overwrite deze child class de movement van de parent class.

class Pawn : Piece
{

    public Pawn(string color, Tile tile) : base("Pawn", color, tile.Y, tile.X, "")
    {
    }

    public override bool GetPossibleMoves(Tile currentTile, Tile targetTile)
    {
        Console.WriteLine("Pawn Movement");

        int direction = (GameState.CurrentTeam.TeamId == "White") ? 1 : -1; 

        if (currentTile.X == targetTile.X && currentTile.Y + direction == targetTile.Y && targetTile.OccupyingPiece == null)
        {
            return true;
        }

        if ((currentTile.Y + direction == targetTile.Y) && 
            (currentTile.X + 1 == targetTile.X || currentTile.X - 1 == targetTile.X) && 
            targetTile.OccupyingPiece != null && 
            targetTile.OccupyingPiece.Color != this.Color)
        {
            return true;
        }

        return false;
    }

}
public override bool GetPossibleMoves(Tile currentTile, Tile targetTile)

Conslusie

Ik heb erg mijn best gedaan op het maken van deze opdracht. Ik ben vooral zelf op onderzoek gegaan naar bronnen en informatie over OOP om zelf zoveel mogelijk ervan te leren, maar er waren ook punten dat ik er zelf niet uit kwam.

Een voorbeeld hiervan is dat ik een beetje vastliep bij abstraction, het concept Procces abstraction snapte ik niet. Ik had er een idee van, maar ik was niet zeker of de betekenis die ik in mijn hoofd had wel de juiste was. Ik heb toen aan Aram gevraagd of hij mij hierbij kon helpen. Toen we er samen ook niet uitkwamen heb ik de betekenis aan Jur gevraagd en welke voorbeelden ik hiervoor zou kunnen gebruiken. Hij zei dat bij process abstractie de onderliggende details van een proces zijn verborgen. Hierbij heeft hij het voorbeeld gebruikt van een koffiezetapparaat.

Ik heb verder nog meer hulp aan mede-studenten gevraagd. Toen ik klaar was met het maken van de opdracht heb ik aan Sed en Noah gevraagd of zij hem nog konden doorlezen en mij feedback kunnen geven over de uitleg en voorbeelden die ik heb gebruikt. Verder hebben zij ook voor spel- en grammaticafouten gekeken. De feedback die ze mij hebben gegeven, heb ik weer meegenomen in het verbeteren van de opdracht.

Hierna heb ik deze opdracht ook nog laten doorlezen door een student mentor, namelijk Nick. Hij heeft mij meerderen feedbackpunten gegven die ik weer heb verwerkt, verder heeft hij me oop beoordeeld op K5 met deze opdracht als bewijs.

Verder heb ik ervoor gekozen om zoveel mogelijke voorbeelden uit JavaScript én C# te gebruiken. Ik had aan Mike gevraagd of ik C# of JavaScript moest gebruiken, en hij zei dat ik mocht kiezen welke ik wilde gebruiken voor deze opdracht. Ik heb ervoor gekozen om ze allebei te gebruiken, zodat ik zo veel mogelijk uit deze opdracht haal.

Het is natuurlijk vervelend om een extra opdracht te maken naast het normale schoolwerk, maar ik heb veel geleerd van deze opdracht. Er zijn dingen waar ik eerst nog niet veel vanaf wist, zoals waarom ik een property private zou gebruiken en wat nou het verschil is tussen abstraction en encapsulation. Deze vragen zou ik nu wél kunnen beantwoorden.

Bronnen

Wat is OOP?

Pilaren van OOP

Abstarction

abstract (C# Reference)

Pijlers van OOP

Why private variables:

Inheritance in C#

OOP: Inheritance

Polymorphism in C#


Last update: April 4, 2024