simplestarの技術ブログ

目的を書いて、思想と試行、結果と考察、そして具体的な手段を記録します。

CubeArtWorld:ギミックの説明

CubeArtWorld とは?

2020年12月頃に公開された3Dサンドボックスオンラインゲームのこと
simplestar-game.itch.io

VRoidHub 連携で自分のアバターで始めることができ、ゲーム内で購入できるワールド編集チケットさえあれば、世界の一区画のキューブを左クリックで破壊、右クリックで配置できる。
有名な他のサンドボックス系ゲームと比べると、配置する際にキューブの形を変えられること、回転を与えられることが大きな違いとして挙げられる。
ほかにもゲーム内で購入できるキャンバス編集権があれば、自分だけのキューブに金属、プラスチック、ライト、空色など様々な絵の具で好きに絵を描いて、日々コピーして数を増やしつつ、これにも形・回転を与えて配置でき、独自の世界表現が可能になっています。

クリエイティブ要素のほかにも、坂道を転がる鉄球や乗って滑るスケートボード、過去の世界へ飛べるタイムゲートなど、動きをつけた絵が撮れる、けど世界に配置し続けられないインスタントなアイテムがいくつか存在しています。
ギミックが登場するまでは、世界はスタティックで、鑑賞するのがメインのキューブアートな世界でした。

f:id:simplestar_tech:20220129103057p:plain

ギミックキューブへの切り替え方

キャンバス所有者のみ Edit ボタンを押して、この Type のドロップダウンから Gimmick を選んで保存できます。

f:id:simplestar_tech:20220129103741p:plain
キャンバス編集権の方のみこのUIをいじれる

ギミックはこれまでのスタティックな世界をダイナミックに変えるアクセント
これを理解できる最小限の解説を以下に続けます

ギミックの再生・発動

f:id:simplestar_tech:20220129104751p:plain
再生ボタン

ギミックを再生するためには、キャンバスパネルを開いてから Play ボタンを押します。
そのほかにも Trigger アクションの条件を満たすか、他のギミックキューブから SendKeys を受け取る、Combine で結合される範囲に配置されていることで発動します。

ギミックの作成

ギミックはアクションと呼ばれる行要素のタイプを選んで、サブタイプ・パラメータを決め、これをリスト形式でつなぎながら、全体の動きをつけていきます。
タイプが多いので、まずは例を示してみます。

城門が開くギミック

何かスイッチのようなキューブを踏むと、「カチッ」と音が鳴り「ゴゴゴゴゴゴゴ」と音を鳴らして遠くの城門がゆっくりと開くギミック
しばらくすると勢いよく門が落下してピタリと門が閉じます

使用されているギミックキューブは足もとのスイッチと、門の二つ、まずは足もとのスイッチ動作をしているギミックアクションを以下に示します。

f:id:simplestar_tech:20220129105941p:plain
スイッチ側

上から順番にタイプと動作を説明しましょう

Trigger

近づいたり、上に乗ったり、下を潜ったりしたときにギミックを発動させるトリガーの役割を果たします。Sub に GetOn が指定されているので、これは上に乗ったら発動するギミックをこの一行で定義しています。Trigger は一番最初の行にしか設置できない制約があります。

Sleep

指定したフレームの数または秒数を待機します。この行は値に 0 を指定しているので待たずに次のアクションへ進みます

Sound

音を鳴らすアクションです。Sub の Switch が「カチッ」の音を意味します。Value は音の高低を指定する値です

ここまでで、上に乗ると「カチッ」と音が鳴る というギミックの完成です。

SendKeys

周囲に Key を送るアクションです。Sub には形状を指定でき、Plane は高さ 1, 幅と奥行きが今回は 8 という形ですね。キューブの配置における回転の影響を受けるので、このスイッチは門扉のもう一つのギミックキューブに届くように SendKeys をしています。

ここまでのアクションで、「カチッ」と音を鳴らした後、遠くのもう一つのギミックを発動させるという意味になります。

Sleep

ここで入れているのは、カチカチ鳴らしすぎないように少し待ちを作っています。

Return

元のギミックキューブに戻る動作となります。Return 後は最初の Trigger で待ち受けている状態になるので、上に乗ればまた「カチッ」と音が鳴ります。

スイッチで起動する側の門のギミックをここで確かめましょう

