[SOLVED] Keyboard methods not working

Hi everyone, I am new to playcanvas so I have some questions to ask bcuz i am not using the online editor rather am working on a react project with playcanvas installed via npm.

So here’s the thing, I am making a 2D space shooter game but keyboard methods ( ispressed, waspressed etc…) are not working. I oipen the console and it is giving me error of “cannot read properties of null (reading isPressed)”. If anyone here what is going on please help.

Here is code

app.on("update", (dt) => {
          camera.setPosition(0, 0, 10);

          let rb = ship.rigidbody;

          const moveHorizontal = function () {
            if (app.keyboard.isPressed(pc.KEY_LEFT)) {
              return 1;
            }
            if (app.keyboard.isPressed(pc.KEY_RIGHT)) {
              return -1;
            }
            return 0;
          };

          const moveVertical = function () {
            if (app.keyboard.isPressed(pc.KEY_DOWN)) {
              return -1;
            }
            if (app.keyboard.isPressed(pc.KEY_UP)) {
              return 1;
            }
            return 0;
          };
          const movement = new pc.Vec3(moveHorizontal, moveVertical, 0);
          rb.linearVelocity = movement.scale(10);
        });
      }
    );

Thank you

Hi @Wali_Ahmad and welcome,

If you are using the engine directly, make sure you are initializing a keyboard input handler when you boot the pc.Application instance. Like this, taken from a build downloaded from the editor:

    var createInputDevices = function (canvas) {
        var devices = {
            elementInput: new pc.ElementInput(canvas, {
                useMouse: INPUT_SETTINGS.useMouse,
                useTouch: INPUT_SETTINGS.useTouch
            }),
            keyboard: INPUT_SETTINGS.useKeyboard ? new pc.Keyboard(window) : null,
            mouse: INPUT_SETTINGS.useMouse ? new pc.Mouse(canvas) : null,
            gamepads: INPUT_SETTINGS.useGamepads ? new pc.GamePads() : null,
            touch: INPUT_SETTINGS.useTouch && pc.platform.touch ? new pc.TouchDevice(canvas) : null
        };

        return devices;
    };

    devices = createInputDevices(canvas);

     app = new pc.Application(canvas, {
         elementInput: devices.elementInput,
         keyboard: devices.keyboard,
         mouse: devices.mouse,
         gamepads: devices.gamepads,
         touch: devices.touch,
     });

I am not using the online editor, so does this practice still apply??

Is there something else I need to setup before using it in react?? I really am stuck in this part.

Yes, you need to instantiate the pc.Application similarly to the code I posted above (include input handlers).

1 Like

We have an example here for keyboard input: http://playcanvas.github.io/#/input/keyboard

1 Like

So I pasted the code you sent me in my project, it gives “input_settings is not defined” and nothing moves. Here is the full code.

