碰撞-C#游戏,第3部分:像素完美碰撞检测(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/collision-a-csharp-game-part-3-pixel-perfect-colli-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 5 分钟阅读 - 2312 个词 阅读量 0碰撞-C#游戏,第3部分:像素完美碰撞检测(译文)
原文地址:https://www.codeproject.com/Articles/2134/Collision-A-Csharp-Game-Part-3-Pixel-Perfect-Colli
原文作者:Christian Graus
译文由本站 robot-v1.0 翻译
前言
Finishing my attempt at a simple game in C#
完成我在C#中的简单游戏的尝试
目标(Goals)
从我最初的崇高计划中得出合理的结论后,我仍然确定该游戏中的碰撞检测应该是完美的,而不是近似的.这只能通过直接访问位图数据来完成.由于到目前为止发现的所有操作都比我想要的慢,所以我的第一步是寻求优化自己的操作.(Having come down a fair way from my original lofty plans, I remain determined that collision detection in this game should be perfect, not approximated. This can only be done by direct access to the bitmap data. As I’ve found everything so far to be slower than I would like, my first step was to look to optimize what I had.)
JPEG与位图(JPEG vs. Bitmap)
您会记得我的原始资源都是jpeg,以节省空间,但是我注意到这意味着我必须在绘制时指定颜色范围以掩盖背景.为了提高速度,我使用了位图资源,这意味着用手将所有背景绘制为硬黑色.这意味着您可能会发现游戏似乎没有完美的像素,因为某些旧的蓝色背景可能仍然存在,但在游戏中不可见.我向您保证,我向您展示的技术没有错,我在编辑位图时的工作是正确的.该代码有望为我们的冲突检测成本做好更好的准备,但是您会注意到EXE和项目的大小出现了严重的增长.没有添加新的位图,这只是位图而不是jpeg的代价.(You’ll recall my original resources were all jpegs to save space, but that I noted this meant I had to specify a colour range when drawing in order to mask the background. For the sake of speed, I have gone to bitmap resources, which meant drawing the backgrounds to all be hard black by hand. This means you may find the game does not appear pixel perfect, because some of the old blue background might still be there, but not visible in the game. I assure you the technique I am showing you is not at fault, my job in editing the bitmaps is. The code is hopefully better prepared for the cost of our collision detection, but you’ll notice the serious jump in the size of the EXE and the project. No new bitmaps were added, that’s just the cost of bitmaps as opposed to jpegs.)
使透明(MakeTransparent)
完成此操作后,我可以使用(Having done this, I can use the) MakeTransparent
的方法(method of) Bitmap
,传入(, passing in) Color.Black
作为参数,而我不必再担心遮罩-图像现在将自动被遮盖的黑色区域绘制.(as the parameter, and I do not have to worry again about masking - the image will now automatically draw with the black areas masked.)
每像素碰撞(Per Pixel Collisions)
这给我留下了碰撞代码.第一步很简单,就是通过检查行星来检查我们是否发生碰撞(Which leaves me with the collision code. The first step is easy, that is, to check if we’ve collided by checking the planet) Rectangle
反对船上.这与行星运动和得分保持在同一循环中进行,但是为了清楚起见,我删除了该代码(您上次看到了).(against that of the ship. This takes place in the same loop as the moving of planets and score keeping, but I’ve removed that code for clarity (you saw it last time).)
for (int i = 0; i < m_arAsteroids.Count; ++i)
{
if (arTemp.rcAsteroid.IntersectsWith(m_rcShipPos))
{
// We've hit
}
但是问题是,正如您回想的那样,我们有一个巨大的星球,所以其他所有星球都具有相当大的透明度.即使不是这样,如果玩家进入定义避开行星的矩形内,他们也不会发现自己死亡.我们需要做得更好.解决方案是找出定义两个对象共享区域的矩形,将两个位图的矩形归一化,然后逐步检查它们,以查看相交矩形中的任何像素位置是否包含未在两个位图中都屏蔽的像素值.主要技巧是尽可能限制我们进入的区域,因为这不是一项廉价的操作.(But the problem is that as you recall, we have one huge planet, so the others all have a fair amount of transparency in them. Even if this was not so, no game player would be happy to find they die if they come within the rectangle that defines the planet they are avoiding. We need to do better. The solution is to figure out the rectangle that defines the area shared by both objects, normalize that rectangle for both bitmaps and then step through them together to see if any pixel position in the intersected rectangle contains a pixel vale that is not masked in both bitmaps. The main trick is to limit the area we step through as much as possible, because it’s not a cheap operation.)
private bool HitTest(Asteroid a)
{
Rectangle rcIntersect = a.rcAsteroid; rcIntersect.Intersect(m_rcShipPos);
BitmapData bmData = m_bmShip.LockBits(
new Rectangle(rcIntersect.X - m_rcShipPos.X,
rcIntersect.Y - m_rcShipPos.Y,
rcIntersect.Width, rcIntersect.Height),
ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
BitmapData bmData2 = m_bmPlanets.LockBits(
new Rectangle(87 * a.nBitmap + rcIntersect.X - a.rcAsteroid.X,
rcIntersect.Y - a.rcAsteroid.Y,
rcIntersect.Width, rcIntersect.Height),
ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
System.IntPtr Scan1 = bmData2.Scan0;
unsafe
{
byte * p = (byte *)Scan0;
byte * p1 = (byte *)Scan1;
int nOffset = stride - rcIntersect.Width*3;
for(int y=0;y<rcIntersect.Height;++y)
{
for(int x=0; x < rcIntersect.Width; ++x )
{
if (p[0] != 0 &&
p[1] != 0 &&
p[2] != 0 &&
p1[0] != 0 &&
p1[1] != 0 &&
p1[2] != 0)
{
m_bmShip.UnlockBits(bmData);
m_bmPlanets.UnlockBits(bmData2);
return true;
}
p += 3;
p1 += 3;;
}
p += nOffset;
p1 += nOffset;
}
}
m_bmShip.UnlockBits(bmData);
m_bmPlanets.UnlockBits(bmData2);
return false;
}
所以现在我们先进行矩形测试,然后测试此功能,如果得到(So now we do our rectangle test first, then test this function, and if we get a) true
对于这两者,我们都结束了比赛.一个消息框通知我们我们的得分,然后当我们关闭得分时,游戏将再次开始,并且以新的模式重新生成星空.(for both, we end the game. A message box informs us of our score, and then when we close that, the game starts again, with the star field regenerated in a new pattern.)
这不是很令人兴奋(目标受众是我的5岁女儿),但是它实现了我的个人目标,即给我借口编写更多的C#代码,并且希望我在此过程中涉及的主题引起了我的兴趣.一些CPians.我在硬盘驱动器上的某个地方有一个使用DirectX的Asteroids游戏,我将对其进行挖掘并编写一些相关内容,以便进行比较.考虑到这些东西不是C#的目的,这并不是一个公平的选择,而且我不知道没有DirectX的C ++会有更好的表现.我想说C#借助于GDI +的集成使编写起来更容易,这为我们做了很多工作.(It’s not very exciting (the target audience was my 5 year old daughter), but it achieved my personal goal of giving me an excuse to write some more C# code, and hopefully the topics I’ve covered along the way have been of interest to some fellow CPians. I have an Asteroids game using DirectX on my hard drive somewhere, I will dig it up and write something about it so that a comparison can be made. It’s hardly a fair one, given that this stuff is not what C# is for, and I don’t know that C++ without DirectX would have fared that much better. I’d say C# made this easier to write by virtue of the integration of GDI+ which did a lot of the work for us.)
历史(History)
- 17(17)日(th)2002年4月:初始版本(April, 2002: Initial version)
执照(License)
本文没有附带任何明确的许可,但可能在文章文本或下载文件本身中包含使用条款.如有疑问,请通过下面的讨论区与作者联系.可以找到作者可能使用的许可证列表(This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.A list of licenses authors might use can be found) 这里(here) .(.)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# Windows .NET .NET1.0 Visual-Studio Dev 新闻 翻译