f:id:simplestar_tech:20220129112105p:plain
門側のギミック
Combine

結合を意味していて、柵の形で一つのオブジェクトになるように PhysicalPlane を Sub に選んでいます。Plane は先ほどの SendKeys と同じ形のイメージで、高さ 1 幅と奥行きが今回は 4 の結合範囲でまとめています。こちらもギミックキューブの回転に依存しているため、うまく回転させて縦方向の板の形状で周囲を結合し、門の形をとります。
Physical と 無印の形状がありますが、形で物理挙動をしたいときに Physical を指定し、物理挙動をあきらめるが、結合した形状の内側にプレイヤーが入りたい場合は無印の形状を利用します。

Sound

音を鳴らすアクションです。Explosion という「ドカーン」という音を 0.5 の速度で再生して、ゆっくりの「ゴゴゴゴゴゴゴ」という音を作っています。

Translate

移動するアクションです。LocalX は今回は回転の兼ね合いで、門を上方向に動かす軸を示しています。-5 は上方向に 5キューブ移動という指定となります。

Sub に Speed を指定すると、直前の移動の速度を変化させることができます。3と大きな数字を指定すると速く動かすことができます。

Sub に Finish を指定すると、直前の Translate の移動が完了するまで待機するアクションとなります。

ここまでのアクションで、門の形で結合して「ゴゴゴゴゴゴゴ」という音をたてながら上へ 5キューブ移動する を実現できるようになりました。

Sleep

上に移動した門が 20秒経過するまで固定されます

Physics

Subに指定した物理制約を与えることができます。SliderY の場合上下方向の軸だけ移動できるエレベータのような動作制約で動くことになります。
このタイプは回転の影響をうけません。

Sleep

門が落下する様子を見せるための待機時間です

Return

もう一度門を開かせられるように、すべてのアクションを取り消して元の状態に戻ります。

ギミックタイプ一覧

アクションを組合わせることで、奥深いギミックが作れるようになると思います。
以下に現在提供されているアクションタイプ一覧を示して説明を終えたいと思います。

タイプ 説明
Trigger 乗る、近づくとギミックが発動する
Sound 音を鳴らす
Material 光ったり、透明になったり、色変化や周囲キューブのマテリアルを指定して見た目を変えます
Logic Keyの値を足したり、引いたり、掛けたりします
Sleep 指定した時間だけ次のアクションの実行を遅らせます
Lock 直前のKeyがここで指定した値と一致しないとReturnします
SkipTo 指定したラベルへアクションをスキップします。条件分岐や繰り返し処理を作れます。
Label ジャンプ先を定義するラベルです
Combine 周囲のキューブをギミックキューブを核にして結合します
Rotate ギミックキューブを中心に回ります。プロペラやスクリューなどの表現に使えるでしょう
Translate ギミックキューブが移動します。すごい勢いで動かすとプレイヤーやボールを打ち出す発射装置になったりします
InstantItem すべてのインスタントアイテムに変化します。過去に行く装置になったり、地雷などが作れるでしょう
Disappear 周囲のキューブを巻き込んで消滅します。突然開く扉や、床が消える落とし穴などになります
Key SendKeys に乗せる情報になります。受け取ったキューブは Key の値を処理できます。Lock に差し込んで錠を鍵で開くイメージです
SendKeys 加工したKeyセットを周囲のギミックキューブへ送信し、ギミックを発動させます
Load ギミックアクションリストは必要なときにロードするのでタイミングがずれることがあります。事前に周囲のギミックキューブのロードを完了させるためのアクションです
Return すべてのアクションを取り消して、元の状態に戻します
Physics 物理挙動をギミックキューブに与えます。制約をつけるとスライダーや回転する歯車、レールに沿って動く、などの動きを作れます
HingeJoint 蝶番のような扉の表現が可能になります。角度をつけなければ回転する車軸としても表現できるでしょう。単体では表現できないので周囲にアンカーを刺す設定をします。
SpringJoint ばねのような弾性のある動きをつけられます。アンカーを刺す向きを指定します。
FixedJoint 複数の結合したギミックをさらに組み合わせて複雑な形状を作るときに、固定ジョイントを活用します

Unity: BehaviorTree 勉強2

アニメーションする Task は Running しか返さないというのはどうか?

