Skip to content

Tutorials · Ship Evader · Chapter 4

The ship

25 minutes Uses: Sprite, camera_view, position, direction, clamp, move_to, vec2

By the end

  • An input map of three actions: move on WASD and the arrow keys, fire on Space and pause on Esc
  • The ship in the scene, near the bottom of the field
  • A first script, ship.rgs, that flies the ship and keeps it inside the field
  • How a script becomes a component, with fields the Inspector shows
On this page

Name the controls

A script never asks whether W is down. It asks about an action, a name such as move or fire, and the project’s input map says which keys run it. A player could then fly with the arrows instead of WASD, and no script would change. Input has the whole of it.

  1. Choose View → Input map…. With no input map saved yet, the window starts on six actions of its own: left, right, up, down, jump and action. This starter map binds W and Up twice, to up and to jump, as a platformer wants, and the window notes it in grey under the list; your own actions replace it.
The Input window with no input map saved yet, listing the six actions it starts with, left, right, up, down, jump and action, left selected with its keys Left and A, and under the list a grey note that up and jump share Up and W, the platformer convention
  1. Select each of the six in turn and press Remove. jump would otherwise share Space with fire.
  2. Type move into New action and press Add.
  3. With move selected, press Add composite and choose WASD, then press Add composite again and choose Arrow keys. The list shows two Vector2 rows: W, S, A and D, and Up, Down, Left and Right.
  4. Add an action called fire, press Record a control, and press Space.
  5. Add an action called pause, press Choose key…, type esc, and choose Esc. Esc cancels a recording, so it can only be chosen from the list. Nothing reads pause until chapter 15.
  6. Press Save. The window writes input.ron into the project.
The Input window with three actions, move, fire and pause, and move selected: two Vector2 composites, one of W, S, A and D and one of the arrow keys Up, Down, Left and Right
The Input window with pause selected, bound to Esc as a Press

A composite stands in for a stick: four keys read as one direction, which a script gets as a vector. With two composites on move, either set of keys flies the ship.

Put the ship in

  1. Close the Input window with the × at the right of its title bar: it covers the Viewport, where the ship goes.
  2. Select background in the Hierarchy. A picture dropped into the Viewport lands beside the selected node, under the same parent, so this puts the ship under Game.
  3. Drag art/playerShip1_blue.png from Assets into the Viewport. It lands as a node called playerShip1_blue, at the picture’s own size, 99 by 75.
  4. Double-click its row in the Hierarchy, type ship, and press Enter. F2 renames only after a click in the Hierarchy.
  5. Set its Position to 0 and 480: in the middle, 160 units above the bottom edge.
  6. Leave its Sprite’s Sort Layer at 0, above the background’s -10.

A first script

Rengy Script is a small language for what happens in a game. A script is one component: its fields are rows in the Inspector, and its hooks run as the game does. Rengy Script covers the language; this chapter needs only what follows.

  1. In Assets, press Create, choose New script, type ship, and press Enter. The editor writes ship.rgs into the project folder.
  2. Click the Code tab above the Viewport, then ship.rgs in its Scripts list, which shows every script in the project.
  3. Replace everything in it with the script below, and press Ctrl+S. The panel says Up to date once the script checks.
rgs ship.rgs
/// The player's ship: it flies where `move` points and never leaves the field.
component Ship {
    /// How fast the ship flies.
    #[suffix("u/s")]
    speed: f32 = 420.0,
    /// How close the ship's centre may come to an edge of the field.
    #[suffix("u")]
    margin: f32 = 50.0,

    fn loop(dt: f32) {
        let view = camera_view();
        let next = position() + direction("move").normalized() * (speed * dt);
        move_to(vec2(
            clamp(next.x, view.x + margin, view.z - margin),
            clamp(next.y, view.y + margin, view.w - margin),
        ));
    }
}
The Code panel open on ship.rgs, the Ship component’s eighteen lines, with Up to date in its status line, and the Inspector showing the ship’s Ship component, Speed 420.00 u/s and Margin 50.00 u
component Ship
The script is a component called Ship. Its file is named after it, in lower case with underscores between words: ship.rgs. A file called anything else does not check.
speed and margin
Fields: the component’s rows in the Inspector, with these defaults. #[suffix("u/s")] writes units a second beside the number, and the /// line above each field is its tooltip.
fn loop(dt: f32)
A hook: it runs on every step of the game, 60 a second, with dt the step’s length in seconds.
camera_view
The field the camera shows, as four numbers: .x its left edge, .y its top, .z its right and .w its bottom. Reading the edges from the camera keeps the script right if the field ever changes.
direction
Where an action’s composite points, as a vector. .normalized() makes it one unit long, so two keys at once, a diagonal, are no faster than one.
position, clamp and move_to
Where the node was as the step began; a number held between two others; and where to put the node. Together they move the ship and keep its centre at least margin from every edge.

Because the world’s y grows downward, the top edge, view.y, is the smaller number, and up the field is toward negative y.

Give the ship its script

  1. Click the Viewport tab, select ship, press Add component, and choose Ship. It is listed under a rule, below the built-in components, once its script checks: a script with a mistake in it is not offered.
  2. Press Ctrl+S. The scene stores the Ship’s two fields, Speed 420 and Margin 50.
The ship selected: the Inspector shows its Position, 0 and 480, its Ship component with Speed 420 and Margin 50, and its Sprite, playerShip1_blue at 99 by 75, and the Viewport shows the ship near the bottom of the tall purple field

Check it works