暗夜魔王(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/night-stalker-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 18 分钟阅读 - 8818 个词 阅读量 0暗夜魔王(译文)
原文地址:https://www.codeproject.com/Articles/54688/Night-Stalker
原文作者:Christ Kennedy
译文由本站 robot-v1.0 翻译
前言
A C# game using Sprite-Editor graphics, way-points for AI controlled characters, and a mini-map collision detection scheme.
一个使用Sprite-Editor图形,AI控制角色的航路点以及迷你地图碰撞检测方案的C#游戏.
介绍(Introduction)
美泰公司Intellivsion控制台的原始<暗夜魔王>游戏很棒!我一直玩到划桨破裂为止,这是我第二次重新创建游戏,首先是在Visual Basic 6.1中使用图片框为角色设置动画,现在在C#中使用(The original Night Stalker game for Mattel’s Intellivsion console was awesome! I played that until the paddles broke, and this is the second time I’ve recreated the game, first in Visual Basic 6.1 using picture boxes to animate the characters, and now in C# using the) 精灵编辑器(Sprite Editor) 在我以前的一篇文章中进行了介绍.这次,我为创建游戏的精灵花了些自由,并为地狱而修改了地图,但本质上还是相同的游戏.(described in one of my previous articles. This time, I’ve taken some liberty in creating the sprites for the game, and have modified the map just for the hell of it, but it’s still essentially the same game.) 关于编码,程序员可能会发现有趣的航路点方案,该方案告诉AI人物如何使用表从地图的一端到达另一端,而不是每次都计算路径以提高性能.还有一个专门用于碰撞检测的小型地图.(With respect to coding, programmers might find interesting the way-points scheme which tells the AI-characters how to get from one end of the map to another using a table rather than calculate the path every time, in order to boost performance. There’s also a miniaturized map used exclusively for collision detection.) 因此,如果您只想回想一下旧的收藏夹,请查看此内容,但是如果您认为路标和迷你CD-map可以帮助您的代码,那么您就有理由同时做这两个事情.(So, if all you want to do is reminisce about an old favourite, have a look at this, but if you think way-points and a mini CD-map can help your code, then you have an excuse to do both.)
原本的(The Original)
Intellivision的Night Stalker具有一定的关注度,部分原因是游戏的黑暗本质和令人心动的心跳音效影响了听觉范围内的每个人,而且其原因很简单,那就是它是一款出色的游戏.由"机器人专家"的史蒂夫`蒙特罗(Steve Montero)设计和编程,他很自然地编写<暗夜魔王>,因为游戏的主要对手都是机器人.基本原理是:您被困在迷宫中,并且机器人不断出现杀死的人越多,杀人的人数就越多,他们越能猎杀您.同时,您只有6个射手,但您必须打猎迷宫才能重新装弹,并保持步伐随时都有蝙蝠和蜘蛛来补充攻击者的脚步,尽管它们除了使您入睡外什么也不做,但最好还是让自己醒一会儿.(Intellivision’s Night Stalker had a bit of a following, partly due to the dark nature of the game and the eerie heartbeat sound-effect which affected everyone within hearing distance, but also for the simple reason that it was a great game. Designed and programmed by Steve Montero who “is an expert on robotics, it was natural for him to program Night Stalker because the game’s main antagonists are all robots. The basics are this: you’re stuck in a maze, and robots keep appearing out of a robot nest. The more you kill, the more there are, and the better they get at hunting you. Meanwhile, you have nothing but a six-shooter, but you have to hunt the maze in order to reload, and the pace never lets up. There are bats and a spider to complement the array of attackers at your heels, and though they do nothing but put you to sleep, it’s best if you stay awake just a little while longer.)
杰西卡兔子介绍(Introducing… Jessica Rabbit)
我决定使用上面提到的Sprite-Editor来创建一组新的字符,而不是使用我当时认为很棒的旧图形.玩家的角色就是杰西卡兔子(Jessica Rabbit),这是您最喜欢的,而且永远性感.我们可以编造一个故事,讲述罗杰
兔子(Roger Rabbit)的照片,这是杰西卡(Jessica)捣毁他的唯一方法,但是我当地的图书馆没有(Instead of using the old graphics, which I thought were amazing at the time, I decided to create a new set of characters using the Sprite-Editor mentioned above. The player’s character is none-other than your favourite, and always sexy, Jessica Rabbit. We could make up a story about how Roger Rabbit’s been framed, and this is somehow the only way for Jessica to bust him out, but my local library didn’t have a copy of)谁陷害了Roger Rabbit?(Who Framed Roger Rabbit?),所以我没有得到任何声音,尽管我可以尝试YouTube,但我们只能以此为由将罗杰(Roger)留在家里而带走杰西卡(Jessica).无论如何,他总是第三轮.(, so I didn’t get any sound-bytes, and though I could have tried YouTube, we’ll just call that an excuse to leave Roger at home and take Jessica out instead. He was always a third wheel anyway.)
除了新角色,以及玩家和劣等角色可以对角射击这一事实之外,这几乎完全是我记得的方式.因此,继续尝试(Aside from the new characters and the fact that the player and the badder baddies can shoot diagonally, it’s pretty much exactly the way I remember it. So go ahead, and try)不(not)玩的开心.(to have fun playing it.)
代码(The Code)
什么是航点?:(What’s a Way-Point?:)基础(The Basics)
航点的概念是我在一篇名为(The idea of way-points is one that I’ve described in passing in an article called) 战地模拟器(Battlefield Simulator) ,但不包括任何源代码以及在此提到的粗略提及.根据维基百科,航路点是"路线上任何可以轻松识别的映射参考点”.我们将继续讨论,因为这在这里意味着几乎相同的事情.由于此游戏完全在一个不变的地图上进行,因此程序员可以在设计时创建这些路点.对于这个特定的游戏,由于地图相对较小,也许使用航路点有点过分.但是,当您处理巨大的地图时,需要实时沿着正确的路径显示角色,因此,航点是实现此目标的一种方法.(, but did not include any source code along with the cursory mention made there. A way-point, according to Wikipedia, is “any mapped reference point on a route that can be easily identified”. We’ll go with that because it means just about the same thing here. Since this game is played out entirely on a single unchanging map, these way-points can be created by the programmer at design time. For this particular game, perhaps the use of way-points is a bit of an overkill since the map is relatively small. However, when you’re dealing with huge maps and you need to get your characters along a correct path in real-time, way-points are one means by which this can be achieved.)
什么是航点?:(What’s a Way-Point?:)核心(The Core)
暗夜魔王使用三个不同的地图,都反映了相同的迷宫.第一个是玩家在屏幕上看到的,而第二个是专用于图形输出的,而第二个是航点图,用于明确创建航点数据库.看航点图,(Night Stalker uses three different maps that all reflect the same maze. The first one is the one the player sees on the screen, and that one is used exclusively for graphics output, while the second one is the way-points map which is used for the express purpose of creating the way-points database. Looking at the way-points map,)MapsWP.png(MapsWP.png),包含在源代码的resource目录中,您会看到它看起来像是游戏地图的黑白版本,带有一些黄线和一些红点.然后,如果放大图像,您可能会注意到最左上的像素与红点的颜色相同,并且其旁边的像素与墙的颜色相同.这是因为这两种颜色用于标识构成墙壁的红色航路点和黑色僵局.(, included in the source-code’s resource directory, you’ll see that it looks like a black and white version of the game map, with some yellow lines and a few red dots. Then, if you zoom in on the image, you might notice that the top left-most pixel is the same color as the red dots, and the pixel next to it is the same color as the walls. That’s because these two colors are used to identify the red-colored way-points and the black-colored impasse points that make up the walls.) 此时,航点仅存在于图像上,必须通过首先扫描整个位图将其转移到内存中,直到我们找到所有红点并在游戏中拥有所有航点的完整阵列.接下来,在开发阶段运行的"重建航路点"算法搜索每个航路点的相邻航路点,并创建一个在给定预定范围内的所有邻路的列表,并将其保留在下面定义的结构类型的单独数组,并适当地称为" neaghbours":(The way-points exist, at this point, solely on an image, and must be transferred into memory by first scanning the entire bitmap until we’ve found all the red dots and have a complete array of all the way-points in the game. Next, the ‘rebuild way-points’ algorithm, which is run during the development stage, searches for each way-point’s neighboring way-points, and creates a list of all neighbors which are within a given pre-determined range, keeping these in a separate array of a structure type defined below, and called, appropriately enough, ‘neaghbours’:)
public struct udtShortestPathToWayPoint
{
public classWayPoint wp;
public int index;
public string strPath;
}
有了这些信息,AI角色就可以找到自己的航路点,并知道通往任何相邻航路点的路径.而且,由于AI角色制定的所有旅行计划都参考一个航路点,因此他们真正需要知道的是,当他们想要做的事情到达地图的另一侧时,下一个要拜访的邻居.这里的问题是,尽管他们知道从底特律到安阿伯的交通方式,但是即使他们只需要继续开车,他们也不一定知道如何前往杰克逊.因此,他们没有去任何地方,而是坐在汽车里试图决定是否应该去温莎,安阿伯或庞蒂亚克,因为他们不知道从底特律到杰克逊的路.(With this information, the AI-characters can find themselves at a way-point, and know the path to any of the neighboring way-points. And, since all travel plans made by the AI-characters are with reference to a way-point, all they really need to know is which neighbor to visit next when what they want to do is get somewhere on the other side of the map. The problem here is that though they know how to get from, say Detroit to Ann Arbor, they don’t necessarily know how to get to Jackson, even though they only have to keep driving. So, instead of going anywhere, they sit in their car trying to decide whether they should go to Windsor, Ann Arbor, or Pontiac, because they don’t know which way to Jackson from Detroit.)
现在,如果您只拥有告诉您如何从一个城镇到邻近城镇的本地地图,并且想要穿越整个国家,那么您将需要一个表格,您可以在其中交叉引用您的城镇名称在表的顶部边缘插入您想要前往的城镇名称,并沿着表的侧边缘读取您要前往下一个城镇的名称.就像您现在在地图上找到的那些表格一样,它们告诉您两个城市之间的距离,而不是您要行驶的英里数(Now, if all you had were local maps that told you how to get from one town to the neighboring towns, and you wanted to cross the country, then you’d need a table in which you could cross reference the name of the town you’re in along the top edge of the table with the name of the town you want to go to along the side edge of the table, and read the name of the town you need to get to next. It would be like those tables you find on maps now that tell you the distance between two cities, but instead of the number of miles to travel from)**一种(A)**至(to)乙(B),它将告诉您现在所处的位置.(, it would tell you where to go from wherever you are now.)
包含在(The integer values contained in the) nextWPTable[,]
Night Stalker中的array引用当前航路点的邻居列表的索引.考虑从(array in Night Stalker refer to the indices of the current way-point’s neighbor list. Consider the code taken from) classRobot()
暗夜魔王(Night Stalker)游戏中的机器人,机器人需要沿着其到达最终目的地的路线找到正确的航路点的路径.(of the Night Stalker game where the robot needs to find the path to the correct way-point along his route to his final destination.)
if (udrMove.WPnext != udrMove.WPtarget)
{
udrMove.strPath += udrMove.WPnext
.neaghbours[
cLibWPs.nextWPTable[udrMove.WPnext.index,
udrMove.WPtarget.index]
].strPath;
classWayPoint WPNext
= udrMove.WPnext.neaghbours[
cLibWPs.nextWPTable[udrMove.WPnext.index,
udrMove.WPtarget.index]
].wp;
udrMove.WPfrom = udrMove.WPnext;
udrMove.WPnext = WPNext;
}
此示例代码演示了对该表的两个引用.第一个设置在" N"," E"," S"," W"方向上描述的路径,这些路径列在名为(This sample code demonstrates two references to the table. The first sets the path described in the “N”, “E”, “S”, “W” directions, listed in a string field called) strPath
.的(. The) WPnext
的领域(field of the) udrMove
结构是类型(structure is of type) classWayPoint
并且使用从获得的索引来引用此路点的邻居列表(and this way-point’s neighbors list is being referenced using an index gotten from) nextWPTable[,]
使用(using) WPnext.index
(((the) WPs[]
我们正在查看的航路点的数组索引)作为二维数组的列组件,并且(array index of the way-point we’re looking at) as the column component of the 2-dimensional array, and) WPtarget.index
(目标航路点在((the destination way-point’s index in the) WPs[]
数组)作为同一二维的行组件(array) as the row component for the same 2-dimensional) nextWPTable
.该字符串告诉机器人要逐个像素移动到最终目标目的地的下一路点的路径.(. This string tells the robot what path to travel, pixel-by-pixel, to get to the next way-point along its way to the ultimate target destination.)
第二参考设置了一个临时(The second reference sets a temporary) WPNext
到沿该路线的同一中间路线点(现在将成为该路线点),此机器人将沿此代码位使用后续路线.(to the same intermediate way-point along the route which will now be the way-point, subsequent passes along this bit of code for this robot will use.)
为帮助阐明概念,请看下面的图像,该图像显示了6x6示例表中两条路径1-4-5和2-3-6所需的条目.请注意,尽管Night Stalker中的条目是整数值,它对应于当前航路点的邻居列表中的索引(角色下一个航路点需要经过该航路点才能到达某个最终目的地),该示例使用进一步简化示例的方法的"名称".(To help clarify the concept, have a look at the image below which shows the entries needed for the two paths 1-4-5 and 2-3-6 in the 6x6 example table. Note that though the entries in Night Stalker are integer values corresponding to the index (of the next way-point through which the character needs to travel on its way to some final destination) in the current way-point’s neighbors list, this example uses the ‘name’ of the way-points to further simplify the example.)
蓝色示例始于WP#1,并想转到WP#5,因此AI查看表条目(1,5)并读取'4',这意味着它首先必须经过WP#4在通往#5的途中.然后,当在WP#4上时,AI将目标对象(5)与当前(4)进行交叉引用,并查看表条目(4,5)以读取'5’是下一个也是最后一个航路点.类似地,对于从2开始并想要达到6的橙色示例,AI看着(2,6)并读取'3',然后看着(3,6)并读取'6'.(The blue example starts at WP #1, and wants to go to WP #5, so the AI looks at the table entry (1,5) and reads ‘4’, which means that it will first have to travel through WP #4 on its way to #5. Then, when on WP#4, the AI cross references current (4) with target (5), and looks at table entry (4,5) to read that ‘5’ is the next and final way-point. Similarly, for the orange example which starts at 2 and wants to get to 6, the AI looks at (2,6) and reads ‘3’, then looks at (3,6) and reads ‘6’.)
迷你碰撞检测图(Mini Collision Detection Map)
如上所述,“暗夜魔王"碰撞检测方案完全在游戏地图的小型化上运行.原始地图已使用算法进行了小型化,该算法对主地图的5x5区域中像素的颜色求平均,然后将单个像素设置为该原始地图中最重要的颜色.这是在创建输出图形图之前用墙壁的黑白图完成的,因此迷你图主要由黑白像素组成.我之所以这么说,主要是因为还有其他碰撞颜色可用来增强游戏的色彩,但最简单的观察方法是黑白,我将进一步详细解释其他颜色.(As briefly described above, the Night Stalker collision detection scheme runs entirely on a miniaturization of the game map. The original map has been miniaturized using an algorithm which averages the colors of the pixels in a 5x5 region of the main map and then sets a single pixel to the most important color in that original map. This was done with a black and white map of the walls before the output graphics map was created, so the mini map consists mostly of black and white pixels. I say mostly because there are other collision colors that are used to heighten the game, but the simplest way to look at it is black and white, and I’ll explain the other colors in more detail a little further on.) 小型化碰撞检测图的概念在进行逐像素的碰撞测试时利用了较小比例的像素数量减少的优势,从而大大加快了碰撞测试的速度.结果是最多可以减少大约五个像素,这对于该游戏来说是可以接受的.由于所有AI角色都在路径点之间沿轨道行进,因此唯一需要检测的墙碰撞是子弹对象和玩家角色.为此,创建包含对象描述的结构,碰撞检测算法可以理解该结构.(The concept of a miniaturized collision detection map takes advantage of the smaller scale’s diminished number of pixels in doing pixel-by-pixel testing for collisions, thus accelerating the collision tests considerably. The result is an approximation up to five pixels off, which was deemed acceptable for this game. Since all the AI characters march along rails between way-points, the only wall collisions that need detection are bullets objects and the player character. To do this, a structure containing a description of the object is created that the collision detection algorithm can understand.)
public struct udtCDInfo
{
public Size sz;
public Point ptRelPos;
}
尺寸字段((The size field () sz
)以像素为单位描述在小型碰撞检测图中要表示的物体的大小,以及点场(() describes, in pixels, how large the object is to be represented in the miniaturized collision detection map, and the point field () ptRelPos
)描述了对象中心相对于此矩形左上角的位置(() describes the position of the object’s center relative to the top left corner of this rectangle () sz
).这是一个典型的例子:(). Here’s is a typical example:)
udrCDInfo.ptRelPos = new Point(4, 4);
udrCDInfo.sz = new Size(7, 14);
将杰西卡(Jessica)的中心放在大小(7,14)的矩形上的(4,4).在运行调试器时查看这些的选项位于(which places Jessica’s center at (4,4) on a rectangle of size (7,14). The options to view these while running the debugger are in the) formNightStalker
的:(’s:)
public formNightStalker()
功能,包括在下面:(function, and are included here below:)
/// debug start
cLibCD.bolDrawCDInfo =
System.IO.Directory.GetCurrentDirectory().ToUpper().Contains("DEBUG");
//mnuDebug.Visible = System.IO.Directory.GetCurrentDirectory()
// .ToUpper().Contains("DEBUG");
if (false && cLibCD.bolDrawCDInfo)
cLibCD.drawCDOnMap(ref bmpMap);
/// debug end
哪里(where) cLibCD.bolDrawCDInfo
在所有子弹,机器人和杰西卡周围绘制黄色矩形,而对(draws yellow rectangles around all bullets, robots, and Jessica, while the call to) cLibCD.drawCDOnMap(ref Map)
绘制黄色的5x5像素小方块,迷你方块上会出现碰撞方块(draws small yellow 5x5 pixel squares where collision squares appear on the mini) bmpCD
地图.(map.)
军鼓和掩体克星(Snares and Bunker Busters)
其他颜色(The other colors which the) CDmap
其中包括” nares",仅在杰西卡从蝙蝠或蜘蛛入睡后醒来一段时间后"昏昏欲睡"之后,才会在短时间内引起碰撞.这些被涂成"绿色"(includes are for ‘snares’ which only cause collisions during a brief period after Jessica has woken up from having been put to sleep by the bats or spider and is ‘groggy’ for a time. These are painted ‘green’ by the) drawCDOnMap()
功能.(function.)
这是CD地图的局部放大图.(Here’s a zoomed partial view of the CD map.)
创建和使用这种碰撞检测方案的唯一真正困难是写出"地堡破坏者"子弹,其中子弹越高越致命,这会对杰西卡开火.我不确定该怎么做,但后来决定使用单独的颜色来描述掩体的碰撞像素.他们可以在(The only real difficulty in creating and using this collision detection scheme was in writing the ‘bunker-buster’ bullets, the higher up and more deadly of which fiends fire at Jessica. I wasn’t sure how I was going to do this, but then decided on using separate colors to describe the bunker’s collision pixels. They can be seen in the)**光盘(bmpCD)**文件包含在游戏的资源目录中.在开始新游戏时,将在游戏时CD映射中写入该位图的新副本.查看小型地图,您会看到沙坑的左,下和右墙都是灰色的深色阴影,沙坑的内部是较浅的灰色阴影.浅色内部阻止所有子弹穿过,但不阻止杰西卡四处移动.灰色的深色阴影阻止了杰西卡从侧门逃脱,迫使她从掩体顶部的"屋顶"退出.(file contained in the game’s resources directory. At the start of a new game, the game-time CD map is written over with a fresh copy of this bitmap. Looking at the mini-map, you’ll see that the bunker’s left, bottom, and right walls are all a dark shade of grey, with the inside of the bunker a lighter shade of grey. The light colored interior blocks all bullets from travelling through, but do not block Jessica from moving around. While the dark shade of grey prevents Jessica from escaping through a side door, forces her to exit through the ‘roof’ at the top of the bunker.)
然后,当最坏的敌人带着炸弹般的子弹将杰西卡从洞中撞出时,必须摧毁掩体.为此,碰撞检测首先检测出掩体和掩体之间的碰撞,然后调用该函数(Then, when the badder meanies come around with bunker-buster bullets to knock Jessica out of her hole, the bunker must be destroyed. To do this, the collision detection first detects a collision between a bunker-buster and the bunker, then it calls the function) damageBunker()
.(.)
DamageBunker()
就是一切发生的地方.的(is where it all happens. The)**资源(resources)**该目录包含一个微型掩体图像,一个游戏大小的掩体图像,并且在运行时,我们具有微型CD映射的bmpCD副本.在开始时(directory has a mini bunker wall image, a game-sized bunker image, and at run-time, we have a bmpCD copy of the mini CD map. At the start of) damageBunker()
,损坏的位置是已知的,因此剩下要做的就是实际损坏掩体.这很容易:在发生碰撞的地方填充一个预设大小的白色椭圆,然后继续前进.(, the location of the damage is known, so the only thing left to do is to actually damage the bunker. This is quite easy: fill a white ellipse of some preset size on the spot the collision occurred, and move on.)
但是,如果这样做,它将不会向玩家显示杰西卡在遭受所有伤害后仍留在掩体中的危险程度.因此,真正的问题在于向玩家显示沙坑被摧毁了.为此,我们首先将bmpCD地图的掩体剪切到一个临时的位图上,该图太宽2个像素,又太高2个像素.然后,因为我们需要从损坏的沙坑(从先前的打击中损坏)的剩余部分中创建遮罩,因此我们必须制作墙壁(But if you do that, it won’t demonstrate to the player how much danger Jessica is in if she remains in her bunker after all the damage it has incurred. So, the real problem is in showing the player that the bunker is being destroyed. To do this, we first cut out the bmpCD map’s bunker onto a temporary bitmap, 2 pixels too wide and 2 pixels too tall. Then, because we need to create a mask out of what is left of the damaged bunker (damaged from a previous hit), we have to make the walls)和(and)内部是纯色均匀的颜色.但是,如果墙壁(深灰色)已损坏,则一次充水并不能保证洪水会填满损坏的掩体墙的全部剩余物.因此,为确保此泛洪填充操作捕获到墙壁的断开连接的片段,我们从迷你bmpCD上切出的整个临时副本周围绘制了一个像素宽度的边框,该边框的颜色与墙壁相同(深灰色).游戏地图.然后,我们进行泛洪填充以将深灰色的墙壁着色为内部的较浅灰色,然后将其重新复制为较小的位图(较窄的2像素和较短的2像素),除了迷你掩体外,其他都没有损坏,但现在颜色一致.(the interior a solid uniform color. But, if the walls (dark grey) have been damaged, then a flood-fill at one point does not guarantee that the flood will fill the entirety of what remains of the damaged bunker’s walls. Therefore, to guarantee this flood fill operation catches the disconnected fragments of the walls, a one-pixel wide border of the same wall-color as the walls (dark grey) is drawn around the whole temp copy we just cut out from the mini bmpCD game map. Then, we do a flood-fill to color in the dark-grey walls to the lighter grey color of the interior, and recopy this to a smaller bitmap 2-pixels narrower and 2-pixels shorter, with nothing but the mini bunker, damaged, but now of uniform color.)
现在,知道发生了碰撞的地方,我们通过在该位置填充白色椭圆,为损坏的"白色"着色,在此复制且统一的彩色地图上对当前子弹造成的伤害.(Now, knowing where the collision has occurred, we do the current bullet’s damage on this copied and uniform colored map, by filling a white ellipse at that location, coloring the damage ‘white’.)
现在需要使用此掩体有两个原因:(This bunker now needs to be used for two reasons:)
- 作为创建较大遮罩的来源,该遮罩将在损坏的沙坑所在的位置放置一个白色"孔".(As the source to create a larger mask which will put a white ‘hole’ where the damaged bunker is.)
- 作为miniCD掩体墙上的遮罩,我们需要重新绘制将Jessica挡在掩体中的碰撞墙,然后再将这个微型掩体图像粘贴回我们用于所有墙壁碰撞的微型CDmap上.(As a mask over the miniCD bunker walls, which we’ll need to redraw the collision walls that bar Jessica inside the bunker, before pasting this mini-bunker image back onto the mini CDmap we’re using for all our wall-collisions.)
让我们看第一个问题:让玩家看到伤害.我们有一个损坏的沙坑的小型,均色图像.首先将其调整为游戏大小,然后逐像素进行扫描,对于描述未损坏掩体的每个浅灰色像素,游戏大小掩体的遮罩位图会(Let’s look at the first problem: letting the player see the damage. We have a miniaturized, uniform-colored image of the damaged bunker. To first resize it to game-size, it is scanned pixel-by-pixel, and for each light-grey pixel that describes un-damaged bunker, the mask bitmap of a game-sized bunker gets a new)
fillRectangle
画在上面.只要整个蒙版位图使用相同的颜色,该填充矩形可以是任何颜色,我将其称为"(drawn onto it. This fill rectangle can be of any color as long as the entire mask bitmap uses the same color, which I’ll call ‘)clrBunkerInterior
' 这里.然后,当此位图完成时,它将调用(’ here. Then, when this bitmap is complete, it calls)MakeTransparent()
一样的(with the same)clrBunkerInterior
颜色替换默认的"白色",使该浅灰色颜色透明,以便随后在完整的,未损坏游戏尺寸的地堡图像的副本上绘制颜色时,仅绘制白色,并且我们可以进行以下游戏:大小的损坏的掩体图像.(color to replace the default ‘white’, making this light-grey color transparent so that when it is subsequently painted over top of a copy of the complete undamaged game-sized bunker image, only the white gets drawn, and we have a game-sized image of the damaged bunker.) 在每个游戏周期的动画调用过程中,此游戏大小的损坏的掩体图像都以白色作为透明颜色透明,因此我们只能看到剩下的东西,而白色的"孔"使Jessica可以从墙上的任何孔中逸出.您可以在下面的代码摘录中看到这一点:(This game-sized damaged bunker image is made transparent with white as the transparent color, during every game-cycle’s animation call, so that we only see whatever is left, and the white ‘hole’ allows Jessica to escape through any holes in the walls. You can see this in the code excerpt below:)
// resize the CD-bunker image to real-map size (5x bigger)
Bitmap bmpRealMask = new Bitmap(cLibHelper.bmpBunker.Width,
cLibHelper.bmpBunker.Height);
SolidBrush brsClrDoor = new SolidBrush(clrBunkerDoor);
SolidBrush brsWhite = new SolidBrush(Color.White);
using (Graphics g = Graphics.FromImage(bmpRealMask))
{
g.FillRectangle(brsWhite,
new Rectangle(0,
0,
bmpRealMask.Width,
bmpRealMask.Height));
for (int intX = 0; intX < bmpCDBunker.Width ; intX++)
for (int intY = 0; intY < bmpCDBunker.Height ; intY++)
if (bmpCDBunker.GetPixel(intX, intY) == clrBunkerDoor
|| bmpCDBunker.GetPixel (intX, intY) == clrBunkerWalls)
g.FillRectangle(brsClrDoor,
new Rectangle((intX) * 5,
(intY ) * 5,
5,
5));
else
g.FillRectangle(brsWhite,
new Rectangle((intX ) * 5,
(intY ) * 5,
5,
5));
}
// make the bunker-door color transparent
bmpRealMask.MakeTransparent(clrBunkerDoor);
using (Graphics g = Graphics.FromImage(cLibHelper.bmpBunker))
g.DrawImage(bmpRealMask, new Point(0, 0));
将损坏的墙壁绘制到微型地图上需要用透明版本的均匀颜色的微型损坏的掩体遮盖微型墙壁,并将其复制到未损坏的微型墙壁图像的顶部,以仅绘制白色的(损坏的部分)在墙上的沙坑.然后,将损坏的墙壁图像复制到损坏的沙坑上方,然后再粘贴到小型bmpCD贴图上.(Drawing the damaged walls onto the mini map requires that the miniature walls be masked with a transparent version of the miniature damaged bunker of uniformed color and copying this over top of the undamaged mini-walls image to draw only the white (damaged part) of the bunker over the walls. Then, the damaged walls image is copied over top of the damaged bunker before being pasted onto the mini bmpCD map.)
装载机锁?没问题(Loader Lock? Not a Problem)
我不确定如何处理"(I’m not sure how to deal with the ‘) LoaderLock
每次我运行使用DirectX音频的项目时,调试器都会坚持警告我,但是启动该项目后第二次按F5键可以清除该问题,而可执行文件则不会发出任何问题.显然,有一种方法可以让您的C#项目忽略该加载程序锁定警告,但我还没有找到它.(’ issue which the debugger insists on warning me about every time I run a project that uses DirectX audio, but pressing F5 a second time after launching the project clears that up, and the executable makes no issue of it. Apparently, there’s a way to tell your C# project to just ignore this loader-lock warning, but I haven’t found it yet.)
杰西卡不好?她说她就是那样被吸引的!(Jessica bad? And she said she was just drawn that way!)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# Windows DirectX Dev 新闻 翻译