【pixi.js】画面にマップチップを表示しよう:PIXI.Graphics編

javascript

マップチップ 描写

こんにちは。継続の錬金術士なおキーヌです。

ブログ毎日更新は116日目になります。

【pixi.js】Electronで動くゲームプログラミングをしよう準備編の続きですね。

今回はpixi.jsでマップチップを敷き詰めていくための処理を作っていきます。

本来は海や山や草原などのマップチップを並べるのですがそのためにはPIXI.Spriteクラスを使って、
ローダーでテクスチャをロードしてPIXI.Spriteクラスにテクスチャを適用するという手順が必要になります。

その前にPIXI.Spriteクラスの兄弟であるPIXI.Graphicsクラスを使って疑似的にマップチップを表示します。

PIXI.Graphicsであれば塗りつぶしや線の描画がファイルロードなどをせずにすぐに使えるので、
仮に何かをテストで表示したいときは便利なので積極的に使っていきましょう。

マップチップ描写用の基本的な処理が出来てしまえば、後はPIXI.GraphicsをPIXI.Spriteに置き換えるだけです。

それでは作っていきましょう。

PIXI.Graphicsを使ってマップチップを画面に表示しよう

マップチップ 画面描写

出力結果の画像が無いと講座としてはどうかなって思えてきたので、
今回からはなるべく画像付きのゲーム制作講座を心掛けていきますのでよろしくお願いします。

やることリストは下記になります。

  • クラス変数にPIXI.Graphics型の変数を用意
  • 変数にnew PIXI.Graphicsでインスタンスを生成
  • PIXI.Graphics変数の座標、位置、塗りつぶし等を1つの関数にまとめる
  • ステージ追加用の関数を作る
  • 初期化プロセス関数に↑で作った2つの関数を呼び出す
  • npm run renderer-devでコンパイルしてnpm run dev で実行する。(今後表記省略)

それでは早速PIXI.Graphicsを使って画面に描写してみましょう。

クラス変数にPIXI.Graphics型の変数を用意してインスタンスを生成

    // マップ用変数
    private MapChip:PIXI.Graphics = new PIXI.Graphics();

PIXI.Graphics型のprivate変数を作って、そこにnew PIXI.Graphicsをしてインスタンスを生成します。

これ以降はクラス内であれば「this.変数名」で呼び出せます。

PIXI.Graphics変数の座標、位置、塗りつぶし等を1つの関数にまとめる

本来、javascriptであれば関数を作るときはfunction~となりますが
TypeScriptではクラスの中で関数を作る場合、変数と同じようにprivateやpublic等アクセス修飾子をつけます。

何もつけないとpublicになってしまうので、クラス内でしか使わない場合はprivateにしておきましょう。

他にも親子関係にあるクラスだけが使えるprotectedというのもあるのですが、
プログラミング初心者のうちはあまり使わないです。

それではマップチップの大きさや塗りつぶしなどを指定する関数を作りましょう。

関数は他の関数を作っている感じでどこに記述してもいいですが、
関連のあるものは近くに置いておくとメンテナンスしやすいです。

関数がどんどん増えて来たら別のファイルにして管理しやすくするのが基本ですが
慣れるまでは呼び出しエラー等を引き起こすと思うので、今は1つのファイルにまとめておいた方がいいです。

    // マップチップ初期化
    private mapChipInit() {
        // x座標設定
        this.MapChip.x = 0;
        // y座標設定
        this.MapChip.y = 0;
        // 横幅設定
        this.MapChip.width = 16;
        // 縦幅設定
        this.MapChip.height = 16;
        // 塗りつぶし
        // this.MapChip.lineStyle(4, 0xff00ff, 1);
        this.MapChip.beginFill(0xff00ff);
        this.MapChip.drawRect(0,0,16,16);
        this.MapChip.endFill();        
    }

リテラルで数値を指定していますが、のちにSpriteクラスに変更するので一旦これでいきます。

ステージ追加用の関数を作る

続いて作ったマップチップの変数をステージに追加していきます。

先ほど作った生成関数の中にいれてもいいのですが、初回にステージ追加するものは一ヶ所にまとめて関数化しておくと、
デバッグする時に表示したり非表示にしたりしたい場合にあっちこっちの関数を見に行かなくても済みます。

    // 初回ステージ追加
    private addStageInit() {
        this.App.stage.addChild(this.MapChip);
    }

今後、何かをステージに追加する時はここに並べていきます。

初期化プロセス関数に↑で作った2つの関数を呼び出す

