Zelda Link’s Awakening has a camera that behaves like shown below. Let’s implement it in Kaplay.
This post assumes basic knowledge of Kaplay (Formely known as Kaboom.js) and JavaScript. Kaplay is a JavaScript library for making games quickly. To learn how to use it, you can watch my project based tutorials on YouTube here or dive into the docs here.
Plan
Implementing player controls.
Implementing camera scrolling.
Pushing the player within the room when the camera is scrolling.
Implementing Player Controls
If you look at the Zelda gameplay above you’ll notice that Link is pushed within the next room when the camera starts scrolling. During that time, the player can no longer go back.
Therefore, we need to implement our player controls in a way that allows them to be disabled. We do this to prevent the player from going backward while the camera is moving forward making the player disappear from the visible area of the camera.
Let’s write some setup code :
import kaplay from "kaplay"
const k = kaplay()
k.loadBean()
const redRoom = k.add([
k.rect(500, 500),
k.area(),
k.anchor("center"),
k.color(255, 0, 0),
k.pos(k.center()),
])
const blueRoom = k.add([
k.rect(500,500),
k.area(),
k.anchor("center"),
k.color(0, 0, 255),
k.pos(k.center().x + 500, k.center().y),
])
k.add([
k.area({shape: new k.Rect(k.vec2(0), 20, 500)}),
k.anchor("center"),
k.pos(k.center().x + 245, k.center().y),
"gate"
])
You should have the following result :
Here we created our two rooms and a gate hitbox which when collided with will make the camera scroll. If you press f1 to open the debug mode, you’ll be able to see it.
Now let’s continue our script by creating our player and creating two methods one for setting the player controls and the second one for disabling them. I have also created a “direction” property which allow us to set the direction where the player is going. This will be used to know which side of the gate should the player be pushed to when the camera scrolls.
const player = k.add([
k.sprite("bean"),
k.area(),
k.anchor("center"),
k.pos(k.center()),
{
speed: 300,
direction: null,
setControls() {
this.inputController = k.onKeyDown((key) => {
if (key === "left") {
this.move(-this.speed, 0)
this.direction = "left"
return
}
if (key === "right") {
this.move(this.speed, 0)
this.direction = "right"
return
}
})
},
disableControls() {
this.inputController.cancel()
}
}
])
player.setControls()
The onKeyDown Kaplay function returns an event controller which has the cancel() method available. This will allow us to disable the player controls when we need to push the player to the next room. Here we use the inputController property to store this event controller. Since we’re adding this to “this”, the property will be accessible from other methods of the player game object.
Finally after having created our player, we call the setControls() method allowing the player to move. You should have the following result :
Implementing Camera Scrolling
We want to make the camera scroll when the player collides with the invisible gate. To achieve this, add an onCollide handler, like this :
player.onCollide("gate", (gate) => {
k.tween(
k.camPos().x, // initial cam x coordinate
player.direction === "left" ? redRoom.pos.x : blueRoom.pos.x,
1,
(value) => k.camPos(value, k.camPos().y),
k.easings.linear
)
})
Here we use a tween that will gradually change the position of the camera from it’s current coordinates to the coordinates of either the red room or the blue room depending on the direction of the player. For more info about how tween works, refer to the Kaplay docs here.
Now you should have the following result :
Pushing the player within the room when the camera is scrolling
To achieve this we need to disable player controls as soon as the player collides with the gate and then push them to the room they wanted to go in. Here is the updated onCollide logic to achieve this.
player.onCollide("gate", async (gate) => {
player.disableControls()
const offset = (player.direction === "left" ? -1 : 1) * 96
k.tween(
player.pos.x,
player.pos.x + offset,
1,
(value) => player.pos.x = value,
k.easings.linear
)
await k.tween(
k.camPos().x,
player.direction === "left" ? redRoom.pos.x : blueRoom.pos.x,
1,
(value) => k.camPos(value, k.camPos().y),
k.easings.linear
)
player.setControls()
})
We first disable the player controls so that they can’t change their mind once they have decided to enter the next room.
We compute an offset that determines by how much the player will be pushed in the room.
If the direction of the player was “left” we would make the offset a negative value otherwise it would be positive so that the player is pushed to the right.
We then use a tween to push the player towards the room.
We use another tween to make the camera scroll. However, we use async/await so that the function within the onCollide will not proceed to re-enable the player controls until the camera has finished scrolling.
You should get the following result :
Conclusion
That’s it. While this is a simplified example, you can use what you learned here to make your own Zelda style camera for your games.
If you want to learn more about what you can do with the camera in Kaplay, you can read my previous post.
If you don’t want to miss out when I post new articles like this, subscribe!