いきなり3DのMapを作成するのも理解が難しそうだったので、
2Dの衝突判定のサンプルであるTransformedCollisionGame のソースを見ることにする。
決して、パイプラインのソースがよく解らなかったとかじゃないからね(汗
Windows用のソリューションを開いてみると、
いつも通りprogram.csとGame.csがあって、今回はBlock.csというのもあるみたいだ。
Block.csの中をのぞくと・・・
Vector2とfloatのフィールドがあるだけ。
ふむ。
ブロックは複数表示するからクラスにして、状態をそれにもたせてるんですな。
で、メインのprogram.csです。
ひとまず、順にフィールドから観ていく。
・XNA1.0の頃のソースのためGraphicsDeviceManagerを宣言。
・画像を読み込むために、Texture2Dを作成。
・頂点データ(?)のために、Color[]を作成。
・描写のためのバッチを作成(SpriteBatch)。
・キャラクターの位置を保持する、Vector2。
・キャラクターの移動速度、int
・画面に表示するブロックのList
・ブロックを新たに作成する頻度(BlockSpawnProbability)
・そのまま・・・BlockFallSpeed
・ブロックを高速回転させよう(BlockRotateSpeed)
・ブロックの中心位置かな(blockOrigin)
safeBoundsは、SafeAreaPortionで指定された分移動範囲を狭める。
(初期のままだとSafeAreaPortionを変更するとY座標も移動してしまう。
0.5以下の値で試さないとパーソンが消えちゃう。
安全地帯へ逃げたのかな?)
--------------
そして、メソッドを観ていく。
Initialize()では、
特に変わったことをしてなく
viewportを取得して移動範囲とパーソンの初期位置を指定する。
LoadContent()も、
テクスチャを読み込み、データを取得する。
blockTexture = Content.Load<Texture2D>("SpinnerBlock");
blockTextureData = new Color[blockTexture.Width * blockTexture.Height];
blockTexture.GetData(blockTextureData);
personTexture = Content.Load<Texture2D>("Person");
personTextureData = new Color[personTexture.Width * personTexture.Height];
personTexture.GetData(personTextureData);
バッチ作成とブロックの中心を取得する。
blockOrigin = new Vector2(blockTexture.Width / 2, blockTexture.Height / 2);
spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
で、メインのUpdate(GameTime gameTime)です。
始めの方に入力デバイスを取得して、入力値を反映する。
その後に、MathHelper.Clampを使用してパーソンが画面位置から出ないようにしている。
personPosition.X = MathHelper.Clamp(personPosition.X,
safeBounds.Left, safeBounds.Right - personTexture.Width);
で、3D位置に変換している。
次に、ブロックの新規作成判定。
特に変わったことなく、Randomクラスを使用して追加している。
衝突判定を行うために、personRectangle(Rectangleクラス)をパーソンの位置から作成する。
で、全ブロックの位置を更新し、パーソンとの衝突判定を行う。
まずは、Blockのフィールドを更新する。
blocks[i].Position += new Vector2(0.0f, BlockFallSpeed);
blocks[i].Rotation += BlockRotateSpeed;
で、3D座標を作成する。
移動は左上を原点に計算するので
Matrix.CreateTranslation(new Vector3(-blockOrigin, 0.0f))
をかけてから、
回転させ、移動させる。
で、パーソンと同じようにRectangleを作成する。
単純な衝突判定を行い(personRectangle.Intersects(blockRectangle))
で、最高に肝のIntersectPixelsメソッド・・・・。
わからねー・・・orz
//A = personTransform, B = blockTransform
Matrix transformAToB = transformA * Matrix.Invert(transformB);
はいったい何?
その後は、パーソンのピクセル分ループさせて、
パーソンのテクスチャのα値が0じゃなくて、
ブロックのテクスチャのtransformAToB座標のα値が0じゃないなら
衝突していない。
と判定している。
//xAとyAはパーソンのピクセル位置
Color colorA = dataA[xA + yA * widthA];
Color colorB = dataB[xB + yB * widthB];
if (colorA.A != 0 && colorB.A != 0)
return true;
なんとなく
このメソッドはパーソンとブロックの短形が重なっていていないことないので、
ブロックはパーソンと重なっている部分だけを検査していって、
パーソンも、ブロックも黒かったら衝突という事にしているのでは?
と予想がつくが、Matrixの計算結果の意味がわからないと・・・
パーソンにブロックの逆行列をかけると何が起こる?
うーん・・・。
--追記1
スクリーン座標からワールド座標を得る
座標系は
ローカル座標->ワールド座標->スクリーン座標 という順に変換して画面に描写しているわけで
座標系を逆に戻していくには逆行列を作成すればいい。
ふむ。逆行列はそういう性質があると。
じゃ、パーソンのワールド座標とブロックのワールド座標の逆行列をかけるということは・・・
パーソンのワールド*ブロックのローカル座標をかけるということ。
うーん?
パーソンをブロックの中心に移動させるってこと?
--追記2
わかった!
まずは、コメントを見ると書いてあった。
「ワールド座標のパーソンとブロックのローカル座標からマトリックスを作ります」と。
英語ダカラって無視しないで、よく読めと。
まずは、例の掛算をすることで
ブロックのローカル座標でパーソンのいる位置を表すMartixが作成できる。(これがほぼ回答ですにゃ)
setpXとsetpYをわざわざ作っているのは、
ブロックのローテーションがパーソンと違っているので単純なループだとずれが生じてしまうから。
で、パーソンは単純に一ピクセルずつ見ていって、
ブロックはさっき作ったMatrixの位置(パーソンが乗っかっている部分)のピクセルを見ていく。
両方のα値が0じゃないなら接触しているってことだから!!
どかーん!!
ってわけですん。
なるほど!
2Dの衝突判定のサンプルであるTransformedCollisionGame のソースを見ることにする。
決して、パイプラインのソースがよく解らなかったとかじゃないからね(汗
Windows用のソリューションを開いてみると、
いつも通りprogram.csとGame.csがあって、今回はBlock.csというのもあるみたいだ。
Block.csの中をのぞくと・・・
Vector2とfloatのフィールドがあるだけ。
ふむ。
ブロックは複数表示するからクラスにして、状態をそれにもたせてるんですな。
で、メインのprogram.csです。
ひとまず、順にフィールドから観ていく。
・XNA1.0の頃のソースのためGraphicsDeviceManagerを宣言。
・画像を読み込むために、Texture2Dを作成。
・頂点データ(?)のために、Color[]を作成。
・描写のためのバッチを作成(SpriteBatch)。
・キャラクターの位置を保持する、Vector2。
・キャラクターの移動速度、int
・画面に表示するブロックのList
・ブロックを新たに作成する頻度(BlockSpawnProbability)
・そのまま・・・BlockFallSpeed
・ブロックを高速回転させよう(BlockRotateSpeed)
・ブロックの中心位置かな(blockOrigin)
safeBoundsは、SafeAreaPortionで指定された分移動範囲を狭める。
(初期のままだとSafeAreaPortionを変更するとY座標も移動してしまう。
0.5以下の値で試さないとパーソンが消えちゃう。
安全地帯へ逃げたのかな?)
--------------
そして、メソッドを観ていく。
Initialize()では、
特に変わったことをしてなく
viewportを取得して移動範囲とパーソンの初期位置を指定する。
LoadContent()も、
テクスチャを読み込み、データを取得する。
blockTexture = Content.Load<Texture2D>("SpinnerBlock");
blockTextureData = new Color[blockTexture.Width * blockTexture.Height];
blockTexture.GetData(blockTextureData);
personTexture = Content.Load<Texture2D>("Person");
personTextureData = new Color[personTexture.Width * personTexture.Height];
personTexture.GetData(personTextureData);
バッチ作成とブロックの中心を取得する。
blockOrigin = new Vector2(blockTexture.Width / 2, blockTexture.Height / 2);
spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
で、メインのUpdate(GameTime gameTime)です。
始めの方に入力デバイスを取得して、入力値を反映する。
その後に、MathHelper.Clampを使用してパーソンが画面位置から出ないようにしている。
personPosition.X = MathHelper.Clamp(personPosition.X,
safeBounds.Left, safeBounds.Right - personTexture.Width);
で、3D位置に変換している。
次に、ブロックの新規作成判定。
特に変わったことなく、Randomクラスを使用して追加している。
衝突判定を行うために、personRectangle(Rectangleクラス)をパーソンの位置から作成する。
で、全ブロックの位置を更新し、パーソンとの衝突判定を行う。
まずは、Blockのフィールドを更新する。
blocks[i].Position += new Vector2(0.0f, BlockFallSpeed);
blocks[i].Rotation += BlockRotateSpeed;
で、3D座標を作成する。
移動は左上を原点に計算するので
Matrix.CreateTranslation(new Vector3(-blockOrigin, 0.0f))
をかけてから、
回転させ、移動させる。
で、パーソンと同じようにRectangleを作成する。
単純な衝突判定を行い(personRectangle.Intersects(blockRectangle))
で、最高に肝のIntersectPixelsメソッド・・・・。
わからねー・・・orz
//A = personTransform, B = blockTransform
Matrix transformAToB = transformA * Matrix.Invert(transformB);
はいったい何?
その後は、パーソンのピクセル分ループさせて、
パーソンのテクスチャのα値が0じゃなくて、
ブロックのテクスチャのtransformAToB座標のα値が0じゃないなら
衝突していない。
と判定している。
//xAとyAはパーソンのピクセル位置
Color colorA = dataA[xA + yA * widthA];
Color colorB = dataB[xB + yB * widthB];
if (colorA.A != 0 && colorB.A != 0)
return true;
なんとなく
このメソッドはパーソンとブロックの短形が重なっていていないことないので、
ブロックはパーソンと重なっている部分だけを検査していって、
パーソンも、ブロックも黒かったら衝突という事にしているのでは?
と予想がつくが、Matrixの計算結果の意味がわからないと・・・
パーソンにブロックの逆行列をかけると何が起こる?
うーん・・・。
--追記1
スクリーン座標からワールド座標を得る
座標系は
ローカル座標->ワールド座標->スクリーン座標 という順に変換して画面に描写しているわけで
座標系を逆に戻していくには逆行列を作成すればいい。
ふむ。逆行列はそういう性質があると。
じゃ、パーソンのワールド座標とブロックのワールド座標の逆行列をかけるということは・・・
パーソンのワールド*ブロックのローカル座標をかけるということ。
うーん?
パーソンをブロックの中心に移動させるってこと?
--追記2
わかった!
まずは、コメントを見ると書いてあった。
「ワールド座標のパーソンとブロックのローカル座標からマトリックスを作ります」と。
英語ダカラって無視しないで、よく読めと。
まずは、例の掛算をすることで
ブロックのローカル座標でパーソンのいる位置を表すMartixが作成できる。(これがほぼ回答ですにゃ)
setpXとsetpYをわざわざ作っているのは、
ブロックのローテーションがパーソンと違っているので単純なループだとずれが生じてしまうから。
で、パーソンは単純に一ピクセルずつ見ていって、
ブロックはさっき作ったMatrixの位置(パーソンが乗っかっている部分)のピクセルを見ていく。
両方のα値が0じゃないなら接触しているってことだから!!
どかーん!!
ってわけですん。
なるほど!