止める条件があるのなら、その親に Conditional Evaluator を置き、これが失敗を返したら、子であるアニメーション Task は中断されるため

参考

www.slideshare.net


目的地が設定されているか?
yes→目的地へ向かう
no→次の行動を選択

selector

sequence

  • hasDestination
  • gotoDestination

sequence

  • nextAction

結局アクションを定義してから組み合わせになるのか

ランダムに目的地を決める
プレイヤーを見つけているか?
プレイヤーの方向の目的地を決める
目的地は決まったか?
目的地に向かって歩く
目的地に着いたか?
十分プレイヤーに近づいたか?
プレイヤーの方向を向いているか?
プレイヤーの方向を向く
座り込む
座り続ける
立ち上がる


うーん、一連のながれが sequence で、その一連のながれが通らないときに selector で別の sequence へ流れるかんじ?

最初は
十分プレイヤーに近づいたか?→yes→プレイヤーの方向を向く→十分プレイヤーに近づいたか?→yes→座り込む→十分プレイヤーに近づいたか?→yes→プレイヤーの方向を向いているか?→yes→座り続ける
目的地に着いたか?→yes→
目的地は決まったか?→yes→目的地に向かって歩く
プレイヤーを見つけているか?→yes→プレイヤーの方向の目的地を決める

え、ループできるのか
ループってどうやってツリー表現

考え中

なるほど、継続しつづけるアクション 待機モーションなどを running し続けるで良さそう
これが最終的な安置として

どうやって抜け出すの?

それが前回勉強したなにかの conditional なんちゃら

Selector Evaluator

実行中を返す Action が子タスクの優先度の低いものであったなら、それより高い優先度の Action の評価をもう一度行う

これもそうだけど、もっと self とか low priority とかでもできたような?

Sequence NodeのAbort TypeをNoneからSelfに変更すると、子ノードの running 中の左側を毎回評価して、failure なら runnning を中断できる
つまり、抜け出せる AbortType self で

または、同階層の右側が running でも Abort Type Lower Priority でも

なるほど Abort の目的語が Lower Priority で右がわ、Self が自身の子ノードという意味だったのか

やっと解読できてきた
つまり

Unity: Behavior Designer のノードの勉強

基本的なことはこちら
simplestar-tech.hatenablog.com

ビヘイビアツリーを構成しているノードは三つに分けられる、それぞれ Task, Composite, Decorator である。

・Task はツリーのリーフ要素で、1フレームに許された計算時間で条件判定やアクションを実行し、戻り値として1)Running(まだタスクが残っている), 2)Failure(条件に合わない、または失敗), 3)Success(条件一致、または成功) の三つのいずれかを返す。
・Composite は子ノードの実行を制御するノードで、シーケンスとセレクターの二種類が存在する。
シーケンスは最初の子ノードが実行完了するまで待機し、成功を返した場合に、次の子ノードを実行し、この操作を繰し、最後の子ノードが成功を返したら、シーケンスノードも成功を返す。一度でも子ノードが失敗を返したら、残りの子ノードは無視して失敗を返す。子ノードが実行中を返すようなら、シーケンスも実行中を返す。
セレクターは優先度順に子ノードの選択を行い、選択したノードを実行する。シーケンスと違う点は、どれか一つの子ノードが成功を返した時点で、まだ実行していない子ノードがあっても、成功を返す点である。
セレクターには指定した割合の確率で選択する Probability Selector や、1フレームにすべての子ノードを実行する Parallel がある。
・Decorator ノードは特質系で、子ノードを一つしかとることができない。ノードのタイプによって振る舞いはさまざまで、たとえば n 回子ノードを繰り返し実行してから成功を返したり、子ノードがn秒以上実行中だったら成功失敗に関わらず強制的に失敗を返したりする。

これから Behavior Tree を活用していくので、使い方に慣れるため、各ノードの動きを確認しながら、道具として使えるようになるため、覚えていこうと思います。

## Parallel

子タスクを一斉に並列実行し、いずれかが失敗を返したらすべての子タスクを停止して失敗を返す
実行中の子タスクが残るなら、実行中を返し
すべての子タスクが成功したとき、成功を返す
イメージとしては並列実行の And 条件 if 文って感じですかね

f:id:simplestar_tech:20210703130241p:plain
Parallel

## Parallel Complete