const Playcanvas = () => {
  const canvasRef = useRef(null);
  const appRef = useRef(null);

  useLayoutEffect(() => {
    var createInputDevices = function (canvas) {
      var devices = {
        elementInput: new pc.ElementInput(canvas, {
          useMouse: INPUT_SETTINGS.useMouse,
          useTouch: INPUT_SETTINGS.useTouch,
        }),
        keyboard: INPUT_SETTINGS.useKeyboard ? new pc.Keyboard(window) : null,
        mouse: INPUT_SETTINGS.useMouse ? new pc.Mouse(canvas) : null,
        gamepads: INPUT_SETTINGS.useGamepads ? new pc.GamePads() : null,
        touch:
          INPUT_SETTINGS.useTouch && pc.platform.touch
            ? new pc.TouchDevice(canvas)
            : null,
      };

      return devices;
    };

    let devices = createInputDevices(canvasRef.current);

    const app = new pc.Application(canvasRef.current, {
      elementInput: devices.elementInput,
      keyboard: devices.keyboard,
      mouse: devices.mouse,
      gamepads: devices.gamepads,
      touch: devices.touch,
    });

    app.start();

    app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
    app.setCanvasResolution(pc.RESOLUTION_AUTO);

    window.addEventListener("resize", function () {
      app.resizeCanvas();
    });

 const camera = new pc.Entity("camera");
    camera.addComponent("camera", {
      clearColor: new pc.Color(0.1, 0.1, 0.1),
    });

    const light = new pc.Entity("light");
    light.addComponent("light");


var ship = new pc.Entity();
        ship.addComponent("sprite", {
          type: pc.SPRITETYPE_SIMPLE,
          spriteAsset: spriteAsset,
        });

        app.root.addChild(ship)
;
        ship.setPosition(0, -2, 0);
        ship.setLocalScale(0.1, 0.1, 0);
        ship.addComponent("rigidbody", {
          type: pc.BODYTYPE_KINEMATIC,
          mass: 10,
        });
       app.on("update", (dt) => {
          camera.setPosition(0, 0, 10);

          let rb = ship.rigidbody;

          const moveHorizontal = function () {
            if (keyboard.isPressed(pc.KEY_LEFT)) {
              return 1;
            }
            if (keyboard.isPressed(pc.KEY_RIGHT)) {
              return -1;
            }
            return 0;
          };

          const moveVertical = function () {
            if (keyboard.isPressed(pc.KEY_DOWN)) {
              return -1;
            }
            if (keyboard.isPressed(pc.KEY_UP)) {
              return 1;
            }
            return 0;
          };
          const movement = new pc.Vec3(moveHorizontal, moveVertical, 0);
          rb.linearVelocity = movement.scale(10);
        });
      }
    );

    appRef.current = app;
  }, []);

  return (
    <>
      <div style={{ overflow: "hidden", width: "100%", height: "100vh" }}>
        <canvas ref={canvasRef} />
      </div>
    </>
  );
};

That was example code taken from a PlayCanvas exported build, not to be used directly but studied on.

Here is a simplified version, study and adjust it to your code:

     var app = new pc.Application(canvas, {
         keyboard: new pc.Keyboard(window),
         mouse: new pc.Mouse(canvas),
         touch: pc.platform.touch ? new pc.TouchDevice(canvas) : null,
     });
1 Like

I changed canvas with canvasRef.current since that is referencing the canvas and still no effect.

var app = new pc.Application(canvasRef.current, {
         keyboard: new pc.Keyboard(window),
         mouse: new pc.Mouse(canvasRef.current),
         touch: pc.platform.touch ? new pc.TouchDevice(canvasRef.current) : null,
     });

Not sure what the issue is then. Is everything else, apart from input, working correctly?

Have you checked the example @yaustar provided?

Well I have created entity both sprites and models and they work, I have also tried the above examples to no avail. I want to move the entity using its rigidbody component but input just doesn’t work.

Not sure how to help you here, try to find a way to share your project with us (or part of your project) so we can debug directly.

1 Like

here is the git repositry https://github.com/filesumairasim/playcanvas-test.git. Really appreciate the help.

1 Like

So the issue now is in your JS, these functions will never execute since nobody is calling them (you only pass a reference):

const movement = new pc.Vec3(moveHorizontal, moveVertical, 0);

It should be like this:

const movement = new pc.Vec3(moveHorizontal(), moveVertical(), 0);

Then your isPressed calls work as expected.

Your spaceship though won’t move since you are attempting to move a kinematic object using linear velocity. Either set it to dynamic or use setPosition or translate to move it.

Here is how I got it to work for you:

const movement = new pc.Vec3(-moveHorizontal(), moveVertical(), 0).scale(0.01);
ship.translate(movement);
//rb.linearVelocity = movement.scale(10);

1 Like

Now it works nicely, thank u so much for your time I really appreciate it.

1 Like

@Leonidas i m using playcanvas engine via npm in my react project.since i m struggling to make it .
i m bit curious about have u worked with the approach that i m following.
if yes plz let me know.