有關獲取的接觸點,你鏈接到已經完成了艱難的工作代碼,而不是返回返回true通過變換回世界空間座標的第一部分。
下面有從http://xbox.create.msdn.com/en-US/education/catalog/tutorial/collision_2d_perpixel_transformed
public static IEnumerable<Vector2> IntersectPixels(
Matrix transformA, int widthA, int heightA, Color[] dataA,
Matrix transformB, int widthB, int heightB, Color[] dataB)
{
// Calculate a matrix which transforms from A's local space into
// world space and then into B's local space
Matrix transformAToB = transformA * Matrix.Invert(transformB);
// When a point moves in A's local space, it moves in B's local space with a
// fixed direction and distance proportional to the movement in A.
// This algorithm steps through A one pixel at a time along A's X and Y axes
// Calculate the analogous steps in B:
Vector2 stepX = Vector2.TransformNormal(Vector2.UnitX, transformAToB);
Vector2 stepY = Vector2.TransformNormal(Vector2.UnitY, transformAToB);
// Calculate the top left corner of A in B's local space
// This variable will be reused to keep track of the start of each row
Vector2 yPosInB = Vector2.Transform(Vector2.Zero, transformAToB);
// For each row of pixels in A
for(int yA = 0; yA < heightA; yA++)
{
// Start at the beginning of the row
Vector2 posInB = yPosInB;
// For each pixel in this row
for(int xA = 0; xA < widthA; xA++)
{
// Round to the nearest pixel
int xB = (int)Math.Round(posInB.X);
int yB = (int)Math.Round(posInB.Y);
// If the pixel lies within the bounds of B
if(0 <= xB && xB < widthB &&
0 <= yB && yB < heightB)
{
// Get the colors of the overlapping pixels
Color colorA = dataA[xA + yA * widthA];
Color colorB = dataB[xB + yB * widthB];
// If both pixels are not completely transparent,
if(colorA.A != 0 && colorB.A != 0)
{
// then an intersection has been found
yield return Vector2.Transform(new Vector2(xA, yA),transformA);
}
}
// Move to the next pixel in the row
posInB += stepX;
}
// Move to the next row
yPosInB += stepY;
}
// No intersection found
}
稍微修改後的代碼作爲所述第二部分的常用方法是添加一個小的力相反的方向碰撞排斥它們。關於遊戲物理的這個article是一個很好的入門書,並且很少有像Farseer這樣強大的現成物理引擎。
樣本代碼是用以轉換精靈,如果你不需要此功能,您也許可以簡化代碼。如果您在移動物理引擎時不使用物理引擎來避免重疊,則可能需要移動另一個物理引擎等,物理引擎會爲您處理此問題。
編輯: 下面是一些小的變化到MSDN樣本所以每個接觸點繪製一個綠色像素。
添加這些字段
//Contact points are cleared and re-added each update
List<Vector2> contactPoints = new List<Vector2>();
//Texture for contact display
Texture2D pixelTex;
添加到LoadContent()
地方
pixelTex = new Texture2D(GraphicsDevice, 1, 1);
pixelTex.SetData<Color>(new[] { Color.White });
更換的Update()
結束本
// Update each block
personHit = false;
contactPoints.Clear();
for(int i = 0; i < blocks.Count; i++)
{
// Animate this block falling
blocks[i].Position += new Vector2(0.0f, BlockFallSpeed);
blocks[i].Rotation += BlockRotateSpeed;
// Build the block's transform
Matrix blockTransform =
Matrix.CreateTranslation(new Vector3(-blockOrigin, 0.0f)) *
// Matrix.CreateScale(block.Scale) * would go here
Matrix.CreateRotationZ(blocks[i].Rotation) *
Matrix.CreateTranslation(new Vector3(blocks[i].Position, 0.0f));
// Calculate the bounding rectangle of this block in world space
Rectangle blockRectangle = CalculateBoundingRectangle(
new Rectangle(0, 0, blockTexture.Width, blockTexture.Height),
blockTransform);
// The per-pixel check is expensive, so check the bounding rectangles
// first to prevent testing pixels when collisions are impossible.
if(personRectangle.Intersects(blockRectangle))
{
contactPoints.AddRange(IntersectPixels(personTransform, personTexture.Width,
personTexture.Height, personTextureData,
blockTransform, blockTexture.Width,
blockTexture.Height, blockTextureData));
// Check collision with person
if(contactPoints.Count != 0)
{
personHit = true;
}
}
// Remove this block if it have fallen off the screen
if(blocks[i].Position.Y >
Window.ClientBounds.Height + blockOrigin.Length())
{
blocks.RemoveAt(i);
// When removing a block, the next block will have the same index
// as the current block. Decrement i to prevent skipping a block.
i--;
}
}
base.Update(gameTime);
添加到Draw()
spriteBatch.End()之前
foreach(Vector2 p in contactPoints)
{
spriteBatch.Draw(pixelTex, new Rectangle((int)p.X, (int)p.Y, 1, 1), Color.FromNonPremultiplied(120, 255, 100, 255));
}
謝謝您的回覆,但我有困難的時候將這種變化。首先,我不熟悉「收益率」以及爲什麼會在這種情況下使用它。 (已查找它,但在MSDN上,但我很難理解它)此外,在這種情況下返回什麼,以及我將如何處理它。在我調用函數作爲if語句的「參數」之前。但我不認爲這將在這種情況下工作。 – APalmer 2011-05-11 04:40:23
我使用了收益率,因爲可能有多個聯繫點。結果是IEnumerable,所以你可以在結果上使用'foreach'或者使用Linq的ToArray,ToList擴展方法。您可以將點添加到列表中並返回,但是根據需要使用yield獲取,所以使用Linq可以使用'IntersectPixels(...)。Any()'作爲返回bool的原始方法的替代品。檢查編輯的例子。 – Kris 2011-05-11 18:19:19
先生,你是我的英雄。我相信我欠你一個火雞三明治。 – APalmer 2011-05-14 23:09:26