How would you be able to push boxes into walls?

So, i’m almost done with my baba is you tilemap demo, but just as i was about to finish i encountered this issue. Take a look:
skillissuegemtree
The boxes dissapear when i push them into the border! For clarity, baba also stops when you go into the border.

For this, i dont actually need code, i just need a general idea of how to fix this. This is the algorithm i have currently:

step 1: find what baba is trying to push
step 2: push that box
step 3: check if the box has a box in front of it

repeat step 3 and 2 until no boxes are in front of eachother anymore

important: there is a IsWallAt(location) function, that may help you

Code (feedback would be appreciated)
namespace spriteMap {
    export const tileMapSizePix = 8
    export const tilesXPerScreen = Math.floor(19 / (tileMapSizePix / 8))+1
    export const tilesYPerScreen = Math.floor(14 / (tileMapSizePix / 8))+2
    export const clearImage = img`
        . c . . c c c .
        c c c . . c . .
        c . c . c c c .
        . . . . . . . .
        c c . . . . . .
        c c c . . . . .
        c . c . . . . .
        . . . . . . . .
    `//image.create(tileMapSizePix, tileMapSizePix)
    //["tile", new tileLocation, img``]

    export const allThings: { [key: string]: string } = {
        //Entities
        "baba": "baba",

        //Tiles
        "air": "air",
        "wall": "wall",
        "grass": "grass",

        //Joiners

    }

    export class tileLocation {
        tx = 0
        ty = 0
        constructor(tx: number, ty: number) {
            this.tx = tx;
            this.ty = ty;
        }
    }

    export class tile {
        tx = 0
        ty = 0
        id = "wall"
        img = clearImage
        xoff = 0
        yoff = 0
        moving = false
        constructor(tx: number, ty: number, id: string, img: Image, xoff : number = 0, yoff : number = 0) {
            this.tx = tx;
            this.ty = ty;
            this.id = id;
            this.img = img;
            this.xoff = xoff;
            this.yoff = yoff;
            console.log(spriteMap.allThings)
            if (allThings[id]) {
                this.id = id
            } else {
                this.id = "air" 
            }
            console.log(this.id)
        }

        clone() {
            return new tile(this.tx, this.tx, this.id, this.img)
        }
    }

    export let currentTileMap = [
        new spriteMap.tile(8, 8, "wall", clearImage)
    ]
    currentTileMap = []
    for (let y = 0; y < tilesYPerScreen; y++) {
        for (let x = 0; x < tilesXPerScreen; x++) {
            currentTileMap.push(new spriteMap.tile(x, y, "air", clearImage))
        }
    }
    setTile(new spriteMap.tile(5, 5, "wall", img`
        2 2 2 2 2 2 2 2
        2 3 2 2 3 2 2 2
        2 3 3 2 3 2 2 2
        2 2 2 2 2 2 2 2
        3 3 2 2 2 2 2 2
        2 3 2 2 3 2 2 2
        2 3 3 3 3 2 2 2
        2 2 2 2 2 2 2 2
    `))
    setTile(new spriteMap.tile(6, 5, "wall", img`
        2 2 2 2 2 2 2 2
        2 3 2 2 3 2 2 2
        2 3 3 2 3 2 2 2
        2 2 2 2 2 2 2 2
        3 3 2 2 2 2 2 2
        2 3 2 2 3 2 2 2
        2 3 3 3 3 2 2 2
        2 2 2 2 2 2 2 2
    `))
    setTile(new spriteMap.tile(7, 5, "wall", img`
        2 2 2 2 2 2 2 2
        2 3 2 2 3 2 2 2
        2 3 3 2 3 2 2 2
        2 2 2 2 2 2 2 2
        3 3 2 2 2 2 2 2
        2 3 2 2 3 2 2 2
        2 3 3 3 3 2 2 2
        2 2 2 2 2 2 2 2
    `))


    export function getTileAt(tileLocation : spriteMap.tileLocation) {
        let x = Math.clamp(1, tilesXPerScreen, tileLocation.tx)
        let y = Math.clamp(1, tilesYPerScreen, tileLocation.ty)
        let tile = currentTileMap[x + (y * tilesXPerScreen)]
        return tile
    }

    export function updateGraphics() {

    }

    export function setTile(tile: spriteMap.tile) {
        let x = tile.tx//Math.clamp(1, tilesXPerScreen, tile.tx)
        let y = tile.ty//Math.clamp(1, tilesYPerScreen, tile.ty)
        currentTileMap[x + (y * tilesXPerScreen)] = tile
    }

