Last week, we looked at how you would do sloped platforms like in Donkey Kong. People loved it, but they wanted to know:

## How Would You Do That: Ladders?

So it turns out that the Platformer class in /sys/lib/spriteControllers already handles most of the messy details of climbing. If you define a climb animation, then by default your character can climb anywhere. We defined just such an animation in our little demo:

```
kip.climbAnim = newAnim([
file.loadImage("/sys/pics/KP/KP-climb1.png"),
file.loadImage("/sys/pics/KP/KP-climb2.png")], 10)
```

Try it! If you don't have last week's code handy, you can twist open this section and copy it into Mini Micro:

## Last week's code (click the little triangle to see)

```
import "spriteControllers"
clear
display(5).mode = displayMode.tile
td = display(5)
td.tileSet = file.loadImage("dk_tiles.png")
td.tileSetTileSize = 8
td.cellSize = 32
td.extent = [28, 32]
td.clear
makeFlat = function(x0, x1, y)
for x in range(x0, x1)
td.setCell x, y, 16
end for
end function
makeRampUp = function(x0, x1, y0, startLevel)
level = startLevel
for x in range(x0, x1)
td.setCell x, y0, 32 - level
if level > 0 then td.setCell x, y0+1, 40 - level
if abs(x-x0) % 2 == 0 then continue
level += 1
if level > 7 then
y0 += 1
level = 0
end if
end for
end function
// Set up the level
makeFlat 0, 13, 0
makeRampUp 14, 27, 0, 1
makeRampUp 25, 0, 3, 4
makeRampUp 2, 27, 7, 5
makeRampUp 25, 0, 11, 6
td.setCell 10, 1, 8 // (ladder)
// Set our player character, "Kip"
newAnim = @spriteControllers.newAnimation
kip = new spriteControllers.Platformer
display(4).sprites.push kip
kip.x = 400; kip.y = 80
kip.idleAnim = newAnim(file.loadImage("/sys/pics/KP/KP-stand.png"))
kip.runAnim = newAnim([
file.loadImage("/sys/pics/KP/KP-run1.png"),
file.loadImage("/sys/pics/KP/KP-run2.png")], 10)
kip.jumpUpAnim = newAnim(file.loadImage("/sys/pics/KP/KP-jump.png"))
kip.fallDownAnim = kip.jumpUpAnim
kip.climbAnim = newAnim([
file.loadImage("/sys/pics/KP/KP-climb1.png"),
file.loadImage("/sys/pics/KP/KP-climb2.png")], 10)
kip.curAnim = kip.idleAnim
// determine whether (and where) kip has solid ground below him
kip.groundBelow = function(x,y)
col = floor(x / 32)
row = floor(y / 32)
while true
if row < 0 then return 0
tile = td.cell(col, row)
if 16 <= tile <= 23 or 32 <= tile <= 39 then
return (row+1) * 32 - (tile % 8) * 4
end if
row = row - 1
end while
end function
while true
spriteControllers.updateSprites 1/60
yield
end while
```

`run`

that code, and then just press the up-arrow key anywhere. You'll find Kip happily climbs up (and down) nothingness.

## Adding ladders

Last week we hacked in a single ladder tile, just for decoration. This week, we want more! Again we'll copy the original *Donkey Kong* layout.

`edit`

the program, and scroll down to right below the `makeRampUp`

function (right above `// Set up the level`

). Insert this new function to create a ladder:

```
makeLadder = function(x, y0, y1=null)
if y1 == null then y1 = y0
for y in range(y0, y1)
c = td.cell(x, y)
if 24 <= c <= 39 then
td.setCell x, y, c - 16
else
td.setCell x, y, 8
end if
end for
end function
```

This function takes the X (horizontal) position of the ladder, and one or two Y (vertical) positions for the ladder extent. It iterates over that Y range, and sets a ladder. But what exactly is going on with that `if`

statement?

To understand that, we need to refer back to our tile set:

You can see that tiles 24 through 39 are the partial-girder tiles, places where we have just the top or bottom of a girder (in order to make sloped platforms). How do we modify those to have a ladder? As the tile set is arranged, the proper girder+ladder section is always 16 tile indexes before the girder-only tile. So, if we find the existing cell is in this range, we subtract 16. If the existing cell is anything else, then we just set it to index 8, which is a full ladder piece.

Now replace the next part of code, which sets up the level, with this:

