作者:Lachie Dazdarian(2007年9月)
介绍
不止一次,我通过一个编程新手询问一组从外部文件加载高分表的例程,正确输入新的高分,然后保存修改的高分表。
使用相同的一系列例行练习,从“Ball Blazing Fantasy”开始,我决定为他们写一个教程,并实现一些缺乏灵活性(加上很少的修复)事实上这个例程完成了他们的工作。
本教程还将指出一些有用的(对于高分表管理)附加例程,如名称输入和文件加密,不是我写的。
我们开始做吧!
很明显,我们需要两个单独的子例程,一个用于加载/读取我们的高分表,另一个用于编写/修改它。
我们将从加载/读取高分表开始,因为该部分更容易和逻辑开始。
阅读高分表的子程序应该比较简单。它将打开一个包含名称和分数条目的文件,将它们存储在适当的变量中,然后在屏幕上打印,这部分最依赖于开发者的愿望和需求(打印方法,高分表的位置,格式化等)。
首先,我们应该创建一个包含我们的名字和分数条目的文本文件。创建一个名为'high_scores.dat'的文件,用记事本打开它并输入:
FRED
10000
BILL
9000
SARAH
8000
BOB
7000
RED
6000
SUE
5000
DAVID
4000
GREG
3000
TIM
2000
GEORGE
1000
它包含10个高分条目,格式与名称后跟随评分。我发现这种格式最适合编辑,虽然你可以选择一个所有的名字都列在前面,然后跟着所有的分数。不过,这两种格式的任何类型都没有任何重要的好处,所以我们将与我所看到的一样。
该文件将与以下“ReadHighScore”子程序一起使用。
让我们开始我们的主要程序,并提供一些必要的启动声明:
#include "fbgfx.bi"
Using FB
Const num_of_entries = 10
'num_of_entries'将标记得分条目的数量(高分表中的名称或分数),并且应该与“high_score.dat”文件中的条目数量相对应(不是行,而是高分记录)。
我们现在应该声明我们的子程序:
Declare Sub ReadHighScore (highscore_file As String)
'highscore_file'变量将标记您想要的“ReadHighScore”子程序打开的文件。没有必要声明这样的子程序,但这增加了一些灵活性。
之后,我们应该声明以下变量:
Dim Shared workpage As Integer
Dim Shared hname(num_of_entries) As String
Dim Shared hscore(num_of_entries) As String
'workpage'变量与本教程无关,将用于交换在绘制高分表的循环内的屏幕工作页面。'hname'数组将保存名称条目,而'hscore'数组将保存高分表中的分数条目。
最后,让我们初步化我们的屏幕和工作/可见页面:
ScreenRes 640, 480, 32, 2, GFX_ALPHA_PRIMITIVES+GFX_WINDOWED
ScreenSet 1, 0
按照这段代码,我们应该放这个:
ReadHighScore "high_scores.dat"
End
Sub ReadHighScore (highscore_file As String)
End Sub
你可以编译这个代码,但是没有任何事情会发生,因为“ReadHighScore”子程序是空的。让我们填补!
我们需要通过打开“high_scores.dat”文件并从中读取所需的数据来启动它。请参阅FreeBASIC的OPEN声明,了解如果不熟悉FreeBASIC的文件打开信息。
当我们要使用免费文件句柄打开文件时,我们需要对一个将保存此信息并将其传递给它的变量进行维度。使用此代码:
Dim free_filehandle As Integer
free_filehandle = FreeFile
我们现在应该打开高分档案:
Open highscore_file For Input As #free_filehandle
文件打开后读取(FOR INPUT),让我们使用for循环来检索所有的数据,并将其存储在我们的'hname'和'hscore'变量中:
For count_entry As Integer = 1 To num_of_entries
Input #free_filehandle, hname(count_entry)
Input #free_filehandle, hscore(count_entry)
' If the end of file is reached, exit the FOR loop.
If EOF(free_filehandle) Then Exit For
Next count_entry
请注意如何使用“count_entry”变量,以及如何存储名称的每个条目由附带的分数保存。'hname(1)'将以最高分为标志,而'hscore(1)'是最高分。'hname(num_of_entries)'将标记最低分的名称,而“hscore(num_of_entries)”是高分表中的最低分。
现在不要忘了关闭文件:
Close #free_filehandle
我们现在需要的是一个循环,它将显示所有这些名称和分数,很好地排列在表格中。
Do
ScreenLock
ScreenSet workpage, workpage Xor 1
Line (0,0)-(639,479), RGBA(0, 0, 0, 255), BF
Draw String (285, 120), "TOP SCORES", RGBA(255,255, 255, 255)
For count_entry As Integer = 1 To num_of_entries
Draw String (270, 140 + count_entry * 12), hname(count_entry), RGBA(255,255, 255, 250-count_entry*10)
Draw String (340, 140 + (count_entry) * 12), hscore(count_entry), RGBA(255,255, 255, 250-count_entry*10)
Next count_entry
Draw String (245, 400), "Press ESCAPE to exit", RGBA(255,255, 255, 220)
workpage Xor = 1
ScreenUnlock
Sleep 10
Loop Until MultiKey(SC_ESCAPE)
一个简单的DO ... LOOP,当用户按ESCAPE时结束。
我使用Draw String来打印名称和分数。另一个FOR循环用于循环名称和分数条目,并在下一个更高的位置显示它们的较低分数(注意要显示的文本的Y位置如何与“count_entry”变量相关联 - 增加12以获得更多垂直间距)。我也使用一个小技巧来显示每个下一个比较低的半透明度(最后参数在RGBA功能)。
将所有这些代码放在“ReadHighScore”子程序中后,您可以对其进行编译,并在屏幕上显示所需的结果。
现在,当我们完成了这个问题的简单部分时,让我们将新的条目写入我们的高分表中。
我构建了这样的“WriteHighScore”子程序:
Sub WriteHighScore (highscore_file As String, users_score As Integer)
这意味着它将被称为高分表表文件和我们要输入的分数。如果该分数评估为低于高分表中的最低值,则不会执行任何代码。
该子程序应从以下代码开始:
Dim free_filehandle As Integer
Dim startwrite As Integer
free_filehandle = FreeFile
Open highscore_file For Input As #free_filehandle
For count_entry As Integer = 1 To num_of_entries
Input #free_filehandle, hname(count_entry)
Input #free_filehandle, hscore(count_entry)
' If the end of file is reached, exit the FOR loop.
If EOF(free_filehandle) Then Exit For
Next count_entry
Close #free_filehandle
正如你所看到的那样,它作为“ReadHighScore”子程序开始。为了评估用户的分数和改变非常高的分数表,我们需要打开包含我们的高分条目的文件并将其存储在专用变量中。'startwrite'变量将标记新条目放置在高分表中(哪个位置)的位置。
应该使用一个IF子句来打开后面的代码,只有当用户的分数高于高分表中的最低分(自然)时,IF子句将执行其中的代码:
If users_score > hscore(num_of_entries) Then
For check_score As Integer = 1 To num_of_entries
If users_score > hscore(check_score) Then
InputName
' Record the position where the new score is
' to placed and exit FOR loop.
startwrite = check_score
Exit For
End If
Next check_score
FOR循环通过从最高到最低的高分条目进行,当找到具有较低分数的条目时,这是我们的新条目将被记录的地方(标记为'startwrite'和'check_score') 。例如,在第一个循环中,程序检查'hscore(1)' - 高分表中的最高分。如果用户的得分比其高一些,很明显,用户的得分是新的最高分,“startwrite”需要为1。'InputName'是我们稍后将创建的一个子例程,用户将在其中输入他的名字。:P
接下来是我们的例程的“联系”,将新的高分条目放在正确的位置的代码,并将所有较低的一个下降到一个位置。
检查以下代码:
If startwrite = num_of_entries Then
hscore(startwrite) = users_score
hname(startwrite) = playername
Else
For write_pos As Integer = (num_of_entries - 1) To startwrite Step -1
hscore(write_pos + 1) = hscore(write_pos)
hname(write_pos + 1) = hname(write_pos)
Next write_pos
hscore(startwrite) = users_score
hname(startwrite) = playername
End If
第一个条件检查新条目是否是最高(最后)在高分表中。如果是这种情况,我们不需要降低任何没有得分的条目,只能用新的条目替换最低分数。
如果不是这种情况,则执行FOR循环,从最低高分条目循环到新的高分条目(用'startwrite'标记),意思是从底部到顶部。
例如,如果我们的高分表有10个条目,并且新条目需要放置在第5位,则循环从9到5。当“write_pos”为9时,'hscore(9)'和'hname(9)'的值传递给'hscore(9 + 1)'和'hname(9 + 1)'。当'write_pos'为8时,'hscore(8)'和'hname(8)'的值传递给'hscore(8 + 1)'和'hname(8 + 1)'。等等。
在FOR循环之后,我们需要在其适当的位置输入新的条目(用'startwrite'标记),新的条目被设置为'users_score'和'playername',其中'playername'将被输入到'InputName'子文件中。
“WriteHighScore”子课题我们需要做的最后一件事是将新的高分条目存储回文件:
free_filehandle = FreeFile
Open highscore_file For Output As free_filehandle
For count_entry As Integer = 1 To num_of_entries
Print #free_filehandle, hname(count_entry)
Print #free_filehandle, hscore(count_entry)
Next count_entry
Close free_filehandle
请注意如何使用FOR OUTPUT,并将PRINT写入外部文件。
之后,我发出了一个“ReadHighScore”电话,并用END IF关闭,因为我发现一个新的高分表在输入新条目后应显示出来。
我们现在需要的是创建这样的“InputName”子类:
Sub InputName
ScreenSet workpage, workpage Xor 1
ScreenSet 0,0
Line (0,0)-(639,479), RGBA(0, 0, 0, 255), BF
Locate 12, 17
Input ; "Please input your name: ", playername
End Sub
当然,这在游戏中看起来完全不一样。也许你会要求玩家在游戏中的不同地方输入他/她的名字(就像他/她开始新游戏时)。只要记住你需要一个。
测试例程只是放置...
ReadHighScore "high_scores.dat"
WriteHighScore "high_scores.dat", 4500
End
...第一个SCREENSET(子程序外)??。使用“WriteHighScore”调用更改第二个参数,以在高分表中的不同位置输入不同的分数。我确定你知道,在调用“WriteHighScore”时,第二个参数不能用静态编号进行硬编码,而是使用一个变量来存储玩家的得分,无论你的情况如何。'Player.Score').
下一步是什么?
关于这个问题,我想分享的唯一其他事情是与高分数加密和更好的名称输入程序有关。正如我所使用的两个例程都不是我,我只会刷掉它们,并在一个示例程序中提供它们,您可以根据自己的需要轻松使用。
使用“neoENCpass”和“neodeENCpass”这两个函数完成加密。一个用于加密,一个用于解密。它们用一个字符串(在我们的例子中是高分条目字符串)和密码,密码是您选择的任何字符串,并且必须用于加密和解密(当然)。
在从您解密的文件中检索到一个字符串条目之后,就像这样:
Input #free_filehandle, hname(count_entry)
neoENCdepass SAdd(hname(count_entry)), Len(hname(count_entry)), "yourpass"
使用'hscore'变量作为INTEGER,我们需要使用一个临时的STRING变量,该变量必须被解密,然后将其值传递给'hscore'。
此方法唯一令人讨厌的功能是您需要单独的源代码来加密/解密您的高分文件,因为项目中的例程只有在高分文件以前加密时才能工作。我提供了一个小程序,为您加密。建议您将高分文件的备份保存在单独的文件夹中(我也在zip下载中提供了这一点),即使不加密。
而不是加密你可以使用BINARY文件,我不知道如何使用在这一刻(没有时间学习;我提交的教程在时间的缺口),哪些也不是与ENCRYPTION一样。使用这些例程的加密文件,人们只有在知道密码(大多数人)的情况下才能解密,而任何拥有来源的人都可以读取BINARIES。是的,当向公众提供您的源代码时,请务必更改其中的加密密码。
无论如何,您可能根本不需要或更喜欢加密。但我个人喜欢让我的高分/脚本文件加密,不是每个迪克和汤姆都可以用记事本更改/读取它们。未加密的高分可能会杀死一些球员击败他们的挑战。
名称输入例程我不会去描述,因为这是无关紧要的。你必须编码,阅读它。它比普通的INPUT好得多(您可以使用自定义字体打印库),并允许您限制名称中的字符数。这个例行程序是由“Ryan Szrama”完成的,所有的谢谢他。
下载扩展示例(加密和更好的名称输入):http://lachie.phatcode.net/Downloads/Managing_A_High_Score_Table.zip
这就是本教程。
直到下一次,玩得开心!
Lachie D.编写的一个教程(mailto CHR $(58)lachie13 CHR $(64)yahoo CHR $(46)com; http://lachie.phatcode.net - The Maker Of Stuff)