碰撞-C#游戏,第1部分:视差滚动(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/collision-a-csharp-game-part-1-parallax-scrolling-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 7 分钟阅读 - 3389 个词 阅读量 0碰撞-C#游戏,第1部分:视差滚动(译文)
原文地址:https://www.codeproject.com/Articles/2132/Collision-A-Csharp-Game-Part-1-Parallax-Scrolling
原文作者:Christian Graus
译文由本站 robot-v1.0 翻译
前言
In which I attempt to write a simple game in C#
我尝试用C#编写一个简单的游戏
总览(Overview)
作为我在C#中不断冒险的一部分,我决定编写一个游戏,主要是因为人们似乎喜欢它们,并且我已经使用C ++/DirectX编写了一个Asteroids游戏,而且我认为这意味着我拥有程序逻辑和图形,我只需要我想学习的部分,例如处理键盘输入,资源等.虽然还是有人击败我,所以我决定做一些更简单的事情-一个侧向滚动游戏,其中对象只是为了避免迎面而来的小行星.(As part of my ongoing adventures in C#, I decided to write a game, largely because people seem to like them, and I had an Asteroids game already written using C++/DirectX, and I figured that meant I had the program logic and the graphics, I just needed the parts I wanted to learn, such as handling keyboard input, resources, etc. Someone else beat me to the punch though, so I decided to go for something a little more simple - a sideways scrolling game in which the object is simply to avoid oncoming asteroids.)
视差滚动(Parallax Scrolling)
对于那些不记得的人,视差滚动是一种使事物在3D之前看起来很酷的方法.基本上,它涉及以不同的速率滚动许多不同的位图,从而产生3D幻觉,以相同的方式,如果两个移动对象以相同的速率移动,如果它们与您的距离不同,它们将以不同的速度移动.(For those who don’t remember, parallax scrolling was a method of making things look cool in the days prior to 3D. Basically, it involves scrolling a number of different bitmaps at differing rates, which gives the illusion of 3D, in the same way that two moving objects moving at the same rate would travel at different speeds if they were different distances from you.)
定时(Timing)
基于动作的游戏的第一步是使它以相同的速度运行,而不管所运行的计算机是什么.使用C ++,我可以通过捕获(The first step in an action based game is to make it run the same speed regardless of the computer it’s running on. Using C++, I would do this by catching) WM_IDLE
,并在处理器空闲时绘制我的对象,但是根据自上次移动它们以来经过的时间来移动它们.以这种方式,速度始终是相同的,并且我们获得了处理器可能的最高帧速率.较慢的机器会降低帧速率,而不是游戏速度.(, and drawing my objects whenever the processor is idle, but moving them based on time elapsed since I last moved them. In this manner, the speed is always the same, and we get the highest frame rate possible for the processor. A slower machine slows down the frame rate, not the game.)
好吧,我不知道C#是否具有(Well, I don’t know if C# has an) OnIdle
消息,尽管我知道可以用Petzold书中记录的一些花哨的步法来捕获消息.但是,为了进行练习,我决定改用计时器.在C#中,我们这样设置一个计时器:(message, although I know it’s possible to catch the message using some fancy footwork as documented in the Petzold book. However, for the sake of the exercise, I’ve decided to use a timer instead. In C#, we set up a timer like this:)
private Timer timer = new Timer();
timer.Tick += new EventHandler(OnTimer);
timer.Enabled = true;
timer.Interval = 1000/60;
将该变量设置为类成员,其余变量在初始化时完成.我们正在为计时器定义一个事件处理程序,将其打开并将其设置为每秒关闭60次.计时器只会在系统不繁忙时触发,因此我们不能保证每秒精确拍摄60张照片.为了获得更高的准确性,我们将使用(The variable is set as a class member and the rest is done on initialisation. We are defining an event handler for the timer, turning it on and setting it to go off 60 times a second. A timer will only fire if the system is not busy, so we are not guaranteed that we will get precisely 60 shots a second. To get a better degree of accuracy, we will use a) DateTime
反对计时我们的计时器.我们创建一个成员(object to time our timer. We create a member) DateTime
叫(called) m_DateTime
并使用设置(and set it using) DateTime.Now
.然后,在我们的计时器功能开始时,执行以下操作:(. Then at the start of our timer function, we do this:)
TimeSpan ts = DateTime.Now - m_DateTime;
if (ts.Milliseconds > 1000/m_nFPS)
{
m_DateTime = DateTime.Now;
m_DateTime.AddMilliseconds(ts.Milliseconds - (1000/m_nFPS));
换句话说,如果经过的时间大于我们期望的每秒帧数之间的时间,则我们将采取行动,进行绘制并将变量重置为(In other words, if the time that has passed is more than the time between our desired frames per second value, we spring into action, do our drawing and also reset the variable to be) Now()
再次,加上任何剩余的偏移量.稍后我们将看到,尽管我使用一些简单的图形测试了此代码,但是一旦滚动位图就没有意义了,因为关闭定时器后,它变平了,我得到了2-3 fps. C#对于动作游戏来说不够快,或者至少它没有提供我可以看到的在位图上快速执行滚动的方式.(again, plus any remaining offset. As we will see later, although I tested this code using some simple drawing, as soon as we scroll the bitmap it is moot, because after turning the timer off, so it goes flat out, I get about 2-3 fps. C# is not fast enough for action games, or at least it does not provide a way I can see to perform the scrolling on the bitmap quickly.)
资源资源(Resources)
.NET平台具有一种有趣的资源处理方式.基本上,资源是通过选择(The .NET platform has an interesting way of dealing with resources. Basically, a resource is added by selecting)项目|添加现有项目(Project | Add Existing Item),然后在解决方案资源管理器中单击该项目,可以将其更改为"嵌入资源"的"构建操作",即它成为您的一部分(, and then by clicking on that item in the Solution Explorer, it can be changed to a Build Action of ‘Embedded Resource, i.e., it becomes part of your).可执行程序(.exe).要加载位图资源,请使用以下行:(. To load a bitmap resource, I use this line:)
m_bmPlanets = new Bitmap(GetType(), "Planets.jpg");
现在,我的位图是从资源中加载的.根据您的默认名称空间,您可能需要指定名称空间名称(例如Collision),以加载资源.我必须承认我花了一个小时才开始工作,但我不确定我做了什么….(Now my bitmap is loaded from the resources. Depending on your default namespace, you may need to specify a namespace name, such as Collision in this case, in order to load a resource. I must admit I spent an hour on this before it started to work, and I’m not sure what I did….)
平铺(Tiling)
我最初的策略是创建一个背景不断变化的系统,因此我建立了两个资源位图,一个位图可连续容纳相同分辨率的星型图,一个位图可容纳每个图块一个星球,所有图块均一样的大小.然后,我构建了一个比屏幕宽的图块宽度的位图,并在每次屏幕滚动图块宽度时将其填充,在屏幕上绘制新图像,以便它们滚动到视图中.我很快发现这很慢.我发现无需编写图像过滤器即可滚动位图的唯一方法是进行克隆,然后将其复制回自身,偏移一定数量的像素.为了提高速度,我现在有一个重复系统,在该系统中我将两个位图都绘制了两次,并使用(My initial strategy was to create a system where the background was constantly changing, and so I’ve built two resource bitmaps, one that holds star patterns of the same resolution in a row, and one that holds a planet per tile, all tiles again the same size. Then I built a bitmap that was a tilewidth wider than the screen, and filled it every time the screen had scrolled a tilewidth, drawing new images off screen so they scrolled into view. I soon discovered it was very slow. The only way I found to scroll a bitmap without writing an image filter was to make a clone, and copy it back to itself offset by a certain number of pixels. For speed, I now have a repeating system, where I draw both bitmaps twice over, and use the) TranslateTransform
在绘制两个位图之前先移动Graphics对象的外观.可悲的是,它也非常慢,让我得出结论,没有快速的方法可以完成我要尝试的操作.我之前介绍的时序代码在演示中已关闭,因为它没有被使用.(to move the aspect of the Graphics object before drawing my two bitmaps. Sadly, it is also very slow, leaving me to conclude that there is no quick way to do what I am trying to do. The timing code I presented before is turned off in the demo, because it doesn’t get used.)
透明位图(Transparent Bitmaps)
我发现的另一件事是,为了以透明的方式在恒星上绘制行星,我需要使用(The other thing I found is that in order to draw the planets over the stars with transparency, I needed to use the) ImageAttributes
目的.位图有一个(object. Bitmaps have a) MakeTransparent
方法,该方法需要用一种颜色使之透明,但是当我使用另存为jpeg的资源时,我发现此方法无效. JPEG是一种有损压缩,这意味着您得到的不是您放入的东西.具体地说,不是全部都是硬黑色,而是我的透明区域在黑色范围内,因此我需要过滤0,0,0,到35\35\35来获得我所需的遮罩效果.(method, which takes a colour to make transparent, but as I used resources saved as a jpeg, I found this did not work. JPEG is a lossy compression, which means what you get out is not what you put in. Specifically, instead of all being hard black, my transparent area was in a range of black, such that I needed to filter 0,0,0, through to 35, 35, 35 to get the masking effect I needed.)
ImageAttributes iattrib = new ImageAttributes();
iattrib.SetColorKey(Color.FromArgb(255, 0, 0, 0),
Color.FromArgb(255, 35, 35, 35));
iattrib.SetWrapMode(System.Drawing.Drawing2D.WrapMode.Tile,
Color.Black, false);
gr.DrawImage(m_bmPlanetLayer, new Rectangle(0, 0, 640, 320),
m_nPlanetPos, 0, 640, 320, GraphicsUnit.Pixel, iattrib);
从这里到哪里?(Where to From Here?)
发现GDI +太慢了,无法完成我想要的操作,因此我决定简化一下.在下一期中,我将在屏幕上跟踪行星和我可以在其中移动的船.它不会再滚动星星了,希望可以提供足够的速度来为上一期作准备,在那里我将进行逐像素命中测试,以了解何时飞入行星.(Having found that GDI+ is too slow to do what I wanted, I have decided to simplify. The next installment will have planets which I track on the screen, and a ship I can move in it. It will not scroll the stars anymore, hopefully providing a speed increase sufficient to prepare for the last installment, where I will be doing a per pixel hit test to know when I’ve flown into a planet.)
历史(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 新闻 翻译