ティラノビルダー作品をアツマールに投稿する。【アツマールAPI】【Live2D】

ティラノビルダーでアツマールにテスト投稿出来たのでメモ残します。
https://game.nicovideo.jp/atsumaru/games/gm7877

作成者＆対象者：Javaとティラノスクリプト素人
アドバイスくださったアツマールキャンプの方々に感謝致します。

●●●アツマールAPIドキュメント●●●
https://atsumaru.github.io/api-references/

■アツマールで外部URLジャンプする。■■■■■
APIとのやり取りは基本iscriptを使用します。
![urlAPIjump.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/85b42199-49f6-062c-fcdc-ffd401809d6c.gif)

```
window.RPGAtsumaru.popups.openLink("https://game.nicovideo.jp/atsumaru/search/tag/一週間でゲームを作ろうの会");

```
ダブルクォーテーションの中を入れ換えるといけます。
ただし実行中にAPI呼び出すとエラー吐くので注意（完成した後とかに導入した方がいいかもしれません）

■アツマールのスコアボード登録する。■■■■■
iScriptを使います。

![exports4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/f95c6bb0-dfef-d3c3-0417-3e5538465036.jpeg)

scoreboard01に999点を格納する（実際は変数を入れてください）。

```
window.RPGAtsumaru.experimental.scoreboards.setRecord(1,999);
```

書き込み後に、更新するのに少し時間が必要なのでウェイトを入れます。

scoreboard01を表示する。

```
window.RPGAtsumaru.experimental.scoreboards.display(1);
```

そのままゲーム形式をブラウザゲームにして出力したファイルをZip圧縮して投稿したいところですが

![export.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/c31e5bd3-ca3b-178c-79b1-4cc55eabce38.png)



![exports3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/8f8e8540-3543-901a-f37a-e1498fa0075a.jpeg)
そのままアツマールにブラウザー形式でアップロードすると許可されないファイル形式が発見されてしまい投稿できないので、問題のファイルを削除します。

注意：Exportに出力されて出来たファイルから探して削除すると更新するたびに、毎回エラーが出るので、exportではなくmyprojectフォルダーの中のプロジェクトから探して削除します。



簡単なのは、左の白のティラノアイコンを押すとmyprojectフォルダーが開きます。
![folders.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/e0fd626b-b8b8-105c-83d7-7de95de36530.jpeg)

myproject>作ったプロジェクト名>tyrano>libs>texillateの中の.gitattributesを削除。
![exports.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/85a3b234-b7db-e8b2-1a75-c3ea26c928cc.jpeg)

![exports6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/c2430aa5-e59f-e5fb-3a6d-40340e7f2d27.jpeg)
無事にアツマールにアップロード出来ました。

■アツマールに保存する■■■■■
ティラノビルダーの保存は標準にセーブすると67ブロック使います。
アツマールは全体のセーブできる容量が決まってるので複数セーブが不要なら１スロットにするといいかもしれません。
![exports7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/42f46ca1-14ad-f0bd-5ea4-18c56f60362d.jpeg)

ただし直接WebStorageというブラウザに保存方法を使うとさらにブロック数を少なくすることが出来ます。

webstorageの保存

```
//save
var data = [];
data.push({name:'atsumaru', age:'15'});
data.push({name:'nikoniko', age:'18'});
localStorage.setItem('json',JSON.stringify(data));

```

webstorageの読込み

```
//load
var data = JSON.parse(localStorage.getItem("json"));
console.log(data);

```

WebStorageの保存はブラウザを変更したり機種が変わるのに対応していないのでアツマールロードAPIを使うと良いようです。教えてくださったキャンプの方に感謝

```
var data = [];
data.push({name:'taro', age:'15'});
data.push({name:'hanako', age:'18'});
window.RPGAtsumaru.storage.setItems([
{ key: "json", value: JSON.stringify(data) }
]);
```


```
window.RPGAtsumaru.storage.getItems().then(function (result) {
var file = result.find(function (obj) { return obj.key === 'json' });
RESULT = JSON.parse(file.value);
});
```

[wait time=2000]

```
console.log(RESULT);
```

■プレイするユーザーidとユーザー名を取得する■■■■■
![exports5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/7b873761-76bd-b594-2a0c-791025d020b1.jpeg)

ひとまず変数に格納します

```
window.RPGAtsumaru.experimental.user.getSelfInformation().then(function (result) {
tf.RE_bk=result
});
```

非同期なので、しばらく時間が経つと変数に格納されてます。（中身を使うなら２～３秒ウエイトをかけたほうが良いです。）
中身は↓で取得出来ます。

tf.RE_bk.id;
tf.RE_bk.name;


ユーザーidは数字なので表示させるためにString()で文字列に変更します。

