在C#中每个像素的冲突问题 [英] Per-pixel collision problem in C#

查看:137
本文介绍了在C#中每个像素的冲突问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写在C#中的小的2D游戏引擎为我自己的目的,和它的作品除了精灵碰撞检测的罚款。我决定把它每个像素检测(最简单的对我实施),但它不工作它应该的方式。该代码检测碰撞长在它发生之前。我已经研究了检测的每一个组成部分,但我无法找到问题

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.

碰撞检测方法:

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;
	}
}

图片旋转方法:

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.

推荐答案

我想我找到了你的问题。

I think I've found your problem.

internal static Rectangle GetRotateDimensions(int imgx, int imgy, int imgwidth, int imgheight, double rotation, bool Crop) {
    Rectangle sz = new Rectangle(); // <-- Default constructed rect here.
    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);

            // <-- Never gets the X & Y assigned !!!
    }



因为你永远不分配IMGX和IMGY X和矩形的Y坐标,GetRotateDimensions的每一个电话将产生相同位置的矩形。它们可以是不同的大小,但是它们始终处于默认的X,Y位置。这将导致您看到,因为你试图检测两个精灵碰撞的任何时间,GetRotateDimensions会把自己的边界在相同的位置,无论他们实际上是那里的真正的早期碰撞。

Since you never assigned imgx and imgy to the X and Y coordinates of the Rectangle, every call of GetRotateDimensions will produce a Rectangle with the same location. They may be of differing sizes, but they will always be in the default X,Y position. This would cause the really early collisions that you are seeing because any time you tried to detect collisions on two sprites, GetRotateDimensions would put their bounds in the same position regardless of where they actually are.

一旦你已经修正了这个问题,你可能会碰到另一个错误:

Once you have corrected that problem, you may run into another error:

Rectangle rect;
Image img1 = GraphicsHandler.ResizeImage(GraphicsHandler.RotateImagePoint(s1.Image, s1.Position, s1.Origin, s1.Rotation, out rect), s1.Scale);
// <-- Should resize rect here.
int posx1 = rect.X;
int posy1 = rect.Y;

您获得从RotateImagePoint功能的边界矩形,但你调整图像大小。从矩形的X和Y也有可能不是完全相同的图像的大小的边界。我猜你的意思是在图像的中心留在原地,而所有的点对合同或者从调整大小中央扩大。如果是这样的话,那么你需要调整矩形以及为了得到正确的位置的图像。

You get your boundary rect from the RotateImagePoint function, but you then resize the image. The X and Y from the rect are probably not exactly the same as that of the resized boundaries of the image. I'm guessing that you mean for the center of the image to remain in place while all points contract toward or expand from the center in the resize. If this is the case, then you need to resize rect as well as the image in order to get the correct position.

这篇关于在C#中每个像素的冲突问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