概述
到这一节为止,我们已经学习了如何在CanvasItem
中绘制简单几何图形、图片以及样式盒。但是对于很重要的文字一直没有涉及。
本节就来讲一下字符和字符串绘制函数,以及替换它们的两个类。
系列目录
- 0.概述
- 1.绘制简单图形
- 2.设定绘图变换
- 3.绘制纹理
- 4.绘制样式盒
- 5.绘制字符和字符串
- 6.TextLine和TextParagraph详解
- 7.自定义节点TextBoard
- 8.绘制点索引
- 9.绘制表格
CanvasItem内置字符和字符串绘制函数
CanvasItem
内置了以下几个函数用来绘制字符和字符串:
draw_char()
:用来绘制单个字符draw_string()
:用来绘制字符串draw_string_outline()
:用来绘制字符串的文本描边draw_multiline_string()
:用来绘制多行文本
同时因为绘制文本与具体的字体挂钩,所以也可以用Font
类的一些方法来作为辅助。
绘制字符
draw_char()
参数如下:
参数 | 类型 | 默认值 | 说明 |
---|---|---|---|
font | Font | 字体 | |
pos | Vector2 | 绘制位置 | |
char | String | 要绘制的字符 | |
font_size | int | 16 | 字号 |
modulate | Color | Color(1, 1, 1, 1) | 调制颜色 |
测试代码:
extends Node2D
func _draw() -> void:
# 绘制坐标原点到绘图原点的矩形
draw_rect(Rect2(Vector2(),Vector2(200,200)),Color.AQUA)
# 修改绘图坐标原点
draw_set_transform(Vector2(200,200))
var font = ThemeDB.fallback_font
draw_char(font,Vector2(),"9")
在上面的代码中:
- 在绘制字符之前,我们将绘图原点设为了
(200,200)
- 并绘制了从坐标原点到绘图原点
(200,200)
的矩形 - 用
ThemeDB.fallback_font
获取了Godot主题的默认字体 - 最后通过
draw_char
在(200,200)处,以默认的16号字体大小和默认的白色绘制了字符"9"
。
绘制效果:
可以看到draw_char()
绘制的字符是以左下角为绘制位置,向上,向左绘制的。
注意:如果给draw_char()
传入的字符串长度不为1会报错,也就是说绘制空字符串或者长度大于1的字符串都会报“长度不为1”的错:
绘制字符串
将draw_char()
换为draw_string()
就可以绘制字符串了:
extends Node2D
func _draw() -> void:
# 绘制坐标原点到绘图原点的矩形
draw_rect(Rect2(Vector2(),Vector2(200,200)),Color.AQUA)
# 修改绘图坐标原点
draw_set_transform(Vector2(200,200))
var font = ThemeDB.fallback_font
draw_string(font,Vector2(),"绘制文本测试")
绘制效果:
可以看到依然是从左下角位置开始。
设定文本裁切
draw_string(font,Vector2(),"绘制文本测试",HORIZONTAL_ALIGNMENT_CENTER,50)
上面的代码设定draw_string()
的width
参数为50
,这意味着超过50
像素的宽度后,字符串会被裁剪。
绘制文本描边
通过draw_string_outline()
可以绘制文本的描边。
extends Node2D
func _draw() -> void:
# 绘制坐标原点到绘图原点的矩形
draw_rect(Rect2(Vector2(),Vector2(200,200)),Color.AQUA)
# 修改绘图坐标原点
draw_set_transform(Vector2(200,200))
var font = ThemeDB.fallback_font
draw_string(font,Vector2(),"绘制文本测试")
draw_string_outline(font,Vector2(),"绘制文本测试",0,-1,16,1,Color.BLACK)
计算和绘制字符串矩形
如果我们想更好的控制绘制的字符串,必须要获取字符绘制的矩形区域信息。
Font
的get_string_size()
可以返回相应字体和设置下一段字符串所占据的矩形区域尺寸。- 返回的尺寸宽度是比较精确的,但是高度有很大的偏差,因为它返回的是字体中所有字形的平均高度。
以下面代码为例:
extends Node2D
func _draw() -> void:
# 绘制坐标原点到绘图原点的矩形
draw_rect(Rect2(Vector2(),Vector2(200,200)),Color.AQUA)
# 修改绘图坐标原点
draw_set_transform(Vector2(200,200))
# 设定文本和字体
var font = ThemeDB.fallback_font
var text = "中文123abcghx"
var font_size = 56
var alignment = HORIZONTAL_ALIGNMENT_CENTER
var size = font.get_string_size(text,alignment,-1,font_size)
# 获取字符串的矩形区域
var string_rect = Rect2(Vector2(0,-size.y),size)
# 绘制字符串的矩形区域
draw_rect(string_rect,Color.BROWN)
# 绘制文本
draw_string(font,Vector2(),text,alignment,-1,font_size)
绘制的效果:
可以看到获取的字符串区域有一定的偏差。尤其是高度部分。所以我们需要其他的思路来降低这种误差。
这里补充一点额外的东西:
- 英文字体设计中有基线的概念,因为英文小写字母有的顶部会延伸出去一部分,而有的会在底部延伸出一部分。为了美观,就以一个基准线来排列,也就是基线。
- 在Godot的
Font
类中,以基线将英文小写字母的高度分为了两部分,分别可以用get_ascent
和get_descent
获取这两部分的值。
经过实际测试:
Font
的get_string_size()
或get_height()
返回的高度,减去get_descent()
,是最接近真实的高度。- 而
Font
的get_string_size()
或get_height()
返回的高度,减去2倍的get_descent()
,就是最接近中文和阿拉伯数字真实的高度。
据此,我编写了以下两个函数:
# 获取字符串的尺寸
func get_string_size(font:Font,
string:String,
alignment:HorizontalAlignment=HORIZONTAL_ALIGNMENT_LEFT,
width:=-1,
font_size:=16
):
var w = font.get_string_size(string,alignment,width,font_size).x
var h = font.get_height(font_size) - font.get_descent(font_size)
return Vector2(w,h)
# 获取字符串的矩形
func get_string_rect(font:Font,
string:String,
alignment:HorizontalAlignment=HORIZONTAL_ALIGNMENT_LEFT,
width:=-1,
font_size:=16
):
var size = get_string_size(font,string,alignment,width,font_size)
var pos = Vector2(0,-(size.y - font.get_descent(font_size)))
return Rect2(pos,size)
get_string_size()
:获取更接近真实的字符串尺寸get_string_rect()
:获取更接近真实的字符串矩形区域
改进后的代码:
extends Node2D
func _draw() -> void:
# 绘制坐标原点到绘图原点的矩形
draw_rect(Rect2(Vector2(),Vector2(200,200)),Color.AQUA)
# 修改绘图坐标原点
draw_set_transform(Vector2(200,200))
# 设定文本和字体
var font = ThemeDB.fallback_font
var text = "中文123abcghx"
var font_size = 56
var alignment = HORIZONTAL_ALIGNMENT_CENTER
# 获取字符串的矩形区域
var string_rect = get_string_rect(font,text,alignment,-1,font_size)
# 绘制字符串的矩形区域
draw_rect(string_rect,Color.BROWN)
# 绘制文本
draw_string(font,Vector2(),text,alignment,-1,font_size)
绘制效果:
绘制换行文本
使用CanvasItem
的draw_multiline_string()
方法,可以绘制换行文本。
extends Node2D
func _draw() -> void:
# 绘制坐标原点到绘图原点的矩形
draw_rect(Rect2(Vector2(),Vector2(200,200)),Color.AQUA)
# 修改绘图坐标原点
draw_set_transform(Vector2(200,200))
# 设定文本和字体
var font = ThemeDB.fallback_font
var text = "中文123abcghx"
var font_size = 56
var alignment = HORIZONTAL_ALIGNMENT_CENTER
var width = 160
var size = font.get_multiline_string_size(text,alignment,width,font_size)
var d = font.get_descent(font_size)
# 获取字符串的矩形区域
var string_rect = Rect2(Vector2(0,-size.y/2),size)
# 绘制字符串的矩形区域
draw_rect(string_rect,Color.BROWN)
# 绘制多行文本
draw_multiline_string(font,Vector2(),text,0,width,font_size)
同样,可以看到获得的实际矩形,不是很精确:
使用TextLine和TextParagraph
Godot封装了更好用的单行文本和段落文本类,不仅更易于理解和使用,而且获得的文本矩形也更精确,可以获得更好的控制。
所以我个人建议是在绘制文本时直接构造TextLine
和TextParagraph
实例,而完全弃用CanvasItem
内置字符和字符串绘制函数。
使用TextLine构造和绘制单行文本
extends Node2D
# 设定文本和字体
var font = ThemeDB.fallback_font
var font_size = 56
var pos = Vector2(200,200)
func _draw() -> void:
# 绘制坐标原点到绘图原点的矩形
draw_rect(Rect2(Vector2(),pos),Color.AQUA)
# 修改绘图坐标原点
draw_set_transform(pos)
# 创建单行文本
var text = TextLine.new()
text.add_string("单行文本测试",font,font_size) # 修改绘图坐标原点
# 绘制单行文本的矩形区域
draw_rect(Rect2(Vector2(),text.get_size()),Color.BROWN)
# 绘制单行文本
text.draw(get_canvas_item(),Vector2())
在上面的代码中:
- 通过
TextLine.new()
创建了TextLine
的实例text
- 通过
add_string()
方法向text
添加了一段文本 - 通过
text
的draw()
方法,绘制文本
绘制效果:
可以看到TextLine
的绘制方式就比较符合直觉了,而且获取的矩形区域也比较精确。
设定宽度和裁切文本
TextLine
可以设定最大宽度width
,超过这个宽度的文本将不会被绘制。
extends Node2D
func _draw() -> void:
# 绘制坐标原点到绘图原点的矩形
draw_rect(Rect2(Vector2(),Vector2(200,200)),Color.AQUA)
# 修改绘图坐标原点
draw_set_transform(Vector2(200,200))
# 设定文本和字体
var font = ThemeDB.fallback_font
var font_size = 56
# 创建单行文本
var text = TextLine.new()
text.add_string("ha ha ho ho heiehi hiehie ",font,font_size)
text.width = 160 # 限制宽度
# 绘制单行文本的矩形区域
draw_rect(Rect2(Vector2(),text.get_size()),Color.BROWN)
# 绘制单行文本
text.draw(get_canvas_item(),Vector2())
绘制效果:
使用TextParagraph构造和绘制段落文本
extends Node2D
# 设定文本和字体
var font = ThemeDB.fallback_font
var font_size = 56
func _draw() -> void:
# 绘制坐标原点到绘图原点的矩形
draw_rect(Rect2(Vector2(),Vector2(200,200)),Color.AQUA)
# 修改绘图坐标原点
draw_set_transform(Vector2(200,200))
# 创建TextParagraph
var textP = TextParagraph.new()
textP.add_string("ha ha ho ho",font,font_size)
textP.width = 160 # 限制宽度
# 绘制单行文本的矩形区域
draw_rect(Rect2(Vector2(),textP.get_size()),Color.BROWN)
# 绘制多行文本
textP.draw(get_canvas_item(),Vector2())
- 注意,设定换行宽度后,英文将以空格作为自动换行的依据之一,在标点符号后要加一个空格才能正常的自动换行。比如:
"Hello,my Godot"
必须在每个标点之后添加一个空格成为"Hello, my Godot"
才能正确换行:
- 前者因为没有在逗号后面加空格,所以没有正确的自动换行。
- 或者你也可以添加换行符
\n
来强制换行。 - 你可以认为,英文有两种换行,一种是基于单词的换行,也就是空格隔开的内容。另一种是强制换行,也就是手动加
\n
。 - 中文的规则则简单的多,可以正确的自动换行,当然也可以使用强制换行。
总结
- 本节简要讲述了
CanvasItem
内置的字符和字符串绘制函数及其缺点 - 然后讲述了更好用的
TextLine
和TextParagraph
,用于绘制单行和多行文本。 - 实际上
TextLine
和TextParagraph
好有很多特性和功能,可以让我们轻松实现很多东西。但是篇幅所限,留到下节。 - 对于文本绘制的综合使用,也会专门留几个案例,也是相当有趣。
今天的文章三个常用的绘图函数命令_canvas可画怎么使用分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/83058.html