(Best viewed in a browser with JavaScript enabled. You can click the play/run-buttons to run the JavaScript in the embedded editors. It should behave mostly like running the same code in the JavaScript console. (Hitting F12 or something and finding the console might also be useful if you wanna look around and inspect stuff more or something.))
We want to move the cat. We can make a function that returns its position, so that we know where to move it from. (Cats tend to move from where they are.)
We will make vectors for the directions the cat can move in, and a plus-function that we can use for adding a direction to a position. We’ll use the (lowercase) letters that are used in Sokoban solutions as property names.
Should be the position of the square to the left of the cat.
Stupid is fun
Okay the array with the arrays with the characters is not a great way to model things, but I like using the symbols from the level format. Like this is fun:
But it is awkward having more than one symbol for one thing (it’s the player if it’s a @or a +, and so on). Something that takes different “collision layers” or something into account probably makes it easier to implement some things.
Also, instead of one move being a functional update of the game state or something like that, we’ll just mutate the arrays. I dunno I just think the side-effecty way to do the movement is somehow neat. And it’s fun to kind of recklessly mutate state and then trust that we can implement undo-functionality in order to restore the state we destroyed :)
Moving one thing
So I think is at least mildly stupid-clever, what with the arrays and the indexes, but kind of fun. We use indexOf to check if the from-square is the expected thing (player or box), and to check that the to-square is floor. indexOf also finds out if a square has a goal on it:
If fromIdx is 0 the to-square has the expected thing and its on empty floor.
If it is 1 the square has the expected thing on a goal square.
If it is less than 0 the expected thing is not on the square and we can’t make the move.
Same with toIdx but for floor: 0 is empty floor, 1 is goal square with nothing on it. Less than 0 means it’s blocked (wall or a floor/goal square with something on it).
And then we use those indexes to choose the correct characters for the two squares when making the moves. If the to-square was a goal square then we choose the “on goal” character from thing, and so on.
Pushing a box
Anyway: We attempted to move things four times. First the box near the top one move to the left. Then the player to the left, three times. The last player-move didn’t go through since the to-square was blocked by the box. When moving the player we want to attempt to move any box on the to-square first, in the same direction. Then we can add the move to the move list by checking which moves went through:
If the player didn’t move, no move was made.
If the player moved and a box was moved we add the direction letter in uppercase.
If the player moved and no box was moved we add the direction letter in lowercase.
It can’t be the case that a box was moved and the player did not move. If a box was moved that must have made room for the player to make its move too.
The movelist says LDl: We pushed a box to the left, then pushed a box down, then moved to the left. (Then tried to move to the left again. But wall.)
Controls
That’s pretty much it for movement. If we make so we can push some buttons to call the movePlayer function things will be pretty gamelike:
The tabIndex thing makes it so that the canvas can have focus and send keydown events. So you should be able to click the level and then move the cat with wasd. Also buttons. Maybe you can click on them if you don’t have a keyboard.