RPGツクールでDOMを使ってみた

# 音量調節スライダーとDOMの紹介

## はじめに

こんにちは。くろうどです。
DOMを使用して音量調節スライダープラグインを作成したので、その紹介と中身について説明したいと思います。

DOMって時々聞くけど何なの？っていうRPGツクールMZユーザー向けです。

## 音量調節スライダー

音量調節スライダープラグインは、オプション画面の音量調節部分にスライダーを表示するプラグインです。
スライダーを左右に動かす事で音量変更できます。

DOMを使って作成しました。

尚、見た目はブラウザ依存となっています。
スマホ対応するために RangeTouch というライブラリを使用しています。ただし、操作感はイマイチです。
スライダー表示時は決定ボタンによる音量変更ができないようにしていますので、キーボード操作時は左右キーを使ってください。

[KRD_MZ_InputRange.jsをダウンロード](https://github.com/kuroudo119/RPGMZ-Plugin/raw/master/KRD_MZ_InputRange.js)

![音量調節スライダーの表示](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373498/0ce06c13-304d-4eb8-49f3-6884685678b6.png)

## DOMについて

DOMとは Document Object Model の略らしいです。プログラミング言語からHTMLやCSSを扱う仕組みの事です。
どういう事かと言うと、JavaScriptでHTMLタグを追加したり、CSSを変更したり出来ます。

例えば、以下のHTMLタグはスライダーの表示です。
HTMLファイルにこれを書いてもただ表示されるだけで、音量調節できません。
このHTMLタグで音量調節できるようにするために今回はDOMを使用しました。

```html
<input type="range">
```

## HTMLとCSSについて

ここで補足ですが、HTML（ハイパーテキスト・マークアップ・ランゲージ）とはブラウザ表示の元となるファイルの事です。
RPGツクールMVおよびRPGツクールMZでも、index.htmlファイルからJavaScriptが呼ばれゲームが実行されます。

HTMLタグを使って表示内容を記述します。
例えば、表示する文章やリンクです。

CSS（カスケーディング・スタイルシート）とはHTMLでの表示の見た目を整える方法が書かれたファイルです。
RPGツクールMVでは gamefont.css があり、RPGツクールMZでは game.css があります。

CSS ではHTMLタグに対してどのように表示するか等（スタイル）が書かれています。
例えば、色やフォントサイズです。

ただし、HTMLもCSSもRPGツクールで変更する事は無いと思います。
単純にHTMLタグを追加してもゲームに影響が無いからです。

## 音量調節スライダーのDOM

音量調節スライダーのソースコードはGitHubにありますので、全体はそちらを参照してください。

[KRD_MZ_InputRange.jsを見る](https://github.com/kuroudo119/RPGMZ-Plugin/raw/master/KRD_MZ_InputRange.js)

## InputRangeクラス

```JavaScript
class InputRange {
  constructor(value, x, y, window2, symbol, id) {
      // コンストラクタの処理
  }
}
```

↑ まずは、クラス宣言とコンストラクタです。

コンストラクタとはインスタンス生成時（クラスをnewした時）に呼ばれる関数（メソッド）です。
普通の関数のように引数を設定できます。

尚、window2 は window が既にあるから別名を付けたものです。
この window2 にはRPGツクールの Window_Options が入って来ます。
そうしないと、音量の値が変更できないからです。

### HTMLタグの作成

```JavaScript
this._input = document.createElement("input");
```

↑ input タグを作成します。
this.\_input変数（メンバ変数）にinputタグを入れました。
変数名は自由に付けられるので this.\_input でなくても構いません。

```JavaScript
this._input.type = "range";
this._input.id = id;
this._input.value = value.toString();
this._input.min = "0";
this._input.max = "100";
this._input.step = "10";
```

↑ ここからは、HTMLタグの属性を追加します。
それぞれ input タグの属性です。

```html
<input type="range" id="InputRange" value="50" min="0" max="100" step="10">
```

↑ 上のJavaScriptはこのHTML文と同じになります。
（id と value は変数なので可変ですが）

### CSSの設定

```JavaScript
this._input.style.position = "fixed";
this._input.style.left = x.toString() + "px";
this._input.style.top = y.toString() + "px";
this._input.style.opacity = "1";
this._input.style.zIndex = "50";
```

↑ 次にCSSを設定します。
this.\_input の後ろに style と付いているのがCSS（スタイル）を指しています。
先程作成した this.\_input に対してスタイルを設定しています。

```css
<style type="text/css">
  #InputRange {
    position: fixed;
    left: 200px;
    top: 300px;
    opacity: 1;
    z-index: 50;
  }
</style>
```

↑ 上のJavaScriptはこのCSSと同じです。
（x と y は変数なので可変ですが）

このように、HTMLタグを createElement して、属性やスタイルを設定していきます。
いろんなHTMLタグを createElement してみてください。

HTMLタグや設定可能な属性、スタイルは異なるので、詳しくは調べてください。

ちなみに、上で『同じです』と言ったHTMLタグとCSSを index.html に追加するだけでもスライダーが表示されます。
スライダーを動かしても何も起こりませんが……。

### HTML(body)への追加

```JavaScript
document.body.appendChild(this._input);
```

↑ 間を飛ばしますが、こうして createElement したタグの設定が終わったら appendChild で body タグに追加します。
これにより、このクラスを new すると画面に表示されます。

（今回は RangeTouch というライブラリを使用したので音量調節スライダーでは this._range.element を設定していますが、通常は this.\_input を設定します）

ちなみに、以下のHTMLタグはラジオボタンですが、似たような感じで createElement して appendChild して new すると表示できます。

```html
<input type="radio">
```

ただし、ここまででは表示されるだけで、スライダーを動かしても音量は変わりません。
音量変更の処理は appendChild の上に書いています。

### マウス操作の設定（イベントリスナー）

```JavaScript
function move(input, window2, symbol) {
  const value = Number(input.value);
  window2.changeValue(symbol, value);
}

// Mouse
this._input.addEventListener('mousemove', function(ev, win = window2, sbl = symbol){
  move(this, win, sbl);
}, false);
```

↑ 音量変更の処理がコレです（タッチは同じなので省略します）

addEventListener を設定しています。
このイベントリスナーは 'mousemove' なので、this.\_input 上でマウスが移動した時に呼ばれます（クリックの有無は関係ないはず）

今回はスライダーの機能を使いたいので、 preventDefault はしません。
（ ev.preventDefault() を実行すると、本来のHTMLタグの機能を無効化します。これは、オリジナル機能を作りたい時に使います）

```JavaScript
move(this, win, sbl);
```

↑ ここの move を呼ぶ時の this は this.\_input です。
スコープが途切れる（はずな）ので、値を送っています。

window2 には Window_Options が入っているので changeValue関数で音量を変えています。

### おまけ

```JavaScript
// Nothing right click.
this._input.oncontextmenu = function() {
  return false;
};

Graphics.zoomRange(id, x, y);
```

↑ InputRangeクラスの残りは oncontextmenu （スライダー上での右クリック無効化）と、ウィンドウサイズ変更時のスライダー表示位置の変更（zoomRange は独自関数）です。

## 画面への表示と削除（newとremoveChild)

画面への表示は作成した InputRange クラスを new する事です。
new する場所はRPGツクールでの表示したいシーンです。

RPGツクールの Scene_Base には create や terminate といった、処理が書かれていないけど宣言されてる関数があります。
シーン作成時やシーン終了時に実行される関数です。

Scene_Base にあるということは、継承している Scene_Options にもあります。
今回はコレを使います。
(create じゃなくて start を使いましたが)

```JavaScript
const KRD_Scene_Options_start = Scene_Options.prototype.start;
Scene_Options.prototype.start = function() {
  KRD_Scene_Options_start.apply(this, arguments);
  if (!show) {
    show = true;

    const x = baseX;
    const y = baseY;
    const lineHeight = baseLineHeight;
    this._bgmRange = new InputRange(AudioManager.bgmVolume, x, y, this._optionsWindow, "bgmVolume", "bgmRange");
    // 以下略
  }
};
```

↑ start のスライダー1個分の処理です。

new InputRange しています。
これにより画面にスライダーが表示されます。

ポイントは this.\_optionsWindow を引数に設定している事でしょうか。
他の引数は数値や文字列ですが、これは Window\_Options のかたまり（インスタンス）を送っています。

```JavaScript
const KRD_Scene_Options_terminate = Scene_Options.prototype.terminate
Scene_Options.prototype.terminate = function() {
  KRD_Scene_Options_terminate.apply(this, arguments);
  if (show) {
    show = false;
    // ↓作成したIDの""なしを引数にする
    document.body.removeChild(bgmRange);
    // 以下略
  }
};
```

↑ terminate のスライダー1個分の処理です。

removeChild により削除しています。
（removeChild の引数がよく分からなかったのですが、文字列だとNGだったので、クォーテーション無しにしています）

今回はシーンを跨いでの表示はしないので、同じシーンで start および terminate しています。

## おわりに

さて、ここまでDOMについて説明してきましたが、残念ながら、RPGツクールでは特に必要ないんです。

見た目はブラウザ依存だし、今回は説明していませんが、ウィンドウサイズによって表示位置がずれるから表示位置を計算しないといけないし……。
（見た目はCSSで変えられるかも？）

それではまたどこかで。