作った関数「mapChipInit」と「addStageInit」をコンストラクタ関数内で呼び出してみましょう。

コンストラクタでは「initializePIXI」を呼び出していますので、この関数の中に
作った関数を呼び出すようにしてみましょう。

追加した部分は【追加】と記述しています。

    // 初期化プロセス
    private initializePIXI() {

        // ピクセル倍率変更
        this.pixelScaleUP();

        // htmlのbodyにPIXIAPPを追加
        document.body.appendChild(this.App.view);

        // マップチップ初期化【追加分】
        this.mapChipInit();

        // オブジェクトをステージに追加【追加分】
        this.addStageInit();
    }

コンパイルして実行してみよう

ここまで出来たらコンソール画面で下記のコマンドを入力してコンパイルしてください。

npm run renderer-dev

コンパイルが終わったら起動してみましょう。

npm run dev

問題なく起動出来たらこのように表示されるはずです。

pixi.js コンパイル結果

次回は配列化して画面全体に敷き詰めよう

今回は復習も兼ねてマップチップを1つだけ表示しました。

今回で配列化までやってしまってもよかったのですが、初心者向けの記事なので
長くなりすぎても疲弊してしまうので小刻みにやっていきます。

一気にやると最初にやったことが忘れやすくなるのでその対策にもなりますね。

決して記事数稼ぎではありません!(笑)

最後に今回のソースコードを乗せておきます。

import * as PIXI from 'pixi.js'
import { SYSTEM } from '../../config/system';

class PIXI_MainProcess {

    /**
     * ----------------------------------------------------
     * エイリアス作成
     * ----------------------------------------------------
     *  */ 
    // pixi.jsアプリケーション
    private PIXI_Application = PIXI.Application
    // ローダー
    private PIXI_loader = PIXI.loader
    // リソースローダー
    private PIXI_resources= PIXI.loader.resources

    /**
     * ----------------------------------------------------
     * クラス変数
     * ----------------------------------------------------
     *  */ 
    // pixiアプリケーション生成
    private App:PIXI.Application = this.pixiApplicationCreate(SYSTEM.width,SYSTEM.height);

    // マップ用変数【追加】
    private MapChip:PIXI.Graphics = new PIXI.Graphics();

    // コンストラクタ
    constructor() {

        // 初期化プロセス
        this.initializePIXI();
    }

    // 初期化プロセス
    private initializePIXI() {

        // ピクセル倍率変更
        this.pixelScaleUP();

        // htmlのbodyにPIXIAPPを追加
        document.body.appendChild(this.App.view);

        // マップチップ初期化
        this.mapChipInit();

        // オブジェクトをステージに追加
        this.addStageInit();

    }

    // PIXIアプリケーションオブジェクト作成
    private pixiApplicationCreate(screenWidth:number,screenHeight:number) {
        return new this.PIXI_Application({
            width:screenWidth,
            height:screenHeight,
            antialias: false,
            transparent: false,
            resolution: 1
            }
        );
    }

    // ピクセル倍率を2倍に変更
    private pixelScaleUP() {
        this.App.renderer.roundPixels = true;
        this.App.renderer.resize(SYSTEM.width, SYSTEM.height);
        this.App.stage.scale.set(2,2);
        this.App.stage.interactive = true;
        PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
    }


    // // セットアップ関数
    private setup(app:PIXI.Application) {

        app.ticker.add(delta => this.gameloop(delta));

        // // .load()は「undifinedを指定して何も返さない」としなければtslintでエラーが出る
        // // void型にして下記を消すとクラス変数がnullにされてしまうのでこれで対応
        // return undefined;
    }

    // メインループ
    private gameloop(delta:number) {
    }


    // マップチップ初期化
    private mapChipInit() {
        // x座標設定
        this.MapChip.x = 0;
        // y座標設定
        this.MapChip.y = 0;
        // 横幅設定
        this.MapChip.width = 16;
        // 縦幅設定
        this.MapChip.height = 16;
        // 塗りつぶし
        // this.MapChip.lineStyle(4, 0xff00ff, 1);
        this.MapChip.beginFill(0xff00ff);
        this.MapChip.drawRect(0,0,16,16);
        this.MapChip.endFill();        
    }

    // 初回ステージ追加
    private addStageInit() {
        this.App.stage.addChild(this.MapChip);
    }

}

export default PIXI_MainProcess;

const GameFrame:PIXI_MainProcess = new PIXI_MainProcess;