Cannot read properties of undefined (reading 'iface')

Hello, i was messing around with an extension again: the scroller extension.
There was no more than 1 layer to scroll so i decided to implement it myself: but this weird error keeps happening and i have no clue what im doing wrong again.
Cannot read properties of undefined (reading ‘iface’)

What i think this means is that im trying to get something from a undefined value, although, it is defined, so im super confused why this keeps happening.
What’s “undefined” is the bg variable in the uncommented section. What errors is line 40-43.

level1BackGround2 and level1BackGround1 are defined, so that isn’t the problem. This problem even happens if i replace assets.Imagelevel1BackGround2 with imgblahblah...

The first two lines explain what the list is, take a look for yourselves:

let parallax : any[][] = [[assets.image`level1BackGround1`, 0.1, 0.1, 0, 0, 0, 0], [assets.image`level1BackGround2`, 0.2, 0.2, 0, 0, 0, 0]] //This is what the list looks like 
//[image, multiplierX, multiplierY, xOffset, yOffset, cameraX, cameraY]
enum CameraScrollMode {
    //% block="only horizontally"
    OnlyHorizontal,
    //% block="only vertically"
    OnlyVertical,
    //% block="both directions"
    BothDirections
}
let xOffset = 0;
let yOffset = 0;
let currentXSpeed = 0;
let currentYSpeed = 0;
let cameraScrolling = true;
let cameraScrollMode = CameraScrollMode.OnlyHorizontal;
let cameraXMultiplier = 1;
let cameraYMultiplier = 1;
let lastCameraX = game.currentScene().camera.offsetX;
let lastCameraY = game.currentScene().camera.offsetY;

game.currentScene().eventContext.registerFrameHandler(scene.PRE_RENDER_UPDATE_PRIORITY + 1, () => {
    if (parallax) {
        for (let i = 0; i < parallax.length; i++) {
            let bg = parallax[i][0]
            if (cameraScrolling) {
                if (cameraScrollMode === CameraScrollMode.OnlyHorizontal || cameraScrollMode === CameraScrollMode.BothDirections) {
                    parallax[i][3] -= (game.currentScene().camera.offsetX - parallax[i][5]) * parallax[i][1];
                }

                if (cameraScrollMode === CameraScrollMode.OnlyVertical || cameraScrollMode === CameraScrollMode.BothDirections) {
                    parallax[i][4] -= (game.currentScene().camera.offsetY - parallax[i][6]) * parallax[i][2];
                }
            }
            else {
                parallax[i][3] += currentXSpeed * game.currentScene().eventContext.deltaTime;
                parallax[i][4] += currentYSpeed * game.currentScene().eventContext.deltaTime;
            }

            while (parallax[i][3] >= bg.width) parallax[i][3] -= bg.width;
            while (parallax[i][3] < 0) parallax[i][3]  += bg.width;
            while (parallax[i][4] >= bg.height) parallax[i][4] -= bg.height;
            while (parallax[i][4] < 0) parallax[i][4] += bg.height;

            parallax[i][5] = game.currentScene().camera.offsetX;
            parallax[i][6] = game.currentScene().camera.offsetY;
            console.log(parallax[i][3])
        }
    }
})

scene.createRenderable(-1000, function (target: Image, camera: scene.Camera) {
    /*
    if (currentState.xOffset) {
        if (currentState.yOffset) {
            target.drawTransparentImage(bg, (currentState.xOffset | 0) - bg.width, (currentState.yOffset | 0) - bg.height);
            target.drawTransparentImage(bg, (currentState.xOffset | 0) - bg.width, (currentState.yOffset | 0));
            target.drawTransparentImage(bg, (currentState.xOffset | 0), (currentState.yOffset | 0) - bg.height);
            target.drawTransparentImage(bg, (currentState.xOffset | 0), (currentState.yOffset | 0));
        }
        else {
            target.drawTransparentImage(bg, (currentState.xOffset | 0) - bg.width, 0);
            target.drawTransparentImage(bg, (currentState.xOffset | 0), 0);
        }
    }
    else if (currentState.yOffset) {
        target.drawTransparentImage(bg, 0, (currentState.yOffset | 0) - bg.height);
        target.drawTransparentImage(bg, 0, (currentState.yOffset | 0));
    }
    */
});

it would be really cool if the scroller extension actually had multiple layers

I think you ran into a bug in our compiler! The typing of the parallax array is probably the issue; arrays of type any[] can be a little finicky.

