GameMaker8.0 :新手教程 Part 26 -文件流(下)-

分类栏目:gamemaker教程

495

GameMaker8.0 :新手教程 Part 26 -文件流(下)-

7、数据结构+文本文件流

不知道还有多少人还记得我们在第十四章所介绍的存档读档系统,当时我说过不需要搞懂原理,只要会用就行。而现在,就到了搞懂它的原理的时候了。
为了方便阅读,我将当时写的saveGame()脚本与loadGame()脚本全部搬过来:
//saveGame();
{
var _file, _map;
_file = file_text_open_write(working_directory + "save.dat");
_map = ds_map_create();


ds_map_add(_map, "room", room);
ds_map_add(_map, "death", world.death);
ds_map_add(_map, "time", world.time);
ds_map_add(_map, "score", world.score);


file_text_write_string(_file, ds_map_write(_map));
ds_map_destroy(_map);
file_text_close(_file);
}
//loadGame();
{
var _file, _map, _room;
_file = file_text_open_read(working_directory + "save.dat");
_map = ds_map_create();
ds_map_read(_map, file_text_read_string(_file));


_room = ds_map_find_value(_map, "room");
world.death = ds_map_find_value(_map, "death");
world.time = ds_map_find_value(_map, "time");
world.score= ds_map_find_value(_map, "score");


room_goto(_room);
ds_map_destroy(_map);
file_text_close(_file);
}
只要没有跳过第二十五章,应该就能很轻松的看出这两个脚本的原理:

(saveGame)以文本文件流打开一个文件->创建一个数据结构->将数据写入数据结构->将数据结构转换为字符串->将字符串写入文件中->销毁数据结构->关闭文件。
(loadGame)以文本文件流打开一个文件->创建一个数据结构->从文本文件流中读取出字符串->从字符串中读取数据结构->从数据结构中读取数据->销毁数据结构->关闭文件。

这就是GM8文本文件流的真正用法。
使用数据结构的好处有两点,第一,同一个数据结构能同时储存字符串和实数,第二,一个数据结构只转换为一个字符串,因此不需要考虑换行符的问题。
当然,使用数据结构也有一个缺点,那就是文件内存极大,因为数据结构转换为字符串后,要保证读取出来还是同一个数据结构,因此会添加许多格式控制符,甚至比数据结构本身的数据内存还大。
这里偷偷的再说一下,GM8数据结构用ASCII码的ASCII码来储存字符串,假设一个字符串"fuck",储存进数据结构,会先转换为ASCII码66 75 63 6B(此处以十六进制代表,每两位为一个字节),然后再把"6675636B"当成字符串转换为ASCII码36 36 37 35 36 33 36 42(十六进制)来储存。因此,储存四个字符的"fuck",硬生生的占用了八个字节。再加上一些格式控制符,用GM8的数据结构向文件中只写入一个"fuck",文件大小足足有56个字节:
GameMaker8.0 :新手教程 Part 26 -文件流(下)-
以此牺牲内存来换取便利。

另外,不同的数据结构储存相同的数据转换为字符串所占用的内存也是不一样的,上面的"fuck"例子中使用的是list。

8、文件路径

