Skip to main content

Your First Power-Up

Now that we're set up with VS Code, let's get to writing some actual code!

Defining a Power-Up

Let's start off by creating our power-up.

@PowerUp
struct TopDownPlayerControls {
move_left: Key = Key.A
move_right: Key = Key.D
move_up: Key = Key.W
move_down: Key = Key.S
}

A Power-Up is really just a plain FFS struct, but with some extra conditions:

  • It needs to have the @PowerUp attribute
  • All its fields must have default values

Each field on a power-up will be automatically made available as part of the editor UI when attached to a layer. This power-up, for example will be rendered as follows:

Power-Up UI

Running Tasks on Power-Ups

Power-ups are essentially just data, so if we want behaviour, we need to define a task that uses it somehow. Let's get this character moving.

A task is simply a function with the @Task attribute that takes power-ups and engine state as parameters, and gets automatically run on every layer in the scene with the matching power-ups, once per frame.

In this case, we're going to write a function that actually implements our desired movement behaviour.

@Task
fn update_player_movement(
controls: &TopDownPlayerControls,
transform: &Transform,
input: &InputState,
step: &Timestep,
) {
// for top-down movement, we're going to need two input axes, vertical and horizontal
// then we normalise that vector so that moving diagonally isn't extra-fast
let direction = Vec2(
x = input.position_axis(controls.move_left, controls.move_right),
y = input.position_axis(controls.move_down, controls.move_up),
).normalise_or_zero()

// we want our character to move at 5 metres per second, regardless of framerate
// multiplying the velocity by the timestep achieves this
let velocity = direction * 5.0
transform.position += velocity * step.as_seconds()
}

Let's analyse those parameters a little:

  • controls: TopDownPlayerControls is the power-up we just defined!
  • transform: Transform is a core engine power-up that tells us where in the scene a layer is
  • input: InputState is an engine interface for querying input state, e.g. whether a key is pressed
  • step: Timestep is an engine interface for tracking how long a step is, so we can make all our code framerate-agnostic

So firstly, we create a 2D direction vector by interpreting our four keybinds as two axes. With that vector, we can then multiply it by 5.0 to get our actual velocity, and then, after making the velocity framerate-agnostic, we can add that movement to our player's Transform, creating smooth movement!

Testing in the Editor

Now that we're happy with this, you should be able to run the Fiero: Sync command in VS Code, and test out your project in the editor! Try changing the speed, resyncing, and seeing how the changes get reflected in your game.