Что касается первой части получения точек контакта, то код, с которым вы связались, проделал тяжелую работу, вместо того, чтобы возвращать 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
}
Что касается второй части, общий метод состоит в том, чтобы добавить небольшую силу, противоположную направлению столкновения, чтобы отразить их. Эта статья по игровой физике является хорошим учебником, и есть несколько готовых физических движков, которые были бы надежны, как Farseer .
Пример кода для преобразованных спрайтов. Если вам не нужна эта функция, вы, вероятно, могли бы упростить код. Если вы не используете физический движок, чтобы не допустить их перекрытия при перемещении, может потребоваться перемещение другого и т. Д., Физический движок позаботится об этом за вас.
Edit:
Вот несколько небольших изменений в образце 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));
}