Skip to content
Snippets Groups Projects
game.js 28 KiB
Newer Older
  • Learn to ignore specific revisions
  • Bye's avatar
    Bye committed
    /* 
        For js13k 2022
        Theme: death
    */
    
    // Functions for my little game engine thing
    const log = (logType, msg) => {
        console.log(`[${logType}] ${msg}`);
    }
    
    
    // CONFIG
    const fontStack = '"Comic Sans MS"';
    var id = 0;
    var pi = Math.PI;
    
    Bye's avatar
    Bye committed
    gPar = (key) => {
    
        // Address of the current window
        let address = window.location.search
    
        // Returns a URLSearchParams object instance
        let parameterList = new URLSearchParams(address)
    
        // Returning the respected value associated
        // with the provided key
        return parameterList.get(key)
    }
    
    var customLv = gPar("lv");
    
    Bye's avatar
    Bye committed
    
    class Canvas {
        constructor(id) {
    
    Bye's avatar
    Bye committed
            this.c = document.getElementById(id);
            this.ctx = this.c.getContext('2d');
            this.w = this.c.width;
            this.h = this.c.height;
    
    Bye's avatar
    Bye committed
            // get the width and height of the canvas from CSS
    
    Bye's avatar
    Bye committed
            this.tW = this.c.offsetWidth;
            this.tH = this.c.offsetHeight;
            this.scale = this.tW / this.w;
    
    Bye's avatar
    Bye committed
            this.camera = {x: 0, y: 0};
    
            this.mousePos = {x: 0, y: 0};
            this.realMousePos = {x: 0, y: 0};
    
        }
    
        fill(color) {
            this.ctx.fillStyle = color;
    
    Bye's avatar
    Bye committed
            this.ctx.fillRect(0, 0, this.w, this.h);
    
    Bye's avatar
    Bye committed
        }
    
        // Mouse position crap
        getMousePos(evt) {
    
    Bye's avatar
    Bye committed
            var rect = this.c.getBoundingClientRect(), // abs. size of element
              scaleX = this.c.width / rect.width,    // relationship bitmap vs. element for x
              scaleY = this.c.height / rect.height;  // relationship bitmap vs. element for y
    
    Bye's avatar
    Bye committed
    
            this.mousePos.x = ((evt.clientX - rect.left) * scaleX) + this.camera.x;
            this.mousePos.y = ((evt.clientY - rect.top) * scaleY) + this.camera.y;
          
            return {
              x: (evt.clientX - rect.left) * scaleX,   // scale mouse coordinates after they have
              y: (evt.clientY - rect.top) * scaleY     // been adjusted to be relative to element
            }
          }
    
        translate(x, y) {
            this.ctx.translate(x, y);
        }
    
        rotate(angle) {
            this.ctx.rotate(angle);
        }
    
        // Drawing
        drawImg(img, x,y,w,h, direction=0, originx=x+w/2, originy=y+h/2) {
            this.ctx.save();
            this.ctx.translate(originx-this.camera.x, originy-this.camera.y);
            this.ctx.rotate(direction * pi/180);
            this.ctx.drawImage(img, (-w/2), -h/2, w, h);
            this.ctx.restore();
        }
        sliceImage(img, x, y, w, h, cropX, cropY, cropW, cropH, direction=0) {
            this.ctx.save();
            this.ctx.translate((x+w/2)-this.camera.x, (y+h/2)-this.camera.y);
            this.ctx.rotate(direction * pi/180);
            this.ctx.drawImage(img, cropX, cropY, cropW, cropH, -w/2, -h/2, w, h);
            this.ctx.restore();
            // console.log(`${x}, ${y}, ${w}, ${h}, ${cropX}, ${cropY}, ${cropW}, ${cropH}`);
        }
        
        drawImage(img, x, y, w, h, direction=0) {
            // alias for drawImg
            this.drawImg(img, x, y, w, h, direction);
        }
    
        drawRect(x, y, w, h, color="white") {
            this.ctx.fillStyle = color;
            this.ctx.fillRect(x-this.camera.x, y-this.camera.y, w, h);
        }
    
        strokeRect(x, y, w, h, color) {
            this.ctx.strokeStyle = color;
            this.ctx.strokeRect(x-this.camera.x, y-this.camera.y, w, h);
        }
    
        drawFont(string, x, y, color, align="start") {
            this.ctx.fillStyle = color;
            this.ctx.textAlign = align;
            this.ctx.fillText(string, x-this.camera.x, y-this.camera.y);
        }
    
    
    Bye's avatar
    Bye committed
        dT(string, x, y, scaley, scalex, color, align="start", vAliign="top", ops={}) {
    
    Bye's avatar
    Bye committed
    
            // console.log(ops);
    
            // console.log(string)
    
            string = string.toUpperCase();
            let chars = string.split("");
            // console.log(chars);
            
            let charWidth = 7
            let strLength = (chars.length * charWidth - 1) * scalex; 
    
            let charHeight = 7
            let strHeight = (charHeight * scaley);
    
            switch(align) {
                case "start":
                case "left":
                    x = x;
                    break;
                case "center":
                case "middle":
                    x = x - strLength/2;
                    break;
                case "end":
                case "right":
                    x = x - strLength;
                    break;
            }
            switch(vAliign) {
                case "top":
                    y = y;
                    break;
                case "middle":
                case "center":
                    y = y - strHeight/2;
                    break;
                case "bottom":
                    y = y - strHeight;
                    break;
            }
    
            
            let charI = 0;
            let nextOffset = (7 * scalex);
            let lastWasFull = false;
            
            for (let char of chars) {
                
                this.ctx.fillStyle = color;
                let row = 0;
                let col = 0;
                // offset is the amount of pixels to offset the character by. you can calculate this by multiplying the current character (they're all the same size) by the scalex and scaley
                let offset = nextOffset;
    
                if (lastWasFull) {
                    offset -= (0.5 * scalex);
                    lastWasFull = false;
                }
                
                if(ops.shortFullStop) {
                    if(char == ".") {
                        lastWasFull = true;
                    }
                }
    
    
    Bye's avatar
    Bye committed
                char = fI[char];
    
    Bye's avatar
    Bye committed
                if (char == undefined) {
                    // leave a blank space
                } else {
                    for (let cRow in char) {
                        col = 0;
                        // for each pixel in the row
                        for (let c of char[cRow]) {
                            if (c == 1) {
                                this.ctx.fillRect((x + (col * scalex) + (charI * offset)) - this.camera.x,( y + (row * scaley)) - this.camera.y, scalex, scaley);
    
                            }
                            col++;
                        }
                        row++;
                    }
                }
    
                charI++;
                // console.log(charI)
    
                nextOffset = (7 * scalex);
    
            }
    
    
    Bye's avatar
    Bye committed
            return {
                "w": strLength
            }
    
    
    Bye's avatar
    Bye committed
        }
    
        setFont(fontStack, size="10") {
            this.ctx.font = `${size}px ${fontStack}`
        }
    
        drawLine(x1, y1, x2, y2, color) {
            this.ctx.strokeStyle = color;
            this.ctx.beginPath();
            this.ctx.moveTo(x1-this.camera.x, y1-this.camera.y);
            this.ctx.lineTo(x2, y2);
            this.ctx.stroke();
        }
    
        // Camera stuff
    
    Bye's avatar
    Bye committed
        mvCamera(x, y) {
    
    Bye's avatar
    Bye committed
            this.camera.x += x;
            this.camera.y += y;
        }
    
        setCamera(x, y, s=1) {
            this.camera.x = x;
            this.camera.y = y;
        }
    
    }
    
    // Entity classes
    
    class Entity {
        constructor(name, x, y, sprite=undefined) {
            this.name = name,
            this.x = x,
            this.y = y,
            this.sprite = sprite
        }
        step() {
            console.log(`${this.name} is stepping`);
            console.log(`${this.name} is at ${this.x}, ${this.y}`);
        }
        draw () {
    
        }
        intersects(other) {
            return (this.x < other.x + other.w && this.x + this.w > other.x && this.y < other.y + other.h && this.y + this.h > other.y)
        }
    }
    
    class Room {
        constructor(name) {
            this.id = id;
            id += 1;
            this.name = name;
            this.objects = [];
            this.hitboxes = [];
            this.background = [];
    
    Bye's avatar
    Bye committed
            this.w = c.w;
            this.h = c.h;
    
    Bye's avatar
    Bye committed
        }
    
        spawn(entity) {
            this.objects.push(entity)
        }
    
        step() {
            // step all objects in the room
            for (let obj of this.objects) {
                obj.step();
            }
        }
    
        draw() {
            // draw all objects in the room
            for (let obj of this.objects) {
                obj.draw();
            }
        }
    
        drawGUI() {
    
        }
    
        keyDown(key) {
            // console.log(key);
        }
        keyHeld(key) {
            // console.log(key);
        }
        click(x, y) {
            // console.log(x, y);
        }
    
    Bye's avatar
    Bye committed
        mHeld(x,y){
    
        }
    
    Bye's avatar
    Bye committed
    
        start() {
    
        }
    
    }
    
    // INIT CANVAS
    
    Bye's avatar
    Bye committed
    var fI = fntINDEX; // in letters.js
    var c = new Canvas('gameCanvas');
    
    Bye's avatar
    Bye committed
    // check if the canvas is supported
    
    Bye's avatar
    Bye committed
    if(!c.ctx) {
    
    Bye's avatar
    Bye committed
        alert("Your browser does not support the canvas element");
    }
    
    Bye's avatar
    Bye committed
    gameCtx = c.ctx;
    c.fill("#1c1c1c");
    c.setFont(fontStack);
    
    Bye's avatar
    Bye committed
    gameCtx.imageSmoothingEnabled = false;
    var gameStart = false;
    
    
    Bye's avatar
    Bye committed
    c.dT("Death By Hamster", c.w / 2, c.h / 2 - 40, 2, 2, "white", "middle");
    
    Bye's avatar
    Bye committed
    
    // Load images
    var images = {
        "mouse": {
            "ingame": "./assets/aimerthing.png",
            "cursor": "./cursor.png"
        },
        "level": {
            "tileset": "./t.png"
        },
        "player": {
            "debugarrow": "./assets/arrow.png",
            "car": "./hamster.png",
            "gun": "./gun.png",
    
    Bye's avatar
    Bye committed
        },
        "ui": {
            "a": "./arw.png" // arrow
    
    Bye's avatar
    Bye committed
        }
    };
    
    var loader = new Room("loader");
    var loadingText = "Loading...";
    var loadingError = 0;
    loader.drawGUI = () => {
    
    Bye's avatar
    Bye committed
        c.dT(loadingText, c.w / 2, c.h / 2, 2, 2, "white", "middle");
    
    Bye's avatar
    Bye committed
        if (loadingError) {
    
    Bye's avatar
    Bye committed
            c.dT(loadingErrorText, c.w / 2, c.h / 2 + 20, 1, 1, "red", "middle");
    
    Bye's avatar
    Bye committed
        }
    }
    var rooms = [];
    
    var loadedImages = 0;
    var totalImages = 0;
    
    // count the total number of images to load
    for (let key in images) {
        for (let subkey in images[key]) {
            totalImages++;
        }
    }
    
    loadingText = `Loading...`;
    
    loadingText = `Loading images (${loadedImages} / ${totalImages})`
    
    
    // after all images are loaded, and no errors occured, start the game
    for (var key in images) {
        for (var subkey in images[key]) {
            
            // attempt to load the image
            var IMG = new Image();
            IMG.addEventListener('load', () => {
                loadedImages++;
                loadingText = `Loading images (${loadedImages} / ${totalImages})`
                if (loadedImages == totalImages) {
                    loader.step = () => {
                        cRoom = rooms[1];
                    }
                    loadingText = "Loaded! Please wait...";
                }
            });
            IMG.addEventListener('error', (e) => {
                loadingError = 1;
                loadingErrorText = `Error loading image ${e.target.src}`;
            } );
            IMG.src = images[key][subkey];
    
            // add the image to the images object
            images[key][subkey] = IMG;
            
            // draw the loading text by drawing a rectangle over the previous text, and drawing the new text
            loadingText = `Loading images (${loadedImages} / ${totalImages})`
            
        }
    }
    
    var levels = [
        {
    
    Bye's avatar
    Bye committed
            "name": "Tutorial",
            "data": "[[1,1,2],[1,1,3],[5,1,4],[1,1,1],[2,0,3],[2,0,2],[2,0,1],[4,0,0],[5,1,0],[5,2,0],[5,3,0],[5,4,0],[5,6,0],[5,5,0],[5,7,0],[6,8,0],[0,9,0],[0,10,0],[2,8,1],[2,8,2],[2,8,3],[8,8,4],[5,7,4],[5,5,4],[5,6,4],[5,4,4],[5,2,4],[5,3,4],[7,0,4],[1,2,3],[9,2,2],[1,2,1],[1,3,1],[1,3,2],[1,3,3],[1,4,3],[1,4,2],[1,4,1],[1,5,1],[1,5,2],[1,5,3],[1,6,3],[10,6,2],[1,6,1],[1,7,1],[1,7,2],[1,7,3]]"
        },
        {
            "name": "First Floor"
        },
    
    Bye's avatar
    Bye committed
    ]
    
    hamsterRef = {
        "file": images.player.car,
    
    Bye's avatar
    Bye committed
        "nl": {
    
    Bye's avatar
    Bye committed
            "x": 1,
            "y": 1,
            "w": 32,
            "h": 16,
        },
    
    Bye's avatar
    Bye committed
        "b": {
    
    Bye's avatar
    Bye committed
            "x": 35,
            "y": 1,
            "w": 32,
            "h": 16,
        },
    
    Bye's avatar
    Bye committed
        "br": {
    
    Bye's avatar
    Bye committed
            "x": 1,
            "y": 20,
            "w": 32,
            "h": 16,
        },
    
    Bye's avatar
    Bye committed
        "r": {
    
    Bye's avatar
    Bye committed
            "x": 35,
            "y": 20,
            "w": 32,
            "h": 16,
        }
    }
    
    var levelRef = {
        "file": images.level.tileset,
        "default": {
            "x": 0,
            "y": 0,
            "w": 32,
            "h": 32,
    
    Bye's avatar
    Bye committed
            "type": "blank"
    
    Bye's avatar
    Bye committed
        },
        "tiles": [
            {
            },
            {
                "x": 32,
    
    Bye's avatar
    Bye committed
                "type": "floor"
    
    Bye's avatar
    Bye committed
            },
            {
                "x": 64,
    
    Bye's avatar
    Bye committed
                "type": "wall"
    
    Bye's avatar
    Bye committed
            },
    
    Bye's avatar
    Bye committed
            {
                "x": 96,
    
    Bye's avatar
    Bye committed
                "type": "wall"
    
    
    Bye's avatar
    Bye committed
            },
            {
                "x": 128,
    
    Bye's avatar
    Bye committed
                "type": "wall"
    
    Bye's avatar
    Bye committed
            },
            {
                "x": 160,
    
    Bye's avatar
    Bye committed
                "type": "wall"
    
    Bye's avatar
    Bye committed
            },
            {
                "x": 192,
    
    Bye's avatar
    Bye committed
                "type": "wall"
    
    Bye's avatar
    Bye committed
            },
            {
                "x": 224,
    
    Bye's avatar
    Bye committed
                "type": "wall"
    
    Bye's avatar
    Bye committed
            },
            {
                "x": 256,
    
    Bye's avatar
    Bye committed
                "type": "wall"
    
    Bye's avatar
    Bye committed
            },
            { // player
    
    Bye's avatar
    Bye committed
                "x": 32,
                "type": "floor"
    
    Bye's avatar
    Bye committed
            },
            { // human
    
    Bye's avatar
    Bye committed
                "x": 32,
                "type": "floor"
    
    Bye's avatar
    Bye committed
            }
    
    Bye's avatar
    Bye committed
        ]
    }
    
    for (let tile of levelRef.tiles) {
        // if the tile is missing properties from the default, add them
        for (let key in levelRef.default) {
            if (!tile[key]) {
                tile[key] = levelRef.default[key];
            }
        }
    }
    
    console.debug(images)
    var targFPS = 60;
    var frame = 0;
    
    
    var menu = new Room("menu");
    
    
    Bye's avatar
    Bye committed
    menu.s = 0
    menu.o = [
        {
            "t": "Play",
    
    Bye's avatar
    Bye committed
            "a": _=>{ setRoom(4) } // go to game room
    
    Bye's avatar
    Bye committed
        },
        {
            "t": "Editor",
            "a": _=>{ setRoom(3) } // go to level editor
        }
    ]
    
    
    Bye's avatar
    Bye committed
    
    menu.drawGUI = () => {
    
    Bye's avatar
    Bye committed
        c.dT("Death by Hamster", c.w/2, c.h/2-25, 4, 4, "white", "middle", "middle");
        c.dT("W/Up or S/Down to select", c.w/2, c.h/2, 1,1,"gray","middle","middle");
        c.dT("Space or ENTER to activate", c.w/2, c.h/2+8, 1,1,"gray","middle","middle")
        for (let o in menu.o) {
            let txt = c.dT(`${menu.o[o].t}`, c.w/2, (c.h/2+50)+(o*20), 2,2,"#fff","middle","top");
            if (menu.s == o) {
                let a = images.ui.a;
                let ap = ((c.w/2)-(txt.w/2))-a.width-4;
                let ap2 = ((c.w/2)+(txt.w/2))+a.width-4;
                c.drawImg(a, ap, (c.h/2+50)+(o*20), a.width*2, a.height*2)
                c.drawImg(a, ap2, (c.h/2+50)+(o*20), a.width*2, a.height*2, 180)
            }
        }
    
    Bye's avatar
    Bye committed
    }
    const nextRoom = () => {
        // move to the next room
        roomI++;
        if (roomI >= rooms.length) {
            roomI = 0;
        }
        cRoom = rooms[roomI];
        cRoom.start();
    }
    
    const prevRoom = () => {
        // move to the previous room
        roomI--;
        if (roomI < 0) {
            roomI = rooms.length - 1;
        }
        cRoom = rooms[roomI];
        cRoom.start();
    }
    
    const setRoom = (roomI) => {
        // set the current room to the given room
        cRoom = rooms[roomI];
    
    Bye's avatar
    Bye committed
        cRoom.start();
    
    Bye's avatar
    Bye committed
    }
    menu.keyDown = (key) => {
    
    Bye's avatar
    Bye committed
        if (key == "ArrowUp" || key == "KeyW") {
            menu.s -= 1
            if (menu.s < 0) {
                menu.s = menu.o.length-1
            }
        }
        if (key == "ArrowDown" || key == "KeyS") {
            menu.s += 1
            if (menu.s > menu.o.length-1) {
                menu.s = 0
            }
        }
        if (key == "Space" || key == "Enter") {
            menu.o[menu.s].a();
    
    Bye's avatar
    Bye committed
        }
    }
    
    var gameRoom = new Room("Game");
    gameRoom.level = levels[0];
    var player   = new Entity("Player", 0,0);
    player.speed = 0;
    player.maxSpeed = 5;
    player.direction = 0;
    player.accel = 1;
    player.sprite = images.player.car;
    console.debug(player.sprite);
    
    Bye's avatar
    Bye committed
    player.crop = hamsterRef.nl;
    player.x = 0;
    player.y = 0;
    
    Bye's avatar
    Bye committed
    player.w = player.crop.w*2;
    player.h = player.crop.h*2;
    
    player.step = () => {
        // move in this.direction, which is an angle in degrees
        player.x += player.speed * Math.cos(player.direction * pi / 180);
        player.y += player.speed * Math.sin(player.direction * pi / 180);
    
        player.speed *= 0.009;
    
    
    Bye's avatar
    Bye committed
        // check that the player won't go into a wall on the next step, and if so, stop.
        for (let tile of gameRoom.level) {
            if (player.x/64 > tile.x && player.x/64 < tile.x + tile.w && player.y/64 > tile.y && player.y/64 < tile.y + tile.h) {
                player.speed = 0;
            }
        }
    
    
    Bye's avatar
    Bye committed
        // keep the camera centered on the player
    
    Bye's avatar
    Bye committed
        c.setCamera(player.x - c.w/2, player.y - c.h/2);
    
    Bye's avatar
    Bye committed
    
    }
    
    console.log(player);
    
    player.draw = () => {
        // draw this.sprite at this.x, this.y
    
    Bye's avatar
    Bye committed
        c.sliceImage(player.sprite, player.x, player.y, player.w, player.h, player.crop.x, player.crop.y, player.crop.w, player.crop.h, player.direction);
    
    Bye's avatar
    Bye committed
        // canvas.strokeRect(player.x, player.y, player.w, player.h, "white");
    
        let gun = images.player.gun;
    
    Bye's avatar
    Bye committed
        let gunOx = 13;
    
    Bye's avatar
    Bye committed
        let gunOy = 0;
    
        let carCx = player.x + player.w/2;
        let carCy = player.y + player.h/2;
        
        // get gunx and guny by moving backwards (gunOx and gunOy) from the center of the car in this.direction
        let gunx = carCx - gunOx * Math.cos(player.direction * pi / 180) - gunOy * Math.sin(player.direction * pi / 180);
        let guny = carCy - gunOx * Math.sin(player.direction * pi / 180) + gunOy * Math.cos(player.direction * pi / 180);
        player.gx = gunx
        player.gy = guny
    
        // get the angle between the gun and the mouse
    
    Bye's avatar
    Bye committed
        player.aim = Math.atan2(c.mousePos.y - guny, c.mousePos.x - gunx) * 180 / pi;
    
    Bye's avatar
    Bye committed
    
        // canvas.drawText(`Width${gun.width} Height${gun.height}`, gunx, guny-15, 1, 1, "green", "middle", "middle");
    
    Bye's avatar
    Bye committed
        c.drawImg(gun, gunx, guny, gun.width*2, gun.height*2, player.aim, gunx, guny); // these two vars at the end are where the gun's center is placed
    
    Bye's avatar
    Bye committed
        // canvas.drawRect(gunx, guny, 1,1, "red");
    
    }   
    
    player.shoot = () => {
        // shoot a bullet
        let bullet = new Entity("Bullet", player.gx, player.gy);
        bullet.speed = 20;
        bullet.direction = player.aim;
        
        bullet.step = () => {
            // for each step, check if it's path intersects with any other entity
            for (let i = 0; i < cRoom.objects.length; i++) {
                let ent = cRoom.objects[i];
                if (ent != bullet && ent.intersects(bullet)) {
                    // if it does, remove the bullet and the entity unless it's the player
                    if (ent != player) {
                        cRoom.objects.splice(i, 1);
                        cRoom.objects.splice(cRoom.objects.indexOf(bullet), 1);
                    }
                    return;
                }
            }
            // if it doesn't, move the bullet
            bullet.x += bullet.speed * Math.cos(bullet.direction * pi / 180);
            bullet.y += bullet.speed * Math.sin(bullet.direction * pi / 180);
        }
        bullet.draw = () => {
    
    Bye's avatar
    Bye committed
            c.drawRect(bullet.x, bullet.y, 2,2, "white");
    
    Bye's avatar
    Bye committed
        }
        cRoom.spawn(bullet);
    }
    
    
    gameRoom.spawn(player);
    
    gameRoom.keyDown = (key) => {
        console.log(key);
    
        if (key == "ArrowUp" || key == "KeyW") {
            player.speed += player.accel*2;
            if (player.speed > player.maxSpeed) {
                player.speed = player.maxSpeed;
            }
        }
        if (key == "ArrowDown" || key == "KeyS") {
            player.speed -= player.accel*1.5;
            if (player.speed < -player.maxSpeed) {
                player.speed = -player.maxSpeed;
            }
        }
        if (key == "ArrowLeft" || key == "KeyA") {
            player.direction -= 2.5;
            if (player.direction < 0) {
                player.direction = 360;
            }
        }
        if (key == "ArrowRight" || key == "KeyD") {
            player.direction += 2.5;
            if (player.direction > 360) {
                player.direction = 0;
            }
        }
        if (key == "Space") {
            player.shoot();
        }
    }
    gameRoom.keyHeld = (key) => {
        if (key == "ArrowUp" || key == "KeyW") {
            player.speed += player.accel*1.9;
            if (player.speed > player.maxSpeed) {
                player.speed = player.maxSpeed;
            }
        }
        if (key == "ArrowDown" || key == "KeyS") {
            player.speed -= player.accel*1.53;
            if (player.speed < -player.maxSpeed) {
                player.speed = -player.maxSpeed;
            }
        }
        if (key == "ArrowLeft" || key == "KeyA") {
            player.direction -= 2.5;
            if (player.direction < 0) {
                player.direction = 360;
            }
        }
        if (key == "ArrowRight" || key == "KeyD") {
            player.direction += 2.5;
            if (player.direction > 360) {
                player.direction = 0;
            }
        }
    }
    gameRoom.click = (e) => {
        player.shoot();
    }
    
    
    Bye's avatar
    Bye committed
    gameRoom.start = () =>{
        if (customLv) {
            gameRoom.level = customLv
        }
        gameRoom.level = JSON.parse(gameRoom.level);
    
        for (let tile of gameRoom.level) {
            if (tile[0] === 9) {
    
    Bye's avatar
    Bye committed
                player.x = (tile[1]*64)+32
                player.y = (tile[2]*64)+32
            }
            if(tile[0]===10){
                let checkwall = (tx,ty) => {
                    for (let tile of gameRoom.level) {
                        if (levelRef.tiles[tile[0]].type == "wall" && tile[1] == tx && tile[2] == ty) {
                            return true;
                        }
                    }
                    return false;
                }
    
                let pooman = new Entity("Human", (tile[1]*64),(tile[2]*64), images.mouse.cursor)
                pooman.step = _=>{
                    if (pooman.timer<=0){
                        let director = Math.floor(Math.random()*4)
                        pooman.direction = director*90;
                        let tX = Math.floor(pooman.x / 64)
                        let tY = Math.floor(pooman.y / 64)
                        if (director === 0){
                            if (!checkwall(tX,tY-1)){
                                pooman.y -= 64;
                            }
                        }
                        if (director === 1){
                            if (!checkwall(tX+1,tY)){
                                pooman.x += 64;
                            }
                        }
                        if (director === 2){
                            if (!checkwall(tX,tY+1)){
                                pooman.y += 64;
                            }
                        }
                        if (director === 3){
                            if (!checkwall(tX-1,tY)){
                                pooman.x -= 64;
                            }
                        }
                        pooman.timer = 90;
                    }
                    pooman.timer--;
                }
                pooman.draw = _=>{
                    c.drawImage(images.mouse.cursor, pooman.x, pooman.y, 64, 64, pooman.direction);
                    c.dT(`${pooman.timer} :: ${pooman.direction}`, pooman.x, pooman.y, 1, 1, "white", "middle", "middle");
                }
                pooman.timer = 90;
                gameRoom.spawn(pooman);
    
    Bye's avatar
    Bye committed
            }
    
    Bye's avatar
    Bye committed
        }
    }
    
    gameRoom.draw = () => {
    
    Bye's avatar
    Bye committed
        for (let tile of gameRoom.level) {
    
    Bye's avatar
    Bye committed
            // [index, x, y]
    
    Bye's avatar
    Bye committed
            c.sliceImage(levelRef.file, (tile[1]*32)*2, (tile[2]*32)*2, 32*2,32*2, levelRef.tiles[tile[0]].x, 0, 32, 32);
    
    Bye's avatar
    Bye committed
        }
        
        for (let i = 0; i < cRoom.objects.length; i++) {
            cRoom.objects[i].draw();
        }
    }
    
    
    Bye's avatar
    Bye committed
    let editor = new Room("Editor");
    
    Bye's avatar
    Bye committed
    editor.i = 0;
    editor.t = levelRef;
    editor.l = []
    editor.n = "LV1"
    editor.saving = false
    editor.sa = 0
    
    editor.start = _=>{
        editor.dPos = [15,65]
    }
    editor.draw = _=>{
        for (let tile of editor.l) {
            // [index, x, y]
            c.sliceImage(levelRef.file, (tile[1]*32)+editor.dPos[0], tile[2]*32+editor.dPos[1], 32,32, tile[0]*32, 0, 32, 32);
            c.drawRect(editor.dPos[0], editor.dPos[1], 1,1, "red")
        }
    }
    editor.step = _=>{
        if (editor.i < 0) {
            editor.i = levelRef.tiles.length-1;
        }
        if (editor.i > levelRef.tiles.length-1) {
            editor.i = 0;
        }
    }
    editor.generate = _=>{
        editor.saving=1
        let encodedLevel = encodeURIComponent(JSON.stringify(editor.l))
        if (encodedLevel != editor.data){
            encodedLevel = "?lvl=" + encodedLevel;
            document.getElementById("leveltext").innerText = encodedLevel
        }
        editor.data = encodedLevel;
        editor.saving=0;
        editor.sa = 1;
    }
    editor.click = (x,y)=>{
        if (y < 50) {
            if (x> 516 && y < 50) {
                if (!editor.saving){
                    editor.generate()
                }
                editor.saveclick = true
            }
        }
         else {
            x = Math.floor((x-editor.dPos[0])/32)
            y = Math.floor((y-editor.dPos[1])/32)
            // console.debug(x,y)
            for (let t in editor.l) {
                if (editor.l[t][1] == x && editor.l[t][2] == y) {
                    editor.l[t] = [editor.i, x, y];
                    return;
                }
            }
            editor.l.push([editor.i,x,y])
            editor.sa = 0
        }
    }
    editor.keyHeld = (key) => {
        switch (key) {
            case "KeyW":
            case "ArrowUp":
                editor.dPos[1] += 4
                break;
            case "KeyS":
            case "ArrowDown":
                editor.dPos[1] -= 4
                break;
            case "KeyA":
            case "ArrowLeft":
                editor.dPos[0] += 4
                break;
            case "KeyD":
            case "ArrowRight":
                editor.dPos[0] -= 4
                break;
        }
    }
    
    
    Bye's avatar
    Bye committed
    editor.drawGUI = _=>{
    
    Bye's avatar
    Bye committed
        c.drawRect(0,0,c.w,50,"gray")
        c.dT(`DBH Editor::${editor.n}`, 15,25,2,2,"#fff","start","middle");
        let s = c.dT(`Save`, c.w-15,25,2,2,"#fff","end","middle");
        if (c.mousePos.x > (c.w-30)-s.w && c.mousePos.y < 50) {
            // console.debug((c.w-30)-s.w)
            c.dT(`Save`, c.w-15,25,2,2,"#e5e5e5","end","middle");
        }
        if (editor.sa) {
            c.dT(`Save`, c.w-15,25,2,2,"#1fdc2f","end","middle");
        } if (editor.saving) {
            c.dT(`Save`, c.w-15,25,2,2,"#1fccdc","end","middle");
        }
    
        c.sliceImage(editor.t.file, c.mousePos.x+16,c.mousePos.y+16,32,32,32*editor.i,0,32,32);
    }
    
    let lvlS = new Room("Level Select")
    lvlS.s = 0
    lvlS.o = levels
    
    lvlS.drawGUI = () => {
        c.dT("Death by Hamster", c.w/2, 25, 2, 2, "white", "middle", "top");
        c.dT("Level Select", c.w/2, 44, 1,1,"gray","middle","middle");
        for (let o in lvlS.o) {
            let n = parseInt(o)+1
    
    Bye's avatar
    Bye committed
            c.dT(`${n}`, (20)+(32*n), 70, 2, 2, "#fff", "middle", "middle")
            if (o == lvlS.s) {
                c.strokeRect((20-14)+(32*n), 70-16, 32, 32, "#fff")
    
    Bye's avatar
    Bye committed
            }
        }
    }
    
    lvlS.keyDown = (key) => {
    
    Bye's avatar
    Bye committed
        if (key == "ArrowUp"||key=="ArrowRight"||key == "KeyW"||key=="KeyD") {
    
    Bye's avatar
    Bye committed
            lvlS.s -= 1
            if (lvlS.s < 0) {
                lvlS.s = lvlS.o.length-1
            }
        }
    
    Bye's avatar
    Bye committed
        if (key == "ArrowDown" ||key=="ArrowLeft"||key == "KeyW"|| key == "KeyA") {
    
    Bye's avatar
    Bye committed
            lvlS.s += 1
            if (lvlS.s > lvlS.o.length-1) {
                lvlS.s = 0
            }
        }
        if (key == "Space" || key == "Enter") {
            gameRoom.level = lvlS.o[lvlS.s].data;
            setRoom(2)
        }
    
    Bye's avatar
    Bye committed
    }
    
    
    Bye's avatar
    Bye committed
    rooms.push(loader);
    
    Bye's avatar
    Bye committed
    rooms.push(menu);
    rooms.push(gameRoom);
    
    Bye's avatar
    Bye committed
    rooms.push(editor);
    rooms.push(lvlS);
    var roomI = !gPar("goto") ? 0 : gPar("goto");
    
    
    Bye's avatar
    Bye committed
    var cRoom = rooms[roomI];
    
    
    Bye's avatar
    Bye committed
    var keysPressed = {};
    var keysLastPressed = {};
    
    document.addEventListener('keydown', (e) => {
        keysPressed[e.code] = true;
    });
    document.addEventListener('keyup', (e) => {
        keysPressed[e.code] = false;
        keysLastPressed[e.code] = false;
    } );
    
    var lastTime = 0;
    
    var mse = {x: 0, y: 0};
    var lastClick = {x: 0, y: 0};
    
    Bye's avatar
    Bye committed
    var startclicked = false;
    var endclicked = false
    
    Bye's avatar
    Bye committed
    
    
    Bye's avatar
    Bye committed
    c.c.addEventListener('mousemove', (e) => {
        mse = c.getMousePos(e);
    
    Bye's avatar
    Bye committed
    } );
    
    
    Bye's avatar
    Bye committed
    c.c.addEventListener("mousedown", (e) => {
        // console.log(e);
    
    Bye's avatar
    Bye committed
        lastClick = c.getMousePos(e);
        mse = c.getMousePos(e);
    
    Bye's avatar
    Bye committed
        startclicked = true;
    
    Bye's avatar
    Bye committed
    });
    
    Bye's avatar
    Bye committed
    c.c.addEventListener("mouseup", (e)=>{
        // console.log(e);
        lastClick = c.getMousePos(e);
        mse = c.getMousePos(e);
        endclicked = true;
    })
    
    window.onwheel = (e)=>{
        if (e.deltaY > 0) {
            editor.i += 1;
        }
        if (e.deltaY < 0) {
            editor.i -= 1;
        }
    }
    
    cRoom.start();
    
    Bye's avatar
    Bye committed