パスワードを忘れた? アカウント作成
14330637 journal
日記

yumeの日記: Unity制作 メデューサ・ゲーム #3

日記 by yume

●メデューサ・ゲーム

●メデューサの視野角を制限する
メデューサは現状では、360度の視野角(計算的には-π~π)を持っている。これを「前を向いているなら、後ろは見えない」というように、数値によって制限された視野角にしたい。
流れとしては:
・弧度viewingAngleを持っておく
・マウスポジションから2D座標aimPositionをとる
・aimPositionに対する弧度をとる(-π~+π)

え~と、それから……。

既存のFOVメソッドでは:
・ポリゴン頂点に向かって弧度goalRadianをとる
・goalRadianに向かってRaycastする
という仕組みなので、このRaycastする前に、goalRadianが「視野角内か」を判定し、視野角外なら無視すればよいはず。

例えば、aimPositionが0、viewingAngleが0.785だとしたら、goalRadianが(-0.785)~(0.785)の範囲にあるか調べればよい。
言い換えると

if (goalRadian >= (aimRadian - (viewingAngle)) && goalRadian <= (aimRadian + (viewingAngle)))
{
//do something
}

で、この範囲なら……。いや、これじゃだめかな。
例えばaimRadianが3.0の時は、最小値は2.215だが、最大値が3.785とかになってしまう。弧度は-π~+πの範囲だ。
この場合の正しい範囲は 最小値2.215、最大値-0.645だが……。 2.215より大きくて-0.645より小さい数字、なんてことになる。

いや、aimRadianからの差を求めればいいのか?
例えば 3.0の時、goalRadianが1.0だったら、その差は2.0、viewingAngleは0.785だから、差の方が大きい=視野角外
同3.0の時、goalRadianが-3.0だったら……。計算上の差は6.0、でもほんとの差は約0.283。ダメじゃん。ムムム……。

hakuhin.jp曰く、
角度の差を求めるには
・角度Aから角度Bを引く(sub)
・subを0~360の範囲に丸める(sub -= Math.floor(sub / 360.0) * 360.0)
・角度差が-180~180の範囲に収めるように丸める(if(sub>180.0) sub -= 360.0;

ふーむ?
メデューサ・ゲームの場合、与えられた差を何であれ-π~πの範囲に丸められるといいんだろうか。
実際のRadianの差は、π以下になるはずだ(180度真後ろでちょうどπなので)
言い換えると、πを超える差が出ている場合、それは左向きの角度をまたいでいるということだから、
本当の差は……。差 - 2π?
6.0 - 2π = -0.283。あ、これでいいかも。

if(sub > Math.PI)
{
        sub = (float) sub - (Math.PI * 2);
}

かな。ちゃんと絶対値にしなきゃならないが。
視野角が0.785だとして、
goalが-2.0、aimが1.0の時……差は3.0。視野外。あってる。
goalが3.14、aimが0.0の時……差は3.14。視野外。OK
goalが3.0、aimが-0.2の時……差は3.2。丸めて3.08。視野外。OK
goalが0.1、aimが0.0の時……差は0.1、視野内。OK
goalが-2.0、aimが3.0の時……差は5.0、丸めて1.283。視野外。OK。
goalが-3.0、aimが3.0の時……差は6.0、丸めて0.283。視野内。OK。
いけそう。
前回のvisibleVertexの取得の前に、

//弧度差チェック
float radDiff = Math.Abs(ownerControll.aimRadian - goalRadian);
if (radDiff > (float)Math.PI) radDiff = Math.Abs(radDiff - (float)Math.PI * 2);
//弧度差がviewingAngleを超えてるなら、無視。
if (radDiff > viewingAngle) continue;

を追加。

このままだと、メッシュがうまく形成できないだろうから、視界の範囲のふちにそれぞれRayを飛ばし、衝突点を取る必要があるだろう。
それも追加して、いざ動かすと
Mesh.vertices is too small. The supplied vertex array has less vertices than are referenced by the triangles array.
というエラーが出た。これは頂点が少なすぎるというときに出るエラーのようだ。
メッシュの頂点を視界外に持っていくとエラーが出ているっぽい。
うーん、どこかで何かを間違っているのか、アルゴリズムそのものに瑕疵があるのか……。

今日はもう遅いので、思いついたところを並べて明日考える。

・右上に視界を持って行ってスタートすると、ひとまずエラーは出ないが、視点を動かして頂点ポイントを視界からひとつでも外すとエラーがでる。
その時、エラーが出る前のMeshのverticesは30、Trianglesは84。(厳密にいえば代入前のリスト)
エラーが出た時点でのverticesは27、Trianglesは75。3の倍数ずつ減ってるから、おかしくないような……。
・視界外ポイントを除外する部分をコメントアウトすると動く(もちろん視野の概念も消える)
その時のverticesは51、Trianglesは147。

んー、メッシュ作成メソッドでは(前回から「最後のつなげる三角形」は消した)

//頂点リストをクリア
meshPoints.Clear();
meshTriangles.Clear();

//プレイヤー原点を入力
meshPoints.Add(ownerBody.transform.position);
meshTriangles.Add(0);

//最初の三角形の頂点をとる
meshPoints.Add(visibleVertex[0].EndPoint);
meshTriangles.Add(1);
meshPoints.Add(visibleVertex[1].EndPoint);
meshTriangles.Add(2);

//次以降の三角形をとる。
for (int i = 2; i < visibleVertex.Count; i++)
{
        //三角形の頂点番号を打っておく
        meshTriangles.Add(0);
        meshTriangles.Add(i);

        //頂点をとる。頂点番号を打つ。
        meshPoints.Add(visibleVertex[i].EndPoint);
        meshTriangles.Add(i + 1);

        //メッシュに代入
        FOVMesh.vertices = meshPoints.ToArray();
        FOVMesh.triangles = meshTriangles.ToArray();
        FOVMesh.RecalculateNormals();
}

meshPointsがverticesに、meshTrianglesがtrianglesに代入されるわけで、
meshPointsは:
・プレイヤー原点
・最初の2点
・次、頂点1点ごとに1点。
meshTrianglesは:
・プレイヤー原点
・最初の2点
・頂点1点ごとに3点。

えーと、meshPoints総数は:
・壁ポリゴンの頂点総数は16(background含め)
・衝突点はその3倍の48
・さらに、視界のふちの2とプレイヤー原点1
合計51。あってる。
Triangle総数は:
プレイヤー原点 1
最初の2点 2
その後、3番目以降頂点ごとに3
3 + (51-3)*3 = 147
あってる。
エラーが出た時点では27:75
3+(27-3)*3 = 75
あってるじゃん? なぜだろう。

エラーが出るのはメッシュ作成メソッドだが、メッシュ作成メソッドに使うリストは単なるリストで、しかもソート済み。
頂点取得メソッドで弧度差チェックを除外するとエラーが出ない。ソートはメソッドのすべてが終わった最後に行ってるから、ソート前のリストがすでにおかしいというだろうか。
やはり弧度差チェックメソッドがおかしい?
しかし視界から外れた瞬間にエラーってどういうことだ。マウスの座標をとるタイミングがおかしい?

typodupeerror

目玉の数さえ十分あれば、どんなバグも深刻ではない -- Eric Raymond

読み込み中...