GMS2:draw_text_ext小坑一枚
大多数情况下,我们做游戏总要用到文字,而大量的文字显示就需要考虑排版。
文字最基本的排版手段就是换行,那么我们该怎么在游戏中让文字自动换行呢?
如果看过一些教程的朋友应该都知道再 GMS2 里普通的文字绘制函数是:
draw_text(x,y,string)
而另外还有一个略微高阶一点的函数是:
draw_text_ext(x, y, string, sep, w);
理论上,这个带 ext 后缀的函数就是自带的具备自动换行功能的函数了,其中“sep”即行间距,而“w”正是设定的单行文字像素宽度,理论上当文字长度超过这个宽度时就会自动换行,许多关于对话框实现、文字显示的教程里也都会使用这个函数,但是当你自己去尝试使用这个函数时却往往会发现,自动换行并没有起效……
记得最早在 indienova 上有人介绍 FriendlyCosmonaut 的对话框教程时下面就展开过讨论,后台也有朋友提过这个问题,不过当时一直没明白原因,因为测试的时候发现有的时候可以,有的时候又不行,非常不稳定。直到有一天 QQ 群里的朋友一语道破:
因为根据拉丁语系都是以单词为单位组成句子的,而单词跟单词之间必有空格,为了保证单词完整可读,所以 draw_text_ext 这个函数是在当单行文字宽度超过了你设置的限制并且有空格时才进行换行
而我们中文的字与字之间不需要空格,于是就出现了这种很神奇的无法自动换行的“BUG”解决的方法其实也简单,第一种最简单的就是你在本该换行的地方敲上一个空格,让这个函数发现此处有空格该换行了。但这种做法只适合做测试或者一两处文字随手改一下的情况,如果文字量大,而且时不时需要重新调整排版,那工作量就非常感人了。
所以,我们还有一个办法,自己写一个脚本来给中文自动换行即可,此处 QQ 群里的“口十”同学贡献了自用的一个脚本可供诸位参考,其中还针对行末是标点符号的情况做了特殊处理,确保把标点符号留在行尾(不过符号不够完整,各位可根据自己的使用需求进行修改调整)。
/// @func draw_chinese_text_ext(x, y, str, sep, w, less_or_more);
/// @param x_ordinate x 坐标
/// @param y_ordinate y 坐标
/// @param string 绘制的字符串内容
/// @param sepration 行间距
/// @param width 单行最大像素宽度
/// @param l_or_m 单行取大于或小于上述宽度
var xx = argument[0];
var yy = argument[1];
var str = argument[2];
var sep = argument[3];
var w = argument[4];
var l = noone;
if (argument_count > 5) l = argument[5] else l = true;
var x0 = xx;
var y0 = yy;
while!(str == ""){
var s = "";
var i = 0;
var ww = 0;
var con = "";
do{
i++;
s = string_copy(str, 1, i);
ww = string_width(s)
con = string_copy(s, i, 1);
}until(ww >= w) or (i >= string_length(str)) or (con == "#");
if (con!="#"){
if (l) and (ww > w){
var char = string_char_at(s, string_length(s));
var t = char == ")" or char == "," or char == "。" or char == "!" or char == "?";
if !(t){
i--;
s = string_copy(str, 1, i);
}
}
draw_text(x0, y0, s);
y0 += sep;
str = string_delete(str, 1, i);
} else {
s = string_copy(str, 1, i-1);
draw_text(x0, y0, s);
y0+=sep;
str = string_delete(str, 1, i);
}
}
return noone;
哇在群里提问大大们的问题被整理出来啦~~
这个函数,不能加入\n或是\r,我加入后,换行效果会紊乱
asdhuyr3 这我就不清楚是哪里出问题了,放个自己用的能正常工作的代码,谨供参考
///text_[page_]即需自动换行处理的字符串
for(char_count_ = 0; char_count_< string_length(text_[page_]) ; char_count_++){
//auto return
var _text_words = string_copy(text_[page_],1,char_count_);
var _str_width = string_width(_text_words);
if _str_width > box_width_ {
//add a return
text_[page_] = string_insert("\n",text_[page_],char_count_);
}
}
我直接在draw事件里写的,因此 text_[page_] 是一个实例变量,可以在for循环里直接改,如果你想用函数+局域变量实现的话你加个return应该也是没有问题的
感觉只要逐字添加时,直接在超过规定宽度的位置插入个换行符\n就解决了,省不少代码