GameMaker Studio 2

创建于:2017-04-19

创建人: dougen

190 信息 1080 成员
游戏开发工具 GameMaker Studio 2 的讨论小组

GMS2:draw_text_ext小坑一枚

顺子 2018-09-04

大多数情况下,我们做游戏总要用到文字,而大量的文字显示就需要考虑排版。

文字最基本的排版手段就是换行,那么我们该怎么在游戏中让文字自动换行呢?

如果看过一些教程的朋友应该都知道再 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;


(转发自:原日志地址

近期喜欢的会员

 
Rusty 2018-09-05

感觉只要逐字添加时,直接在超过规定宽度的位置插入个换行符\n就解决了,省不少代码

 
mimicwillsi 2018-09-05

哇在群里提问大大们的问题被整理出来啦~~

 
asdhuyr3 2018-09-07

这个函数,不能加入\n或是\r,我加入后,换行效果会紊乱

 
顺子 2018-09-08

Rusty 如果手动写死换行的话,如果调整文字尺寸或者修改了显示区域的宽度那就要重新排版了

 
Rusty 2018-09-09

顺子 不是,我是说这个逐字添加

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)...



 
Rusty 2018-09-09

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应该也是没有问题的

 
顺子 2018-09-09

Rusty 哦哦,可以是也可以的……反正方法很多,思路些微差别而已,今天又有人在群里也分享了自己的解决方案回头也发一下:)

 

加入 indienova

  • 建立个人/工作室档案
  • 建立开发中的游戏档案
  • 关注个人/工作室动态
  • 寻找合作伙伴共同开发
  • 寻求线上发行
  • 更多服务……
登录/注册