最新のティラノスクリプト×Live2Dの開発環境を構築する

マルチプラットフォームに対応可能な無料のJavaScriptノベルゲームエンジン・**ティラノスクリプト**。
ティラノスクリプトは、専用のプラグインを読み込むことで、**Live2D**のモデルを扱うことができます。
それに関連するこの記事では、以下の項目の達成を目標として解説を行います。

- 最新のティラノスクリプトでLive2Dのモデルを扱える環境を構築する。
- 構築した環境で実際に独自モデルを追加・操作する知識を身に着ける。

#1. 環境の構築
##1-1. 準備するもの

環境の構築にあたって、次のソフトウェアが必要です。

- 適当なZipファイル解凍ツール

##1-2. ダウンロードと解凍

まず、**環境の構築に必要なファイルをすべてダウンロード**してしまいましょう。
バージョンが複数ある場合、基本的に**最新のバージョン**をダウンロードします。

1. [こちら](http://tyrano.jp/dl/)から、**ティラノスクリプト（スタンダードパッケージ）**をダウンロードする。
2. [こちら](http://tyrano.jp/sample/show/2)から、**Live2Dプラグイン**をダウンロードする。(※)
3. [こちら](http://sites.cybernoids.jp/cubism-sdk2/webgl2-1)から、**Live2D SDK WebGL**をダウンロードする。(※)
4. [こちら](http://tyrano.jp/book/live2d)から、**ティラノスクリプト公式Live2Dモデル**をダウンロードする。

※ダウンロードには利用規約への同意が必要です。
　また、アンケートへの回答を求められる場合があります。

すべてをダウンロードすると、次のZipファイル群が揃うはずです。
(ファイル名の「v213」や「v457」などの部分は最新のバージョンが何かで変わります。)
手持ちのZip解凍ソフトウェアですべて解凍してしまいましょう。

　　![01.png](https://qiita-image-store.s3.amazonaws.com/0/187671/f875785e-6a4a-351f-84bf-0a457092963a.png)
　　
　　 :arrow_down: 解凍！:arrow_down:

　　![02.png](https://qiita-image-store.s3.amazonaws.com/0/187671/58db2955-a112-158c-34c2-b864aa7aa346.png)


このとき、Zipファイルを解凍すると「**__MACOSX**」というフォルダや
「**.DS_Store**」というファイルが出てくることがあります。

　　![03.png](https://qiita-image-store.s3.amazonaws.com/0/187671/036a8729-e07a-bab7-9fd7-761ba80b6865.png)

これはMacで圧縮されたZipファイルをWindowsで解凍した場合に出てくるもので、
とくに必要のないファイルです。したがって、**すべて削除してよい**です。
ファイル名で検索してから一括削除するとスムーズでしょう。

##1-3. Live2D SDK の移動

「Live2D_SDK_WebGL_2.1.00_1_jp/lib/**live2d.min.js**」ファイルを、
「**tyrano_live2dplugin_v213**/data/others/live2d/lib」フォルダにコピーします。

　　![04.png](https://qiita-image-store.s3.amazonaws.com/0/187671/44628796-0a7a-f6ca-dcba-c88efa8b86f0.png)

##1-4. Live2D プラグインの移動

実は、この段階で「tyrano_live2dplugin_v213/index.html」を起動すれば、
すでにLive2Dがティラノスクリプトで動いていることを確認できます。

しかしバージョンが問題で、Live2Dプラグインが含まれているティラノスクリプトの
パッケージ「tyrano_live2dplugin_v213」のバージョンは4.10です。**古い**です。
したがって、最新のティラノスクリプトへの移行を行います。

「tyrano_live2dplugin_v213/**scenario**」と「tyrano_live2dplugin_v213/**others**」の
両フォルダを、「**tyranoscript_v457**/data」フォルダにコピー（上書き）します。

　　![05.png](https://qiita-image-store.s3.amazonaws.com/0/187671/edc62dc8-c735-ba2d-4ee3-19f9779f22ea.png)

**これで、最新のティラノスクリプトでLive2Dを扱う準備ができました。**
**さらに、独自モデルを追加して動かしていきます。**

#2. 独自モデルを扱う

##2-1. 準備するもの

この章では次のソフトウェアが必要です。

- ティラノスクリプトのプロジェクトを起動できるツール（ティラノライダー等）
- 適当なテキストエディタ
 
##2-2. プロジェクトにモデルを追加する

デフォルトでは「**ハル**」「**エプシロン**」という2名のサンプルモデルが組み込まれています。
ここに自分のモデルを追加してみましょう。
さしあたって、ティラノスクリプト公式Live2Dモデル「**あかね**」を組み込んでみます。

「akane_v1/**runtime**」フォルダを「tyranoscript_v457/data/others/live2d/**assets**」フォルダにコピーし、
さらに「runtime」フォルダの名前を「**akane**」に変更しておきます。

　　![06.png](https://qiita-image-store.s3.amazonaws.com/0/187671/b9bda624-94dc-d282-cae7-12f0f887ab85.png)

さらに「tyranoscript_v457/data/others/live2d/**Live2dmodel.js**」ファイルをエディタで開き、
最後の行に次の記述を加えます。

```js:Live2dmodel.jsの最後の行に追加すべき記述
// Live2Dモデル（akane）
LIVE2D_MODEL['akane'] = {
    "filepath":"data/others/live2d/assets/akane/",
    "modeljson":"akane_v1.model.json"
};
```

2行目の`akane`の部分には、
シナリオファイルで利用するキャラクターのIDを指定します。
半角英数にしておくのが無難でしょう。

3行目の`data/others/live2d/assets/akane/`の部分には、
モデルのデータが入っているフォルダのパスを指定します。

4行目の`akane_v1.model.json`の部分には、
3行目で指定したフォルダ内に存在するLive2DモデルのJSONファイル名を指定します。

最終的に「Live2dmodel.js」ファイル内の記述が次のようになっているか、確認してください。

```js:Live2dmodel.js
// プリロードするモーショングループ
// (尺が長いモーションは事前ロードするのでmodel.jsonのidleグループに入れて下さい)
var PRELOAD_GROUP = "idle";

// Live2Dモデルの配列
var LIVE2D_MODEL = [];

// Live2Dモデル（haru）
LIVE2D_MODEL['haru'] = {
    "filepath":"data/others/live2d/assets/haru/",
    "modeljson":"haru.model.json"
};

// Live2Dモデル（Epsilon2.1）
LIVE2D_MODEL['Epsilon'] = {
    "filepath":"data/others/live2d/assets/Epsilon2.1/",
    "modeljson":"Epsilon2.1.model.json"
};

// Live2Dモデル（akane）
LIVE2D_MODEL['akane'] = {
    "filepath":"data/others/live2d/assets/akane/",
    "modeljson":"akane_v1.model.json"
};
```

##2-3. シナリオ上で表示させてみる

「tyranoscript_v457/data/scenario/**scene1.ks**」をエディタで開き、
先頭の行に次の記述を追加します。

```tcsh:scene1.ks
; 初期化
[cm]
[clearfix]
[bg storage="room.jpg" time="0"]
[showmenubutton]
[position layer="message0" page="fore" left="20"    top="400"    width="920"  height="200"]
[position layer="message0" page="fore" margint="45" marginl="50" marginr="70" marginb="60"]
[layopt   layer="message0" visible="true"]
[ptext    layer="message0" name="chara_name_area" color="white" size="24" x="50" y="410"]
[chara_config ptext="chara_name_area"]

; Live2Dモデルの定義
[live2d_new  name="akane" left="0" top="0" glscale="1.5"]

; Live2Dモデルの表示
[live2d_show name="akane" time="0" top="-100"]

; 停止
[s]
```

**さて、ここまでできたら、ゲームを起動してみましょう。**
ゲームを起動して「はじめから」をタッチすると、次のようなゲーム画面になるはずです。

![07.png](https://qiita-image-store.s3.amazonaws.com/0/187671/54184232-7c95-b001-1c4a-3a2dbbd006f5.png)

● `[live2d_new  name="akane" left="0" top="0" glscale="1.5"]`
　 Live2Dモデルを定義しています。
　 `name`属性には、「Live2Dmodel.js」で定義しておいたIDを指定します。

● `[live2d_show name="akane" time="0" top="-100"]`
　 実際にモデルを表示しています。

###補足
モデルを表示した段階で、モデルには自動で**アイドリングモーション**がついています。
アイドリングモーションというのは、その状態が無限にループ・維持されるモーションのことです。

初期状態のアイドリングモーションがどこで定められているのかというと、
それはモデルのJSONファイル内の記述で決まっています。

```js:akane_v1.model.json
{
	/*...省略...*/
	"motions":{
		"idle":[
			{"file":"motions/akn_idle_01.mtn"}
		],
	/*...省略...*/
```

`"idle": [ ... ]`という記述がありますね。これはJavaScriptの配列を定義しています。
この"idle"配列の先頭に定義されたモーションファイルが、
初期状態のアイドリングモーションになるわけです。

##2-4. モーションとエクスプレッションを再生する

さしあたり、モデルは無事に表示することができました。
次に**モーション**（motion, 動き）や**エクスプレッション**（expression, 表情）を再生してみましょう。
「scene1.ks」の先頭を次のように書き換えます。

```tcsh:scene1.ks
; 初期化
[cm]
[clearfix]
[bg storage="room.jpg" time="0"]
[showmenubutton]
[position layer="message0" page="fore" left="20"    top="400"    width="920"  height="200"]
[position layer="message0" page="fore" margint="45" marginl="50" marginr="70" marginb="60"]
[layopt   layer="message0" visible="true"]
[ptext    layer="message0" name="chara_name_area" color="white" size="24" x="50" y="410"]
[chara_config ptext="chara_name_area"]

; Live2Dモデルの定義
[live2d_new  name="akane" left="0" top="0" glscale="1.5"]

; Live2Dモデルの表示
[live2d_show name="akane" time="0" top="-100"]

クリックで一度笑います。[p]

; モーションを再生する
[live2d_motion name="akane" filenm="akn_m_01.mtn"]

[wait time="2000"]
クリックでアイドリングモーションを変更します。[p]

; アイドリングモーションを変更する
[live2d_motion name="akane" filenm="akn_m_04.mtn" idle="ON"]

[wait time="2500"]
クリックで表情を変更します。[p]

; 表情を変更する
[live2d_expression name="akane" filenm="f_08"]

[wait time="2000"]
クリックで消します。[p]

; モデルを消す
[live2d_hide name="akane" time="1000"]

; 停止
[s]
```

● `[live2d_motion name="akane" filenm="akn_m_01.mtn"]`
　 モーションの再生を行っています。
　 `filenm`属性には、再生するモーションのファイル名を**拡張子付き**で指定します。

● `[live2d_motion name="akane" filenm="akn_m_04.mtn" idle="ON"]`
　 アイドリングモーションの再生を行っています。
　 `idle`属性に`ON`を指定する必要があります。

● `[live2d_expression name="akane" filenm="f_08"]`
　 エクスプレッションの再生を行っています。
　 `filenm`属性には、再生するエクスプレッションのファイル名を**拡張子無し**で指定します。

● `[live2d_hide name="akane" time="1000"]`
　 モデルを消しています。

##2-5. その他

その他のタグやガイドラインについては、[公式サイト](http://tyrano.jp/sample/show/2)を確認するとよいでしょう。
また、非公式ですが[こちら](http://blog-imgs-114.fc2.com/t/e/m/tempura9357/live2d_tags.html)にLive2D関連のタグリファレンスを用意しました。

##2-6. おまけマクロ

次のようなマクロを作ると、モデルの操作が楽になると思われます。
JavaScriptに詳しい方は、Switch文ではなく連想配列を用いてデータを取り出す形に書き換えると
よりスマートな記述になると思われます。

```tcsh:scene1.ks
; 初期化
[cm]
[clearfix]
[bg storage="room.jpg" time="0"]
[showmenubutton]
[position layer="message0" page="fore" left="20"    top="400"    width="920"  height="200"]
[position layer="message0" page="fore" margint="45" marginl="50" marginr="70" marginb="60"]
[layopt   layer="message0" visible="true"]
[ptext    layer="message0" name="chara_name_area" color="white" size="24" x="50" y="410"]
[chara_config ptext="chara_name_area"]

; Live2Dモデルの定義
[live2d_new  name="akane" left="0" top="0" glscale="1.5"]

; Live2Dモデルの表示
[live2d_show name="akane" time="0" top="-100"]

; マクロの定義
[macro name="akane_motion"]
    [iscript]
        tf.m = tf.e = true;
        switch (mp.m) {
        case "通常"    : mp.m = "akn_idle_01.mtn"; break;
        case "笑う"    : mp.m = "akn_m_01.mtn"; break;
        case "怒る"    : mp.m = "akn_m_02.mtn"; break;
        case "悲しむ"  : mp.m = "akn_m_03.mtn"; break;
        case "驚く"    : mp.m = "akn_m_04.mtn"; break;
        case "首を振る": mp.m = "akn_m_05.mtn"; break;
        case "頷く"    : mp.m = "akn_m_06.mtn"; break;
        default        : tf.m = false;
        };
        switch (mp.e) {
        case "通常"  : mp.e = "f_01"; break;
        case "無表情": mp.e = "f_02"; break;
        case "怒る"  : mp.e = "f_03"; break;
        case "悲しむ": mp.e = "f_04"; break;
        case "笑う"  : mp.e = "f_05"; break;
        case "驚く"  : mp.e = "f_06"; break;
        case "照れる": mp.e = "f_07"; break;
        case "呆れる": mp.e = "f_08"; break;
        default        : tf.e = false;
        };
    [endscript]
    [live2d_expression cond="tf.e===true" name="akane" filenm="%e"]
    [live2d_motion     cond="tf.m===true" name="akane" filenm="%m" idle="%idle"]
[endmacro]

; マクロを利用してモーション再生
[akane_motion m="驚く"     e="照れる" idle="ON"][l]
[akane_motion m="通常"                idle="ON"]
[akane_motion m="首を振る" e="呆れる"          ][l]
[akane_motion m="頷く"     e="通常"            ][l]
[akane_motion m="笑う"     e="笑う"            ][l]

; 停止
[s]
```