■アツマールはAPIを使う場合アクセス制限がある。■■■■■
（API呼び出し回数制限は、プレイヤー毎に5秒に1回程度ぐらいをめどに使用）
一度に呼び出すのは1分に12回ぐらいと思われる。1分立つと呼び出す回数リセット。
回数制限あるAPIは以下
・スコアボードAPI (予定)
・グローバルサーバー変数API
・プレイヤー間通信有効化API
・共有セーブAPI
・ユーザー情報取得API
・シグナル送信API

■ゲームをプレイしているユーザーとは別のユーザーの情報を取得するには、最初にAPI「プレイヤー間通信の有効化」を宣言する必要があります。

```
RPGAtsumaru.experimental.interplayer.enable()
```

■コメントをシーンで切り替えて流す

タイトルで全部コメントが流れますので、シーンを変更するコメントAPIを使用してシーン毎のコメントを流すことができます。

```
window.RPGAtsumaru.comment.changeScene( "scene01");
//window.RPGAtsumaru.comment.resetAndChangeScene("scene01");
```

■シグナルの送受信■■■■■
・シグナルを受信する。
![inputus.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/39e8f52e-b8b0-e862-8a44-18e1e8d1d8da.jpeg)


・シグナルを送信する。
テキスト入力を使用してメッセージを送る方法です。
![sendsignal.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/e5d1eaa8-4d5d-b7c3-0784-2fd57478da4f.jpeg)
注意するところ
・分岐ボタンを使わずに画像ボタンを使う
・入力コミットが必要

```

window.RPGAtsumaru.experimental.signal.sendSignalToGlobal(f.inputMessage);
```





■■■　雑メモ　■■■■■

■ティラノビルダーでiscriptやティラノスクリプト使う場合
スクリプトを書く場合は、エラーを吐いたときに番号言われても、何が悪いのか検討付きにくいので、一度ティラノスクリプトを設定してＡＴＯＭ等のエディターでシナリオを開けれるようにしておくと、エラー箇所が一目瞭然になります。マルチモニタが便利


■変数の計算処理？はアツマール上で画面右下にバラバラに「セーブしました」が走るので見づらい時がある。毎フレームやるとずらっと並ぶので注意
![aaa.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/09ba3097-ba45-8ec1-28f2-8b70f5724976.jpeg)


■標準のボタンの色を変更する
tryrano.cssの中のBlack　のグラデの値を変更する。

■メッセージ内の文字色のデフォルト色を変更する
Config.tjsの文字色を変更する。

■ティラノスクリプト内でiscript（JAVAスクリプト）が使える。
できる限りiscriptで書きたいところですが、表示とかあるとティラノ機能を使う場合、ティラノスクリプトの条件文を使うことになります。
ifをティラノスクリプトで書いて、処理をiscriptを使う[iscript]計算式[endscript]事ができます。

■画像ボタンを動かす
ボタン画像はdata/imageフォルダー以下に格納する。（他の画像素材と格納場所が違うので注意）

```
*select1
[button x="260" name="aaa" y="100" graphic="BB.png" target=*select1 ]
[kanim name="aaa" keyframe="animation0" time="5000" trans time=2000 ]
[s]
```

例imageフォルダーのしたにmybuttonフォルダ作ってbb.pngを格納した場合はgraphic="mybutton/BB.png"と書く


■ステータスをずっと表示したい場合
レイヤー1の表示をTrue　宣言します。

```
[layopt layer=1 visible=true]
[ptext name="level" text=&tf.level size=25 x=640 y=80 color="white" layer=1]
```

値をあとで書き替える場合はoverwrite=trueにしないと追加して表示が二重になります。

```
[ptext name="level" text=&tf.level size=25 x=640 y=80 color="white" layer=1 overwrite=true]
```

レイヤーから名前をつけたptext等を解放する

```
[free layer=1 name="obj_ptext"]
```

■関数（ファンクション)を使う。
よく使う計算式などは関数作ると便利です。

```

f.playerdamage=function playerDamage(damage){
    f.player["HP"] = f.player["HP"] - damage;
    return f.player["HP"];
}
```

変数に入れて使います、プレイヤーに25ダメージを与える場合は

```
f.playerdamage(25);
```

関数を呼び出します。



■マクロを使う
よく使うのはマクロ化した方が良いです。最初のシナリオでマクロを組んどきます。
（途中からシナリオを再生する場合は注意が必要です）
![Sprite-0002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/2fff96a0-dbdb-ccd3-1641-8dd35a9c35d0.jpeg)

```
[macro name="disp"]
・・・・・
[endmacro]
```
ステータスの値を変更して表示を書き替えるのは、よく使うので例えばDispという名前をつけてマクロを作っているとどこからでも[disp]で呼び出せるようにします。

■連想配列を使う
iscript内では、JavaScriptが使えるので連想配列も使えます。

