I have a C# snippet code about sprite collision in C# game programming, hope you guys will help me to clarify it.
I dont understand method IsCollided, especially the calculation of d1 and d2 to determine whether the sprites collide or not, the meaning and the use of Matrix Invert() and Multiphy in this case as well as the use of Color alpha component to determine the collision of 2 sprites.
Thank you very much.
public struct Vector
{
public double X;
public double Y;
public Vector(double x, double y)
{
X = x;
Y = y;
}
public static Vector operator -(Vector v, Vector v2)
{
return new Vector(v.X-v2.X, v.Y-v2.Y);
}
public double Length
{
get
{
return Math.Sqrt(X * X + Y * Y);
}
}
}
public class Sprite
{
public Vector Position;
protected Image _Image;
protected Bitmap _Bitmap;
protected string _ImageFileName = "";
public string ImageFileName
{
get { return _ImageFileName; }
set
{
_ImageFileName = value;
_Image = Image.FromFile(value);
_Bitmap = new Bitmap(value);
}
}
public Matrix Transform
{
get
{
Vector v = Position;
if (null != _Image)
v -= new Vector(_Image.Size) / 2;
Matrix m = new Matrix();
m.RotateAt(50.0F, new PointF(10.0F, 100.0F));
m.Translate((float)v.X, (float)v.Y);
return m;
}
}
public bool IsCollided(Sprite s2)
{
Vector v = this.Position - s2.Position;
double d1 = Math.Sqrt(_Image.Width * _Image.Width + _Image.Height * _Image.Height)/2;
double d2 = Math.Sqrt(s2._Image.Width * s2._Image.Width + s2._Image.Height * s2._Image.Height)/2;
if (v.Length > d1 + d2)
return false;
Bitmap b = new Bitmap(_Image.Width, _Image.Height);
Graphics g = Graphics.FromImage(b);
Matrix m = s2.Transform;
Matrix m2 = Transform;
m2.Invert();
Matrix m3 = m2;
m3.Multiply(m);
g.Transform = m3;
Vector2F v2 = new Vector2F(0,0);
g.DrawImage(s2._Image, v2);
for (int x = 0; x < b.Width; ++x)
for (int y = 0; y < b.Height; ++y)
{
Color c1 = _Bitmap.GetPixel(x, y);
Color c2 = b.GetPixel(x, y);
if (c1.A > 0.5 && c2.A > 0.5)
return true;
}
return false;
}
}
It's a little convoluted. The two parts:
Part One (simple & fast)
The first part (involving v, d1 + d2) is probably confusing because, instead of doing collision tests using boxes, the dimensions of the image are used to construct bounding circles instead. A simple collision test is then carried out using these bounding circles. This is the 'quick n dirty' test that eliminates sprites that are clearly not colliding.
"Two circles overlap if the sum of there(sic) radii is greater than the distance between their centers. Therefore by Pythagoras we have a collision if:
(cx1-cx2)2 + (cy1-cy2)2 < (r1+r2)2"
See the "Bounding Circles" section of this link and the second link at the foot of this answer.
commented code:
Note: You may want to considering using an axially aligned bounding box test instead of a circle here. if you have rectangles with disparate widths and lengths, it'll be a more effective/accurate first test.
Part Two (slower)
I haven't got time to check the code 100%, but the second part --having established that the two sprites are potentially colliding in step one-- is performing a more complicated collision test. It is performing a per-pixel collision test using the sprite's image source -- specifically its alpha channel. In games, the alpha channel is often used to store a representation of transparency. The larger the value, the more opaque the image (so 0 would be 100% transparent, 1.0f would be 100% opaque).
In the code shown, if the pixels in both sprites are overlapping and both have alpha values of > 0.5f, the pixels are sharing the same space and represent solid geometry and are thus colliding. By doing this test, it means that transparent (read: invisible) parts of the sprite will not be considered when testing for collisions, so you can have circular sprites that do not collide at the corners etc.
Here's a link that covers this in a bit more detail.