Skip to main content

How to: Top-down Joystick movement

One of the most first things you'll want to do when creating a top-down game is to allow the player to move their character around. This guide will show you how to set up a simple top-down character movement system that works when using the WASD keys, a gamepad and an on-screen joystick for touchscreen players.

The simplest way to support all the various control schemes is to use the Joystick as your primary input method, and then use KeyboardVirtualJoystick and VirtualJoystick to simulate a joystick when a Gamepad is not connected.

Joystick control

Let's start with the Joystick:

let speed = 20
with Joystick {
if Joystick.IsEmpty {
delete behavior<move>
} else {
behavior<move> on BeforePhysics {
// Make the character look where they are going
Heading = Angle(Joystick)
ForcefulStep(Joystick * speed / TicksPerSecond)
}
}
}

We use a with block to run the code whenever the Joystick changes. This will replace a behavior called move, which is responsible for moving the character. We make this behavior run before the physics phase of each tick using BeforePhysics. ForcefulStep is used to move the character in the direction of the Joystick. The step is forceful, meaning if our character collides with anything during its step, it will push it out of the way. We also adjust the Heading of the character to face the direction it is moving.

It is also good to delete a behavior when it will not do anything, as this saves processing time and can help your game run better on lower-end devices. In this case, when the Joystick is a zero Vector @(0,0), the character won't be moving anywhere, and so we can use delete behavior<move> to remove the behavior.

You will also notice that we specify speed as a variable at the top of the code. This could instead come from a function parameter, for example. We then divide the speed by TicksPerSecond to calculate how much of the speed we should apply each frame.

WASD or Arrow Keys

Many games support moving with the WASD keys or the Arrow keys. Now that your Joystick is set up, you can add support for these keys with the KeyboardVirtualJoystick function:

KeyboardVirtualJoystick(up=KeyW, left=KeyA, down=KeyS, right=KeyD)

Or for arrow keys:

KeyboardVirtualJoystick(up=ArrowUp, left=ArrowLeft, down=ArrowDown, right=ArrowRight)

This function will add a behavior to the current entity that will simulate a Joystick using the keyboard, for as long as the current entity continues to exist.

Touchscreens

The VirtualJoystick function will display a virtual joystick which players can use to control their character. In most cases, this is only useful for touchscreen users, so you can use the TouchscreenMode to limit this to touchscreen users.

As VirtualJoystick inserts a user interface element, it must be placed inside a Section of the user interface. The most reliable way to do this is to place it inside a BottomLeftCommand which places it in an overlay on top of the game screen.

with TouchscreenMode {
if TouchscreenMode {
BottomLeftCommand<joystick>(offset=@(6,6)) {
VirtualJoystick(radius=5)
}
} else {
delete BottomLeftCommand<joystick>
}
}

Since BottomLeftCommand is an overlay, it requires an offset. Make sure to give it an offset that is bigger than the radius of the VirtualJoystick so that the joystick is clear of the corner of the screen.

It is possible however to place the VirtualJoystick inside a BottomLeftContent section instead. This means that anything else in BottomLeftContent will be pushed up by the joystick, instead of overlapping with it, which might work better for your game. BottomLeftContent is stacked from bottom to top, so to make sure your joystick is the bottom of the stack, give it a low order number like -100.

with TouchscreenMode {
if TouchscreenMode {
BottomLeftContent<joystick>(order=-100) {
VirtualJoystick(radius=5)
}
} else {
delete BottomLeftContent<joystick>
}
}

Full code listing

This is one example of a complete game that supports top-down movement with a Joystick, WASD keys and a virtual joystick for touchscreen users. If you would like to try it, click the Launch Editor button in the top right of this page, create a new project and use copy-and-paste to overwrite the contents of the main.easel file with the code below.

pub game fn World.Main() {
SpawnEachPlayer owner {
KeyboardVirtualJoystick(up=KeyW, left=KeyA, down=KeyS, right=KeyD)

with TouchscreenMode {
if TouchscreenMode {
BottomLeftCommand<joystick>(offset=@(6,6)) {
VirtualJoystick(radius=5)
}
} else {
delete BottomLeftCommand<joystick>
}
}

Subspawn ship {
Ship
}
}
}

pub fn ship.Ship([owner]) {
use body=ship
use speed=30
use radius=1, shape=Circle, color=#00ff00

Body(pos=@(0,0))
PolygonSprite

with Joystick {
if Joystick.IsEmpty {
delete behavior<move>
} else {
behavior<move> on BeforePhysics {
Heading = Angle(Joystick)
ForcefulStep(Joystick * speed / TicksPerSecond)
}
}
}
}