有关获取的接触点,你链接到已经完成了艰难的工作代码,而不是返回返回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