子タスクを一斉に並列実行し、最も早く答えを出した子タスクの答えを返す
全部成功していて、残る実行中のものがあったとしても、最初に成功を返した子タスクを見つけた時点で成功を返す
イメージとしては並列実行の Or 条件 if 文って感じですかね、False を返すのが先だと False が返るところが全然違う

f:id:simplestar_tech:20210703131331p:plain
Parallel Complete

## Parallel Selector

子タスクを一斉に並列実行し、すべて失敗となるまで待つが、いずれかが成功を返した瞬間に子タスクをすべて停止して成功を返す
イメージとしては並列実行の Or 条件 if 文って感じですね
f:id:simplestar_tech:20210703131954p:plain

## Priority Selector

float GetPriority(); を Action Task 側で実装して返す必要がある
この値が大きい順で子タスクを順番に実行して、先に成功を返したタスクが生まれたら成功を返すもの

f:id:simplestar_tech:20210703142958p:plain
Task class

## Random Selector

ランダムに子タスクの順番を決めて Selector として、成功を見つけるまで続け、成功を返す子タスクによって、続く子タスクの実行を停止して、成功を返す
イメージとしては順番実行の Or 条件 if 文って感じで、評価順がランダムというものですね

f:id:simplestar_tech:20210703143258p:plain
Random Selector

## Random Sequence

ランダムに子タスクの順番を決めて Sequence として、すべてが成功するまで続け、失敗を返す子タスクによって、中断して子タスクの実行を停止して、失敗を返す
最後の子タスクが成功したときにやっと成功を返すという
イメージとしては順番実行の And 条件 if 文って感じで、評価順がランダムというものですね

f:id:simplestar_tech:20210703150525p:plain
Random Sequence

## Selector

いずれかが成功したら成功を返し、残りの実行を中断する
イメージとしては順番実行の Or 条件 if 文って感じ

f:id:simplestar_tech:20210703150847p:plain
Selector

## Selector Evaluator

実行中を返す Action が子タスクの優先度の低いものであったなら、それより高い優先度の Action の評価をもう一度行う様子
実行中のタスクより低い子タスクの実行はせず
優先度が高いタスクは常にチェックしたいといったギミックに良いのかも たとえばプレイヤーを視認していること という条件に使って、続くアクションに追いかけるといった running ステータスを返す何かが挟まるなど
イメージとしては順番実行の Or 条件 if 文って感じだが、どういうわけかさっき調べた条件をもう一度しらべいにく
いくつもの Task のうち、最初に成功を返した Task の結果をもって成功を返す

f:id:simplestar_tech:20210703151759p:plain
Selector Evaluator

## Sequence

順次実行して、失敗が返ると即子タスクを停止して失敗を返す
イメージとしては順番実行の And 条件 if 文って感じ

f:id:simplestar_tech:20210703153116p:plain
Sequence

## Utility Selector

float GetUtility の値が大きいものを常に選んで実行する
子タスクすべてを見ていて、Utility 値が実行中に小さくなったなら、他の Utility 値が大きいタスクの実行へと移る
いずれかが成功を返したら、他のタスクを停止して成功を返す でも、いずれの子タスクも Running を返すようにする使い方がメインなのかな
Priority Selector との違いは、それまで最高Utility だったタスクが Running 中でも、他の Utility が高まったら中断するところかな

f:id:simplestar_tech:20210703153501p:plain
GetUtility
f:id:simplestar_tech:20210703154804p:plain
Utility Selector

Unity:非VRからVRモード切替機能とその逆切り替えをするScript記述方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Management;

namespace CubeWalk
{
    /// <summary>
    /// VRモード切替器
    /// </summary>
    public class VRSwitcher : MonoBehaviour
    {
        /// <summary>
        /// 非VR時にのみアクティブになるオブジェクト群
        /// </summary>
        [SerializeField] List<GameObject> keyMouseObjects;
        /// <summary>
        /// VR時にアクティブになるオブジェクト群
        /// </summary>
        [SerializeField] List<GameObject> vrObjects;
        /// <summary>
        /// VR アセット位置調整用
        /// </summary>
        [SerializeField] Transform vrAssets;
        /// <summary>
        /// プレイヤーオブジェクト発見用
        /// </summary>
        [SerializeField] Transform players;

        public void EnableVR()
        {
            StartCoroutine(this.CoEnableVR());
        }

