青蛙跳(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/frog-go-hop-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 13 分钟阅读 - 6192 个词 阅读量 0青蛙跳(译文)
原文地址:https://www.codeproject.com/Articles/7169/Frog-Go-Hop
原文作者:MeterMan
译文由本站 robot-v1.0 翻译
前言
A Frogger clone written in C#. Using doublebuffering timers and other technics.
用C#编写的Frogger克隆.使用双缓冲计时器和其他技术.
介绍(Introduction)
这是Atari制作的原始青蛙的副本.这是我的第一个使用C#的游戏.我希望,在阅读本文之后,您将掌握一些制作自己的有趣游戏所需的技能.剪贴画被认为是从免费剪贴画站点中摘录的公共领域.我用过计时器(This is a clone of the Original Frogger by Atari. This is my first game using C#. I hope, after you read this article, you take with you some skills needed to make your own fun games. The clipart is believed to be of public domain taken off of free clipart sites. I have used timers and) OnPaint
事件以使用GDI双缓冲绘制图像以减少闪烁.我都用过(events to draw the images using the GDI double-buffering to reduce flicker. I have used both)Quartz.dll(Quartz.dll)和我自己的个人班级((and my own personal class ()tonysound.cs(tonysound.cs)),我写了一篇文章,播放声音事件和背景音乐.单击我的文章链接以查找此文章.(), which I wrote an article on, to play sound events and background music. Click on my articles link to find this article.)
变数(Variables)
速度变量(Speed variables)
如代码所示,我已经设置了几个速度变量(I have set up several variables for speed as you can see in the code) #region
标题(titled) variables
.速度变量用于控制(. The speed variable is to control the increments of the) Image
被绘制的对象.例如,如果我希望对象缓慢移动,则数字增量较小,因此它确实可以在屏幕上快速移动.对于游戏的每个级别,我都会在当前速度上加一个.这将增加对象移动的增量,并使对象看起来移动得更快.(object being drawn. For instance, if I want the object to move slow, you would have a low number increment so it does move across the screen as fast. For each level of the game, I will add one to the current speed. This will increase the object movement increments and make the object appear to be move faster.)
**X坐标(X Coordinates)**X坐标像(The X coordinates like) Lane1var1
以此类推,用于游戏场上的X坐标.每个对象都有其X,Y坐标的位置.因此,如果我们移动x,则显然它将向左或向右移动.这就是青蛙和汽车的运动方式.我增加了x(and so on are for the X coordinate on the playfield. Each object has a location of its X,Y coordinate. So if we move the x, it will obviously go either left or right. This is how the frogs and cars move. I increment the x for the) Image
计时器内的对象,例如:(object inside the timer, for example:)
if (long1varx<672)
long1varx+=logset1speed;
else
long1varx=-71;
if (long2varx<672)
long2varx+=logset1speed;
else
long2varx=-71;
if (long3varx<672)
long3varx+=logset1speed;
else
long3varx=-71;
如您在此处看到的,我检查第一行中的第一个日志是否小于672.如果是,则添加(As you can see here, I check to see if the first log in the first row is less than 672. If it is, then I add the) logset1speed
导致其更改其x位置.否则,我将其重置为-71的起始位置.我对其他日志也是如此.(to it causing it to change its x position. Otherwise, I reset it to its starting position as -71. I do the same for the other logs as well.)
现在,我移动的青蛙将其x值放入(Now, the Frog I move get his x value inside the) KeyEvent
,然后(, and then when the) timer1
称(calls the) drawstuff(g)
函数,它将获取青蛙的更新的x值并相应地绘制图形.(function, it will get the updated x value of the frog and plot the graphic accordingly.)
public void OnKeyPress(object sender,System.Windows.Forms.KeyEventArgs e)
{
....
if (e.KeyCode == System.Windows.Forms.Keys.Left)
{
Frogx-=30;
Sound.Play(hopsound,
PlaySoundFlags.SND_FILENAME | PlaySoundFlags.SND_ASYNC |
PlaySoundFlags.SND_NOSTOP);
}
.......
上面发生的是(What happens above is the) keypress
每次按键都会触发事件.然后,我检查是否按下了左箭头,右箭头等等.然后,我根据箭头移动青蛙的坐标.如果剩下,则从其原始x位置减去其移动增量.如果是的话,那么我补充.(event is fired with each key press. I then check to see if the left arrow is pressed, the right arrow and so on. I then move the frog’s coordinates based on the arrow. If it’s left, then I subtract its move increment from its original x location. If it’s right, then I add.)
**“目标摄入量"和"蛇摄入量"的布尔值.(Bool values for the Target Taken and Snake Taken..)**我有(I have) bool
像(values like) bool Target1taken
和(and) bool Snake1Taken
.这是设置一个(. What this does is sets a) true
要么(or) false
确定青蛙是否可以进入本垒.如果目标被击中,则意味着青蛙已经到达了这里,无法再次进入.现在,如果那里有蛇,那么他会杀死青蛙,所以我们测试看看他是否在那里,因此如果青蛙跳入他死去的空间.(to determine if the frog can enter the home base. If the target is taken, this means the frog has already made it here and can’t reenter again. Now if a snake is there, well he kills the frog, so we test to see if he is there, so if the frog jumps in the space he dies.)
**分数的静态变量以及原因…(Static variable for score and why…)**如果您想知道为什么我将分数设为变量(If you are wondering why I made the score variable) static
,这就是原因.如果您使用的是使用相同名称空间的另一种形式,则不能在不创建对象实例的情况下使用另一种形式的变量.所以我作弊一点,使变量类型(, here is why. If you are on another form that uses the same namespace, you can’t use the variable from the other form without making an instance of an object. So I cheat a little and make the variable of type) static
,那么我要做的就是输入name.variable name;形式.例如,(, then all I have to do is type the formname.variablename; for example,) Form1.Score
,而我不必创建表单的实例,也就是说,(, and I don’t have to make an instance of the form, in say,) Form4
完全没有(at all.)
**那是什么声音?(WHAT’S THAT NOISE?)**好吧,就像几乎所有游戏一样,您都有声音事件,并且有背景音乐.好吧,这里也不例外.如果您阅读了有关向C#添加声音的文章,您将会了解我所做的事情.我上课了(Well, just like pretty much any game, you have sound events and you have background music. Well, here is no exception. If you read my article about adding sound to C#, you will get an idea of what I have done. I used my class)*tonysound.cs(tonysound.cs)*使用(that uses the)*winmm.dll(winmm.dll)*播放我的声音事件,例如青蛙跳和死亡.现在,背景有所不同.你看,(to play my sound events, like the frog hopping and dying. Now, the background is a little different. You see,)*winmm.dll(winmm.dll)*不支持并行播放声音.因此,我不得不针对背景提出一些不同的建议.我听到您在那边问如何做,所以让我们深入了解它.(doesn’t support sounds being played in parallel. So I had to come up with something a little different for the background. I hear you over there asking how, so let’s dive into it.)
Quartz.dll(Quartz.dll)
为了使用(In order to use)Quartz.dll(Quartz.dll),我们必须将其添加到我们项目的引用中.为此,我们在Source Explorer中转到主项目名称,然后点击(, we have to add it to the references of our project. To do this, we go to the main project name in Source Explorer and hit)添加参考(Add reference).当对话框弹出时,我们点击"浏览"按钮并转到(. When the dialog box pops up, we then hit the Browse button and go to)Windows \ System32(windows\system32)目录并找到(directory and find the)石英文件(quartz.dll).添加完成后,点击确定.然后您会看到(. Once it’s added, then hit OK. You will then see) QuartzTypeLib
已添加.现在,我们准备就绪,可以使用此炫酷的DLL播放一些声音.好吧,就像其他所有东西一样,我们需要一个对象,所以让我们做一个.(has been added. Now we are ready to get busy with making some sound play with this cool DLL. Well, like pretty much everything else, we need an object, so let’s make one.)
public QuartzTypeLib.FilgraphManagerClass mc;
//quartz object needed to play background
现在我们有了对象,在实际播放声音之前,我们需要做一些其他的事情.(Now that we have the object, we need to do a few more things before we actually get the sound playing.)
QuartzTypeLib.FilgraphManager graphManager =
new QuartzTypeLib.FilgraphManager();
// QueryInterface for the IMediaControl interface:
mc =(QuartzTypeLib.FilgraphManagerClass)graphManager;
我们上面所做的是(What we have done above is made a) Graphmanager
播放声音所需.您会注意到,我分配(needed for playing the sound. You will notice, I assign) mc
的价值(the value of) graphManager
已改铸为(which has been recast to the type of) filgraphManagerClass
.既然完成了,我们就准备好与(. Now that this is done, we are ready to rock and roll with the) mc
将为我们播放声音的对象.所以我们必须使线程(object that’s going to play our sound for us. So we have to make thread that calls) soundbackground
播放我们的声音.(to play our sound.)
backgroundplay = new Thread (new ThreadStart(soundbackground));
// start thread to play music
在调用此线程之前,我们要使其在后台运行.因此,当我们关闭程序时,不会导致进程没有关闭.因此,为此,我们在启动线程之前执行以下操作:(Before calling this thread, we want to make it run in the background. So, when we close our program, we do not get processes not closing. So, to do this, we do the following before starting the thread:)
backgroundplay.IsBackground=true; // make the thread a background thread
backgroundplay.Start(); //start the music playing thread
void soundbackground()
{
while(true)
{
// Call some methods on a COM interface
// Pass in file to RenderFile method on COM object.
mc.RenderFile("backmusic.mp3"); // loads the file in
mc.Run(); // starts the playing
if (mc.CurrentPosition==mc.Duration) // checks if ended
{
mc.CurrentPosition=0; // if we have ended we wanna start over
}
// -1 blocks this event infinately and the soundvar is an
// eventcode that gets triggered after time out
mc.WaitForCompletion(-1, out soundvar);
}
}
图像对象并检查其边界(Image Object and Checking Their Bounds)
如果你看下(If you look under the) #region
被称为(section called) Images
,您将看到我在其中制作了一些图像对象的地方.这些是您在屏幕上看到的图像.要测试边界,我们必须使图像呈矩形.看着那(这(, you will see where I have made some image objects. These are the images which you see on the screen. To test the bounds, we have to make image in the form of a rectangle. Look at the) #region Bounds
您会看到声明.(and you see the declarations.)
public System.Drawing.Rectangle RectangleFrog;
public System.Drawing.Rectangle RectangleCar3;
public System.Drawing.Rectangle RectangleCar2;
public System.Drawing.Rectangle RectangleCar1;
public System.Drawing.Rectangle RectangleFastCar;
public System.Drawing.Rectangle RectangleTractor;
public System.Drawing.Rectangle RectangleCow;
现在我们已经声明了对象,我们需要定义它.因此,我们执行以下操作.您将在(Now that we have declared the object, we need to define it. So, we do the following. You will see this in the) tickme
部分.我可以将其放置在其他位置,但没有.(sections. I could have placed it elsewhere, but I didn’t.)
RectangleCar1 = new Rectangle( Lane1var1, 312, Jeep1_Lane1.Width,
Jeep1_Lane1.Height );
RectangleCar2 = new Rectangle( Lane1var2, 312, Jeep2_Lane1.Width,
Jeep2_Lane1.Height );
RectangleCar3 = new Rectangle( Lane1var3, 312, Jeep2_Lane1.Width,
Jeep2_Lane1.Height );
RectangleFastCar = new Rectangle(Lane2var,350,FastCar.Width,FastCar.Height);
RectangleTractor = new Rectangle(Lane3var,370,Tracter.Width,Tracter.Height);
RectangleCow = new Rectangle(Lane3var2,370,Cow.Width-10,Cow.Height-10);
现在我们为对象定义了矩形边界,我们可以测试一下它们是否与其他对象相交.这很有用,因为如果说青蛙与汽车相交,那么我们显然希望青蛙死亡.因此,C#通过允许我们使用一个称为(Now that we have our rectangle bounds defined for our objects, we can test to see if they intersect with other objects. This is useful because, if say the frog intersects with the car, then we obviously want the frog to die. So C# makes this easy for us by allowing us to use a function called) IntersectsWith
.如果你看着(. If you look in the) tickme
功能,您将看到我检查青蛙是否被原木上的汽车撞到的地方.(function, you will see where I check to see if the frog is hit by cars on logs etc.)
if (RectangleFrog.IntersectsWith(RectangleCar2)||
RectangleFrog.IntersectsWith(RectangleCar1)||
RectangleFrog.IntersectsWith(RectangleCar3)||
RectangleFrog.IntersectsWith(RectangleFastCar)||
RectangleFrog.IntersectsWith(RectangleTractor)||
RectangleFrog.IntersectsWith(RectangleCow))
{
lives--;
livesfunction();
}
上面的操作是检查青蛙图像是否碰到汽车,牛或拖拉机之一.如果确实如此,那么我们将减少一生,然后致电(What the above does is it checks to see if the frog image touches one of the cars or the cow or the tractor. If it does, then we are going to reduce our lives by one and then call the) lives
看看我们是否没有生命.(function to see if we are out of lives.)
图形双缓冲(Double Buffering for Graphics)
我不会对此进行详细介绍,因为我已经写了一篇文章.请看(I will not go into great detail on this because I wrote an article on it already. Please look at the) 防闪烁图形(AntiFlicker Graphics) 文章在这里.阅读上述文章后,您将看到必须启用双重缓冲,因为默认情况下该功能处于关闭状态.另外,您还必须(article here. After reading the aforementioned article, you will see you have to enable double buffering because it is off by default. Also, you have to make an) onpaint
事件,然后调用(event and then call the) DrawStuff
定时器功能使图形移动而不会闪烁和滞后.(function from a timer to get the graphics to move without flicker and lag.)
将分数保存在文本文件中:阅读方法(Keeping Score in a text file:Reading Method)
从一个简单的文本文件中逐行读取高分.我曾考虑过使用数据库,但只是因为我没有看到这个需要而放弃了这个主意.我还考虑过将文件二进制化,在以后的版本中仍可以这样做.是的,我知道您是在说不要再闲逛了.我想看看这是怎么做的,所以我们开始…(The high-score is read in line for line from a simple text file. I thought about using a database but scratched the idea simply because I didn’t see the need. I also thought about making the file binary which I may still do in future versions of this. Yeah, I know you’re saying stop rambling. I want to see how this is done, so here we go…)
try
{
StreamReader s = File.OpenText("Score.txt");
line1=s.ReadLine();
line2=s.ReadLine();
scorecompare= Convert.ToInt32(line2);
label4.Text=line1;
label5.Text=line2;
s.Close();
}
catch
{
MessageBox.Show("Can't find Score.txt");
}
因此,让我们看看这里发生了什么.首先,我们使(So, let’s take a look at what is going on here. First, we make our) try
和(and) catch
所以如果(so if the)score.txt(score.txt)文件丢失,那么我们想告诉用户程序崩溃的原因.然后,我们确保拥有(file is missing, then we want to tell the user the reason the program has crashed. We then make sure up top we have) using System.IO;
,因此我们可以使用(, so we can use the) StreamReader
.因此,我们将一个类型的变量(. So, we make a variable of type) StreamReader
并将其链接到(and link it to the path of)score.txt(score.txt).完成后,我们再分配(. Once this is done, we then assign) line1
第一次读取的值,即第一行.然后对(the value of the first read, which is line one. Then do the same for) line2
.然后我接受并转换(. Then I take and convert) line2
包含分数的整数并将其存储在(which contains the score to an integer and store it in the) scorecompair
,因此我们可以稍后将高分与当前得分进行比较.然后,我简单地将高分名称和高分分数放在各自的标签文本中.(, so we can compare the high-score to the current score later. Then, I simply take and place the high-score name and the high-score score in their respective label text.)
将分数保存在文本文件中:写入方法(Keeping Score in a Text file: Write Method)
好吧,您可能想知道我们如何做到这一点(Well, you are probably wondering how did we go about making this)score.txt(score.txt)文件?好吧,如果仔细看一下代码,您会注意到,如果(file? OK, if you look closely at the code, you will notice that if the) scorecompare
小于当前分数,则当前玩家的分数最高,因此我们只显示一个表格即可(is less than the current score, then the current player has the highest score, so we simply display a form that gets the) score
;记住,我们做到了(; remember, we made it) static
所以我们可以使用它?好吧,在获得分数之后,我们需要用户的名字.完成所有这些操作后,我们将具有一个执行以下操作的提交按钮:(so we could use it? Well, after we have the score, we want the user’s name. After all this is in place, we have a submit button that does the following:)
private void button1_Click(object sender, System.EventArgs e)
{
FileInfo f = new FileInfo("Score.txt");
StreamWriter w = f.CreateText();
w.WriteLine(textBox1.Text.ToString());
w.WriteLine(Form1.score.ToString());
w.Close();
Close();
}
作者注(Note from Author)
的(The)Quartz.dll(Quartz.dll)很有趣.我意识到,有了它,我可以轻松地制作一个媒体播放器.我想到要在音乐播放时让我的一只狗摇尾巴.这个项目对我来说很有趣,而且学习很棒.我一直想学习C#并制作游戏.在Code Project成员的帮助下,您知道自己是谁,我得以将这一梦想变为现实.令我困惑的一件事是(is pretty interesting to mess with. I realized, with it, I could easily make a media player. I thought about making one of my dogs wag his tail as the music plays. This project was pretty fun for me and a great learning experience. I always wanted to learn C# and make a game. With the help of Code Project’s members, you know who you are, I was able to put that dream into reality. One thing that still puzzles me is)winmm.dll(winmm.dll).我听说它会在IRC上同时播放两个声音,但是我从未见过任何有效的代码.因为从我的角度来看,它没有阻塞方法,所以当另一个事件触发时,最后一个被调用的事件具有优先权.另一件事使我丧命.我想做Direct X,现在仍然会.我可能必须获得Visual Studio的最新版本,但是无论如何,这是必须的.我尝试了所有我知道的方法来正确安装DirectX.它只是拒绝这样做.我遵循了几种方法,例如注册DLL,复制DLL等.因此,在我的工作量减轻了一些之后,我将卸载VS,然后重新安装所有VS,看看是否可行.另一件事.我现在是计时器的忠实粉丝.他们使我的生活变得轻松多了.哦,我确实学到了一件有趣的事.如果包括(. I have heard that it will play two sounds in parallel from individuals on IRC but I have never seen any working code on how it is done. Because, from what I see, it doesn’t have a blocking method, so when another event fires, the one that was last called takes priority. Another thing that kills me. I wanted to do Direct X and still will. I might have to get the newest version of Visual Studio though, but anyway, here is the deal. I have tried every method I know of to get DirectX to install correctly. It simply refuses to do so. I followed several methods like registering the DLLs, copying the DLLs, and so forth. So after I get a little less busy, I’m going to uninstall VS and reinstall it all and see if that works. One other thing. I am now a big fan of timers. They made my life a lot easier. Oh, I did learn one interesting thing. If you include) using System.Diagnostics;
,您可以致电(, you can then call) process.Start("a url");
它将使您的用户向您发送电子邮件或访问您的网站等.(and it will let your users email you or go to your website or whatever.)
概要(Summary)
希望在阅读本文之后,您将带给您一些想法,为您的家人甚至您自己制作一些出色的游戏.我一直想买旧式的蛙跳器,并确定可以买到,但我知道为什么我不学习如何制作,所以就在那里.我的Frogger版本.我确定该软件中存在错误,并且在我找到它们后将予以纠正.如果您喜欢此代码,(Hopefully after reading this article, you will have taken with you some ideas to make some fantastic games for your family and even yourself. I always wanted the old style frogger and sure I could have bought it, but I figured why don’t I learn how to make it, so there you have it. My version of Frogger. I’m sure there are bugs in this software and they will be corrected as I find them. If you like this code,)帮我个忙(do me a favor).给我发电子邮件至(. Send me an email to)Junkmail4tony@comcast.net(Junkmail4tony@comcast.net)让我知道你的喜好(and let me know how you like it.)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# WinXP Windows .NET .NET1.0 GDI+ Visual-Studio Dev 新闻 翻译