to fix it, you can use a class instead:

class Parallax {
    constructor(
        public image: Image,
        public multiplierX: number,
        public multiplierY: number,
        public xOffset: number,
        public yOffset: number,
        public cameraX: number,
        public cameraY: number
    ) { }
}

let parallax = [
    new Parallax(assets.image`level1BackGround1`, 0.1, 0.1, 0, 0, 0, 0),
    new Parallax(assets.image`level1BackGround2`, 0.2, 0.2, 0, 0, 0, 0)
]



enum CameraScrollMode {
    //% block="only horizontally"
    OnlyHorizontal,
    //% block="only vertically"
    OnlyVertical,
    //% block="both directions"
    BothDirections
}
let xOffset = 0;
let yOffset = 0;
let currentXSpeed = 0;
let currentYSpeed = 0;
let cameraScrolling = true;
let cameraScrollMode = CameraScrollMode.OnlyHorizontal;
let cameraXMultiplier = 1;
let cameraYMultiplier = 1;
let lastCameraX = game.currentScene().camera.offsetX;
let lastCameraY = game.currentScene().camera.offsetY;

game.currentScene().eventContext.registerFrameHandler(scene.PRE_RENDER_UPDATE_PRIORITY + 1, () => {
    if (parallax) {
        for (let i = 0; i < parallax.length; i++) {
            let bg = parallax[i].image
            if (cameraScrolling) {
                if (cameraScrollMode === CameraScrollMode.OnlyHorizontal || cameraScrollMode === CameraScrollMode.BothDirections) {
                    parallax[i].xOffset -= (game.currentScene().camera.offsetX - parallax[i].cameraX) * parallax[i].multiplierX;
                }

                if (cameraScrollMode === CameraScrollMode.OnlyVertical || cameraScrollMode === CameraScrollMode.BothDirections) {
                    parallax[i].yOffset -= (game.currentScene().camera.offsetY - parallax[i].cameraY) * parallax[i].multiplierY;
                }
            }
            else {
                parallax[i].xOffset += currentXSpeed * game.currentScene().eventContext.deltaTime;
                parallax[i].yOffset += currentYSpeed * game.currentScene().eventContext.deltaTime;
            }

            while (parallax[i].xOffset >= bg.width) parallax[i].xOffset -= bg.width;
            while (parallax[i].xOffset < 0) parallax[i].xOffset += bg.width;
            while (parallax[i].yOffset >= bg.height) parallax[i].yOffset -= bg.height;
            while (parallax[i].yOffset < 0) parallax[i].yOffset += bg.height;

            parallax[i].cameraX = game.currentScene().camera.offsetX;
            parallax[i].cameraY = game.currentScene().camera.offsetY;
            console.log(parallax[i].xOffset)
        }
    }
})

scene.createRenderable(-1000, function (target: Image, camera: scene.Camera) {
    /*
    if (currentState.xOffset) {
        if (currentState.yOffset) {
            target.drawTransparentImage(bg, (currentState.xOffset | 0) - bg.width, (currentState.yOffset | 0) - bg.height);
            target.drawTransparentImage(bg, (currentState.xOffset | 0) - bg.width, (currentState.yOffset | 0));
            target.drawTransparentImage(bg, (currentState.xOffset | 0), (currentState.yOffset | 0) - bg.height);
            target.drawTransparentImage(bg, (currentState.xOffset | 0), (currentState.yOffset | 0));
        }
        else {
            target.drawTransparentImage(bg, (currentState.xOffset | 0) - bg.width, 0);
            target.drawTransparentImage(bg, (currentState.xOffset | 0), 0);
        }
    }
    else if (currentState.yOffset) {
        target.drawTransparentImage(bg, 0, (currentState.yOffset | 0) - bg.height);
        target.drawTransparentImage(bg, 0, (currentState.yOffset | 0));
    }
    */
});

It works! you can have multiple scrolling background images now! although i dont plan to release this as a extension, because the coding is probally really bad, can you maybe try adding this to your scroller extension? I dont know how to make a extension, so yeah

@hasanchik I was planning on adding something like this at some point anyways… just need to find the perfect API first! It needs to work well in blocks as well

You could be able to use the set backgound block, but add a clickable “+” which makes a dropdown menu or just a number that is able to be inputted that allows you to set the layer number. If you set two backgrounds on the same layer it will just overwrite what it had before (just like it is now, even though there’s only one background), but it would be cool to see parallax as part of the scrolling extension! (just an idea!)