```
[iscript]
f.player = {
  "MHP":20,
  "HP":20,
  "ATK":(f.atk+f.sword),
  "DEF":3
};
[endscript]

```
■連想配列でソート

```

var result=[];
var item=[{name:"テツオ",age:11},{name:"サクラ",age:18},{name:"トメ",age:54}];
item.push({name:"キク",age:24});
item.push({name:"アキラ",age:38});

for(var i=0;i<item.length;i++){
 result[i] =item[i].name+item[i].age;
}
alert(result);

//名前でソート
item.sort(function(a,b){
 if(a.name>b.name){
   return 1;
 }else{
   return -1;
 } }
)
//表示
for(var i=0;i<5;i++){
 result[i] =item[i].name+item[i].age;
}
alert(result);

```



■アツマールはブラウザゲームなのでBGMやSEはoggに要変換、動画はWebm拡張子ですが、Firefoxやサファリに対応するようにmp4やaac形式(m4a)を同じフォルダーに入れる必要があるようです。

Webmに変換するアプリはアップロード変換が多いのですが、ダウンロードして変換できるXMediarecordというフリーツール使っています。ファイルを追加後に＋listに加えてEncordを押すとエンコードはじまりWEBMが簡単に作成出来ます。

■iscriptでティラノスクリプトを使えるっぽい

```
if (tf.info == undefined) {
console.log("ログインチェック失敗。ログインしてください：undefined");
}else{
tf.logincheck=true;
console.log("ログイン成功です")
TG.kag.ftag.startTag("jump",{target:"*hoge"});
}
```

■Switch文が使える

```
switch (tf.buystate){
case "purchase_success":
console.log("---success");
tyrano.plugin.kag.ftag.startTag("jump", {target:"*success"});
break;

case "purchase_canceled":
console.log("---canceled");
tyrano.plugin.kag.ftag.startTag("jump", {target:"*canceled"});
break;

default:
break;
}
```



■リアルタイム風も出来る。
ラベルを作ってそこへジャンプをすれば、その間がリアルタイム風な処理になる。
十字カーソルで移動して　Ｘ座標が５０切ったら終了ラベルに飛ぶ。

何故かptexの座標を変えてoverwriteしても位置が変更しなかったので一度消して書き替えている。

```
@layopt layer=1 visible=true

[ptext name="obj_ptext" text=&tf.cnt size=30 x=&f.xxx y=&f.yyy color="white" layer=1 overwrite=true]
*test01
[iscript]
addEventListener("keydown", keydownfunc);
addEventListener("keyup", keyupfunc);

function keydownfunc( event ) {
var key_code = event.keyCode;
	if( key_code === 37 ) {f.xx =-1;}
	if( key_code === 38 ) {f.yy = -1;}
	if( key_code === 39 ) {f.xx = 1;}
	if( key_code === 40 ) {f.yy = 1;}
}
 
function keyupfunc( event ) {
var key_code = event.keyCode;
	if( key_code === 37 ) {f.xx =0;}
	if( key_code === 38 ) {f.yy = 0;}
	if( key_code === 39 ) {f.xx =0;}
	if( key_code === 40 ) {f.yy = 0;}
}

f.xxx=f.xxx+f.xx;
f.yyy=f.yyy+f.yy;

tf.cnt="x:"+f.xxx+" y:"+(f.yyy);
[endscript]
[free layer=1 name="obj_ptext"]
[ptext name="obj_ptext" text=&tf.cnt size=30 x=&f.xxx y=&f.yyy color="white" layer=1 overwrite=true]
[if exp = "f.xxx < 50"]
やったね成功だ！！
[jump target=*test02]

[endif]

@jump target=*test01

*test02
```


■キーアニメーション
Time=で設定した時間でｐ＝○％→20％→60％→100％に遷移する。
wait=falseですぐに開始。（透明から表示して移動、透明に戻る）

```
[layopt layer=0 visible =true]

[keyframe name="animation0"]

[frame p=0% x="-300"  y="-200" opacity=0]
[frame p=20% x="300" y="-200" opacity=100]

[frame p=60% x="300"  opacity=100]
[frame p=100% x="0" opacity=0]
[endkeyframe]

[chara_new name="image" storage="chara/1/cha01.png"   ]
[chara_show name="image" wait=false ]

[kanim layer=0 keyframe="animation0" time="5000" trans time=2000 ]

```

↓名前を付けた場合、レイアーに限らずアニメーション出来る（同じレイヤーの画像を同時に別方向へ動かしている）

