モチベーション維持のためにLGTMください。
やったこと
今回は道の動的生成をバージョンアップさせました。
具体的には下記の2点を行いました。
1.障害物を設置することで迷路のような作りにすること
2.レシピを作成し、それを入力として生成するつくりにすること
VケットにもいかずUdonをこねこねしています。
— はんちょ (@sadimensions) April 30, 2020
ダンジョンの動的生成の続きです。
十字路をふさぐ障害物を作って迷路上にしています。
しかもダンジョンのレシピも出力!
レシピを同期すれば、そこから他のプレイヤーとも同期できるはず。#UdonSharp pic.twitter.com/mmahSg2WGo
1.の意図
あらかじめプレハブで道のバリエーションを持っておくことも考えたのですが、逐次生成している都合、道の形状のつじつまが合わせられないケースがあると考え、障害物を設置することで迷路を作る構成としました。
おいおい障害物を取り除くような処理を組むかもしれませんので、このやり方がよいかなと。
2.の意図
現在、道のインスタンス化にVRCInstantiateを使用していますが、この関数は非同期です。同期を考えた場合、すべてのユーザーで同じようにVRCInstantiateを実行する必要があります。
つまり、迷路のレシピを同期させておけば間接的に同期できるはずです。
やりかた
今回はUdonSharpの使い方というよりも、ゲームプログラミングとか設計とかそういう感じですね。
今回の大切なところは、迷路のレシピをどのように作成するかという点です。
道の形状はソースコード中0~6の数字が割り当たった7パターンと、その回転4パターンです。
どの形、どれくらいの回転、座標 この三つの情報がスタックされていれば、
途中から入ってきたプレイヤーも迷路を再現できるようになります。
(今回は同期についての実装はありません)
なおレシピのフォーマットは次の通りです。
nrx,y,z
n:道の形状
r:90度の回転回数
x,y,z(リスポーン地点を0,0,0とした際のマス目)
//どのフロアを作成するか選定する
//入力はフロアを作成する座標 と 北0, 東1, 南2, 西3どちらに進んでいるか0~3
//出力はフロアのレシピ
//フロアレシピ定義
//フロア形状n(0~6) y軸回転r(0~3) 座標
//n定義 r定義
//0 :┼ 0 : 0度
//1 :│ 1 : 90
//2 :├ 2 : 180
//3 :┌ 3 : 270
//4 :・(行止り)
//5 :↑上り階段
//6 :↓下り階段
private string FM_choiceGenerateFloor(Vector3 createPos, int orient)
{
int[] n_kouho;
if ((int)createPos.y == 0)
{
//高さが0の時はフルセット
n_kouho = new int[] { 0, 1, 2, 3, 4, 5, 6 };
}else if ((int)createPos.y == (int)FM_FLOOR_HIGHT)
{
//高さが2階のとき
n_kouho = new int[] { 0, 1, 2, 3, 4, 6 };//上りを除く
}
else
{
n_kouho = new int[] { 0, 1, 2, 3, 4, 5};//下りを除く
}
//候補からランダムに選択する
int n = n_kouho[(int)Random.Range(0, n_kouho.Length)];
int[] r_kouho;
//道の形状によって許される回転回数が決まっている。(入り口には障害物を置いてはいけない)
switch (n)
{
//01456は回転しない
case 0:
case 1:
case 4:
case 5:
case 6:
r_kouho = new int[] {0};
break;
case 2:
//2は0,90,180の三択
r_kouho = new int[] {0, 1, 2};
break;
case 3:
//3は0,90の二択
r_kouho = new int[] {0, 1};
break;
default:
r_kouho = new int[] {0};
break;
}
//回転もランダムに選択し、そこに、プレイヤーがどちらの方角から入ってきたかを加味する
int r = (r_kouho[(int)Random.Range(0, r_kouho.Length)] + orient) %4;
//座標そのままだとレシピが長いため、マス単位にする
int x = (int)(createPos.x / (FM_FLOOR_SIZE_HALF * 2));
int z = (int)(createPos.z / (FM_FLOOR_SIZE_HALF * 2));
int y = (int)(createPos.y / FM_FLOOR_HIGHT );
return string.Format("{0}{1}{2},{3},{4}",n.ToString() , r.ToString() ,x,y,z);
}
課題
まだこの方法で同期が実現できるかわかっていません。
近いうちに同期のテストを実施します。
同期テスト結果
World再突入時に再生成されるパターンもあり。
— はんちょ (@sadimensions) May 2, 2020
多分目の前のロボットが何らかの権限を持った状態なのでは?なんて考えています。#UdonSharp pic.twitter.com/oiBKhJ2Q0u
同じワールドにいるならば同期できそうです。
後から入ってきた人もレシピをもとに同期をとるはずが、取れる場合と取れない場合がありました。
原因を探さねば