鏡4枚はやばそうと思ったので常時1枚にする機構を作りました。
通常のぶいちゃの鏡であればInteractによるオンオフは一般的かと思いますが、今回に関しては鏡は「ワールドそのもの」といえる (姿見があって初めて試着 (=店) が機能する) ので「溶けたUI」のほうが自然です。
というわけで、最大1枚にしつつ選択を意識しないための構造を考えることになりました。
単純に考えれば一番近いものを採用するのが良さそうですが、鏡は遠方から見ても意味あるギミックです。
よって視線方向に応じて採用するのも妥当と言えます。
しかし鏡にめっちゃ近いところで横を向いたとしても、それはきっと一瞬横を向いただけで基本的に真正面の鏡を見たいのではないかと思いました。
というわけで「ある範囲内に鏡があれば、それを採用する」「そうでない場合、向いてる方向にある鏡を採用する」ということにしました。
Vector3 playerPos = loPlayer.GetPosition(); Quaternion invPlayerRot = Quaternion.Inverse(loPlayer.GetRotation()); int nearest = -1; float dist = 4.0f; int aiming = -1; float aim = 0.85f; for(int i=0;i<mirrors.Length;i++) { Vector3 p = invPlayerRot * (origins[i] - playerPos); p.Scale(new Vector3(1,0,1)); float l = p.magnitude; if(i == currentMirror) l -= 0.5f; if(dist > l) { nearest = i; dist = l; } float z = p.normalized.z; if(i == currentMirror) z += 0.05f; if(aim < z) { aiming = i; aim = z; } } nextMirror = nearest != -1 ? nearest : aiming;
プレイヤーからのローカル座標に変換して、距離が (4m以下で) 一番近い鏡が nearest
に、向いている方向に一番近い鏡が aiming
に入ります。
ついでに現在アクティブな鏡は判定を緩める処理が入っていて、これは境界でばちばちしないための対策です。まぁ心理的にも合致してそうだった (現状が維持されるのは気持ちとして自然)。
Y座標を潰しているのはあの空間だと高さが意味を持たないからです。
あとはこれを反映するだけです。まぁやるだけ。
今回のこれは「鏡を選択する処理」と「選択を実際に反映する処理」で綺麗にぱきっと分けられて良いですね。
float dt = Time.deltaTime * 4.0f; if(currentMirror >= 0) { if(currentMirror == nextMirror) { if (alphaValue < 1) { alphaValue += dt; if (alphaValue > 1) alphaValue = 1; materials[currentMirror].SetFloat("_Alpha", alphaValue); } } else { alphaValue -= dt; if(alphaValue < 0) { alphaValue = 0; materials[currentMirror].SetFloat("_Alpha", 0); mrs[currentMirror].enabled = false; currentMirror = nextMirror; if(currentMirror != -1) mrs[currentMirror].enabled = true; } else { materials[currentMirror].SetFloat("_Alpha", alphaValue); } } } else { if(nextMirror >= 0) { alphaValue = 0; currentMirror = nextMirror; mrs[currentMirror].enabled = true; } }
鏡のMaterialを弄ってalpha入れられるようにしてあります。(参考にしました)
素直なstate machineで嬉しいですね。うむ。
おわり。まぁこれはふとほしいよねってなってぱらっとつくったやつなので大したあれでもなし。
メイン作業なさってたみなさん本当にお疲れ様でした :pray: