【BeamNG drive】Modの作り方~UI編~

BeamNG.driveを始めて10ヵ月、ついに私もMod作成に手を出してしまいました…!!

ということでMod作成について今回から連載していきたいと思います!!(目標月1更新…)

BeamNG.driveには車やシナリオ、スキンなど、様々な種類のModがありますが、今回はUIのModについてです。

<<注釈>>
・この記事の内容で誤り・疑問点がある場合
末尾のコメント欄からお気軽にコメントください。(名無しでコメントできるように設定してありますが、英語のみのコメント等はスパム扱いされ対応できない場合があります。ご了承ください)
・BeamNG.driveのバージョンについて
この記事はv0.22.3で動作確認しております。アプデに伴い当記事の内容が全く使えないことになる可能性もあるのでご注意ください。(BeamNG.driveって実はまだ早期アクセス版なのよね。。。)

1.UIとは?

ここでいうUIは、タコメーターやナビゲーションメニューといったプレイ中に画面に表示されるもののことです。

技術的にはJavascript(AngularJS), HTML, CSS, SVGといったWEBのフロントエンドっぽいもので作られています。

「「なんか難しそう、、、」」

と感じるかもしれませんが、大丈夫です。

オリジナルのUIをコピペしていけば大体何とかなります。

また、BeamNG.drive特有のこと以外は、ググれば9割がた日本語記事が出てくるので、そういった意味でも作成のハードルは低いかと思います。
(WEB系で働いている人が多いのでしょうね…)

2.Mod作成時の環境(使用ソフト等)

今回は初回なのでMod作成時の環境(使用ソフト等)についても紹介しておきます。
※ここは割と好みの問題なので、あくまで参考程度です。(宗教戦争の意図は一ミリもありません)

UIのMod作成で使用するのは以下の2つです。

  • エディタ(必須):HTML等を編集する
  • SVG編集ソフト(あれば便利):UIのグラフィカルな部分を作成する

エディタ(VS Code)

エディタはVS Codeを使用しておけばまず間違いありません。

無料ですし、HTMLやJSにデフォルトで対応しています。
また、日本語化が容易というのも最高です。
つまりVS Codeが神です。VS Codeを信じる者は救われます。

ダウンロードは以下のページから行えます。
Download Visual Studio Code – Mac, Linux, Windows
※OS・アーキは適切なものを選択してください。
※User/Systemはインストール先がユーザ毎かPC全体かの違いです。通常はユーザで問題ないと思います。

ダウンロード後はインストーラに従っていくだけの簡単なお仕事です。

インストールが完了したら、最後に日本語化を行います。

VSCode日本語化の説明画像

これでエディタ(VS Code)の準備は完了です。

SVG編集ソフト(Inkscape)

続いてSVG編集ソフトです。
簡単に言えばペイントソフトで、SVG形式のファイルの出力・編集に対応しているソフトです。

こちらは必須ではありませんが、グラフィカルなメーター等を作成したい場合はあった方が絶対便利です。

今回はInkscapeというソフトをご紹介します。

これはOSSで無料で使用可能なソフトになっています。
(BeamNG.driveのフォルダを漁ってみた感じだと、BeamNG.drive開発チームもこれを使用してるっぽいです)

ダウンロードは以下から行います。
https://inkscape.org/release/
※OS・アーキは適宜選択してください。

これもインストーラでポチポチやっていくだけなのでインストールで困ることは特にないと思います。
日本語化もインストール時に設定可能です。


UIのMod作成で役に立つソフトの紹介は以上です。

次はいよいよMod作成について説明していきます。

3.はじめてのUI Mod

3-1 フォルダ作成

UIのModは以下のフォルダに配置する必要があるので、まずはフォルダを作成してください。
C:\Users\<ユーザ名>\AppData\Local\BeamNG.drive\0.22\ui\modules\apps\<Mod毎フォルダ>

フォルダ名は半角英数字のみにするのが無難

「Mod毎フォルダ」 内の構成は以下のようになっています。

  1. app.js(必須):UIのメインのファイル。動作を定義するコードが書かれている。
  2. app.json(必須):UIの大きさ等を設定するファイル
  3. app.png(任意):UI選択画面でのアイコン用の画像
  4. settings.json(任意):情報を保持したい場合に使用するファイル
  5. xxx.html(任意):HTMLはapp.js内に記載可能だが、長くなる場合は分ける
  6. xxx.svg(任意):SVGはapp.js内に記載可能だが、長くなる場合や他のツールで作成した図を使用する場合は分ける