```
// Set up the level
makeFlat 0, 13, 0
makeRampUp 14, 27, 0, 1
makeRampUp 25, 0, 3, 4
makeRampUp 2, 27, 7, 5
makeRampUp 25, 0, 11, 6
makeLadder 10, 1; makeLadder 10, 4
makeLadder 23, 1, 3
makeLadder 12, 5, 8
makeLadder 4, 5, 7
makeLadder 8, 9; makeLadder 8, 12
makeLadder 14, 9, 12
makeLadder 23, 9, 11
```

When you run this, you should see a more complete level with ladders, as shown below.

## Climbing on ladders only

To limit where our character can climb, we need to override the `canClimb`

method on our character class. To prove that this works, `edit`

your code, scroll down below the `kip.groundBelow`

function (right above the `while true`

loop), and insert this code:

```
kip.canClimb = function(direction)
return false
end function
```

Now `run`

the program again, and you should find that Kip can't climb at all (even though he still has a climb animation defined).

So the job of this method is to return `true`

when kip can climb, given his current location and the intended climb direction (+1 to climb up, or -1 to climb down).

Now if we didn't have partial-girder, partial-ladder tiles, and if ladders extended through the girders, then implementing this function would be fairly trivial: we'd only need to check if the tile at our feet is the ladder tile. But neither of these things is the case; ladders in Donkey Kong stop *below* the girder they attach to, and because of slopes, we have to deal with funny Y coordinates depending on which particular tile we have. All that makes our `canClimb`

method a bit longer. But here it is:

```
kip.canClimb = function(direction)
col = floor(self.x / 32)
row = floor((self.y - self.footOffset) / 32)
c = td.cell(col, row)
if (c == null or c < 8 or c > 23) and (
direction < 0 or self.state == spriteControllers.CLIMBING) then
// no ladder here, if either we're going down, or we're
// already climbing, then also check the tile right below it
row -= 1
c = td.cell(col, row)
end if
if c == null or c < 8 or c > 23 then return false
// OK, there's a ladder in this cell; but account for slopes
// to figure out exactly where it ends.
climbStep = self.climbSpeed / 60
if 16 <= c <= 23 and direction < 0 then // ladder on top of a girder
minY = self.groundBelow(self.x, self.y)
if self.y - self.footOffset < minY + climbStep then return false
else if 9 <= c <= 15 and direction > 0 then // ladder below a girder
maxY = self.groundBelow(self.x, (row + 1) * 32)
if self.y - self.footOffset + climbStep*2 > maxY then return false
end if
// center ourselves horizontally on the ladder
self.x = (col + 0.5) * 32
return true
end function
```

Let's walk through how this works. First, we get the `col`

umn and `row`

of our feet, and check the cell at that position. If it's not a ladder cell (between 8 and 23), *and* if we're either going down or we're already climbing, then we check the tile below. That deals with the case at the top of a ladder, where we're actually on a girder tile but we still want to consider it climbable.

Then, we have two `if`

blocks that make adjustments for slopes (partial girders). The first one, checking for a tile index from 16 to 23, deals with a ladder section on top of a girder (which occurs at the bottom of a ladder). We make use of the `groundBelow`

function from last week to figure out where the actual girder part is, in pixel coordinates. If our climb down would exceed that, we report false ("can't climb").

The `else if`

block, checking for a tile index from 9 to 15, handles the opposite: this is the girder on top of the ladder, and again we use `groundBelow`

(starting up one row) to figure the maximum Y we should allow the player to climb.

The final part of this method just centers the player on the ladder. You could comment this out if you want to see the effect: without it, you can climb up the side of a ladder, which looks a little funny.

This method was developed iteratively, which is to say, I coded a little, tested a little, and repeated until I was satisfied. That's likely to be the case in your own game, too — getting the feel just right often takes a little experimentation.

## That's all, folks!

And that's it! Once you have that `canClimb`

method properly defined for your game, the library code handles the rest. You should now be able to run, jump, and climb around your level!

As you can see, making a run/jump/climb platformer in Mini Micro is much easier than you'd probably expect (even with sloped platforms!). Why not try making your own game?

Also, I'd like to continue to explore how classic video game effects were done, all on hardware considerably less powerful than Mini Micro. So keep your eye out for things that make you go "hmm," and let me know in the comments below if anything makes you say: **How would you do that?!?**

## Top comments (0)