skip to Main Content

I am trying to implement a small tetris base game i found on github into my webserver but the images for the tiles are not loading into the game and in the console it says failed to load resouce 404 not found and it describes the file it is looking for as the colors i listed in the array in the following code but missing the .png extensions even though the array explicitly should request the image source to be from within a resources folder with the .png extensions

Furthermore it is loading one color, blue but when i refresh the page to try get another color it says for example failed to find file "orange"

The file structure is withi the htdocs of the apache, whose service is running on localhost, and is like the following,

  1. Htdocs
  • index.html (with link to tetris.html)
  • tetris.html
  • tetris.js
  • tetris.css
  • resources folder (this includes all colors in .png form for example blue.png)
window.onload = () => {
    const
        background = document.getElementById("background"),
        scoreLbl = document.getElementById("score"),
        linesLbl = document.getElementById("lines"),
        canvas = document.getElementById("game-canvas"),
        ctx = canvas.getContext("2d");

    let audio = new Audio("resources/music.mp3");

    class Tetromino {
        static COLORS = [".resources/blue.png", ".resources/green.png", ".resources/yellow.png", ".resources/red.png", ".resources/orange.png", ".resources/light-blue.png", ".resources/purple.png"];
        static BLOCK_SIZE = 28;
        static DELAY = 400;
        static DELAY_INCREASED = 5;

        constructor(xs, ys, color = null) {
            this.x = xs;
            this.y = ys;
            this.length = xs.length;
            this.color = color;
            this.img = new Image();
            
    
            // Set up a promise to track image loading
            this.imgLoaded = new Promise((resolve, reject) => {
                this.img.onload = resolve;
                this.img.onerror = reject;
            });
    
            if (color !== null) {
                this.img.src = Tetromino.COLORS[color];
                console.log(this.img.src);
                console.log((TETROMINOES.COLORS[color]));
            }
        }

        update(updFunc) {
            for (let i = 0; i < this.length; ++i) {
                ctx.clearRect(
                    this.x[i] * Tetromino.BLOCK_SIZE,
                    this.y[i] * Tetromino.BLOCK_SIZE,
                    Tetromino.BLOCK_SIZE,
                    Tetromino.BLOCK_SIZE
                );

                updFunc(i);
            }

            this.draw();
        }

        draw() {
            if (!this.img.complete) {
                this.img.onload = () => this.draw();
                return;
            }
            // Print the current tetromine
            for (let i = 0; i < this.length; ++i) {
                ctx.drawImage(
                    this.img,
                    this.x[i] * Tetromino.BLOCK_SIZE,
                    this.y[i] * Tetromino.BLOCK_SIZE,
                    Tetromino.BLOCK_SIZE,
                    Tetromino.BLOCK_SIZE
                );
            }
        }

        collides(checkFunc) {
            for (let i = 0; i < this.length; ++i) {
                const { x, y } = checkFunc(i);
                if (x < 0 || x >= FIELD_WIDTH || y < 0 || y >= FIELD_HEIGHT || FIELD[y][x] !== false)
                    return true;
            }
            return false;
        }

        merge() {
            for (let i = 0; i < this.length; ++i) {
                FIELD[this.y[i]][this.x[i]] = this.color;
            }
        }

        rotate() {
            const
                maxX = Math.max(...this.x),
                minX = Math.min(...this.x),
                minY = Math.min(...this.y),
                nx = [],
                ny = [];

            if (!this.collides(i => {
                    nx.push(maxX + minY - tetromino.y[i]);
                    ny.push(tetromino.x[i] - minX + minY);
                    return { x: nx[i], y: ny[i] };
                })) {
                this.update(i => {
                    this.x[i] = nx[i];
                    this.y[i] = ny[i];
                });
            }
        }
    }

    const
        FIELD_WIDTH = 10,
        FIELD_HEIGHT = 20,
        FIELD = Array.from({ length: FIELD_HEIGHT }),
        MIN_VALID_ROW = 4,
        TETROMINOES = [
            new Tetromino([0, 0, 0, 0], [0, 1, 2, 3]),
            new Tetromino([0, 0, 1, 1], [0, 1, 0, 1]),
            new Tetromino([0, 1, 1, 1], [0, 0, 1, 2]),
            new Tetromino([0, 0, 0, 1], [0, 1, 2, 0]),
            new Tetromino([0, 1, 1, 2], [0, 0, 1, 1]),
            new Tetromino([0, 1, 1, 2], [1, 1, 0, 1]),
            new Tetromino([0, 1, 1, 2], [1, 1, 0, 0])
        ];

    let tetromino = null,
        delay,
        score,
        lines;



    (function setup() {

        canvas.style.top = Tetromino.BLOCK_SIZE;
        canvas.style.left = Tetromino.BLOCK_SIZE;

        ctx.canvas.width = FIELD_WIDTH * Tetromino.BLOCK_SIZE;
        ctx.canvas.height = FIELD_HEIGHT * Tetromino.BLOCK_SIZE;

        // Scale background
        const scale = Tetromino.BLOCK_SIZE / 13.83333333333;
        background.style.width = scale * 166;
        background.style.height = scale * 304;

        // Offset each block to the middle of the table width
        const middle = Math.floor(FIELD_WIDTH / 2);
        for (const t of TETROMINOES) t.x = t.x.map(x => x + middle);

        reset();
        draw();
    })();

    function reset() {
        // Make false all blocks
        FIELD.forEach((_, y) => FIELD[y] = Array.from({ length: FIELD_WIDTH }).map(_ => false));

        ctx.clearRect(0, 0, canvas.width, canvas.height);

        delay = Tetromino.DELAY;
        score = 0;
        lines = 0;
    }
    
    function playMusic() {
        audio.play();
        
        
    }

    function draw() {
        if (tetromino) {

            // Collision?
            if (tetromino.collides(i => ({ x: tetromino.x[i], y: tetromino.y[i] + 1 }))) {
                tetromino.merge();
                // Prepare for new tetromino
                tetromino = null;

                // Check for completed rows
                let completedRows = 0;
                for (let y = FIELD_HEIGHT - 1; y >= MIN_VALID_ROW; --y)
                    if (FIELD[y].every(e => e !== false)) {
                        for (let ay = y; ay >= MIN_VALID_ROW; --ay)
                            FIELD[ay] = [...FIELD[ay - 1]];

                        ++completedRows;
                        // Keep the same row
                        ++y;
                    }

                if (completedRows) {
                    // Print againt the table
                    ctx.clearRect(0, 0, canvas.width, canvas.height);
                    for (let y = MIN_VALID_ROW; y < FIELD_HEIGHT; ++y) {
                        for (let x = 0; x < FIELD_WIDTH; ++x) {
                            if (FIELD[y][x] !== false) new Tetromino([x], [y], FIELD[y][x]).draw();
                        }
                    }

                    score += [40, 100, 300, 1200][completedRows - 1];
                    lines += completedRows;
                } else {
                    // Check if player has lost
                    if (FIELD[MIN_VALID_ROW - 1].some(block => block !== false)) {
                        alert("Game Over! n nScore: "+ score + "nLines Cleared: " + lines);
                        reset();
                    }
                }


            } else
                tetromino.update(i => ++tetromino.y[i]);
        }
        // No tetromino failing
        else {

            scoreLbl.innerText = score;
            linesLbl.innerText = lines;

            // Create random tetromino
            tetromino = (({ x, y }, color) =>
                new Tetromino([...x], [...y], color)
            )(
                TETROMINOES[Math.floor(Math.random() * (TETROMINOES.length - 1))],
                Math.floor(Math.random() * (Tetromino.COLORS.length - 1))
            );

            tetromino.draw();
        }

        setTimeout(draw, delay);
    }

    // Move
    window.onkeydown = event => {
        playMusic();
        switch (event.key) {
            
            case "ArrowLeft":
                if (!tetromino.collides(i => ({ x: tetromino.x[i] - 1, y: tetromino.y[i] })))
                    tetromino.update(i => --tetromino.x[i]);
                
                break;
            case "ArrowRight":
                if (!tetromino.collides(i => ({ x: tetromino.x[i] + 1, y: tetromino.y[i] })))
                    tetromino.update(i => ++tetromino.x[i]);
                break;
            case "ArrowDown":
                delay = Tetromino.DELAY / Tetromino.DELAY_INCREASED;
                break;
            case " ":
                tetromino.rotate();
                break;
            case "ArrowUp":
                tetromino.rotate();
                break;
        }
    }
    window.onkeyup = event => {
        if (event.key === "ArrowDown")
            delay = Tetromino.DELAY;
    }

}

