VCIで設定を保存できないものだろうか？

#はじめに
こちらの記事は[VCI Advent Calendar 2020](https://qiita.com/advent-calendar/2020/vci)の第１３日目の記事です。

#VCIで困ること
VCIを作ったり、使用していて思うことはいろいろありますが今回の問題はこれ。

◆部屋を立ち上げた時に、VCIの設定を落ちる前の状態に戻したい

ちょっと意味が分かりませんね。

VCIは、Vキャス内に出した後いろいろと設定を変更できます。
例えばにゃふ屋のラジカセなんかだとボリュームや効果音の設定を変更することができます。
![2020072820490537.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545584/de8f2be3-5ff8-7640-947f-f6f738cdb92a.jpeg)
設定変更をして、部屋を出てから戻ってくると・・・。
VCIは同じ場所に居るのに、設定が初期化されます。

でも、ラジカセで毎回ボリュームを設定しなおすのは面倒ですよね。

なんとか設定値を保存して、部屋に戻った時も設定が残る方法を考えてみましょう。

※現在のにゃふ屋のラジカセは設定が保存されるようになりました。今回のこちらの記事の方法を使用しています


#なんの値を保存したいか？
例えば（保存したいVCIの設定値）
・ラジカセ：ボリュームの設定値、効果音のON/OFFなど
・コメビュ：画面の色、ネームプレートの位置など

毎回同じ設定にるすのは面倒です、設定を保存させてください。

#VCIで設定した値を保存したい
いろいろ試してみましたが、変数は初期化をしなくてもクリアされてしまいますし、最悪nilなどが残ってエラーになります。

普通のソフトなら、ファイルに書き出しと読み込みで対応しますが、luaには実装されていません。
Vキャスの偉い方（誰かな？）にお聞きしたら、セキュリティの問題が有るから難しいだそうです。ごもっとも。

なんとか保存する方法を試してみましたが、設定値を保存することはできませんでした。

分からないことはググレ！
3代前のご先祖様の言葉です。（嘘）

見つかりませんね。(´・ω・｀)
VCI関係はまだまだネット上に記事が少ないため見つかりませんでした。

次は、誰かに聞きましょう。（｀・ω・´）

「それなら、オブジェクトの位置でデータを保存することができますよ。」

(；ﾟДﾟ)

なるほど、そういうことでしたか。
VCIのすごい方達がこの方法を使っているとのことでした。

#実際にどうやるか、考えてみた
実験のためシンプルなデータで考えてみましょう。

適当にUnityでキューブを使ったとして考えます。
このキューブのX座標だけを使います。

キューブが0m地点にあれば数値0を返して、1m地点にあれば数値1を返せば1ビットのデータ（スイッチのONとOFF）を
保存するメモリの代わりになりそうです。
（まずは考え方だけで、実際はいろいろあるので後回し・・・）

数値がクリアされてもオブジェクトの位置は部屋に保存されていることを利用するわけです。

1bitが表現できればあとはどうにでもなる！ 
よわよわプログラマの私でもなんとなく分かります。
1bit表現を使う時は16進数で表現した方が分かりやすいので、ちょこちょこ16進数も入ってきまけど。

さて、1bitが保存できれば、VCIの何かのパラメータのON/OFFを保存できますね。
すごい進歩。👍

でも1bitの状態と言えば、ON/OFF、色を設定しようとするとONが白、OFFが黒みたいに2色しか表現できません。
いきなり65536色切り替えとか言われても難しいので、考えるときは1,2,たくさんで考えてプログラムを作りましょう。

#もっと大きなデータを保存したい
さすがに0/1が保存できたからと言って、解決できる項目は少ないですね。
もう少し大きな数字の保存を考えます。

プログラムなので何かと出てくる256（0-255）、16進数にするとFFになります。
0/1の情報を8個を使用して保存できる値です。

そうじゃない、1個のキューブでも大丈夫！

0-1mのX座標で0/1を表現できるのですから0-255mのX座標を使用すれば可能ですね。

#もっともっと大きなデータを保存したい
理論上は使用する座標を0から1万mとかにすればもっと数を増やせるわけです。
Unityで表現できる距離の限界値は知らないので、ほどほどにしておいてください。

距離をベースの限界値が見えてきたら、キューブを複数用意すれば解決します。

注意：それでもSubItemの数には制限があるようなので無制限というわけではない

数字にすると0-999あればなんとなくいろいろな事ができるようになりますが、文字データなんかは無理ですね。
漢字である4byte文字はFFFF(16進数)=65535(10進数)となりますから漢字1文字も表示できないですよ。
それなら、0-65535mまで使用するキューブを100個用意すれば100文字の漢字入り文書を保存できるのですが。

100文字ってTwitterで使う文字数(140文字)よりも短いですし、SubItemも増えるので現実的では無さそうです。

#もっとスマートに実用的な範囲の値を考える
0-999でもいいのですが、16進数にすると3E7(Hex)とう中途半端（プログラマーにとって）な数字です。
プログラマーに気持ちのいい数字256(0-255,16進数でFF)を使って考えていきます。
これで8個のON/OFF状態を保存できます。

まだまだあるぞ、Unityさんは3D座標系ですから、X/Y/Zの3軸分の座標を持っています。
これを使用すれば1個のキューブ扱える数値が増えます。

X座標で255、Y座標で255、Z座標で255とすればFFFFFF(16進数)=16777215(10進数)が保存できます。

これで1個のオブジェクトで漢字1.5文字分のデータが保存できるようになります、少ない・・・
それでもちょっとしたデータを保存するには十分な値でしょう。

こちらの3次元を使用したReadData、SaveDataのLuaソースコードを公開します。

```Lua:SaveReadData.lua
local DataName = "Cube" --データを保存するSubItemの名前
local Data = vci.assets.GetSubItem(DataName)
local HozonData ={} --保存データの書き込み、読み込み用

function ReadData() -- データの読み込み用
    local pos=Data.GetPosition()
    HozonData[1] = math.floor(pos.x + 0.5) -- X座標を四捨五入
    HozonData[2] = math.floor(pos.y + 0.5) -- Y座標を四捨五入
    HozonData[3] = math.floor(pos.z + 0.5) -- Z座標を四捨五入
end

function SaveData(x,y,z) -- データの書き込み用
    local pos=Vector3.__new(x,y,z)
    Data.SetPosition(pos)
end

ReadData()
print("ReadData："..HozonData[1]..","..HozonData[2]..","..HozonData[3])

SaveData(255,255,255)
print("SaveData："..HozonData[1]..","..HozonData[2]..","..HozonData[3])
```
このサンプルを部屋に出すと、デバッグウィンドウにReadDataでVCIを出した時のDataObject座標が出ます。
![2020121221213663.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545584/bf015bb8-d841-0eef-0247-a0ad5b3a61c6.jpeg)

部屋から出て戻ると255,255,255が表示されます。
![2020121221230225.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545584/44fa134a-cbe3-a9f7-28f7-959050ef0534.jpeg)

ReadDataのルーチンで何か計算していますが、これは位置の誤差を補正するために1m未満を四捨五入しています。

設定した座標と読み込んだ座標は微妙にずれますからご注意ください。

■もう少しだけ
サンプルではキューブを使用していましたが、SubItemであれば何でもいいのでEmptyObjectがおすすめです。
画面上に表示もされないし、握ったり移動する必要も有りませんからね。
使用するSubItemの重力設定とかはこんな感じで。![Cube.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545584/9a5363d3-3e64-c9e8-0a22-444619479762.jpeg)

実際に使う時は、Unity側で設定するSubItemのY座標を-500mに設定して、読み込んだY座標が-100以下なら
初期化ルーチンを実行する、って使い方をしています。

■おまけ
座標は負の値も使えますのでいろいろやってみてください。

誰かに「データはどこに保存されているんですか？」って聞かれたら。
「あのあたり」、っと答えてあげましょう。
![2020121221363630.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545584/f196ad93-1ef2-0452-42ba-c20947004503.jpeg)
見やすいようにCubeでテストしている時の画像です。


[TSO にゃふ屋](https://seed.online/users/106600#products)

それでは、まったね～。:blush: