Tutorials
3. Move player with arrow keys

3. Move player with arrow keys

Let's wire up the keyboard to control the player position. We'll listen for keydown events on the window and move the player based on which arrow key is pressed.

You may notice a delay between movements. That's because our transactions take some time to confirm. Even though the block time for our local anvil node is set to just one second, it still feels sluggish. That's kind of the nature of the blockchain, but we'll improve on that in the next step with optimistic rendering.

Movement helpers

To keep our React code tidy, we'll create a few helper methods for movement that we can export alongside our systems and components after they've been set up.

import { SystemAbis } from "contracts/types/SystemAbis.mjs";
import { EntityID, getComponentValue } from "@latticexyz/recs";
import { createFaucetService, SingletonID } from "@latticexyz/network";

export const setup = async () => {

  const moveTo = async (x: number, y: number) => {
    const tx = await result.systems["system.Move"].executeTyped({ x, y });
    await tx.wait();
  };
 
  const moveBy = async (deltaX: number, deltaY: number) => {
    const playerPosition = getComponentValue(components.Position, playerEntity);
    if (!playerPosition) {
      console.warn("cannot moveBy without a player position, not yet spawned?");
      return;
    }
    await moveTo(playerPosition.x + deltaX, playerPosition.y + deltaY);
  };
 
  return {
    ...result,
    world,
    singletonEntityId: SingletonID,
    singletonEntity,
    playerEntityId,
    playerEntity,
    components,
    api: {
      moveTo,
      moveBy,
    },
  };
};

Keyboard movement

Now we can listen for for arrow key presses to move the player in the corresponding direction.

import { useEffect } from "react";
import { useComponentValue } from "@latticexyz/react";
import { useMUD } from "./MUDContext";
 
export const GameBoard = () => {

  const {
    components: { Position },
    api: { moveTo, moveBy },
    playerEntity,
  } = useMUD();
 
  useEffect(() => {
    const listener = (e: KeyboardEvent) => {
      if (e.key === "ArrowUp") {
        moveBy(0, -1);
      }
      if (e.key === "ArrowDown") {
        moveBy(0, 1);
      }
      if (e.key === "ArrowLeft") {
        moveBy(-1, 0);
      }
      if (e.key === "ArrowRight") {
        moveBy(1, 0);
      }
    };
 
    window.addEventListener("keydown", listener);
    return () => window.removeEventListener("keydown", listener);
  }, [moveBy]);
 
  const playerPosition = useComponentValue(Position, playerEntity);
 
  return (
    <div className="inline-grid p-2 bg-lime-500">
      {rows.map((y) =>
        columns.map((x) => (
          <div
            key={`${x},${y}`}
            className="w-8 h-8 flex items-center justify-center cursor-pointer hover:ring"
            style={{
              gridColumn: x + 1,
              gridRow: y + 1,
            }}
            onClick={(event) => {
              event.preventDefault();
              moveTo(x, y);
            }}
          >