I tried to load the tetris file and expect the game to be playable (it has worked before but it wasnt on apache it was on an esp32 webserver were i posted the file ) but after a lot of troubleshooting the only color that was loading was blue

The files are being served as text/html and this also removes the file extension, so it cannot find the file blue.png, for example, because the file it is trying to find is actually called blue. Console

Requests

2

Answers


  1. Chosen as BEST ANSWER

    It was a cache issue, i opened it on a different laptop.


  2. It looks to me like you’re only calling two of the arguments and You’re not specifying a color when you create the instance of Tetromino.

    TETROMINOES = [
            new Tetromino([0, 0, 0, 0], [0, 1, 2, 3]),
            new Tetromino([0, 0, 1, 1], [0, 1, 0, 1]),
            new Tetromino([0, 1, 1, 1], [0, 0, 1, 2]),
            new Tetromino([0, 0, 0, 1], [0, 1, 2, 0]),
            new Tetromino([0, 1, 1, 2], [0, 0, 1, 1]),
            new Tetromino([0, 1, 1, 2], [1, 1, 0, 1]),
            new Tetromino([0, 1, 1, 2], [1, 1, 0, 0])
        ];
    

    This snippet is calling the XS and YS arguments but color is null.

    If you look at the constructor

    constructor(xs, ys, color = null) {
    

    Color is the third argument and you’re only providing two if you look here:

    if (color !== null) {
                this.img.src = Tetromino.COLORS[color];
                console.log(this.img.src);
                console.log((TETROMINOES.COLORS[color]));
            }
    

    color defaults to null so The block in which you’re setting the image source isn’t being called.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search