    export function isWallAt(tileLocation : spriteMap.tileLocation) {
        let wall = false
        if (tileLocation.tx < 1 || tileLocation.ty < 1) {
            wall = true
        }
        if (tileLocation.tx > tilesXPerScreen-2 || tileLocation.ty > tilesYPerScreen-2) {
            wall = true
        }
        if (getTileAt(tileLocation).id != "air") {
            wall = true
        }
        return wall
    }

    export function isBorderAt(tileLocation: spriteMap.tileLocation) {
        let wall = false
        if (tileLocation.tx < 1 || tileLocation.ty < 1) {
            wall = true
        }
        if (tileLocation.tx > tilesXPerScreen - 2 || tileLocation.ty > tilesYPerScreen - 2) {
            wall = true
        }
        return wall
    }

    export function moveToTile(sprite: Sprite, tileLocation : spriteMap.tileLocation) {
        if (sprite.data["moving"] == true) {
            return false
        } 
        let tileloc = tileLocation//new spriteMap.tileLocation(Math.clamp(1, tilesXPerScreen-1, tileLocation.tx), Math.clamp(1, tilesYPerScreen-2, tileLocation.ty))
        if (isWallAt(tileLocation) == true) {
            return false
        }
        sprite.data["moving"] = true
        for (let i = 0; i < tileMapSizePix; i++) {
            pause(10)
            let x = utilities.lerp(sprite.x, tileloc.tx * tileMapSizePix, i / tileMapSizePix)
            let y = utilities.lerp(sprite.y, tileloc.ty * tileMapSizePix, i / tileMapSizePix)
            sprite.x = x
            sprite.y = y
        }
        sprite.x = tileloc.tx*tileMapSizePix
        sprite.y = tileloc.ty*tileMapSizePix
        sprite.data["moving"] = false
        return !isWallAt(tileLocation)
    }

    export function stepTile(tile: spriteMap.tileLocation, x: number, y: number, i: number = 0) {
        let movingTile = getTileAt(tile)
        if (movingTile.moving == true) {
            return false
        }
        if (isBorderAt(new spriteMap.tileLocation(tile.tx + x, tile.ty + y))) {
            return false
        }
        if (isWallAt(new spriteMap.tileLocation(tile.tx + x, tile.ty + y))) {
            //timer.after(10, function() {
            //let temp = (0 == 1)//simulateStepTile(new spriteMap.tileLocation(tile.tx + x, tile.ty + y), x, y)
            if (true) {
                i+=1
                stepTile(new spriteMap.tileLocation(tile.tx + x, tile.ty + y), x, y, i)
            } else {
                return false
            }
           // })
        }
        setTile(new spriteMap.tile(tile.tx, tile.ty, "air", clearImage))
        let offx = x * tileMapSizePix * -1
        let offy = y * tileMapSizePix * -1
        let tile2 = new spriteMap.tile(tile.tx + x, tile.ty + y, movingTile.id, movingTile.img, offx, offy)
        tile2.moving = true
        setTile(tile2)
        timer.background(function() {
            for (let i = 0; i < tileMapSizePix; i++) {
                pause(10)
                let x = utilities.lerp(offx, 0, i / tileMapSizePix)
                let y = utilities.lerp(offy, 0, i / tileMapSizePix)
                tile2.xoff = x
                tile2.yoff = y
            }
            tile2.xoff = 0
            tile2.yoff = 0
            tile2.moving = false
        })
        return true
    }

    export function step(sprite: Sprite, x : number, y : number) {
        let loc = getSpritesTile(sprite)
        loc.tx += x
        loc.ty += y
        if (isWallAt(loc) && getTileAt(loc).id != "air") {
            //let tile = getTileAt(loc)
 
            timer.background(function() {
                stepTile(loc, x, y)
            })
            //let curloc = getSpritesTile(sprite)
            //setTile(new spriteMap.tile(loc.tx,loc.ty,"air", clearImage))
            //setTile(new spriteMap.tile(loc.tx + x, loc.ty + y, tile.id, tile.img))
            //moveToTile(sprite, loc)
            return false
        } else {
            moveToTile(sprite, loc)
            return true
        }
    }

    export function getSpritesTile(sprite : Sprite) {
        let x = Math.floor(sprite.x/tileMapSizePix)
        let y = Math.floor(sprite.y / tileMapSizePix)
        return new tileLocation(x,y)
    }

    scene.createRenderable(0, function () {
        for (let i = 0; i < currentTileMap.length; i++) {
            let tile = currentTileMap[i]
            let img1 = tile.img
            let x = (tile.tx-1) * tileMapSizePix + (tileMapSizePix / 2)
            let y = (tile.ty-1) * tileMapSizePix + (tileMapSizePix/2)
            image.screenImage().drawTransparentImage(img1, x+tile.xoff, y+tile.yoff)
        }
    })
}
1 Like

Can you share your project? That would help me debug

1 Like