A camera system quickly becomes essential as your game grows in complexity. Kaplay, has one built-in and the goal of this post is to explain how to use it.
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.
The camPos() Function
Kaplay offers the camPos() function which allows you to do two things :
Get the current camera position.
Set the current camera position.
Getting The Current Camera Position
Calling the camPos() function returns a Vec2 which contains the current x and y coordinates of the camera. Here is an example :
import kaplay from "kaplay"
const k = kaplay()
console.log(k.camPos())
// access x coord only
console.log(k.camPos().x)
// access y coord only
console.log(k.camPos().y)
Setting The Current Camera Position
There are 2 ways to do this. When you call camPos(), you can pass two values one for the x coordinate and one for the y coordinate. You can also pass a Vec2 with those values. Finally, if you want to pass the same value for x and y you can achieve this by passing only one value to camPos().
Here is what it looks like in practice :
k.camPos(100, 100) // sets the camera x = 100 and y = 100
k.camPos(k.vec2(100, 100)) // same as the above. No advantage compared to the above
k.camPos(k.vec2(100)) // when you want to set the same value for both
k.camPos(100) // you can still set both x and y by just passing one value
Practical Application #1 : Make The Camera Follow The Player
To achieve this, you can combine a camPos() call within an onUpdate loop to make the camera follow the player. Here is an example :
import kaplay from "kaplay"
const k = kaplay()
k.loadBean() // load the default bean sprite
const obstacle = k.add([
k.rect(100, 100),
k.pos(k.center().x + 100, k.center().y)
])
const player = k.add([
k.sprite("bean"),
k.pos(k.center()),
{speed: 200}
])
player.onKeyDown((key) => {
if (key === "left") {
player.move(-player.speed, 0)
}
if (key === "right") {
player.move(player.speed, 0)
}
})
player.onUpdate(() => {
k.camPos(player.pos)
})
Practical Application #2 : Zelda-like Camera Scrolling
What if instead of the camera following the player, you wanted the camera to scroll when the player goes to the next room. This is similar to how the camera works in 2D top-down Zelda games.
To achieve something similar, you can use the camPos() function with a tween (used for transitions and animations) like shown below :
import kaplay from "kaplay"
const k = kaplay()
k.loadBean()
k.add([
k.rect(500, 500),
k.area(),
k.anchor("center"),
k.color(255, 0, 0),
k.pos(k.center()),
"redRoom"
])
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),
"blueRoom"
])
const player = k.add([
k.sprite("bean"),
k.area(),
k.anchor("center"),
k.pos(k.center()),
{speed: 200}
])
player.onKeyDown((key) => {
if (key === "left") {
player.move(-player.speed, 0)
}
if (key === "right") {
player.move(player.speed, 0)
}
})
player.onCollide("redRoom", (redRoom) => {
k.tween(
k.camPos().x, // initial cam x coordinate
redRoom.pos.x, // final cam x coordinate we want
1, // how long the transition will take (1 sec)
(value) => k.camPos(value, k.camPos().y), // function that updates the cam position gradually
k.easings.linear // determines the rate of change which follows a linear function here. There are many different easings available.
)
})
player.onCollide("blueRoom", (blueRoom) => {
k.tween(
k.camPos().x,
blueRoom.pos.x,
1,
(value) => k.camPos(value, k.camPos().y),
k.easings.linear
)
})
The camScale() Function
This function is used for zooming the camera or de-zooming it. It can accepts a Vec2 or a single value which determines the zoom level. The default camera zoom level is 1.
k.camScale(2) // zoom the camera twice
k.camScale(0.5) // de-zoom the camera by half
k.camScale(2, 1) // zoom on the x axis twice but keep the default zoom on the y axis. This results in a stretched camera
k.camScale(-1) // the camera flips so everything is upside down
Practical Application : Zooming The Camera During An Important Player Action.
Similarly to scrolling the camera using a tween and camPos(), you can use camScale() with a tween to make the camera zoom-in when something important happens in your game.
I think that by taking inspiration from the previous example, you can figure this out. Try doing it on your own!
The shake() Function
Kaplay has a built-in function that shakes the camera. It takes a number that determines the shaking intensity. Unfortunately, you can’t control the duration of the shake. To use it simply, call the function.
k.shake(130) // the higher the value the more intense the shake
Practical Application : Shake The Camera When The Player Gets Hit!
import kaplay from "kaplay"
const k = kaplay()
k.loadBean()
k.add([
k.sprite("bean"),
k.area(),
k.anchor("center"),
k.pos(k.center()),
"player"
])
const bullet = k.add([
k.rect(20, 20),
k.color(255, 0, 0),
k.area(),
k.anchor("center"),
k.pos(100, 500),
])
bullet.onUpdate(() => {
bullet.move(200, 0)
})
bullet.onCollide("player", () => {
k.destroy(bullet)
k.shake(30)
})
The camRot() Function
As the name implies camRot() is used to rotate the camera. It takes a value in degrees and not radians. So passing 90 will rotate the camera by 90°.
k.camRot(90)
You might need to rotate the camera in your game but I haven’t found a use for it in my projects yet. However, I felt it was still important to mention it.
The fixed() Component
The fixed() component can be added to a game object to make it independent from the camera. This means that changes in camPos(), camScale() and camRot() will have no effect on the game object having this component. It’s very useful for when you want to build user interfaces using game objects. For example, a health bar or a score which will always remain at the top of the screen.
To use it, simply add the fixed() component to a game object :
k.add([
// previous components omitted for brevity
k.fixed()
])
Conclusion
Hope this post was useful! If you’d like to read more content like this, subscribe to not miss out on future posts.
The camera system has more nuances, that’s why I recommend reading the post below which will teach you how to implement player controls for a mobile game in Kaplay.
You’ll learn about the difference between screen positions and world positions which are related to the camera system.
Very helpful! One day I hope to make a tribute to Link's Awakening in Kaplay and this looks exactly the kind of camera I need. I also got help from MF in the Discord.
One thing I haven't ironed out yet is how to freeze and move Link 16px into the next room as he enters. It happens in the video gif. This is to avoid the camera moving fully into the next screen while Link walks back offscreen, getting stranded. I thought some clever collision box placement and arresting the controls could get this effect. Does that sound like the right approach?