        public void Enable2D()
        {
            XRGeneralSettings.Instance.Manager.StopSubsystems();
            XRGeneralSettings.Instance.Manager.DeinitializeLoader();
            foreach (var item in this.vrObjects)
            {
                item.SetActive(false);
            }
            foreach (var item in this.keyMouseObjects)
            {
                item.SetActive(true);
            }
        }
        
        IEnumerator CoEnableVR()
        {
            yield return XRGeneralSettings.Instance.Manager.InitializeLoader();
            while (!XRGeneralSettings.Instance.Manager.isInitializationComplete)
            {
                yield return null;
            }
            XRGeneralSettings.Instance.Manager.StartSubsystems();

            // VR開始位置をプレイヤー位置に調整
            foreach (Transform vrm in this.players)
            {
                if("Player" == vrm.tag)
                {
                    this.vrAssets.position = vrm.position;
                    break;
                }
            }

            foreach (var item in this.keyMouseObjects)
            {
                item.SetActive(false);
            }
            foreach (var item in this.vrObjects)
            {
                item.SetActive(true);
            }
        }
    }
}

CubeArtWorld:爆発するキューブと四散する仕組み

爆発すると周囲のキューブをごっそり削り取り、削り取られたキューブが四散するというものが可能なのか調べていきます

f:id:simplestar_tech:20210319173631p:plain
ラクガキキングダムのインポートできます

できましたー

CubeArtWorld:過去へさかのぼるタイムトラベル

f:id:simplestar_tech:20210223170337p:plain
過去の世界とは

実はこの半年、ゲーム内のワールドデータのバックアップを毎日取ってきているため、これを時刻指定で参照して拾ってこれさえすれば、過去を再現した世界を見ることができるようになります!!

さっそく作れるのか技術課題を明らかにしてみましょう。

## 過去データ形式

日付ごとにファイルが作られています。
ワールドごとにとびとびなので、日付を決めただけでは、正しい過去の日付を見つけることができない

リストを日々更新することになるが、ファイル一覧をなめるのは無駄が多い
そこで、バックアップ処理で追記していく json を Title Internal に置くことにしてみましょう

また、TitleInternalData の規則に変な奴がいるので、CubeDataLife としてリネームしておくことにします。
関連処理の lambda 実装を追って、移行計画も立ててみましょう

キー名を統一するだけに見えたので、いきなり試行 朝3時に定期実行が来るので、様子を見ます→キー使用コードの差し替え漏れでバックアップが機能しませんでした。
修正したので次の日こそ!

構想では 2020年7月21日が紀元とされていて、そこから暦を一日ずつ刻むことにして
[1, 2, 3, 4, 5, 9, 100, 101, 200, 209]
といった形で配列を刻みます

TimeSpan span = DateTime.UtcNow- new DateTime(2020/7/21) ;
span.Days //差の日数

時刻から日数、日数よりさかのぼって発見する記録日数が見つけられたなら
日数を紀元に足して記録日を求める
DateTime today = new DateTime(2020/7/21).AddDays(span.Days);

var suffix = date.ToString("_yyyy-MM-dd");
で求めたい過去のデータを見つけられる気がする

まずは一度 s3 のファイルリストを取得するところからですね

ファイルリストは取れました。求めていたファイル名にも復元できます。

続いてクライアントからどうやって取り出すのか

## タイムドアアイテム

インスタントアイテムとして、ガフの扉を配置すると、日時を指定できるようになり (2020/7/21 ~ 今日まで)
選ぶと同時に扉が上昇しながら大きくなり 天井で巨大化
周囲のキューブが崩れ、自身と共に扉に向かって浮き上がっていき ゆっくりとホワイトアウトすると

過去世界データを引いて、世界が再構築され、その世界に扉から今度は落下して着地する
以後はもう一度ガフの扉を開くまで、過去世界でアイテムを増やすことも減らすこともできない世界に取り残されて、残らない過去への干渉を続けるだけになる

ガフの扉で最大の今日の日付を選ぶと、元の世界に戻ってくる

というの作るとしたら

## サーバー側の仕事

戻りたい過去の日付をサーバーに送り、過去の世界のデータダウンロード url を発行して返す という仕組みが世界データロードで差しかわれば
キャッシュを残さずに動けるかも

ということで、s3 の一次的なダウンロード url の発行というものを行います