GM8提供了一些函数可以对文件路径操作,辅助文件流。
working_directory 游戏的工作目录。在.gmk里调试游戏时指.gmk所在目录,生成exe后指.exe所在的目录。
program_directory 游戏的程序目录。指.exe所在的目录。当你生成exe发布时,在exe里这个变量与working_directory没有任何区别。但是在.gmk里调试游戏时,GM8会在一个临时目录生成临时exe以供调试,调试结束会自动删除临时目录和临时exe,此时program_directory的值是这个临时目录。
temp_directory 游戏的缓存目录。游戏在运行时会缓存一些内容在这个目录里,游戏结束时自动删除目录。
注意,这三个变量所代表的路径不包括最后的反斜杠。
file_exists(file) 返回指定文件路径的文件是否存在。
file_delete(file) 删除指定文件路径的文件。
file_rename(old name, new name) 重新命名文件。
file_copy(file, new file) 复制指定文件路径的文件到new file路径的新文件。
directory_exists(path) 返回指定的目录是否存在。必须是完整路径(即以盘符开始),不能是相对路径。
directory_create(path) 如果目录不存在,则创建这个目录。必须是完整路径,不能是相对路径.
file_find_first(mask, attr) 返回第一个满足mask和attr的文件名称,如果文件不存在,会返回空字串。注意,返回的文件名不包含路径。参数mask是路径与文件扩展名的结合字符串,例如"C: emp*.doc"表示寻找C: emp目录下的doc格式文件,并将找到的第一个文件的文件名返回。参数attr(属性,attribute)用于限定搜寻的文件类型,注意,attr只代表优先搜索,在找不到对应类型的文件时,会继续寻找其他正常的文件并返回文件名。attr的可选值有:
false 无附加属性的普通文件
fa_readonly 只读文件
fa_hidden 隐藏文件
fa_sysfile 系统文件
fa_volumeid 文本文件
fa_directory 目录
fa_archive 档案
fa_readonly + fa_hidden 只读文件和隐藏文件。其他组合同理。如果要代表所有类型的文件,既可以全部相加,也可以使用-1代替。
file_find_next() 返回下一个满足之前的file_find_first中的mask和attr的文件名称,如果文件不存在,会返回空字符串。
file_find_close() 在调用file_find_first和file_find_next时,GM会保存搜索的进度,因此搜索完要使用这个函数释放内存。
file_attributes(file, attr) 返回指定路径的文件是否符合指定的attr。
filename_name(file) 返回指定文件路径的文件名部分,包含扩展名。例如,filename_name("C: emp t.doc")返回"tt.doc"。
filename_path(file) 返回指定文件路径的路径部分,包括最后的反斜杠。例如,filename_name("C: emp t.doc")返回"C: emp"。
filename_dir(file) 返回指定文件路径的路径部分,不包括最后的反斜杠。例如,filename_dir("C: emp t.doc")返回"C: emp"。
filename_drive(file) 返回指定文件路径的盘符部分,不包括反斜杠。例如,filename_drive("C: emp t.doc")返回"C:"。
filename_ext(file) 返回指定文件路径的扩展名,包括最前的点。 例如,filename_drive("C: emp t.doc")返回".doc"。
filename_change_ext(file, ext) 将指定文件路径的扩展名改为新扩展名并返回。参数ext应该包含最前面的点。注意,这个函数并不是真的改了文件扩展名,仅仅只是在返回的字符串中替换了扩展名而已。使用空字符串(即"")作为新扩展名可以移除扩展名。
这里值得一提的是file_find_first的参数attr,我们知道GM8只有实数和字符串,因此fa_xxx毫无疑问也是实数:
GameMaker8.0 :新手教程 Part 26 -文件流(下)-
可以看到各个attr所对应的实数都是2的幂次倍,对应的二进制分别是00000001,00000010,00000100,00001000,00010000,00100000,刚好每一个数据只有一个位是1,当各个不同的atrr相加时,就相当于1的位相加,比如fa_readonly(00000001) + fa_sysfile(00000100) + fa_archive(00100000) = 37(00100101)。而所有属性相加得到63,二进制是00111111,-1的二进制是11111111,因此可以用-1来代替63。这种存储数据的方式叫做按位存储,有兴趣去可以了解一下位运算:位运算教程,以后也许有可能这个教程里也会加一章位运算。

以下函数会弹出消息框要求玩家选择路径,并且返回这个路径:
get_open_filename(filter, fname) 弹出一个弹窗,要求玩家选择一个文件打开,返回这个文件的文件名(包含路径)。参数fname为默认文件名。参数filter为筛选方案,格式为"种类1|扩展名1;扩展名2|种类2|扩展名3....",具体例子请参考下面的截图。
get_save_filename(filter, fname) 弹出一个弹窗,要求玩家选择文件储存路径,返回这个文件的文件名(包含路径)。参数同上。
关于参数filter,下面是filter为"Image|*.png;*.jpg;*.bmp;*.ico|Vedio|*.mp4;*.flv|Text|*.txt;*.doc;*.docx"时的效果:
GameMaker8.0 :新手教程 Part 26 -文件流(下)-
注意这两个函数不会真的打开文件,仅仅只获取路径。