%%html

<style>
    #canvas {
        margin: 0;
        border: 1px solid white;
    }
</style>
<canvas id="canvas"></canvas>
<script>
    // Create empty canvas
    let canvas = document.getElementById('canvas');
    let c = canvas.getContext('2d');
    // Set the canvas dimensions
    canvas.width = 650;
    canvas.height = 400;
    // Set gravity value
    let gravity = 1.5;
    // Define the Player class
    class Player {
        constructor() {
            // Initial position and velocity of the player
            this.position = {
                x: 100,
                y: 200
            };
            this.velocity = {
                x: 0,
                y: 0
            };
            // Dimensions of the player
            this.width = 30;
            this.height = 30;
        }
        // Method to draw the player on the canvas
        draw() {
            c.fillStyle = 'red';
            c.fillRect(this.position.x, this.position.y, this.width, this.height);
        }
        // Method to update the player position and velocity
        update() {
            this.draw();
            this.position.y += this.velocity.y;
            this.position.x += this.velocity.x;
            // Apply gravity if player is not at the bottom
            if (this.position.y + this.height + this.velocity.y <= canvas.height)
                this.velocity.y += gravity;
            else
                this.velocity.y = 0;
        }
    }
    // Define the Platform class
    class Platform {
        constructor(image) {
            // Initial position of the platform
            this.position = {
                x: 0,
                y: 300
            }
            this.image = image;
            this.width = 650;
            this.height = 100;
        }
        // Method to draw the platform on the canvas
        draw() {
            c.drawImage(this.image, this.position.x, this.position.y, this.width, this.height);
        }
    }
    // Define the Tube class
    class Tube {
        constructor(image) {
            // Initial position of the tube
            this.position = {
                x: 500,
                y: 180
            }
            this.image = image;
            this.width = 100;
            this.height = 120;
        }
        // Method to draw the tube on the canvas
        draw() {
            c.drawImage(this.image, this.position.x, this.position.y, this.width, this.height);
        }
    }
    // Define the BlockObject class
    class BlockObject {
        constructor(image) {
            // Initial position of the block object
            this.position = {
                x: 200,
                y: 100
            };
            this.image = image;
            this.width = 158;
            this.height = 79;
        }
        // Method to draw the block object on the canvas
        draw() {
            c.drawImage(this.image, this.position.x, this.position.y);
        }
    }
    //--
    // NEW CODE - CREATE GENERICOBJECT CLASS FOR THE BACKGROUND IMAGES
    //--
    class GenericObject {
        constructor({ x, y, image }) {
            this.position = {
                x,
                y
            };
            this.image = image;
            this.width = 760;
            this.height = 82;
        }
        // Method to draw the generic object on the canvas
        draw() {
            c.drawImage(this.image, this.position.x, this.position.y);
        }
    }
    // Load image sources
    let image = new Image();
    let imageTube = new Image();
    let imageBlock = new Image();
    //--
    // NEW CODE - ADD IMAGES FOR BACKGROUND
    //--
    let imageBackground = new Image();
    let imageHills = new Image();
    image.src = 'https://samayass.github.io/samayaCSA/images/platform.png';
    imageTube.src = 'https://samayass.github.io/samayaCSA/images/tube.png';
    imageBlock.src = 'https://samayass.github.io/samayaCSA/images/box.png';
    //--
    // NEW CODE - IMAGE URLS FOR BACKGROUND IMAGES
    //--
    imageBackground.src = 'https://samayass.github.io/samayaCSA/images/background.png';
    imageHills.src = 'https://samayass.github.io/samayaCSA/images/hills.png';
    // Create instances of platform, tube, block object, and generic objects
    let platform = new Platform(image);
    let tube = new Tube(imageTube);
    let blockObject = new BlockObject(imageBlock);
    //--
    // NEW CODE - CREATE ARRAY FOR GENERIC OBJECTS THEN ADD THE HILLS AND BACKGROUND
    //--
    let genericObjects = [
        new GenericObject({
            x:0, y:0, image: imageBackground
        }),
        new GenericObject({
            x:0, y:70, image: imageHills
        }),
    ];
    player = new Player();
    // Define keys and their states
    let keys = {
        right: {
            pressed: false
        },
        left: {
            pressed: false
        }
    };
    // Animation loop
    function animate() {
        requestAnimationFrame(animate);
        c.clearRect(0, 0, canvas.width, canvas.height);
        //--
        // NEW CODE - DRAW GENERIC OBJECTS WITH FOR EACH LOOP
        //--
        genericObjects.forEach(genericObject => {
            genericObject.draw()
        });
        // Draw platform, player, tube, and block object
        platform.draw();
        player.update();
        tube.draw();
        blockObject.draw();
        // Handle collisions and interactions
        // Handle collision between player and block object
        if (
            player.position.y + player.height <= blockObject.position.y &&
            player.position.y + player.height + player.velocity.y >= blockObject.position.y &&
            player.position.x + player.width >= blockObject.position.x &&
            player.position.x <= blockObject.position.x + blockObject.width
        )
        {
            player.velocity.y = 0;
        }
        // Handle collision between player and platform
        if (
            player.position.y + player.height <= platform.position.y &&
            player.position.y + player.height + player.velocity.y >= platform.position.y &&
            player.position.x + player.width >= platform.position.x &&
            player.position.x <= platform.position.x + platform.width
        )
        {
            player.velocity.y = 0;
        }
        // Handle interaction with tube
        if (
            player.position.y + player.height <= tube.position.y &&
            player.position.y + player.height + player.velocity.y >= tube.position.y &&
            player.position.x + player.width >= tube.position.x &&
            player.position.x <= tube.position.x + tube.width
        ) {
            player.velocity.y = 0;
            player.position.y += 0.1;
            player.velocity.y = 0.0001;
            gravity = 0.2;
        }
        // Adjust gravity after leaving the tube
        if (player.position.y + player.height == tube.position.y + tube.height ||
            player.position.y + player.height <= tube.position.y ||
            player.position.x + player.width <= tube.position.x ||
            player.position.x >= tube.position.x + tube.width) {
                gravity = 1.5;
            }
        // Handle collision with tube sides
        if (
            player.position.x + player.width<= tube.position.x &&
            player.position.x + player.width + player.velocity.x >= tube.position.x &&
            player.position.y + player.height >= tube.position.y &&
            player.position.y <= tube.position.y + tube.height
        )
        {
            player.velocity.x = 0;
        }
        if (
            player.position.x >= tube.position.x + tube.width &&
            player.position.x + player.velocity.x <= tube.position.x + tube.width &&
            player.position.y + player.height >= tube.position.y &&
            player.position.y <= tube.position.y + tube.height
        )
        {
            player.velocity.x = 0;
        }
        if (
            player.position.x >= tube.position.x &&
            player.position.x + player.velocity.x <= tube.position.x &&
            player.position.y + player.height >= tube.position.y &&
            player.position.y <= tube.position.y + tube.height
        )
        {
            player.velocity.x = 0;
        }
        if (
            player.position.x + player.width <= tube.position.x + tube.width &&
            player.position.x + player.width + player.velocity.x >= tube.position.x + tube.width &&
            player.position.y + player.height >= tube.position.y &&
            player.position.y <= tube.position.y + tube.height
        )
        {
            player.velocity.x = 0;
        }
        // Move the player horizontally and adjust other objects
        if (keys.right.pressed && player.position.x < 400) {
            player.velocity.x = 15;
        }
        else if (keys.left.pressed && player.position.x > 100) {
            player.velocity.x = -15;
        }
        //--
        // NEW CODE - PARALLAX SCROLLING EFFECT (MAKE THE BACKGROUND MOVE TO CREATE ILLUSION OF PLAYER MOVING)
        //--
        else {
            player.velocity.x = 0;
            if (keys.right.pressed && !keys.left.pressed) {
                platform.position.x -= 15;
                tube.position.x -= 15;
                blockObject.position.x -= 15;
                // make the background move slower for a cooler effect
                genericObjects.forEach(genericObject => {
                    genericObject.position.x -= 5;
                });
            }
            else if (keys.left.pressed && !keys.right.pressed) {
                platform.position.x += 15;
                tube.position.x += 15;
                blockObject.position.x += 15;
                genericObjects.forEach(genericObject => {
                    genericObject.position.x += 5;
                });
            }
        }
    }
    // Start the animation loop
    animate();
    // Event listener for key presses
    addEventListener('keydown', ({ keyCode }) => {
        switch (keyCode) {
            case 65:
                console.log('left');
                keys.left.pressed = true;
                break;
            case 83:
                console.log('down');
                break;
            case 68:
                console.log('right');
                keys.right.pressed = true;
                break;
            case 87:
                console.log('up');
                player.velocity.y -= 20;
                break;
        }
    });
    // Event listener for key releases
    addEventListener('keyup', ({ keyCode }) => {
        switch (keyCode) {
            case 65:
                console.log('left');
                keys.left.pressed = false;
                break;
            case 83:
                console.log('down');
                break;
            case 68:
                console.log('right');
                keys.right.pressed = false;
                break;
            case 87:
                console.log('up');
                player.velocity.y = -20;
                break;
        }
    });
</script>

Specific Hack

  • Add flying enemies that move at different rates (ex: birds with lasers)

Open Ended Hack

  • Expand the map