Pixi.js + TypeScript + Viteでゲームを作る 2. キャラクターの表示とキー入力

pixi.js

Pixi.js + TypeScript + Viteでゲームを作る 2. キャラクターの表示とキー入力

<< 前回の記事 1. Hello,world

前回の記事ではPixi.jsをTypeScriptで呼び出してみました、今回はPixi.jsを使ってキャラクターを表示して、キーボード入力で操作をしてみます。 基本的にPixi.js公式のチュートリアルをTypeScriptに置き換えながら進めているだけなので、詳細はリンクを参照してください。

キャラクターの読み込み処理の追加

 await Assets.load([
    {
        alias: 'spineSkeleton',
        src: 'https://raw.githubusercontent.com/pixijs/spine-v8/main/examples/assets/spineboy-pro.skel',
    },
    {
        alias: 'spineAtlas',
        src: 'https://raw.githubusercontent.com/pixijs/spine-v8/main/examples/assets/spineboy-pma.atlas',
    },
    {
        alias: 'sky',
        src: 'https://pixijs.com/assets/tutorials/spineboy-adventure/sky.png',
    },
    {
        alias: 'background',
        src: 'https://pixijs.com/assets/tutorials/spineboy-adventure/background.png',
    },
    {
        alias: 'midground',
        src: 'https://pixijs.com/assets/tutorials/spineboy-adventure/midground.png',
    },
    {
        alias: 'platform',
        src: 'https://pixijs.com/assets/tutorials/spineboy-adventure/platform.png',
    },
]);

キャラクター用Classの作成

キャラクターを制御するためのクラスを作成します。 これはpixi.jsに密接に紐づいていて、コンストラクタでpixi.jsのContainerとspineを生成します

import { Spine } from "@pixi/spine-pixi";
import { Container } from "pixi.js";

// Class for handling the character Spine and its animations.
export class SpineBoy {
  public view: Container;
  public spine: Spine;
  constructor() {
    // Create the main view.
    this.view = new Container();
    // Create the Spine instance using the preloaded Spine asset aliases.
    this.spine = Spine.from({
      skeleton: "spineSkeleton",
      atlas: "spineAtlas",
    });
    // Add the spine to the main view.
    this.view.addChild(this.spine);
  }
}

controllerの作成

// Map keyboard key codes to controller's state keys

const KEYS = [
    'Space',
    'KeyW',
    'ArrowUp',
    'KeyA',
    'ArrowLeft',
    'KeyS',
    'ArrowDown',
    'KeyD',
    'ArrowRight',
]
type Key = typeof KEYS[number];

const keyMap: {
    [key in Key]: string;
} = {
    Space: 'space',
    KeyW: 'up',
    ArrowUp: 'up',
    KeyA: 'left',
    ArrowLeft: 'left',
    KeyS: 'down',
    ArrowDown: 'down',
    KeyD: 'right',
    ArrowRight: 'right',
};

// Class for handling keyboard inputs.
export class Controller
{
    keys: Record<string, { pressed: boolean, doubleTap: boolean, timestamp: number }>;
    constructor()
    {
        // The controller's state.
        this.keys = {
            up: { pressed: false, doubleTap: false, timestamp: 0 },
            left: { pressed: false, doubleTap: false, timestamp: 0 },
            down: { pressed: false, doubleTap: false, timestamp: 0 },
            right: { pressed: false, doubleTap: false, timestamp: 0 },
            space: { pressed: false, doubleTap: false, timestamp: 0 },
        };

        // Register event listeners for keydown and keyup events.
        window.addEventListener('keydown', (event) => this.keydownHandler(event));
        window.addEventListener('keyup', (event) => this.keyupHandler(event));
    }

    private keydownHandler(event: KeyboardEvent)
    {
        const key = keyMap[event.code];

        if (!key) return;

        const now = Date.now();

        // If not already in the double-tap state, toggle the double tap state if the key was pressed twice within 300ms.
        this.keys[key].doubleTap = this.keys[key].doubleTap || now - this.keys[key].timestamp < 300;

        // Toggle on the key pressed state.
        this.keys[key].pressed = true;
    }

    private keyupHandler(event: KeyboardEvent)
    {
        const key = keyMap[event.code];

        if (!key) return;

        const now = Date.now();

        // Reset the key pressed state.
        this.keys[key].pressed = false;

        // Reset double tap only if the key is in the double-tap state.
        if (this.keys[key].doubleTap) this.keys[key].doubleTap = false;
        // Otherwise, update the timestamp to track the time difference till the next potential key down.
        else this.keys[key].timestamp = now;
    }
}

コメント

タイトルとURLをコピーしました