```

[layopt layer=0 visible =true]

[keyframe name="animation0"]
[frame p=0% x="-300"  y="-200" opacity=0]
[frame p=20% x="300" y="-200" opacity=100]
[endkeyframe]

[keyframe name="animation1"]
[frame p=0% x="300"  y="200" opacity=0]
[frame p=20% x="-300" y="200" opacity=100]
[endkeyframe]

[chara_new name="miku" storage="chara/1/cha01.png"   ]
[chara_new name="aki" storage="chara/1/cha01.png"   ]

[chara_show name="miku" wait=false ]
[chara_show name="aki" wait=false ]

[kanim name="miku" keyframe="animation0" time="5000" trans time=2000 ]
[kanim name="aki" keyframe="animation1" time="5000" trans time=2000 ]


```

ティラノビルダーでアラートを出す。

```
[eval exp="f.suki='好きか？'"]

*Question
[glink enterse=09_button_1.ogg leavese=09_button_2.ogg clickse=09_button_3.ogg x="200" y="300" text="好き" target="*suki" color="pink"]
[glink enterse=09_button_1.ogg leavese=09_button_2.ogg clickse=09_button_3.ogg x="400" y="300" text="嫌い" target="*kirai" color="pink"]
[s]

*suki
[eval exp="f.suki='好き'"]
[dialog type=confirm text="好きを選んでしまったが本当にそれでいいのか？" target="end"]
[jump target *next]
[s]

*kirai
[eval exp="f.suki='嫌い'"]
[dialog type=confirm text="嫌いを選んでしまったが本当にそれでいいのか？" target="end"]
[jump target *next]
[s]

*end
あなたの事が[emb exp="f.suki"]だ
```




■■■　Live2Dモデルをティラノビルダーにインポートする。■■■

ティラノビルダー側でリップシンクさせる場合は
modelerのモデリング＞パラメータ＞まばたき・リップシンク設定で口の開閉にチェック入れます。
![ripsync.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/feedbddf-805e-24c9-f95a-1750f6121881.gif)

![export.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/d8d8a8ea-a6cb-aff7-7128-c1cfd09e6ffe.gif)
不要そうな物理をはずしてSDK3.3で吐き出しました。

animatorのモーション書き出しで
リップシンクとまばたきを焼き込むのチェックをはずして、リップシンクを｢書き出さない」にしました。


・公式Live2Dの組込記事
https://docs.live2d.com/cubism-editor-manual/export-moc3-motion3-files/?locale=ja

・ティラノビルダーの組込記事
https://b.tyrano.jp/tech/page/live2d_v3




Live2D Cubism3からティラノビルダー184ｂに持っていく際、Moc3.jsonとMotionを吐き出しても非表示のままで表示しないです。（公式のLive2Dのモデルはインポート出来ますが・・・画像のように何も表示されません。）
![toumei.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/4b3199cb-c2d9-2e8c-698c-7bd856a6006e.gif)

公式のテンプレートLive2Dモデルはそのままティラノビルダーに読み込めるのですが、自前のLive2Dモデルとモーションを吐き出しても、ティラノビルダー読み込むと非表示になります。
原因が、検索しても出てきません。
Json見てみるとモーションの記述が無いのが原因ぽいので"DisplayInfo": "mark_free_t02.cdi3.json",の後に書き足します

![motiontuika.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/0109b56d-98a2-adba-0d7b-59ae62be095b.gif)

モーションが1つの場合は、Live2d3．3ViewerにMoc3とMotionをドラッグしてCTRL+Sで上書きすると、Json内のモーション名が””の間に書かれていないので"idle"のように記述するとティラノビルダー上で表示するようになります。



![in.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/9acce170-92d2-47a6-c304-6f0492ea211f.gif)
複数の場合Viewerで複数のモーションを入れて上書きしてJson開くとモーションの構造がちょっと変なので手動で書き変えた方が早いです。
以下のように変更します。

```

　　　　"DisplayInfo": "mark_free_t02.cdi3.json",
        "Motions": {
            "idle": [
                {
                    "File": "Motions/idle.motion3.json"
                }
            ],
            "walk": [
                {
                    "File": "Motions/walk.motion3.json"
                }
            ],
            "run": [
                {
                    "File": "Motions/run.motion3.json"
                }
            ]
	},
	"Groups": [
```

Live2D4.xをティラノビルダーで読み込む手順youtube動画
[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/NG_V3Nfsoco/0.jpg)](http://www.youtube.com/watch?v=NG_V3Nfsoco)

なんとかティラノビルダーでlive2DCubism3のアニメーションが表示するようになりました。
![mark.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/9a873161-b6ab-ded1-34a2-a8d875152d2b.gif)

リップシンクはチュートリアル通り
![marktryano.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362013/49a09ec6-76d7-d537-c9b2-2d2947c963e9.gif)

ぎりぎりに読み込むと口パクはちょっと（１～２秒）してから口が動きはじめるので少し前に読み込んでおくと良いかも

またティラノビルダーいじって加筆していこうと思います。