もろもろできましたね
リリースしました

CubeArtWorld:ユーザーショップ機能

長らく作ってる姿をお見せしてきたゲームは、ついに昨年クリスマスにリリースしました!
booth.pm

ひそかにブログを見守ってくれたそこのあなたに、ぜひ買って遊んで、口コミで世に広めてもらいたいです。ご協力お願いします。

今回は、そのゲームタイトル「 Cube Art World 」に入る大型アップデート:ユーザーショップ機能について構想から記していきます。

ユーザーショップデータ

プレイヤーがキャンバスキューブと呼ばれる、所有権を有するキューブにアイテムと価格設定を加えて在庫とともに陳列するというデータをサーバー側にて刻むとすると
さて、このデータをどこに置くか どうやって他プレイヤーがアクセスするかについて考えていきたいと思います

現在のキャンバスキューブのメタデータにショップアイテム配列を追加する というのもありかもしれません。
別に用意して、データを取りに行ってあるかどうか確かめる方法もあるのですが、これは UI について決めていくと、そのハマり具合がわかり、決まりそうです。

ということで、現在のキャンバス UI から見ていきましょう。

f:id:simplestar_tech:20210214135022p:plain
キャンバス閲覧時

こちら、編集することができる者だけ Edit ボタンを押して次の編集UI に移行することができます。

f:id:simplestar_tech:20210214135206p:plain
キャンバス所有者のみが開ける編集画面

既存の UI はそのままに、ここにユーザーアイテムショップ機能をつけるとして、発想としてはショップを開くボタンを置いてみるとします。

メインの Cube Type を Canvas として、これをドロップダウンリストで Shop に切り替えられるとしましょう
この考え方の良いところは、既存の UI 設計を崩さず、新しい UI に切り替えて提供できる点です。

今の状態をそのままに、リストディフォルトを Canvas とします。データに無い場合はこれ
そして、Shop に切り替えたときに、既存の UI はすべて消え、新しいショップ用 UI に切り替わります。

そこにはアイテム選択と価格、在庫数を入れるフォームを用意し、Add ボタンでリストに追加
既存リスト項目の編集、削除が行えることにします。前後移動も可能な左右やじるしボタンも用意

項目はサムネイルとアイテム名 キャンバスの場合はタイトル 簡易説明が付く 価格 GD と、販売予定個数

あと、今後購入履歴を過去 5件ほど記録して、これをプレイヤーが認識できることとします

保存する情報はどこか
メタデータには ドロップダウンの選択項目のみ記録して、配置パスは分けます
キャンバスIDで管理はされますので、キャンバスから参照、編集には困らない

タイプがキャンバスの場合は既存のフロー
ショップの場合は先行してショップ情報を引き出して、これを使って、ショップ用の UI を表示することにします。

ドロップダウンはこの通り

f:id:simplestar_tech:20210214151853p:plain
CubeType選択

UI の行き来を作ってみましょう

販売項目追加において、いったいプレイヤーは何のアイテムを売ることができるのか?
これについて、インベントリ内の運営規定IDのキャンバスと、自身が所有権を持つキャンバスに値を付けて販売できるものとします。

インベントリアイテムリストを絞り込めるかチェックしてみます

リストを選ぶ UI を先に作っていきました

f:id:simplestar_tech:20210214181904p:plain
陳列項目追加 UI

UI の切り替えがうまくいったところで、まずはキャンバスのキューブタイプ情報を既存のメタデータに追加します。
これを保存できるようにして、さらに読み込んでから UI をそのタイプで初期化して表示するように作り替えてみましょう。

続いて、自身の所持金額を左上に表示します
もろもろ初期表示まわりがそろいましたので、続いて、 Add ボタンを押したときに 未設定の陳列アイテム 選びなさい UI が現れるようにします。
ここでSelect を押したとき、インベントリのようで、そうではない所持アイテム一覧のうちフィルターされた ショップ陳列可能なアイテムが並ぶようにしてみます

陳列項目を追加、編集するという UI だけできてきました。

f:id:simplestar_tech:20210216000941p:plain
追加操作を提供 不正があれば理由を示します。

こちらの機能は
simplestar-game.booth.pm

リリースされました!!
経済という概念、プレイヤー同士が金銭でアイテムをやり取りし出すことがはじまります