How to implement player controls for a 2D top-down mobile web game in Kaboom.js
I make JavaScript (Kaboom.js) game programming tutorials on YouTube. Check my channel here.
Let’s assume you’re making a 2D top-down game and you want it playable on both desktop and mobile. The most sensible choice for a player control scheme would be to implement a touch/click around to move controller.
How can you achieve something like that in Kaboom?
Well, here is a basic solution :
const k = kaboom({global: false, touchToMouse: true})
k.loadSprite("bean", "/sprites/bean.png")
const player = k.add([
k.sprite("bean"),
k.pos(k.center()),
{speed: 300}
])
k.onMouseDown(() => {
player.moveTo(k.mousePos(), player.speed)
})
We initialize the Kaboom canvas with two properties. The first one makes sure that we cannot use Kaboom functions globally. Therefore, we must always use all kaboom functions via the k constant. This makes our code less messy in the long run. The second property tells Kaboom to convert any touch events to mouse events.
We use the onMouseDown event listener to know when to make the player move. Since touch events are considered click events, onMouseDown will run regardless. This makes our game work both on mobile and desktop.
We use the moveTo method of the player and pass it the current mouse position by using the mousePos() Kaboom function. The second param of moveTo determines the speed at which the player will move towards the mouse position.
The result you’ll get is shown in the video below.
Now this is fine but what happens if you also happen to use a camera. The current logic will not work.
If we update the previous code to make the camera follow the player and add a box game object as a reference point, we get the following :
const k = kaboom({global: false, touchToMouse: true})
k.loadSprite("bean", "/sprites/bean.png")
const player = k.add([
k.sprite("bean"),
k.pos(k.center()),
{speed: 300}
])
const box = k.add([
k.rect(100, 100),
k.pos(300, 300),
k.area(),
k.outline(3)
])
k.onUpdate(() => {
k.camPos(player.pos)
})
k.onMouseDown(() => {
player.moveTo(k.mousePos(), player.speed)
})
Somehow, the player character seems to be stuck and can no longer advance after a certain point. The solution is to use the world position of the mouse rather than its screen position.
The screen mouse position can only go so far as it is bound to the canvas size instead of the game world.
On the other hand, the world position of the mouse always changes as the camera follow the player. Therefore, the player will always continue to move in the direction of the mouse cursor.
To illustrate the point, here is the updated code along with the result video.
const k = kaboom({global: false, touchToMouse: true})
k.loadSprite("bean", "/sprites/bean.png")
const player = k.add([
k.sprite("bean"),
k.pos(k.center()),
{speed: 300}
])
const box = k.add([
k.rect(100, 100),
k.pos(300, 300),
k.area(),
k.outline(3)
])
k.onUpdate(() => {
k.camPos(player.pos)
})
k.onMouseDown(() => {
player.moveTo(k.toWorld(k.mousePos()), player.speed)
})
We are able to get the world position of the mouse by using the toWorld Kaboom function which takes the current mouse screen position and gives us the world mouse position.
Finally the result we obtain is this :
Conclusion
That’s it! Hope this post was useful. Additionally, if you want to be notified when I post new articles like this one, you can subscribe to my substack down below.
Here are more posts, if you’re interested.