最低限この2ファイルがあればOK

3-2 ファイル作成

次にModのファイルを作成していきます。

まずはapp.jsとapp.jsonがあれば十分なので、この2つのサンプルを置いておきます。

動作確認済みなので、コピペすればBeamNG.drive上で表示可能なUIが作成できるはずです。
(画面上にボタンが表示され、クリックするとカウントが増えていくだけの簡易なUIです)

app.js

angular.module('beamng.apps')
.directive('testApp', [function () {
  return {
    // 画面(HTML)の部分。{{}}で囲った変数は↓の関数内でscope.XXXでアクセス可能。
    template: '<div class="bngApp"><button ng-click="hello()">Click Me</button><span>count: {{ clickCount }}</span></div>',
    replace: true,
    restrict: 'EA',

    // この関数内にやりたいことを書く。
    link: function (scope, element, attrs) {

      // 例:ボタンがクリックされるとカウント
      scope.clickCount = 0;
      scope.hello = function () {
        scope.clickCount += 1;
      };
    }
  };
}])

コード内にコメントしているので解説は省略します。

app.json

{
  "name" : "test",
  "author": "test",
  "version": "0.1",
  "description": "テスト用",
  "directive": "testApp",
  "domElement": "<test-app></test-app>",
  "css": {
    "width": "150px",
    "height": "150px",
    "top": "200px",
    "left": "200px"
  }
}

name“, “aouthor“, “version“, “description“は英語のままなので省略します。適当な値で特に問題ないです。

directive“は、app.jsの2行目directiveと合わせる必要があるので注意しておいてください。

domElement“は、”directive“のlisp-caseで指定してください。上記の例の場合、testApp→test-appになります。

css“は、初期サイズを指定します。上記の例ではピクセル単位で指定していますが%単位で指定することも可能です。

表示イメージ

上記のファイルをUIのフォルダに配置し、BeamNG.driveを起動すると、以下のようにUIに追加されるようになります。

BeamNG.driveのUI選択画面に作成したUIが追加されている

これをクリックして画面に表示させると以下のようになるはずです。

作成したUIがプレイ画面に正しく表示されている

これで「はじめてのUI Mod」は完成です。

ここからは、これをベースに機能追加をしていくことになると思います。

なので次は作成時に役立つヒント・サンプルコードを説明していきます。

これは作りたいUIによって大きく変わってくる部分ですが、この記事ではなるべく一般的・基本的な内容を取り上げていきます。

4.Mod作成のTIPS~基本編~

4-1 動作確認(デバッグ)

まずは作成したUIの動作確認の方法を紹介します。

例えば、上記の例で、scope.clickCount += 1;scope.clickCount += 10;に変更し、クリックするたびに10ずつカウントが増えていくようにしたとします。

この時、BeamNG.drive上で動作確認をしたくなると思うのですが、ファイルを書き換えただけだと、BeamNG.drive側のUIには反映されません。
(これに気付かず3兆年くらい悩んだ)

ファイルを編集した後、UIをリロードする必要があります。

方法自体はとても簡単で、F5キーをクリックして “Reload UI” を実行するだけです。

※F5が機能しない人は、メニューの”Options” > “Controls”から”General Debug” > “Reload UI”のキーを設定してください

また、もっと詳細なエラーログを見たい場合は、以下が使えます。

・UI Console
UI開発時に必要なアレコレが詰まったコンソールになります。
“Ctrl + U”キーで開くことができます。
“Cosole”の部分でエラーログが確認できます。


・System Console
BeamNG.drive全体のシステムコンソールになります。
“^”キーで開くことができます。

こちらにしか出ないエラー等もあるので、私は基本的に両方とも表示した状態でデバッグしています。

4-2 オリジナルのUIを参考にしよう

序盤でも少し触れましたが、UIについては公式のUIのコードが見える場所に置いてあるのでそれを参考にすることができます。

UIを作成する際は、作りたいModに近いUIのファイルをコピペするのが簡単だと思います。

ちなみにBeamNG.drive公式のUIは以下にあります。
C:\Program Files (x86)\Steam\steamapps\common\BeamNG.drive\ui\modules\apps
(インストール方法によって上側が違うかもしれないので適宜読み替えてください)

