【Godot4.3】自定义StyleBox
概述
借鉴B站UP主JACKADUX去年8月份的Godot 进阶技法 | 创建自定义的 StyleBox 资源类型中的案例源码,加上自己的简单发挥,搞定了自定义StyleBox
。
这意味着可以很大程度上不再受限于Godot自己提供的4种StyleBox
的限制,尤其是StyleBoxFlat
,而StyleBox
则是自定义容器和控件样式必备的,也就意味着在UI界面设计上将有更多的可能。
StyleBox总结
StyleBox { 样式盒基类 可以用于: { Panel、PanelContainer Button、LineEdit、CodeEdit、Tree控件等的背景样式设定 分为: { StyleBoxEmpty: { 空样式盒 常用于控件主题覆盖中清除控件获得焦点的外框样式 StyleBoxFlat: { 不使用纹理的样式盒(常用) 可以用纯色形式绘制带圆角和边线的矩形样式盒 StyleBoxLine: { 显示左侧垂直和顶部水平边线 比较鸡肋 StyleBoxTexture: { 可以使用图片作为背景 包括渐变类型的GradientTexture1D、GradientTexture2D 缺点:无法在图片背景包括渐变的基础上进行圆角、边框等的设定 \footnotesize \text{StyleBox} \begin{cases} 样式盒基类\\ 可以用于: \begin{cases} \text{Panel、PanelContainer}\\ \text{Button、LineEdit、CodeEdit、Tree}控件等的背景样式设定\\ \end{cases} \\ 分为: \begin{cases} \text{StyleBoxEmpty}: \begin{cases} 空样式盒\\ 常用于控件主题覆盖中清除控件获得焦点的外框样式\\ \end{cases} \\ \text{StyleBoxFlat}: \begin{cases} 不使用纹理的样式盒(常用)\\ 可以用纯色形式绘制带圆角和边线的矩形样式盒\\ \end{cases} \\ \text{StyleBoxLine}: \begin{cases} 显示左侧垂直和顶部水平边线\\ 比较鸡肋\\ \end{cases} \\ \text{StyleBoxTexture}: \begin{cases} 可以使用图片作为背景\\ 包括渐变类型的\text{GradientTexture1D、GradientTexture2D}\\ 缺点:无法在图片背景包括渐变的基础上进行圆角、边框等的设定\\ \end{cases} \\ \end{cases} \\ \end{cases} StyleBox⎩ ⎨ ⎧样式盒基类可以用于:{Panel、PanelContainerButton、LineEdit、CodeEdit、Tree控件等的背景样式设定分为:⎩ ⎨ ⎧StyleBoxEmpty:{空样式盒常用于控件主题覆盖中清除控件获得焦点的外框样式StyleBoxFlat:{不使用纹理的样式盒(常用)可以用纯色形式绘制带圆角和边线的矩形样式盒StyleBoxLine:{显示左侧垂直和顶部水平边线比较鸡肋StyleBoxTexture:⎩ ⎨ ⎧可以使用图片作为背景包括渐变类型的GradientTexture1D、GradientTexture2D缺点:无法在图片背景包括渐变的基础上进行圆角、边框等的设定
自定义StyleBox
模仿了一个简单实例,应该说要直至核心:
@tool
class_name myStyleBox extends StyleBox
func _draw(to_canvas_item: RID, rect: Rect2) -> void:
RenderingServer.canvas_item_add_circle(
to_canvas_item,
rect.get_center(),
rect.size.y /2.0,
Color.WHITE
)
- 自定义
class_name
并直接继承StyleBox
- 因为
StyleBox
本质是Resource
,而不是CanvasItem
,所以它的_draw()
处理是不同的,需要使用RenderingServer
提供的方法处理绘图,而没有draw_*()
方法可以用 - 参数
to_canvas_item
指代的是应用该StyleBox
的容器或控件,rect
是其矩形包围盒,有了这两项,剩下基本就是处理形状点的求取和绘制了,具体可以参看我往期的Godot绘图函数内容 - 因为要在编辑器中使用,所以需要设定
@tool
标记为工具脚本,否则无法实时生效
上面的自定义StyleBox
添加到Panel
控件效果如下:
可以看到基本的自定义绘制效果我们我们是走通了。接下来就是设定自定义参数,并实时影响绘制效果了。
改进版本
这里我改为一个类似聊天气泡的样式盒效果,添加若干参数,并计算和绘制:
@tool
class_name myStyleBox extends StyleBox
## 箭头的总宽度
@export var d_left:float = 0:
set(val):
d_left = val
emit_changed()
## 箭头的总高度
@export var arrow_height:float = 20:
set(val):
arrow_height = val
emit_changed()
## 箭头的总高度
@export var bg_color:Color = Color.WHITE:
set(val):
bg_color = val
emit_changed()
func _draw(to_canvas_item: RID, rect: Rect2) -> void:
# 箭头
var p1 = Vector2(0,rect.get_center().y)
var p2 = Vector2(d_left,rect.get_center().y - arrow_height/2.0)
var p3 = Vector2(d_left,rect.get_center().y + arrow_height/2.0)
var arrow:PackedVector2Array = [p1,p2,p3]
# 矩形
rect = Rect2(rect.position + Vector2(d_left,0),rect.size - Vector2(d_left,0))
# 绘制
RenderingServer.canvas_item_add_rect(to_canvas_item,rect,bg_color)
RenderingServer.canvas_item_add_polygon(to_canvas_item,arrow,[bg_color])
其中:
- 导出变量用于创建自定义参数,每个参数设定
Setter
,并在接收值的改变后调用自定义Resource
必须调用的emit_changed()
,让Godot编辑器知道资源发生了变化,从而动态的更新
效果:
总结
- 自定义
StyleBox
并不难,本质还是和CanvasItem
绘图类似,只不过需要调用RenderingServer
的绘图函数绘制 - 如果要在Godot编辑器中实时绘制需要设定
@tool
关键字 - 自定义
StyleBox
的_draw()
也与CanvasItem
的_draw()
有所区别,也并不提供queue_redraw()
方法,只能是在自定义参数的Setter
中通过调用emit_changed()
通知Godot编辑器进行更新