P.T.M.C:景观与矿山(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/p-t-m-c-landscape-mines-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 22 分钟阅读 - 10851 个词 阅读量 0P.T.M.C:景观与矿山(译文)
原文地址:https://www.codeproject.com/Articles/5248224/P-T-M-C-Landscape-Mines
原文作者:Christ Kennedy
译文由本站 robot-v1.0 翻译
前言
2D shooter inspired by Descent - rotating screen, network of tunnels, multiple robots & weapons - map editor
受Descent启发的2D射击者-旋转屏幕,隧道网络,多个机器人和武器-地图编辑器
- 下载PTMC_2019_20191012.zip-4 MB(Download PTMC_2019_20191012.zip - 4 MB)
- 下载PTMC_Terra_Start.mp4-9.1 MB(Download PTMC_Terra_Start.mp4 - 9.1 MB) 资料档案(data files) -从我的Google云端硬盘下载数据文件,然后扩展到C:\根目录(- download data files off my GoogleDrive and expand onto C:\ root directory) 更新:(update :)2019/10/12-源代码-越野车编辑器稍微好一点(2019/10/12 - source code - buggy Editor somewhat better)
太平洋时间(P.T.M.C.)
P.T.M.C.是360°游戏系列的一部分(The P.T.M.C. is part of the 360° game series) 血统(Descent) 它将您带入装有武器的PyroGX船上,可以随时沿三个旋转轴中的任何一个旋转您.这是一场摇滚乐的正义游戏^但我经常考虑该游戏的许多"假设".具体地说,如果"下降"游戏世界由可以随意选择探索的太阳系组成.从地雷飞到地雷,从月球飞向月球,从行星飞向小行星?如果这是一个大型多人游戏宇宙怎么办?如果您必须像在<帝国时代>游戏中那样建立并捍卫自己的资源,而又仍然可以随时选择以第一人称射击模式来控制棋盘上的任何单位,该怎么办?买,卖,交易还是偷?扮演商人,佣兵,海盗或军阀的角色?(which puts you inside a PyroGX ship loaded with armaments ready to spin you along any of the three axes of rotation. Its a rockin’ righteous game … but I’ve often considered many ‘what ifs?’ about that game. Specifically, what if the Descent game-world consisted of the solar system that you could choose to explore at your own will. Fly from mine to mine, moon to moon, planet to asteroid? What if it were a massive-multiplayer universe? What if you had to build and defend your resources like in the Age of Empires games while still having the option to take control of any unit on the board in a 1st person shooter mode at any time? Buy, sell, trade or steal? Play the role of a merchant, mercenary, pirate or warlord?) 好吧,您可能会问,这里提供的是什么吗?(Well, you may ask, is that what is on offer here?)
不…很不幸对于我这样的人来说,这是一个太大的项目.(No… unfortunately. That would be much too big a project for the likes of me.) 太平洋时间是我之前发布但之前十年未完成的项目的翻版(P.T.M.C. is a re-make of a previous project I published but never completed almost ten years ago called) 火星任务(Mars Mission) .看看那些文章,因为它们仍然很酷.火星任务的概念非常简单,构建太阳系的2D模型并让玩家随意探索.它具有必须收集并转化为燃料的大气化合物形式的资源.所有已知的行星和卫星都可以使用随机生成的单路径隧道进行探索.您控制着四处走动,执行EVA并飞船的宇航员.我有矿产资源计划,卫星通信计划以及最终针对恶意机器人的格斗游戏的计划,但是在完成它之前,我已经离开了我的计算机约有七年的时间,当我回到计算机上时,我决定进行一次彻底的重写.(. Have a look at those articles because they are still pretty cool. The Mars Mission concept is pretty simple, build a 2D mock-up of the solar-system and let the player explore it at will. It has resources in the form of atmospheric compounds that must be harvested and converted into fuels. All the known planets and moons are there to explore with randomly generated single path tunnels. You control astronauts who walk around, perform EVAs and fly your ship. I had plans for mineral resources, satellite communications and ultimately a fighter game against malicious robots but I was taken away from my computer for some seven years before I could complete it and when I got back to it I decided a complete rewrite was in order.) 探索太阳系的新颖性很有趣,但是很快就消失了,因为没有特定的目标,对玩家而言,除了避免撞车或耗尽燃料外,没有真正的挑战.(The novelty of exploring the solar system is fun but soon wears off as there is no specific goal, no real challenge for the player beyond avoiding a crash or running out of fuel.) 这次是第一次进行格斗游戏…(This time around its a fighter game first…) 所以我们在这里(so here we are…)
背景(Background)
我开始从事P.T.M.C.回到四月,洗完手后(I started working on P.T.M.C. back in April, right after washing my hands of the) 拉丁填字游戏(Latin Crossword Puzzle) .工作了几个月,然后花了一些时间(. Worked on it for a few months then took some time to) 刮刮梅里亚姆-韦伯斯特字典(scrape Merriam-Webster’s Dictionary) 并发布该项目.因此,在P.T.M.C.我觉得我已经做了很多事情,还有很多事情要做,我正处在十字路口上,我可以停下来告诉你(总结)到目前为止我所做的一切,然后再继续下一个工作游戏开发阶段.(and publish that project. So, at this point in P.T.M.C. I feel I’ve done so much already and there’s still so much more to do, I’m at a crossroad where I can stop and tell you (in summary) all that I’ve done so far before I move on to the next phase of game development.) 我等了很久才出版此书…它仍在进行中,但是有(I waited a long time before publishing this … its still a work in progress but there is)所以(so)有很多要谈论的是,我无法将所有内容都放在一篇文章中,也不会尝试像某些人一样详尽地解释所有内容.如果您想让我澄清或扩展任何内容,请在底部留下我的评论,我将拭目以待.(much to talk about that I won’t be able to fit it all in one article and will not try to explain everything in as great a detail as some may like. If you want me to clarify or expand on anything just leave me a comment at the bottom and I’ll see what I can do.) 让我们开始吧 …(let’s get started …)
景观(Landscape)
“风景"是游戏世界,玩家在行星或月球的表面范围内四处飞行,而不是绕行星飞行或从行星飞行至其中一颗月亮.与游戏"下降"保持一致,玩家的飞船不受重力的影响.这使玩家具有更大的可操纵性,并且可以解释为先进的自动飞船控制装置的优势,该功能使玩家无需担心在打斗中跌落高度.计划有多种舰船类型,例如在"火星任务"中,其中一些舰船将比其他舰船具有更多的脆弱性,以权衡当前版本尚未探索的其他能力.(The ‘landscape’ is the gameworld where the player is flying around within a planet or moon’s surface area, as opposed to orbiting around a planet or flying from a planet to one of its moons. In keeping with the game Descent, the player’s ship is not affected by forces of gravity. This allows the player more maneuverability and can be explained away as the benefit of advanced automated ship’s controls that give the player the luxury of not worrying about dropping altitude while in a dog fight. There are plans for multiple ship types, like in Mars Mission, where some ships will have more vulnerabilities than others as a trade off for other capabilities which the current version does not yet explore.)
您可以看一下上面的图像,大致了解游戏中地球的外观.左上角附近的方框区域是您的名为Left_HUD的替代屏幕之一,此处显示了船的后视图.您可以在此图像的底部中心更好地查看您的船,因此您有足够的空间可以看到前面的空间.云是地标的示例,这些地标是在游戏/机器人发射之前或之后绘制的动画精灵,使它们成为前景或背景.下面列出的枚举类型为您提供了一个思路:(You can look at the image above and get a general idea of what the earth’s surface looks like in the game. The square framed region near the top left is one of your alt-screens called Left_HUD that here shows the ship’s rear-view. You can get a better look at your ship at the bottom center of this image so you have plenty of room to look in front of you. The clouds are examples of landmarks which are animated sprites that are drawn either before or after the play/robot ships making them either foreground or background. The enumerated type listed below gives you an idea :)
public enum enuLandmarkType
{
CautionRadiation,
Clouds00,
Clouds01,
DangerLookOut,
ElectricalHazardSign,
FanBlack,
GrillEnd,
Lava,
LavaEnd,
WaterFlow,
ConveyorBelt_Rocks,
BiohazardSymbol,
_num
};
这些只是我到目前为止所包括的.他们是精灵,所以他们依靠(These are just the ones I’ve included so far. They’re sprites, so they rely on the) classSprite
你可以在我的(which you can see in my) 精灵编辑器(SpriteEditor) 文章.所有的船只都是精灵,还有爆炸,UI闪光和导弹.(article. All the ships are sprites, as well as explosions, UI flashes and missiles.)
这是一项正在进行中的工作,因此仍然存在一些问题,例如在玩家位于地面上方时绘制不应在地面下方绘制的东西,例如在洞穴开口上方上方图像中绘制的机器人孵化器正好向地面播放器的Energy HUD显示屏的左侧,但其稳定性足以播放和编辑地图.我之所以一直推迟撰写本文,是因为总是有其他事情要做^可能总是如此.因此,您现在只需要忍受混乱.(This is a work in progress, so it still has issues like drawing things that are below the surface that shouldn’t be drawn while the player is above the surface, like the Robot Incubator drawn in the image above below the cave opening just to the left of the player’s Energy HUD display, but its stable enough to play and edit maps with. The reason why I kept putting off the writing of this article is because there was always something else to do … as there likely always will be. So you’ll just have to put up with the mess for now.)
当您启动游戏时,您将从矿井的底部开始,需要奋斗. Terran地下并不太复杂,可以单独播放,作为最终产品的预览.飞行时,您的飞船将保留在屏幕底部.默认情况下,“鼠标"是主要界面,船上的环在那里帮助您以与鼠标到船中心之间的距离成比例的速度沿鼠标方向滑动船,从而来回移动零速度).使用旋转手柄旋转并按下鼠标键进行射击.(When you launch the game you start in the bottom of the mine and need to fight your way out. The Terran underground is not overly complicated and can be played on its own, as a preview of the final product. Your ship will remain at the bottom of the screen as you fly around. By default the Mouse is the primary interface and the ring around the ship is there to help you move around by sliding the ship in the direction of the mouse at a velocity proportionate to the distance between the mouse and the ship’s center(the smaller inner ring being zero-velocity). Use the whjeel to rotate and mouse button to fire.)
上下文菜单中有许多选项可供您探索.(Many options are available with the context menu, yours to explore.)
您可以关闭鼠标控件并使用键盘(我的偏好),其中:(You can toggle off the Mouse Controls and use the keyboard(my preference) where :)
其余的键盘控件可以在(The rest of the keyboard controls can be seen in the) formPTMC
的文本框事件处理程序. (A和Z放大/缩小)(’s textbox event handler. (A & Z to zoom in/out))
private void TxtInput_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
#region thrusters
case Keys.NumPad7:
eKeyLastPressed = enuKeyStrokes.Turn_Left_Hard;
break;
case Keys.NumPad9:
eKeyLastPressed = enuKeyStrokes.Turn_Right_Hard;
break;
case Keys.NumPad4:
eKeyLastPressed = enuKeyStrokes.Turn_Left;
break;
的(The) txtInput
文本框在picMain的keyUp事件处理程序的开始处被赋予焦点,并且有时会失去焦点,从而使键盘无用,直到用鼠标单击屏幕为止.当用户使用鼠标或按Alt键将其移动到其他表单,然后单击游戏而不是屏幕时,就会发生这种情况.我在做这个工作.(textbox is given focus at the start of the picMain’s keyUp event handler and can occasionally lose focus rendering the keyboard useless until the screen is clicked with the mouse. This will happen when the user uses the mouse or alt-tabs his way to a different form and then click the game but not the screen. I’m working on it.)
滚动山的定义与我在上述"火星任务"项目中使用的非常相似.在X轴上有相等距离的"单元"或杆,它们实际上确定了该点到达地面的高度.它们的集合一起构成了景观.每个行星或月球都有自己的景观,该景观在(The rolling hills are defined in a way very similar to that which I used in the Mars Mission project mentioned above. There are ‘cells’, or posts really, equi-distant apart on the X-axis that determine how high the ground reaches at that point. The collection of them together make up the landscape. Each planet or moon has its own landscape which is defined in the) classLandscape
.(.)
碰撞检测(Collision Detection)
制作视频游戏时,碰撞检测始终是最主要的问题.火星任务碰撞检测与P.T.M.C.碰撞检测非常出色.(Collision detection is always of primary concern when making video games. The similarities between Mars Mission collision detection and P.T.M.C. collision detection are remarkable.) 它们本质上非常相似:(They’re essentially very similar:)
-
测量对象移动的像元范围(measure the range of cells over which the object is moving)
-
比较(compare the) AABB(AABB) (与轴对齐的边界框)(每个单元格之间的距离)到限制船舶运动的框(对P.T.M.C.而言是新的)((axis-aligned bounding box) of each of those cells(space between posts) to the box that bounds the ship’s motion(new to P.T.M.C.))
-
当这两个AABB碰撞时,使用类似于火星任务的逻辑生成更接近的文本(when these two AABBs collide a closer text is made using logic that is similar to Mars Mission)
-
将要测试碰撞的景观线绕着船舶的起始位置旋转,以便执行数学测试以检验与船舶沿X轴正方向的运动发生碰撞(the line of the landscape being tested for collision is rotated about the ship’s start location so as to perform the mathematical test for collision with the ship’s motion along the positive X-axis)
-
形成一个代表船舶将要行驶的区域的矩形(宽度=行驶的距离和高度=船舶"球形"测试区域的直径)(form a rectangle that represents the region where the ship will travel (width = distance travelled & height = the diameter of the ship ‘ball’ shaped test region))
-
测试以查看检测线是否穿透了船舶运动的矩形(test to see if the detection-line penetrates the rectangle of the ship’s motion)
-
当发生时-计算船舶的挠度和预计的最终位置(when it does - calculate the ship’s deflection & projected resultant end-location)
-
然后,它将当前的碰撞点用作新的起点和新的终点位置,并通过算法再次运行该数据,只要它有能量并最终为您提供最终终点和速度(it then uses the current collision point as a new start & the new end-location and runs that data through the algorithm again bouncing off walls as long as it has energy and giving you a final-final end point & velocity) 因为该算法需要先测试所有墙壁,然后才能决定船舶将首先撞到哪面墙壁(如果有),它会列出所有碰撞的清单,并根据行进距离对它们进行重新排序,然后再次通过算法运行.(because the algorithm needs to test all the walls before it can decide which wall (if any) the ship will hit first, it makes a list of all collision, reorders them according to the distance travelled and then runs it through the algorithm again.) 碰撞检测是整个项目的核心,大约需要两个月的时间才能浮出水面.大部分代码可以在洞穴内转移到相同的概念.由于需要对所有运动的物体进行碰撞测试,因此在(The collision detection is central to the entire project and took about two months to get right on the surface. Most of that code was transferable to the same concept inside the caves. Since everything that moves needs to be tested for collisions the collision detection is performed in the)
classObject
它几乎可以在屏幕上保存所有位置和速度的变量.按下退出键将使游戏进入碰撞检测测试模式(我尚未删除此调试工具).在这里,您可以看到隧道段ID号以及该船从当前位置到鼠标光标一步飞行的最终位置.你可以在这里看到(which holds the location and velocity variables of virtually everything on the screen. Pressing the escape-key will put the game in collision detection test-mode (I have yet to remove this debugging tool). Here you can see the tunnel-segment ID numbers as well as the ship’s resultant position were it to fly in one step from its current location to the mouse cursor. You can see in this) 短片(short video) 它如何蜿蜒穿过隧道.在某些情况下,碰撞检测系统无法在测试过程中检测到应有的碰撞,这可能会有所改善,但游戏中的步长永远不会比演示中最短的测试大,因此在某些情况下后续测试将发现失败,从而将飞船推回原位.因此,玩游戏不会导致灾难性的CD故障.在测试CD时单击屏幕,无论您检测到任何碰撞,都将船只放置在您单击的位置,并且CD调试工具仅在触发MouseMove事件时才测试新碰撞,因此更改缩放或旋转地图不会导致CD测试进行和(how it snakes along through the tunnels. There are instances when the collision detection system fails to detect a collision when it should have during testing and this could be improved but the step size during game time is never as large as any but the shortest tests in the demonstration so those incidences where there is failure are caught by subsequent tests the push the ship back into play. As a result playing the game does not result in catastrophic CD failures. Clicking the screen while testing the CD places the ship wherever you clicked regardless of any collisions being detected and since the CD debugging tool only tests a new collision when the MouseMove Event is triggered, changing the zoom or rotating the map will not cause a CD test to be performed and)出现(appear)无法检测到碰撞.只需稍微移动鼠标,即可执行测试.(to fail to detect a collision. Just move the mouse slightly and the test will be performed.)
//
public bool DetectCollision(ref List<classMoveData> lstMoveData)
//
当玩家接近PowerUp或导弹击中目标时,将使用不同的方法.(When the player approaches a PowerUp or a missile hits a target different approaches are used.)
要检测导弹是否击中目标,必须在(To detect whether a missile hits a target or not is done in the) classMissile
.(.)
classLandscape有一个(The classLandscape has a) classQuadTree_PTMC
我改编自(that I adapted from a) 四叉树(quadtree) 我写了一个较早的项目.它通过在每个时钟周期开始时刷新其内容来跟踪所有内容.这肯定可以改善.之所以可以使用,是因为玩家一次只在一个行星表面上,但是当卫星允许玩家跟踪不同卫星上的高空飞船时,不必要的时间花费在为游戏中的每个行星或月球重建整个QuadTree上花费的时间变得相当可观. ..稍后再说.(I wrote for an earlier project. It keeps track of where everything is by refreshing its content at the start of every clock cycle. This could definitely be improved. It works for now because the player is only on one planetary surface at a time but when satellites allow the player to keep track of alt-ships on different moons the time consumed unnecessaily rebuilding entire QuadTrees for every planet or moon in play may become considerable… that’s for later.)
因此,当导弹在飞行中时,除了洞穴壁或行星表面之外,还需要测试碰撞.为此,它查看QuadTree并测试每个对象在笛卡尔(x,y)领域和隧道中是否都在同一区域中(因为隧道的网络重叠但不一定共享相同的游戏空间) .(So when a missile is in flight it needs to test for collision other than the walls of the caves or the surface of the planet. To do this it looks at the QuadTree and tests whether each object is in the same region both in the cartesian (x, y) realm and the tunnels (because the network of tunnels overlap but don’t necessarily share the same game-space).)
这是在(This is done in the) classMissile
的功能:(’s functions :)
//
public classObject Detect_Collisions_Objects(ref PointF ptfCollision)
{
...
}
//
//
bool DetectCollision_Object_FineTest(ref classObject cObjAlt, ref PointF ptfCollision)
{
...
}
//
游戏计时器在formPTMC中调用以下函数(the game timer call the following function in formPTMC)
void detectMissileCollisions()
{
for (int intMissileCounter = 0; intMissileCounter < cLandscape.lstMissiles.Count; intMissileCounter++)
{
classMissile cMissile = cLandscape.lstMissiles[intMissileCounter];
PointF ptfCollision = new PointF();
classObject cObjectCollidedWith = cMissile.Detect_Collisions_Objects(ref ptfCollision);
if (cObjectCollidedWith != null)
{
classMath3.classRadialCoordinate cRadMissileMotion
= new classMath3.classRadialCoordinate(cMissile.cObj.ptfLocation_Old, cMissile.cObj.ptfLocation);
cObjectCollidedWith.Impact(ptfCollision,
cRadMissileMotion,
cRadMissileMotion.Magnitude * cMissile.cObj.dblMass / cObjectCollidedWith.dblMass);
classMath3.classMinMax cMM = new classMath3.classMinMax(10, 25);
classImpactAnimation.Launch(ref cLandscape,
ref cMissile.cObj.cTS_New,
cMissile.cObj.ptfLocation,
cMath.AddTwoPointFs(cObjectCollidedWith.ptfVelocity,
cRND.Get_Point(cMM, cMM)));
cMissile.Die();
}
}
}
它会扫描所有当前景观的导弹并进行碰撞测试.(It scans through all the current landscape’s missiles and tests for collision.) 当导弹与某物碰撞时,它会返回指向所击中对象的指针,并将碰撞点设置为它所接收的参考变量.有了这些信息,就会发生两件事(When a missile collides with something it returns a pointer to the object it hit, and sets the point of collision to the reference variable it recieves as a parameter. With this information, two things happen)
- 被撞击的物体在(the object that was struck is jolted by the collision in the)
cObjectCollideWith.Impact()
呼叫.(call.) - 屏幕上会在碰撞点放一个"冲击"动画(an ‘impact’ animation is put on the screen at the point of collision) 您可以在下面的代码中看到撞击点和导弹的运动信息如何用于使被击中的物体震撼(you can see in the code below how the point of impact & the missile’s motion information are used to jolt the object that was struck)
public void Impact(PointF ptfContact, classMath3.classRadialCoordinate cRadMissileMotion, double dblForce)
{
classMath3.classRadialCoordinate cRadContact = new classMath3.classRadialCoordinate(ptfLocation, ptfContact);
cRadContact.Radians -= cRadMissileMotion.Radians;
PointF ptfContactRotated = cRadContact.toPointF();
double dblSum_XY =1+Math.Abs( ptfContactRotated.X) +Math.Abs( ptfContactRotated.Y);
double dblPC_Move = Math.Abs(ptfContactRotated.X / dblSum_XY);
double dblPC_Rotate = Math.Abs(ptfContactRotated.Y / dblSum_XY);
int intSignRotate = 1;
if (ptfContactRotated.Y < 0)
{ // rotate clockwise (on screen)
intSignRotate = 1;
}
else
{ // rotate counter-clockwise
intSignRotate = -1;
}
// determine unit-vector of missile's velocity
classMath3.classRadialCoordinate cRadUnitVectorMissileVelocity = new classMath3.classRadialCoordinate(cRadMissileMotion.Radians, 1);
PointF ptfUnitVectorMissileVelocity = cRadUnitVectorMissileVelocity.toPointF();
ptfVelocity.X += (float)(ptfUnitVectorMissileVelocity.X * dblForce * dblPC_Move);
ptfVelocity.Y += (float)(ptfUnitVectorMissileVelocity.Y * dblForce * dblPC_Move);
dblAngle += (float)(intSignRotate * (Math.PI / 8.0) * dblPC_Rotate);
}
它查看相对于对象中心的碰撞点.(it looks at the point of impact relative to the center of the object.) 然后是该向量的X和Y分量的绝对值之和.然后,该总和用于评估推力(作用在物体上的力,使其在撞击后移动)以及施加在该物体上的旋转量.如果旋转系统的冲击点的Y分量确定了合成旋转角度的符号,则通过旋转冲击点以使其与导弹的运动方向对齐,可以形成符号.(then is sums the absolute value of the X & Y components of that vector. This sum is then used to evaluate the push (force acting on the object to move it after impact) as well as the amount of rotation imparted on that object. By rotating the point of impact to align with the direction of the missile’s motion the sign if the Y-component of the rotated system’s point of impact determines the sign of the angle of the resultant rotation.)
隧道(Tunnels)
让我们开始吧.(let’s get to it then.) 火星任务中的隧道是简单的单端隧道,在地面上开放且没有分支.他们扭来扭去,但有一个开口和一个末端,几乎没有.在这里,您拥有的是隧道网络.好多了.(the tunnels in Mars Mission were simple one ended tunnels that opened on the surface and had no branches. They twisted and wound around but had one opening and one end, little else. Here, what you have is a network of tunnels. Much better.) 这是视频中游戏空间的地图编辑器的屏幕截图(Here’s a screen capture of the Map-Editor of the game space seen in the video) PTMC_Terra_Start.mp4(PTMC_Terra_Start.mp4) 在本文的顶部.(at the top of this article.)
您可以看到橙色圆圈内的区域,其中两个隧道共享相同的笛卡尔空间,但在游戏中是两个不同的位置.(You can see the areas inside the orange circles where two tunnels share the same cartesian space but are two separate and distinct locations in the game.) 地图编辑器允许您为游戏创建新的地图(因为最近在土星周围发现了大约二十个新月,看起来我永远也不会在我们的Sol系统中赶上所有行星和卫星的designinh游戏地图).做到这一点的方法是在我称为主干网设计中将不同的隧道段链接在一起.在此处并在那里放置骨干隧道段,然后将它们连接在一起,您将获得一个后骨.编辑器会根据您添加的初始隧道线段之间的连接线自动填充它们之间的间隙.在下面的屏幕截图中,您可以看到同一地图区域的主干.(The map editor allows you to create new maps for the game (since some twenty new moons were recently discovered around Saturn looks like I’ll never catch up designinh game maps for all the planets and moons in our Sol system). The way to do that is to link together disparate Tunnel Segments in what I call the backbone design. Drop Backbone Tunnel Segments here and there then connect them together and you have a back bone. The Editor automatically fills in the gaps between them following the connecting lines between the initial tunnel segments that you added. In the screen capture below you can see the same map area’s backbone.)
您可以观看5分钟的简短视频,该视频向您展示在上创建新地图的速度(You can watch a brief 5 minute video that shows you how quick it is to create a new map on) 的YouTube(YouTube) .编辑是(. The editor is)**大多(mostly)**稳定.我的意思是(stable. And by that I mean)**经常保存(save often)**或者您可能希望自己做到了.(or you may wish you did.) 编辑器本身是一项持续不断的工作,我想我会继续努力,为目前已知存在于我们太阳系中的201颗行星和卫星绘制地图,因此这意味着我必须设计尽可能多的地图(天然气巨人土星和木星除外).那是需要完成的艰巨工作.(The Editor itself is an on-going effort and I imagine I’ll continue working on it as I develop the maps for the 201 planets and moons currently known to be in our solar system… so that means I have to design as many maps (except the gas giants Saturn & Jupiter). That’s the grunt work that needs to be done.)
炮塔(Turrets)
既然有太多要讨论的话题,而且我认为我什至不会尝试涵盖所有内容,所以我只想向您介绍我添加的最新内容:炮塔.游戏Descent没有炮塔,但确实有一个"枪童”,被描述为"便携式激光炮塔.落下时,它瞄准附近的敌人并向他们开火.“这种便携式炮塔是随船携带的,只有将其放在隧道中的某个地方才能使用. P.T.M.C.中的炮塔更加精致.(Since there’s so much to talk about and I don’t think I’ll even try to cover everything, I’ll just finish by telling you about the lastest thing I’ve added : the Turret. The game Descent has no turrets but it does have a ‘Gun Boy’ which is described as “A portable laser turret. When dropped, it targets nearby enemies and fires upon them.” This portable turret is carried in your ship’s cargo and only put to use when it is dropped somewhere in the tunnels. The turrets in P.T.M.C. are considerably more refined.)
- 有多种类型.(There are multiple types.)
- 每个人都有自己的盔甲(Each has its own armour)
- 弹药/能量可以在玩家的飞船和炮塔之间转移(Munitions/Energy can be transfered between the player’s ship & the turret)
- 玩家可以设定炮塔将发射哪种武器(Player can set what kind of weapon the turret will fire)
- 可以将炮塔拾起并安装在船的背面板上(Turrets can be picked up and mounted onto the ship’s dorsal plating)
- 炮塔具有Allegiances,可以利用船员的计算机黑客能力(尚未实施船员)来翻转(机器人也可以).(Turrets have Allegiances which can be turned (so do robots) using crewman computer hacking proficiencies(crewmen are not yet implemented).)
- 炮塔的视角可以显示在玩家的屏幕上.(The turret’s point of view can be displayed on to the player’s screen.) 这个(This) 的YouTube(YouTube) 简要演示了如何使用转塔.大多数控件位于上下文菜单UI中,非常简单.狙击手的控件也很基本:指向并单击.您从上下文菜单中选择"狙击手"选项,将枪支瞄准镜放近要瞄准的位置,然后单击屏幕.完成此操作后,您将获得目标的放大视图,可用于更精确地瞄准.如果您认为自己有射击机会,请再次按鼠标键将发射炮塔.(gives a brief demonstration on how to use the Turrets. Most controls are in the context menu UI and are fairly straight forward. The sniper controls are quite basic as well : point and click. You select the Sniper option from the context menu put your gun sight close to where you want to aim and click the screen. When you’ve done this you will get a zoomed-in view of your target which you can use to aim more precisely. If you think you have a shot, pressing your mouse button again will fire the turret.)
平视显示器:HUD(Heads Up Display : HUD)
屏幕上有多个HUD,您可以使用它们查看不同的信号源,包括转塔角度.要设置HUD,请通过上下文菜单中的HUD选项并设置左/右HUD以显示您选择的视角.每个HUD的尺寸在classLandscape中定义.的(The screen has several HUDs which you can use to look at different sources including a turret point of view. To set your HUDs you go through the HUD option in your context menu and set the left/right HUDs to display your choice of perspectives. The dimensions of each HUD are defined in the classLandscape. The) classLandscape
负责通过指定位置,缩放和角度将屏幕绘制到位图(is responsible for drawing the screen to a bitmap given a location, zoom and angle via the) Draw()
功能.由于必须在主屏幕HUD上方绘制alt-HUD,因此当要求Draw()绘制主HUD时,将以递归方式绘制它们.该功能会弹出左HUD图像以提供适合该视图的参数,然后在将左HUD图像返回到屏幕的最终图像之前在主HUD的顶部绘制左HUD图像.(function. Since the alt-HUDs have to be drawn over top of the main screen HUD they are drawn recursively when the Draw() is asked to draw the main HUD. That function spits-up the left-HUD image give the parameters appropriate for that view and then the leftHUD image is drawn over top of the main HUD before it returns the final image that goes to the screen.)
有两个功能对于将游戏世界显示在屏幕上至关重要:(There are two functions that are essential to putting the game world to the screen:)
第一个从游戏世界中获得一个分数,并计算其在屏幕上的位置(The first gets a point from the game-world and calculates its location on the screen)
public PointF Get_PointFInGameWorld(PointF ptfScreen, ref classLandscapeDrawParameters cDrawParameters)
{
classMath3.classRadialCoordinate cRad_RelToCenter = new classMath3.classRadialCoordinate(cDrawParameters.ptOutputCenter, ptfScreen);
cRad_RelToCenter.Radians += cDrawParameters.dblFocusAngle + Math.PI / 2;
PointF ptRelToFocus = cRad_RelToCenter.toPointF();
PointF ptRetVal = new PointF((cDrawParameters.ptfCenterScreenInGameWorld.X
+ intX_MaxGameWorld
+ (int)(ptRelToFocus.X / cDrawParameters.dblGameToScreen_Ratio)) % intX_MaxGameWorld,
cDrawParameters.ptfCenterScreenInGameWorld.Y
+ (int)(ptRelToFocus.Y / cDrawParameters.dblGameToScreen_Ratio));
return ptRetVal;
}
另一个从屏幕上获取一个点并找到其等效的游戏世界位置.(and the other gets a point from the screen and finds its equivalent game-world location.)
public PointF _Get_PointFOnScreen(PointF ptGameWorld, ref classLandscapeDrawParameters cDrawParameters)
{
double dblDrawRotation = -cDrawParameters.dblFocusAngle - Math.PI / 2;
int intCenterTunnelSegment = (int)Math.Floor((double)cDrawParameters.ptfCenterScreenInGameWorld.X / (double)conSurfaceCellWidth);
int intThisTunnelSegment = (int)Math.Floor((double)ptGameWorld.X / (double)conSurfaceCellWidth);
int intDifference = (int)Math.Abs(intCenterTunnelSegment - intThisTunnelSegment);
if (intDifference > (lstSurface.Count / 2)) // assumes player cannot zoom-out further than view full landscape
{ // the seam is between these two PointFs
if (intCenterTunnelSegment > intThisTunnelSegment)
{
PointF ptUnrotated = new PointF((int)((intX_MaxGameWorld - cDrawParameters.ptfCenterScreenInGameWorld.X + ptGameWorld.X) * cDrawParameters.dblGameToScreen_Ratio),
(int)((ptGameWorld.Y - cDrawParameters.ptfCenterScreenInGameWorld.Y) * cDrawParameters.dblGameToScreen_Ratio));
classMath3.classRadialCoordinate cRad = new classMath3.classRadialCoordinate(ptUnrotated);
cRad.Radians += dblDrawRotation;
PointF ptRetVal = cMath.AddTwoPointFs(cDrawParameters.ptOutputCenter, cRad.toPointF());
return ptRetVal;
}
else
{
PointF ptUnrotated = new PointF(-(int)((cDrawParameters.ptfCenterScreenInGameWorld.X + intX_MaxGameWorld - ptGameWorld.X) * cDrawParameters.dblGameToScreen_Ratio),
(int)((ptGameWorld.Y - cDrawParameters.ptfCenterScreenInGameWorld.Y) * cDrawParameters.dblGameToScreen_Ratio));
classMath3.classRadialCoordinate cRad = new classMath3.classRadialCoordinate(ptUnrotated);
cRad.Radians += dblDrawRotation;
PointF ptRetVal = cMath.AddTwoPointFs(cDrawParameters.ptOutputCenter, cRad.toPointF());
return ptRetVal;
}
}
else if (intDifference == lstSurface.Count / 2)
{ // for-loop from 0 to < max ; 0 & max are special
int intX_MaxGameWorld = conSurfaceCellWidth * lstSurface.Count;
PointF ptUnrotated = new PointF((int)(((cDrawParameters.ptfCenterScreenInGameWorld.X > ptGameWorld.X
? -intX_MaxGameWorld
: 0)
+ cDrawParameters.ptfCenterScreenInGameWorld.X - ptGameWorld.X) * cDrawParameters.dblGameToScreen_Ratio),
(int)((ptGameWorld.Y - cDrawParameters.ptfCenterScreenInGameWorld.Y) * cDrawParameters.dblGameToScreen_Ratio));
classMath3.classRadialCoordinate cRad = new classMath3.classRadialCoordinate(ptUnrotated);
cRad.Radians += dblDrawRotation;
PointF ptRetVal = cMath.AddTwoPointFs(cDrawParameters.ptOutputCenter, cRad.toPointF());
return ptRetVal;
}
else
{ // seam is Not BETWEEN these two PointFs
PointF ptUnrotated = new PointF((int)(-(cDrawParameters.ptfCenterScreenInGameWorld.X - ptGameWorld.X) * cDrawParameters.dblGameToScreen_Ratio),
(int)((ptGameWorld.Y - cDrawParameters.ptfCenterScreenInGameWorld.Y) * cDrawParameters.dblGameToScreen_Ratio));
classMath3.classRadialCoordinate cRad = new classMath3.classRadialCoordinate(ptUnrotated);
cRad.Radians += dblDrawRotation;
PointF ptRetVal = cMath.AddTwoPointFs(cDrawParameters.ptOutputCenter, cRad.toPointF());
return ptRetVal;
}
}
由于游戏世界比屏幕上显示的要大得多,因此屏幕的角点用于计算可见的游戏世界的角点.但是玩家会将飞船旋转到任意角度,这意味着屏幕的矩形在水平矩形游戏世界中很少会对齐.因此,将屏幕的对角线作为基本度量,并使用比屏幕的对角线稍大的正方形游戏世界区域搜索四叉树.由于每个行星或月球的表面都围绕着该物体,因此定义它所需的数据需要从头到尾相遇,因此数据的下端(索引为零)与数据的高端相邻(索引=大小数组),但四叉树仅定义为一个简单的矩形.因此,无论何时必须绘制地图两端之间的"缝”,都要求四叉树返回两次搜索的结果,这些搜索结果共同包含位于四叉树矩形空间相对两端的接缝两侧的数据.(Since the gameworld is much bigger than what can be displayed on the screen the corners of the screen are used to calculate the corners of the game world that is visible. But the player rotates the ship to any angle which means that the rectangle of the screen will only rarely ever align in the horizontal rectangular gameworld. So the screen’s diagonal is taken as a base measure and a square gameworld region slightly bigger than the screen’s diagonal is used to search the quadtree. Since the surface of every planet or moon goes around that body the data that defines it needs to meet it head to its tail, The lower end of the data (index zero) is adjacent to the high end of the data(index = size of array) but the quad tree is only defined as a simple rectangle. So whenever the ‘seam’ between the two ends of the map has to be drawn the quadtree is asked to return the results of two searches that together comprise the data found on both sides of the seam located at opposite ends of the quadtree’s rectangular space.) 绘图算法本身已经考虑了每个点,(The drawing algorithm itself has so consider each point and)
- 将这些对象整理在一起(Collate these objects together)
- 获得他们相对于(Get their positions relative to the)
Draw()
功能重点(function’s focus point) - 将该笛卡尔向量转换为径向向量(Convert that cartesian vector to a radial one)
- 将径向坐标旋转到所需的输出角度(Rotate the radial coordinate to the required output angle)
- 调整大小以反映输出缩放系数(resize its magnitude to reflect the output zoom factor)
- 转换回笛卡尔(convert it back to cartesian)
- 将其添加到对焦点的屏幕位置(add it to the focus point’s screen location)
- 选择适合缩放和角度的精灵角度和大小(select the sprite angle and size appropriate for the zoom & angle)
- 以步骤7中确定的屏幕位置为中心,我们很好…(center it about the screen location determined in step #7 and we’re good…) 您可以在观看简短的演示(You can watch a brief demonstration on) 的YouTube(YouTube) 如何设置HUD显示.(how to set the HUD displays.)
静态的(Static)
由于通信是我计划使播放器正常工作的一种方式,因此我实现了一种简单的方法,可以在HUD图像上添加静态图像,以反映该图像接收的质量.游戏资源中有七个初始面具.这些蒙版是使用我从某个网站上下载的静态静态图像生成的.然后将每个像素的所有RBG值都通过一个公共值调整为零.这些更改之后为负的值将设置为零.然后将所有这些值增加16.每个遮罩的RGB值最初更改的值逐渐大于以前的值,以便在将其设置为16之前将更多的较小暗像素强制设置为零.颜色(16\16\16)变为透明.结果是七个静态蒙版具有逐渐变透明的孔,这些孔显示原始图像.静态0的空洞最少,对视力的损害最严重,而static7的空洞最少,对视力的损害最小.为了确保它看起来更像是静态的,而不仅仅是"静态”(我必须很累)不变的屏幕,在将静态蒙版扭曲变形的图像上绘制之前,在随机位置对静态蒙版进行采样,从而赋予其动画效果.(Since communication is something I plan to make the player work for, I’ve implemented an easy way to add static over the HUD images to reflect the quaslity of that imahe’s reception. There are seven startic masks in the game’s resources. These masks were generated by using a generic image of static I downloaded off some web site. Then all the RBG values of each pixel were adjusted towards zero by a common value. Those values that were negative after this change were set to zero. Then all these values were increased by 16. Each mask had its RGB values initially altered by a value progressively larger than the previous so that more of the lesser dark pixels were forced to zero before then being set to 16. Before these masks are used the color (16, 16, 16) is made transparent. The result is seven static masks with progressively more transparent holes that display the original image. Static 0 has the least holes and impairs vision the worst while static7 has nothing but holes and impairs vision the least. To make certain that it looks more like static than just a ‘static’ (I must be tired) unchanging screen the static-masks are sampled at random locations before being drawn over the image they are distorting which gives it an animated feel.) 目前,静态只是用户可以设置的东西,但是交流和黑客技巧很快就会发挥作用,使失真的视觉成为游戏不可或缺的一部分.(For the moment static is just something the user can set but communications and hacking skills will soon come into play making the distorted vision an integral part of the game.)
最后的话(Final words)
不,这不是最后一个.我们才刚刚开始…(No, this is not the last of it. We’re just getting started …)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
XML C# .NET Dev game 新闻 翻译