4-3 HTMLのファイルを分ける場合

HTMLを別ファイルに分けた場合、パスは以下のように設定してください。

angular.module('beamng.apps')
.directive('testApp', [function () {
  return {
    templateUrl: 'modules/apps/「appのフォルダ名」/「ファイル名」.html',
    // こっちは不要
    // template: '<div class="bngApp"><button ng-click="hello()">Click Me</button><span>count: {{ clickCount }}</span></div>',

~~以下省略~~

“template”ではなく”templateUrl”で指定する必要がある点に注意です。
(これに気付かず5000兆年くらい悩んだ)

4-4 SVGファイルを分ける場合

SVGを別ファイルに分けた場合、パスは以下のように設定してください。

angular.module('beamng.apps')
.directive('testApp', [function () {
  return {
    template: '<object type="image/svg+xml" data="modules/apps/「appのフォルダ名」/「ファイル名」.svg"></object>',

~~以下省略~~

4-5 bngApiを使用する場合

bngApiはBeamNG.driveのAPIでBeamNG.driveの情報取得・制御が可能です。

※bngApiの詳細については以下をご参照ください。
https://wiki.beamng.com/Lua:Reference

UIで使用する場合は以下のように記述します。

angular.module('beamng.apps')
.directive('testApp', ['bngApi', function (bngApi) { // bngApiが必要
  return {
    // 画面(HTML)の部分。{{}}で囲った変数は↓の関数内でscope.XXXでアクセス可能。
    template: '<div class="bngApp"><button ng-click="hello()">Click Me</button><span>count: {{ currentTrafficNum }}</span></div>',
    replace: true,
    restrict: 'EA',

    // この関数内にやりたいことを書く。
    link: function (scope, element, attrs) {

      // 例:ボタンがクリックされるとトラフィックの数を取得する。
      scope.currentTrafficNum = 0;
      scope.hello = function () {
        bngApi.engineLua('extensions.gameplay_traffic.getNumOfTraffic()', (result) => {
          scope.currentTrafficNum = result;
        });
      };
    }
  };
}])

4-6 UIをリアルタイムに更新したい場合

ここまでは、「ボタンがクリックされた時に○○」というサンプルを紹介してきました。

しかし、「スピードメーターのようなUIで、リアルタイムにUIを更新したい」ということがあると思います。

その場合は、以下のように記述することでUIをリアルタイムに更新することが可能です。

angular.module('beamng.apps')
.directive('testApp', ['StreamsManager', function (StreamsManager) { // StreamsManagerが必要
  return {
    // 画面(HTML)の部分。{{}}で囲った変数は↓の関数内でscope.XXXでアクセス可能。
    template: '<div class="bngApp"><span>{{ currentWheelSpeed }}</span></div>',
    replace: true,
    restrict: 'EA',

    // この関数内にやりたいことを書く。
    link: function (scope, element, attrs) {
      // StreamsManagerに欲しいstreamの値を設定することでstreamへのアクセスが可能
      var streamsList = ['electrics'];
      StreamsManager.add(streamsList);

      // streamの更新が発生したタイミングで実行される(=リアルタイムに実行される)
      scope.$on('streamsUpdate', function (event, streams) {
        scope.$evalAsync(function () { // SVG描画する時evalAsyncなくても反映されるんだけどなんでなん。。。Agnular詳しい人教えて。。。
          scope.currentWheelSpeed = streams.electrics.airspeed;
        })
      });

      scope.$on('$destroy', function () {
        StreamsManager.remove(streamsList);
      });
    }
  };
}])

上記はstreamを使用する例として書いていますが、streamを使用しないUIをリアルタイムに更新したい場合も同様の書き方で問題なさそうです。
(公式のUIでそういう書かれ方をしていた)

終わりに

今回はここまでです。

UI Mod作成の基本的な部分は一通り網羅できたと思うので、簡単なModであればもう作れるようになっているのではないでしょうか。

次回、応用編では、より細かい部分を解説していきたいと思います。

以上です。

参考

公式ドキュメント
https://documentation.beamng.com/modding/ui/app_creation/

wiki(bngApi(Lua), streamについて)
https://wiki.beamng.com/Lua:Reference
https://wiki.beamng.com/Streams

コメント

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