Skip to content
Snippets Groups Projects
game.js 5.88 KiB
Newer Older
  • Learn to ignore specific revisions
  • Bye's avatar
    Bye committed
    
    
    Bye's avatar
    Bye committed
    import { WIDTH, HEIGHT, GAME_TITLE } from "./config.js";
    
    Bye's avatar
    Bye committed
    import { Canvas } from "./canvas.js";
    import { TextRenderer } from "./text.js";
    import { Room, Object } from "./objects.js";
    
    Bye's avatar
    Bye committed
    import { isKeyUp, whichKeyDown } from "./keyboard.js";
    import { getParameter } from "./utils.js";
    
    Bye's avatar
    Bye committed
    
    let assets = {
        images: {
            splash: "../img/splash1.webp",
    
    Bye's avatar
    Bye committed
            font: "../img/hampsterfont.webp",
    
    Bye's avatar
    Bye committed
            selector: "../img/selector.webp",
    
    Bye's avatar
    Bye committed
        },
    
    Bye's avatar
    Bye committed
    }
    
    
    Bye's avatar
    Bye committed
    let running = 1;
    
    
    Bye's avatar
    Bye committed
    let currentFrame = 0;
    let targetFrames = 60;
    
    let lastFrameTime = performance.now();
    
    
    Bye's avatar
    Bye committed
    let debug = getParameter("debug") || 0;
    
    
    Bye's avatar
    Bye committed
    let rooms = [];
    
    Bye's avatar
    Bye committed
    let debugStatuses = [];
    
    Bye's avatar
    Bye committed
    let canvas = new Canvas("c", WIDTH, HEIGHT);
    let text;
    
    Bye's avatar
    Bye committed
    
    let pressedLastFrame = [];
    
    Bye's avatar
    Bye committed
    canvas.fill("#222034");
    
    let splash = new Image();
    splash.src = assets.images.splash;
    splash.onload = () => {
        canvas.drawImage(splash, canvas.width / 2 - splash.width / 2, canvas.height / 2 - splash.height / 2);
        let font = new Image();
        font.src = assets.images.font;
        font.onload = () => {
            console.log("font loaded")
            text = new TextRenderer(canvas, font);
            window.onerror = (e) => {
    
    Bye's avatar
    Bye committed
                running = 0;
    
    Bye's avatar
    Bye committed
                text.throwPanic(e);
            }
        }
    }
    
    
    Bye's avatar
    Bye committed
    // Entity class is here becuase otherwise every entity would need the canvas passed into it
    class Entity extends Object {
        constructor(x=0, y=0, spritesheet=null, sprite=null) {
    
    Bye's avatar
    Bye committed
            super();
    
    Bye's avatar
    Bye committed
            this.x = x;
            this.y = y;
            this.sprite = sprite;
            this.spritesheet = spritesheet;
    
    Bye's avatar
    Bye committed
        }
    
        draw() {
    
    Bye's avatar
    Bye committed
            canvas.drawImage(this.sprite, this.x, this.y);
    
    Bye's avatar
    Bye committed
        }
    }
    
    // Create all the game rooms
    
    Bye's avatar
    Bye committed
    let roomIndex = 0;
    let currentRoom = rooms[roomIndex];
    
    Bye's avatar
    Bye committed
    
    
    Bye's avatar
    Bye committed
    let searchForRoom = (name) => {
        // returns the room's index in the rooms array
        for (let i = 0; i < rooms.length; i++) {
            if (rooms[i].name == name) return i;
    
    Bye's avatar
    Bye committed
        } throw new Error("Room not found:"+name+". Are you sure it's pushed?");
    
    Bye's avatar
    Bye committed
    }
    
    const changeRoom = (index) => {
        currentRoom = rooms[index];
        roomIndex = index;
    
    Bye's avatar
    Bye committed
        currentRoom.init();
    
    Bye's avatar
    Bye committed
    }
    
    const loadingRoom = new Room("loading");
    
    Bye's avatar
    Bye committed
    loadingRoom.updateStatus = (status) => {
        console.log(status);
        canvas.fill("#222034");
        canvas.drawImage(splash, canvas.width / 2 - splash.width / 2, canvas.height / 2 - splash.height / 2);
        text.render(status, 0, 0);
    }
    
    
    Bye's avatar
    Bye committed
    const debugRoom = new Room("debug");
    
    Bye's avatar
    Bye committed
    debugRoom.init = () => {
        if (!debug) changeRoom(searchForRoom("menu"));
    }
    
    Bye's avatar
    Bye committed
    debugRoom.draw = () => {
    
    Bye's avatar
    Bye committed
        canvas.fill("black");
    
    Bye's avatar
    Bye committed
    }
    debugRoom.drawGUI = () => {
    
    Bye's avatar
    Bye committed
        debugStatuses.push("Current Frame:"+currentFrame+`(~${Math.round((currentFrame/targetFrames)*100)/100} sec)`);
    }
    
    const menuRoom = new Room("menu");
    
    Bye's avatar
    Bye committed
    menuRoom.options = [
    
    Bye's avatar
    Bye committed
        {"label": "Start Game", "action": _ => {changeRoom(searchForRoom("game"))}},
    ];
    
    Bye's avatar
    Bye committed
    if (debug) menuRoom.options.push({"label": "Debug Room", "action": _ => {changeRoom(searchForRoom("debug"))}});
    
    Bye's avatar
    Bye committed
    menuRoom.index = 0;
    
    Bye's avatar
    Bye committed
    
    menuRoom.draw = () => {
        canvas.fill("black");
    }
    menuRoom.drawGUI = () => {
        text.render(GAME_TITLE, 8, 7*4);
    
    Bye's avatar
    Bye committed
        for (let i = 0; i < menuRoom.options.length; i++) {
            if (i == menuRoom.index) {
    
    Bye's avatar
    Bye committed
                text.render(">", 8, 7*(i+5));
            }
    
    Bye's avatar
    Bye committed
            text.render(menuRoom.options[i].label, 16, 7*(i+5));
    
    Bye's avatar
    Bye committed
        }
    }
    menuRoom.keyDown = (key) => {
        if (pressedLastFrame.includes(key)) return;
    
    Bye's avatar
    Bye committed
    
        const keyActions = {
            ArrowUp: () => menuRoom.index--,
            ArrowDown: () => menuRoom.index++,
            Enter: () => menuRoom.options[menuRoom.index].action(),
        };
    
        const action = keyActions[key];
        if (action) action();
        if (menuRoom.index >= menuRoom.options.length) menuRoom.index = 0;
        if (menuRoom.index < 0) menuRoom.index = menuRoom.options.length-1;
    }
    
    Bye's avatar
    Bye committed
    rooms.push(loadingRoom);
    
    Bye's avatar
    Bye committed
    rooms.push(menuRoom);
    
    Bye's avatar
    Bye committed
    rooms.push(debugRoom);
    
    
    Bye's avatar
    Bye committed
    currentRoom = rooms[roomIndex];
    
    Bye's avatar
    Bye committed
    
    let main = () => { // main game loop
    
    Bye's avatar
    Bye committed
        if (!running) return;
    
    Bye's avatar
    Bye committed
        requestAnimationFrame(main);
        let now = performance.now();
        let delta = now - lastFrameTime;
    
        if (delta < 1000 / targetFrames) return;
    
        currentFrame++;
    
    Bye's avatar
    Bye committed
        debugStatuses = [];
    
    
    Bye's avatar
    Bye committed
        currentRoom.step();
    
    
    Bye's avatar
    Bye committed
        currentRoom.draw();
        currentRoom.drawGUI();
    
    
    Bye's avatar
    Bye committed
        let currentKeys = whichKeyDown();
        for (let i = 0; i < currentKeys.length; i++) {
    
    Bye's avatar
    Bye committed
            if (isKeyUp(currentKeys[i]) && pressedLastFrame.includes(currentKeys[i])) continue;
    
    Bye's avatar
    Bye committed
            if (debug) debugStatuses.push(currentKeys[i]);
    
    Bye's avatar
    Bye committed
            currentRoom.keyDown(currentKeys[i]);
        }
        
        pressedLastFrame = currentKeys;    
    
    
    Bye's avatar
    Bye committed
        if (debug) {
            text.render("FPS:" + Math.round(1000 / delta), 0, 0);
    
    Bye's avatar
    Bye committed
            text.render(currentRoom.name, canvas.width-(text.charWidth*(currentRoom.name.length)), 0);
    
    Bye's avatar
    Bye committed
    
            debugStatuses.push("Debug mode");
            if (currentFrame <= 60*5) {
                debugStatuses.push("Dimensions:"+canvas.width+"x"+canvas.height);
                debugStatuses.push("Have fun!");
            }
    
    Bye's avatar
    Bye committed
        }
    
        for (let i = 0; i < debugStatuses.length; i++) {
    
    Bye's avatar
    Bye committed
            // console.debug(debugStatuses[i]);
            if (typeof(debugStatuses[i]) == "string") text.render(debugStatuses[i], 0, canvas.height-text.charHeight*(debugStatuses.length-i));
            if (typeof(debugStatuses[i]) == "object") {text.render(debugStatuses[i].msg, 0, canvas.height-text.charHeight*(debugStatuses.length-i)); debugStatuses[i].ttl--;}
    
    
    Bye's avatar
    Bye committed
        }
    
        lastFrameTime = now;
        }
    
    Bye's avatar
    Bye committed
    
    let init = () => {
        // begin loading all the assets.
        currentRoom.updateStatus("Loading images...");
        for (let image in assets.images) {
            currentRoom.updateStatus("Loading image " + image);
            let img = new Image();
            img.src = assets.images[image];
            img.onload = () => {
                assets.images[image] = img;
            }
        }
    
    Bye's avatar
    Bye committed
        console.log("Images loaded.")
    
    Bye's avatar
    Bye committed
        currentRoom.updateStatus("Loading complete!");
        setTimeout(() => {
    
    Bye's avatar
    Bye committed
            (getParameter("room") ? changeRoom(searchForRoom(getParameter("room"))) : changeRoom(searchForRoom("menu")));
    
    Bye's avatar
    Bye committed
            main();
        }, 1000);
    }
    
    window.onload = () => {
    
    Bye's avatar
    Bye committed
        document.title = GAME_TITLE;
        init();
    
    Bye's avatar
    Bye committed
    }