I am writing a small 2d game engine in C# for my own purposes, and it works fine except for the sprite collision detection. I've decided to make it a per-pixel detection (easiest for me to implement), but it is not working the way it's supposed to. The code detects a collision long before it happens. I've examined every component of the detection, but I can't find the problem.
The collision detection method:
public static bool CheckForCollision(Sprite s1, Sprite s2, bool perpixel) {
if(!perpixel) {
return s1.CollisionBox.IntersectsWith(s2.CollisionBox);
}
else {
Rectangle rect;
Image img1 = GraphicsHandler.ResizeImage(GraphicsHandler.RotateImagePoint(s1.Image, s1.Position, s1.Origin, s1.Rotation, out rect), s1.Scale);
int posx1 = rect.X;
int posy1 = rect.Y;
Image img2 = GraphicsHandler.ResizeImage(GraphicsHandler.RotateImagePoint(s2.Image, s2.Position, s2.Origin, s2.Rotation, out rect), s2.Scale);
int posx2 = rect.X;
int posy2 = rect.Y;
Rectangle abounds = new Rectangle(posx1, posy1, (int)img1.Width, (int)img1.Height);
Rectangle bbounds = new Rectangle(posx2, posy2, (int)img2.Width, (int)img2.Height);
if(Utilities.RectangleIntersects(abounds, bbounds)) {
uint[] bitsA = s1.GetPixelData(false);
uint[] bitsB = s2.GetPixelData(false);
int x1 = Math.Max(abounds.X, bbounds.X);
int x2 = Math.Min(abounds.X + abounds.Width, bbounds.X + bbounds.Width);
int y1 = Math.Max(abounds.Y, bbounds.Y);
int y2 = Math.Min(abounds.Y + abounds.Height, bbounds.Y + bbounds.Height);
for(int y = y1; y < y2; ++y) {
for(int x = x1; x < x2; ++x) {
if(((bitsA[(x - abounds.X) + (y - abounds.Y) * abounds.Width] & 0xFF000000) >> 24) > 20 &&
((bitsB[(x - bbounds.X) + (y - bbounds.Y) * bbounds.Width] & 0xFF000000) >> 24) > 20)
return true;
}
}
}
return false;
}
}
The image rotation method:
internal static Image RotateImagePoint(Image img, Vector pos, Vector orig, double rotation, out Rectangle sz) {
if(!(new Rectangle(new Point(0), img.Size).Contains(new Point((int)orig.X, (int)orig.Y))))
Console.WriteLine("Origin point is not present in image bound; unwanted cropping might occur");
rotation = (double)ra_de((double)rotation);
sz = GetRotateDimensions((int)pos.X, (int)pos.Y, img.Width, img.Height, rotation, false);
Bitmap bmp = new Bitmap(sz.Width, sz.Height);
Graphics g = Graphics.FromImage(bmp);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.RotateTransform((float)rotation);
g.TranslateTransform(sz.Width / 2, sz.Height / 2, MatrixOrder.Append);
g.DrawImage(img, (float)-orig.X, (float)-orig.Y);
g.Dispose();
return bmp;
}
internal static Rectangle GetRotateDimensions(int imgx, int imgy, int imgwidth, int imgheight, double rotation, bool Crop) {
Rectangle sz = new Rectangle();
if (Crop == true) {
// absolute trig values goes for all angles
double dera = de_ra(rotation);
double sin = Math.Abs(Math.Sin(dera));
double cos = Math.Abs(Math.Cos(dera));
// general trig rules:
// length(adjacent) = cos(theta) * length(hypotenuse)
// length(opposite) = sin(theta) * length(hypotenuse)
// applied width = lo(img height) + la(img width)
sz.Width = (int)(sin * imgheight + cos * imgwidth);
// applied height = lo(img width) + la(img height)
sz.Height = (int)(sin * imgwidth + cos * imgheight);
}
else {
// get image diagonal to fit any rotation (w & h =diagonal)
sz.X = imgx - (int)Math.Sqrt(Math.Pow(imgwidth, 2.0) + Math.Pow(imgheight, 2.0));
sz.Y = imgy - (int)Math.Sqrt(Math.Pow(imgwidth, 2.0) + Math.Pow(imgheight, 2.0));
sz.Width = (int)Math.Sqrt(Math.Pow(imgwidth, 2.0) + Math.Pow(imgheight, 2.0)) * 2;
sz.Height = sz.Width;
}
return sz;
}
Pixel getting method:
public uint[] GetPixelData(bool useBaseImage) {
Rectangle rect;
Image image;
if (useBaseImage)
image = Image;
else
image = GraphicsHandler.ResizeImage(GraphicsHandler.RotateImagePoint(Image, Position, Origin, Rotation, out rect), Scale);
BitmapData data;
try {
data = ((Bitmap)image).LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
}
catch (ArgumentException) {
data = ((Bitmap)image).LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, image.PixelFormat);
}
byte[] rawdata = new byte[data.Stride * image.Height];
Marshal.Copy(data.Scan0, rawdata, 0, data.Stride * image.Height);
((Bitmap)image).UnlockBits(data);
int pixelsize = 4;
if (data.PixelFormat == PixelFormat.Format24bppRgb)
pixelsize = 3;
else if (data.PixelFormat == PixelFormat.Format32bppArgb || data.PixelFormat == PixelFormat.Format32bppRgb)
pixelsize = 4;
double intdatasize = Math.Ceiling((double)rawdata.Length / pixelsize);
uint[] intdata = new uint[(int)intdatasize];
Buffer.BlockCopy(rawdata, 0, intdata, 0, rawdata.Length);
return intdata;
}
The pixel retrieval method works, and the rotation method works as well, so the only place that the code might be wrong is the collision detection code, but I really have no idea where the problem might be.