新的,改进的<星际迷航>游戏(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/the-new-improved-star-trek-game-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 17 分钟阅读 - 8272 个词 阅读量 0新的,改进的<星际迷航>游戏(译文)
原文地址:https://www.codeproject.com/Articles/28962/The-New-Improved-Star-Trek-Game
原文作者:djc2032
译文由本站 robot-v1.0 翻译
前言
Windows Form Implementation of the Classic Game
经典游戏的Windows窗体实现
- 下载Console App项目-12.2 KB(Download Console App project - 12.2 KB)
- 下载Windows Forms App-57 KB(Download Windows Forms App - 57 KB)
介绍(Introduction)
此代码实现了传奇的"(This code implements the legendary “)星际迷航(Star Trek)游戏,使用C#和.NET Framework.(” game, using C# and the .NET Framework.)
背景(Background)
我第一次体验<星际迷航>游戏是在70年代中期使用HP3000.我当时使用的是Texas Instruments Silent 700终端进行拨号连接.该设备的背面配有声耦合器,使其看起来像米老鼠的耳朵.您拨打了计算机的号码,然后将听筒放入了声耦合器中,就可以开始使用了. Silent 700具有用于输出的键盘和热敏打印机.玩星际迷航是一种相当的经历.(My first experience with the Star Trek game was in the mid 70s on an HP 3000. I was using a Texas Instruments Silent 700 terminal to do a dial-up connection. This device had an acoustic coupler on the back, making it appear it had Mickey Mouse ears. You dialled the computer’s number and then placed the hand set into the acoustic coupler and you were ready to go. The Silent 700 had a keyboard and thermal printer for output. Playing star trek on it was quite an experience.) 后来我升级到了Tandy1000.它具有256KB的RAM和双软盘驱动器,我认为我现在就可以制造它了.那时我儿子大约12岁,我们买了David Ahl的电脑游戏书,并输入了<星际迷航>游戏资源.我们度过了愉快的时光,但是对于如何改进游戏有着宏大的想法.我们将使银河系三维化,并随着游戏的进行将Klingons融合到Enterprise上.不知何故,我们从未找到开发游戏的时间.(I later upgraded to a Tandy 1000. It had 256KB of RAM and dual floppy drives and I thought I had it made now. My son was about 12 years old by this time, and we bought David Ahl’s book of computer games and keyed in the star trek game source. We had a great time, but had grandiose ideas on how we could improve the game. We were going to make the galaxy three dimensional, and have the Klingons converge on the Enterprise as the game progressed. Somehow, we never found the time to develop the game.) 当我看到夏季编程竞赛宣布要复制旧游戏的公告时,我实际上发现了几年前的设计笔记.我也有这本书,但是那是在阁楼上,在七月,那里的温度接近120度.我决定看看是否可以在网络上找到任何信息,因此我搜索了"星际迷航游戏",并对这个古老游戏的所有信息感到惊讶.有关原始作者的历史以及该游戏如何移植到各种平台的历史,甚至还有原始源的副本以供下载.(When I saw the announcement of the summer programming contest to reproduce the old game, I actually found my design notes from years ago. I also still have the book, but it was in the attic, and in July, the temperature up there approaches 120 degrees. I decided to see if I could find any information on the web so I Googled “star trek game” and was amazed at all the information on this venerable game. There were histories on the original author and how the game had been ported to various platforms, and even copies of the original source for download.) 由于我对游戏运行方式的所有细节都记忆犹新,因此我决定获得要求的最佳方法是使用从中下载的原始基本源代码.(Since my recollection on all the details of how the game worked was rather faint, I decided the best way to obtain the requirements was to use the original basic source code which I downloaded from) 这里.(here.) 我认为是时候该完成我儿子和我二十年前开始并参加编程竞赛的项目了.我现在的工作是担任程序员经理,而我自己就不再做太多开发工作了.目前,我们正在将我们的关键任务应用程序从大型机和UNIX重写为面向服务的体系结构,并将使用C#和.NET Framework.我一直在尝试自学C#,并认为这将是一个很好的机会,了解我的发展.(I decided it was time to finish the project my son and I had started some twenty years earlier and enter the programming contest. My job now is as a manager of programmers and I don’t get to do much development myself anymore. We are currently in the process of rewriting our mission critical applications from mainframe and UNIX to Service Oriented Architecture and will be using C# and the .NET Framework. I have been trying to teach myself C# for some time and thought this would be an excellent opportunity to see how far I’ve come.) 尽管我既不是计算机游戏专家也不是.NET编程专家,但我还是决定尝试一下.我已经成为Code Project的成员一年多了,已经获得了很多有价值的技巧和代码,但是从未做出任何贡献,并且感觉到了时间.经验丰富的.NET和C#程序员可能不会从我的工作中得到很多帮助,但希望您会从这款游戏中获得乐趣.我在其中工作很有趣.(Although I am not an expert in either computer games or .NET programming, I decided to give it a shot. I’ve been a member of Code Project for over a year, have gotten a lot of valuable tips and code, but have never made a contribution, and felt it’s about time. Experienced .NET and C# programmers may not get a lot from my efforts, but hopefully you’ll have fun with the game. I had a lot of fun working on it.) 我的方法是使用两个阶段.在第一阶段,我将把游戏的所有功能实现为C#控制台应用程序.这将定义基本的游戏动作并检出代码.第二阶段是通过将游戏实现为Windows Forms应用程序来现代化用户界面.(My approach was to use two phases. In the first phase, I would get all the functionality of the game implemented as a C# Console Application. This would get the basic game action defined and the code checked out. The second phase was to modernize the user interface by implementing the game as a Windows Forms application.)
第一阶段-控制台应用程序(Phase One - The Console Application)
一旦掌握了原始源代码,便着手用C#编写自己的版本.在查看原始源代码后,我决定保留原始变量名,以便在复制代码时不会感到困惑.计划是回去,并使用比基本字母的一个字母,一个数字的名称更有意义的名称.嗯,最好的计划…(Once I had the original source code in hand, I set about writing my own version in C#. Looking at the original source, I decided to keep the original variable names so I wouldn’t get confused trying to replicate the code. The plan was to go back later and use more meaningful names than the one-letter, one-number names of basic. Ah, the best laid plans…)
如果您下载控制台应用程序并尝试运行它,请注意一下.我建立在一个名为(One quick note if you download the console app and try to run it. I built it in a directory named)C:\ Projects \ Trek1(C:\Projects\Trek1).该程序经过硬编码,可以在此目录中查找指令列表.如果您使用其他目录,则必须在(. The program is hard coded to look for the list of instructions in this directory. If you use a different directory, you will have to change this constant in the) ShowInstructions()
常规.(routine.)
我面临的最大障碍是当前象限的近程传感器描述的显示.(The biggest obstacle I faced was the display of the Short Range Sensor depiction of the current quadrant.)
原始作者使用一种非常聪明的技术来基于32个字符的打印行定义一系列字符串.我决定不尝试在我的控制台应用程序中复制他的逻辑.相反,我使用了(The original author used a very clever technique of defining a series of strings based on a 32 character print line. I decided not to attempt to replicate his logic in my console app. Instead, I used a) string
数组,以打印例程表示当前象限的内容.(array to represent the contents of the current quadrant with a print routine.)
清单1.打印当前象限阵列(Listing 1. Printing the Current Quadrant Array)
StrSensorDisplay[0] = String.Format(" STARDATE {0}", T);
StrSensorDisplay[1] = String.Format(" CONDITION {0}", strStatus);
StrSensorDisplay[2] = String.Format(" QUADRANT ({0}, {1})", Q1, Q2);
StrSensorDisplay[3] = String.Format(" SECTOR ({0}, {1})", S1, S2);
StrSensorDisplay[4] = String.Format(" TOTAL ENERGY {0}", E);
StrSensorDisplay[5] = String.Format(" PHOTON TORPEDOES {0}", P);
StrSensorDisplay[6] = String.Format(" SHIELDS {0}", S);
Console.WriteLine(" 0 1 2 3 4 5 6 7 ");
Console.WriteLine("________________________");
for (I = 0; I<8; I++)
{
Console.Write("{0:3}{1:3}{2:3}{3:3}{4:3}{5:3}{6:3}{7:3}",
StrSector[0, I], StrSector[1, I], StrSector[2, I],
StrSector[3, I], StrSector[4, I], StrSector[5, I],
StrSector[6, I], StrSector[7, I]);
if (I < 7)
Console.WriteLine(StrSensorDisplay[I]);
else
Console.WriteLine();
}
Console.WriteLine("________________________");
这是它在屏幕上的外观:(Here’s how it looks on screen:)
图1-控制台应用程序屏幕.(Figure 1 - Console App Screen.)## 兴趣点(Points of Interest)
我遇到但仍然不完全了解的一件事是(One thing I ran into, and still don’t fully understand, was the behaviour of the) Console.Read
命令.这是我第一次尝试复制基本输入命令的功能.在大多数情况下,用户输入是对提示的一个字符响应.似乎从未清空过字符缓冲区,并且在用户有机会对提示进行响应之前,已获取了先前的响应. .NET类库文档警告有关使用(command. This was my first attempt to replicate the functionality of the basic input command. For the most part, user input is a one character response to a prompt. It appeared the character buffer was never emptied and previous responses were being picked up before the user had the opportunity to respond to prompts. The .NET class library documentation warned about using) Console.Read
并建议使用(and advised using) Console.ReadLine
代替.当我切换到该命令时,我能够按预期获得用户输入.(instead. When I switched to this command, I was able to obtain user input as I expected.)
第二阶段-Windows窗体应用程序(Phase Two - The Windows Forms Application)
一旦控制台应用程序开始工作,我便着手升级用户界面,将游戏实现为Windows Forms Application.(Once I had the console application working, I set about the task of upgrading the user interface, implementing the game as a Windows Forms Application.) 我的用户界面现代化目标是加快游戏速度并在屏幕上显示更多信息.最初的基本程序是为电传打字机编写的,当您使用硬拷贝设备时,该程序运行正常.但是,如果您使用的是Tandy 1000之类的PC,则近距离传感器扫描和其他信息会很快在屏幕外滚动.而且,在计算机提示和玩家做出响应的情况下,玩家与计算机之间反复的来回移动使游戏的节奏变得笨拙.(My objectives in modernizing the user interface were to speed up the game play and make more information on-screen. The original basic program was written for a teletype machine and when you were using a hard copy device, that worked fine. But if you were on a PC like the Tandy 1000, the short range sensor scan and other information scrolled off screen rather quickly. Also, the repetitive back-and-forth between the player and the computer, with the computer prompting and the player responding, made an awkward tempo for the game.)
兴趣点(Points of Interest)
我加快游戏流程的第一件事之一就是将各种命令实现为工具栏上的按钮.这些可以在图6的主屏幕中看到.诸如短程和远程传感器,损坏控制报告和状态报告之类的内容现在一直在屏幕上显示,不需要按钮.(One of the first things I did to speed up game flow, was to implement the various commands as buttons on a tool bar. These can be seen in figure 6, the main screen. Things like short and long range sensors, damage control report, and status report, were now on screen all the time and didn’t require buttons.)
在控制台应用程序中,我永远无法获得部分课程的选择.换句话说,如果计算机程序说在发射鱼雷时使用路线3.5,则它总是会错过.在我所有的测试和调试中,我不确定原始代码是否有效.因此,我选择使用计算机来计算鱼雷轨迹.由于状态报告一直在屏幕上显示,因此唯一剩下的计算机功能就是累积星系图.因此,您将看到一个按钮,其文本显示为"(In the console application, I was never able to get fractional course selections to work. In other words, if the computer routine said to use course 3.5 when firing a torpedo, it always missed. In all my testing and debugging, I’m not sure the original code worked. For this reason, I took out the option to use the computer to calculate the torpedo track. Since the status report was on-screen all the time, the only remaining computer function was the cumulative galaxy map. So you will see a button whose text says “)银河地图(Galactic Map)",不是”(", not “)电脑(Computer)”.(".)
为了控制屏幕,我使该应用程序成为多文档界面或MDI应用程序.我对在Windows Forms应用程序中实现它如此容易感到惊讶.您需要做的就是设置(In order to control the screen, I made the application a Multiple Document Interface or MDI application. I was amazed at how easy this was to implement in a Windows Forms application. All you need to do is set the) IsMdiContainer
主要形式的属性(property of the main form to) true
在设计器中,然后设置MDI(in the designer, and then set the MDI) Parent
子窗体的属性,在激活子窗体之前,应保留到主窗体.以下代码,来自(property of the child form, to the main form before activating the child. The following code, from the) FormLoad
主窗体的事件处理程序,显示了如何执行此操作.(event handler of the main form, shows how to do this.)
注意,我也在设置一些(Note, I am also setting some) public
子代码中的属性,使其能够显示所需的信息.(properties in the child in code, which allow it to display the information needed.) StrSector
是个(is the) string
数组,用于存储当前象限的内容.(array storing the contents of the current quadrant.) D1
是短距离传感器的损坏控制等级.(is the damage control rating for the short range sensors.)
清单2-调用子MDI表单(Listing 2 - Invoking a child MDI Form)
shortrangescan.MdiParent = this;
shortrangescan.Top = panel1.Bottom;
shortrangescan.Left = panel1.Width / 3;
shortrangescan.Width = 258;
shortrangescan.Height = 208;
shortrangescan.StrSector = StrSector;
shortrangescan.D1 = D[1];
shortrangescan.Show();
我想非常具体地控制表单的绘制,我使用了一个子表单并将代码放在(Where I wanted to control the painting of the form very specifically, I used a child form and put the code in the) Paint
事件.这是短距离传感器显示的代码.这是信息如何保持在屏幕上的另一个示例.在游戏结束之前,永远不会关闭此子窗口,并在适当的时候使用(event. Here is the code for the Short Range Sensor display. This is another example of how information stays On-Screen. This child window is never closed until the game is over, and is repainted whenever appropriate using) Invalidate
和(and) Update
命令.(commands.)
清单3-短距离传感器扫描表单绘制事件(Listing 3 - Short Range Sensor Scan Form Paint Event)
private void ShortScanForm_Paint(object sender, PaintEventArgs e)
{
int I = 0;
float x1 = 0.0F;
float y1 = 0.0F;
float x2 = 0.0F;
float y2 = 0.0F;
Pen linePen = new Pen(Color.WhiteSmoke, 1);
Font drawfont = new Font("Courier New", 10);
SolidBrush drawbrush = new SolidBrush(Color.WhiteSmoke);
if (D1 < 0)
{
e.Graphics.DrawString("Short Range Sensors are out!!!",
drawfont, (Brush)drawbrush, 10.0F, 110.0F);
return;
}
e.Graphics.DrawString(" 0 1 2 3 4 5 6 7",
drawfont, (Brush)drawbrush, 20.0F, 10.0F);
for (int x = 0; x < 8; x++)
{
e.Graphics.DrawString(String.Format("{0}", x),
drawfont, (Brush)drawbrush, 15.0F,
(float)(30.0F + (x * 20)));
}
x1 = 20.0F;
y1 = 26.0F;
x2 = 220.0F;
y2 = 26.0F;
e.Graphics.DrawLine(linePen, x1, y1, x2, y2);
for (I = 0; I < 8; I++)
{
String scanline = String.Format("{0:3}{1:3}{2:3}{3:3}{4:3}{5:3}{6:3}{7:3}",
StrSector[0, I], StrSector[1, I], StrSector[2, I],
StrSector[3, I], StrSector[4, I], StrSector[5, I],
StrSector[6, I], StrSector[7, I]);
e.Graphics.DrawString(scanline,
drawfont, (Brush)drawbrush, 20.0F,
(float)(30.0F + (I * 20)));
}
x1 = 20.0F;
y1 = 184.0F;
x2 = 220.0F;
y2 = 184.0F;
e.Graphics.DrawLine(linePen, x1, y1, x2, y2);
}
在其他情况下,要显示的信息是简单文本,我在主窗体上使用了控件.损害控制面板就是一个例子.(In other cases, where the information to be displayed was simple text, I used controls on the main form. The Damage Control panel is an example.)
图2-损坏控制面板.(Figure 2 - Damage Control Panel.)#### 清单4-损坏控制面板(Listing 4 - Damage Control Panel)
public void DamageControlReport()
{
warp_txt.Text = String.Format("{0:#0.000}", D[0]);
if (D[0] < 0.0)
warp_txt.BackColor = Color.Red;
else
warp_txt.BackColor = Color.LightGray;
short_txt.Text = String.Format("{0:#0.000}", D[1]);
if (D[1] < 0.0)
short_txt.BackColor = Color.Red;
else
short_txt.BackColor = Color.LightGray;
long_txt.Text = String.Format("{0:#0.000}", D[2]);
if (D[2] < 0.0)
long_txt.BackColor = Color.Red;
else
long_txt.BackColor = Color.LightGray;
phaser_txt.Text = String.Format("{0:#0.000}", D[3]);
if (D[3] < 0.0)
{
phaser_txt.BackColor = Color.Red;
Phaser_Btn.Enabled = false;
}
else
{
phaser_txt.BackColor = Color.LightGray;
Phaser_Btn.Enabled = true;
}
photon_txt.Text = String.Format("{0:#0.000}", D[4]);
if (D[4] < 0.0)
{
photon_txt.BackColor = Color.Red;
Torpedo_Btn.Enabled = false;
}
else
{
photon_txt.BackColor = Color.LightGray;
Torpedo_Btn.Enabled = true;
}
dmgctl_txt.Text = String.Format("{0:#0.000}", D[5]);
if (D[5] < 0.0)
{
dmgctl_txt.BackColor = Color.Red;
dmgctl_panel.Hide();
}
else
{
dmgctl_txt.BackColor = Color.LightGray;
dmgctl_panel.Show();
}
shield_txt.Text = String.Format("{0:#0.000}", D[6]);
if (D[6] < 0.0)
{
shield_txt.BackColor = Color.Red;
shield_btn.Enabled = false;
}
else
{
shield_txt.BackColor = Color.LightGray;
shield_btn.Enabled = true;
}
computer_txt.Text = String.Format("{0:#0.000}", D[7]);
if (D[7] < 0.0)
{
computer_txt.BackColor = Color.Red;
Computer_Btn.Enabled = false;
}
else
{
computer_txt.BackColor = Color.LightGray;
Computer_Btn.Enabled = true;
}
}
在玩原始游戏时,我最大的问题之一就是选择经线导航和鱼雷发射的路线.看来我永远无法保持直率.每当我必须输入课程信息时,我总是必须将说明的副本放在我面前,并参考小课程地图.图3是始终显示在屏幕上的课程图例.(One of my biggest problems when playing the original game, was selecting the course for warp navigation and torpedo firing. It seemed I could never keep them straight. I always had to keep a copy of the instructions in front of me and refer to the little course map whenever I had to input course information. Figure 3 is the course legend that stays on screen at all times.)
图3-课程图例.(Figure 3 - The Course Legend.)为了管理程序的反馈,我想要一个滚动窗口,其功能类似于控制台应用程序.我使用了一个列表框,这完全满足了我的需求.将项目添加到列表后,它会突出显示,这会使其自动滚动到视图中.这是添加项目并突出显示该代码的代码,(To manage the feedback from the program, I wanted a scrolling window that functioned like the console application. I used a list box and this met my needs perfectly. As an item is added to the list, it is highlighted, which causes it to scroll into view automatically. Here is the code to add an item and highlight it, with the) listbox
本身显示.(itself shown after.)
清单5-将项目添加到列表框并突出显示(Listing 5 - Add Item to Listbox and Highlight)
if (S < 200)
{
if (listBox1.SelectedIndex > -1)
listBox1.SetSelected(listBox1.SelectedIndex, false);
listBox1.Items.Add(String.Format("SHIELDS DANGEROUSLY LOW"));
listBox1.SetSelected(MessageEntries++, true);
}
图4-消息面板.(Figure 4 - Message Panel.)在代码中,我们检查屏蔽层是否少于200个能量单位.如果是这样,我们要警告玩家.什么时候(In the code, we check to see if shields are less than 200 units of energy. If so, we want to warn the player. When) listbox1.SelectedIndex
大于(is greater than) -1
,有一个项目已被选中或突出显示.(, there is an item already selected, or highlighted.) SetSelected
,第二个参数为(, with the second argument as) false
,关闭选择.然后,我们将该项目添加到(, turns off the selection. We then add the item to the) listbox
并将其设置为选中状态.我们还将不断增加已添加的条目数.(and set it as selected. We are also keeping a running count of how many entries have been added.)
我发现某些Windows应用程序有些烦人,其中之一就是每次启动时该应用程序在桌面上徘徊.早在MFC时代,我就设计了一种在Windows注册表中存储主窗口大小和位置的方法.如果在执行过程中移动了窗口,则会自动存储新位置.(One of the things I find somewhat annoying with some Windows applications, is when the app goes wandering all over the desktop everytime you start up. Back in my MFC days, I had devised a method for storing the main window size and location in the windows registry. If the window was moved during execution, the new location was automatically stored.)
搜索类似的技术,我发现有一个包装类(Searching for a similar technique, I found there was a wrapper class for the) Win32
注册表功能.您必须添加语句(registry functions. You have to add the statement) using Microsoft.Win32;
到您的源代码,然后有一些相当容易使用的注册表操作功能.(to your source and then there are some rather easy to use registry manipulation functions available.)
在从事该项目时,我发现了应用程序配置文件方法,Microsoft现在似乎更喜欢使用注册表.但是,在Windows 3.1的使用(While working on this project, I discovered the Application Configuration File approach, which Microsoft seems to now favor over using the registry. However, I had cut my windows programming teeth back in the Windows 3.1 days where the use of) ini
文件很普遍. Windows NT发行时,我发现注册表是一种更令人满意的编程技术.我想我必须在某个时候适应,而不是在尝试完成此项目时.(files was prevalent. When Windows NT came out, I found the registry a much more satisfying programming technique. I guess I’ll have to adapt at some point, but not while trying to finish this project.)
这是注册表代码,(Here is the registry code, which goes in the) Form_Load
事件的主要形式:(event of the main form:)
清单6-从注册表获取窗口属性(Listing 6 - Get Window Attributes from Registry)
// Obtain or create window location settings from registry
RegistryKey reg1 = Registry.CurrentUser;
RegistryKey reg2;
reg2 = reg1.OpenSubKey("Software\\MyProjects\\CSTrek\\Settings");
if (reg2 == null)
{
this.Height = 557;
this.Left = 156;
this.Top = 45;
this.Width = 730;
reg2 = reg1.CreateSubKey("Software\\MyProjects\\CSTrek");
if (reg2 != null)
{
RegistryKey reg3 = reg2.CreateSubKey("Settings");
if (reg3 != null)
{
reg3.SetValue("height", 557);
reg3.SetValue("left", 156);
reg3.SetValue("top", 45);
reg3.SetValue("width", 730);
}
reg3.Close();
}
}
else
{
this.Height = (int)reg2.GetValue("height", 557);
this.Left = (int)reg2.GetValue("left", 156);
this.Top = (int)reg2.GetValue("top", 45);
this.Width = (int)reg2.GetValue("width", 730);
}
reg1.Close();
reg2.Close();
然后,要保存任何可能的新属性,请在(Then, to save any potentially new attributes, in the) Form_Closing
事件处理程序:(event handler:)
清单7-将窗口属性保存到注册表(Listing 7 - Save Window Attributes to Registry)
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
string SubKey = "Software\\MyProjects\\CSTrek\\Settings";
RegistryKey reg1 = Registry.CurrentUser;
RegistryKey reg2 = reg1.OpenSubKey(SubKey,
RegistryKeyPermissionCheck.ReadWriteSubTree);
if (reg2 != null)
{
reg2.SetValue("height", (int)this.Height);
reg2.SetValue("left", (int)this.Left);
reg2.SetValue("top", (int)this.Top);
reg2.SetValue("width", (int)this.Width);
}
reg1.Close();
reg2.Close();
}
在获取用户输入时,我决定使用对话框,并发现它们在.NET中非常容易实现.表单的构建方式与其他任何表单一样,但是您可以打开(When obtaining user input, I decided to use dialogs and found them really easy to implement in .NET. A form is built like any other, but you turn on the) DialogResult
属性和用途(properties and use) ShowDialog()
而不是平原(instead of the plain) Show()
功能,您将看到一个对话框.(function and you have a dialog.)
清单8-显示对话框表单(Listing 8 - Display a Dialog Form)
CourseDlg dlg = new CourseDlg();
dlg.label1.Visible = true;
if (D[0] < 0)
{
dlg.WarpTrackBar.Enabled = false;
dlg.Warp_TxtBox.Enabled = false;
}
else
{
dlg.WarpTrackBar.Enabled = true;
dlg.Warp_TxtBox.Enabled = true;
}
dlg.label2.Visible = true;
dlg.Impulse_TxtBox.Visible = true;
dlg.ImpulseTrackBar.Visible = true;
if (dlg.ShowDialog() == DialogResult.OK)
{
C1 = dlg.CourseTrackBar.Value;
warp = dlg.WarpTrackBar.Value;
impulse = dlg.ImpulseTrackBar.Value;
}
else
return;
的实例变量(An instance variable of the) dialog
类被声明,并且如果您将它们定义为(class is declared, and if you define them as) public
,可以在调用(, they can be set before invoking the) dialog
本身.我使用这种方法来检查翘曲驱动器的状态,并在无法使用时禁用轨迹栏.我还使用了标有"(itself. I use this approach to check the status of the warp drives, and disable the track bar if they are not operational. I also use a track bar labeled “)脉冲功率(Impulse Power)",它始终可用.我使用它来模拟原始游戏使用的扭曲系数小于(”, which is always available. I used this to simulate the original game’s technique of using a warp factor less than) 1
,以在当前象限内导航.(, to navigate within the current quadrant.)
这是对话框在屏幕上的外观:(Here is what the dialog looks like on screen:)
图5-课程对话框表单.(Figure 5 - The Course Dialog Form.)该对话框实际上具有双重职责,是在发射光子鱼雷时获得玩家所需路线的一种形式.这是通过在显示对话框之前禁用扭曲和脉冲功率分量来实现的.(This dialog actually does double-duty, serving as the form to obtain the player’s desired course when firing a photon torpedo. This was accomplished by disabling the warp and impulse power components before displaying the dialog.)
清单8-显示鱼雷航向对话框(Listing 8 - Displaying the Torpedo Course Dialog)
CourseDlg dlg = new CourseDlg();
dlg.label1.Visible = false;
dlg.Warp_TxtBox.Visible = false;
dlg.WarpTrackBar.Visible = false;
dlg.label2.Visible = false;
dlg.Impulse_TxtBox.Visible = false;
dlg.ImpulseTrackBar.Visible = false;
if (dlg.ShowDialog() == DialogResult.OK)
{
C1 = dlg.CourseTrackBar.Value;
// In case we someday figure out how to do fractional courses.
Cf = (double)(C1 * 1);
}
else
return;
在表单设计器中,通过设置(In the form designer, the various dialog buttons are implemented by setting the) DialogResult
按钮的属性之一(property of the button to one of)好(OK),(,)取消(CANCEL),(,)是(YES),(,)没有(NO)等等.我发现这真的很容易使用,您可以实现某些对话框而不必在对话框类本身中编写任何代码.但是,我想在某些情况下验证响应.例如,在(, etc. I found this really easy to use and you are able to implement some dialogs without having to write any code in the dialog class itself. However, I wanted to validate the response in some cases. For instance, in the)盾牌控制(Shield Control)对话框中,我不希望玩家为盾牌请求更多的能量.为此,我没有设置(dialog, I didn’t want the player to request more energy for the shields than was available. To do this, I did not set the) DialogResult
我的财产(property of my)好(OK)设计器中的按钮.相反,我使用了按钮单击事件来进行验证,然后设置(button in the designer. Instead, I used the button click event to do the validation and then set the) DialogResult
属性,如下所示.(property, as shown below.)
清单9-实现对话框的确定按钮(Listing 9 - Implementing a Dialog OK Button)
private void button1_Click(object sender, EventArgs e)
{
EShields = Convert.ToInt32(ShieldEnergy_TxtBox.Text);
if ((EAvail - EShields) > 0)
{
this.DialogResult = DialogResult.OK;
}
else
{
label5.Visible = true;
}
}
放在一起,这是主屏幕的相当狭窄的视图.我不得不将所有东西挤压在一起,以达到600像素的最大宽度要求.但是我保证,如果您下载并编译它,在包含的表单项目中它看起来会好得多.(Putting it all together, here is a rather scrunched view of the main screen. I had to squeeze things together, in order to get down to the 600 pixel maximum width requirement. But I promise it looks much better in the included form project, if you download and compile it.)
图6-主游戏屏幕.(Figure 6 - The Main Game Screen.)## 已知异常(Known Anomalies)
在我能够进行的少量测试中,我发现的一件事是,当您导航到克林贡人居住的象限并且拥有星基时.如果您碰巧在与星空基地相邻的扇区中进入象限,则您处于停靠位置.总能量设置为3000,您将受到"星空基地"的盾牌的保护,但是您的盾牌设置为(One thing I found in the meager amount of testing I was able to do, was when you navigated to a quadrant inhabited by Klingons and also having a Star Base. If you happened to enter the quadrant in a sector adjacent to the Star Base, you were in a docked position. The total energy was set to 3000, you are protected by the Star Base’s shields, but your shields are set to) 0
.如果您尝试离开星空基地,克林贡人将向您开火,您已完成!但是,在此位置,您将拥有无限的能量,并且可以用移相器爆炸,直到象限中的所有克林贡族人都被摧毁为止.(. If you try to navigate away from the Star Base, the Klingons will fire on you and you are done! However, in this position, you have unlimited energy and can blast away with phasers until all the Klingons in the quadrant are destroyed.)
另外,我将游戏结束时的对话框显示为对话框,询问您是否要再次玩.在测试中,我无法遇到所有可能的方式来结束游戏,因此我不确定所有组合是否都能正常运行.(Also, I implemented the end of game as a dialog that gets displayed and asks if you want to play again. In my testing, I was not able to encounter all possible ways for the game to end, so I am not sure all the combinations flow properly.)
结论(Conclusion)
因此,您跋涉无数,希望您喜欢这款经典游戏的现代化版本.放在一起很有趣,而且我学到了很多有关.NET中Windows Forms编程的知识.(So all you trekies out there, I hope you enjoy this modernized version of this classic game. It was a lot of fun putting together, and I learned a lot about Windows Forms programming in .NET.)
历史(History)
- 30(30)日(th)2008年8月:初始职位(August, 2008: Initial post)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C#3.0 C# C#2.0 .NET .NET2.0 新闻 翻译