说明
本文原文写自2022年,内容基于Godot3.5。是本人早期进行Godot组件化和自定义节点探索时的产物,当时的代码和思想可能不太成熟,但贴出来,供需要学习组件化基础思路的同学食用。
概述
血条作为一个非常基础和常见的组件,Godot并没有给我们提供现成的,相反我们需要通过魔改Progress
节点或使用TextureProgress
节点和制作一些图片来实现它们。
本篇内容介绍的是我前不久刚制作的一个简单血条组件,它是基于Progress
节点和StyleBoxFlat
资源修改样式制作的。灵感是Hi小胡的视频。与他一步一步教你不同,我不会教你我是如何一步步制作的。
相反,你只需要在自己的项目里创建一个Progress
节点,你可以将它重命名为“HealthBar”。
为其创建脚本,并复制粘贴如下代码:
# ======================================================================
# 名称:HealthBar
# 描述:一个简单的基于ProgressBar样式修改的参数化血条组件
# 类型:UI组件,原生控件扩展
# 作者:巽星石
# Godot版本:3.5
# 创建时间:2022年10月24日22:56:00
# 最后修改时间:2022年10月29日21:12:08
# ======================================================================
tool
extends ProgressBar
signal dead() # 已经到达最小值
signal val_changed(value) # 血量发生变化
signal is_maxed() # 已经到达最大值
export(Color) var bg_color = Color(0.941176, 0.043137, 0.043137) setget set_bg_color # 背景颜色
export(Color) var fg_color = Color(0.286275, 0.8, 0.258824) setget set_fg_color # 前景颜色
export(Color) var border_color = Color(0.952941, 0.952941, 0.952941) setget set_border_color # 描边 - 颜色
export(int,0,20) var border_width = 2 setget set_border_width # 描边 - 宽度
export(int,0,200) var corner_radius = 2 setget set_corner_radius # 圆角半径
# ========================= Setter&Getter =========================
func set_bg_color(val:Color):
bg_color = val
# 设置StyleBox中的属性
var bg_style = get_bg_style_box()
var fg_style = get_fg_style_box()
bg_style.bg_color = val
func set_fg_color(val:Color):
fg_color = val
# 设置StyleBox中的属性
var fg_style = get_fg_style_box()
var bg_style = get_bg_style_box()
fg_style.bg_color = val
func set_border_color(val:Color):
border_color = val
# 设置StyleBox中的属性
var bg_style = get_bg_style_box()
bg_style.border_color = val
var fg_style = get_fg_style_box()
var fg_border_color = Color(0,0,0,0)
fg_style.border_color = fg_border_color
func set_border_width(val:int):
border_width = val
# 设置StyleBox中的属性
var bg_style = get_bg_style_box()
bg_style.border_width_bottom = val
bg_style.border_width_left = val
bg_style.border_width_right = val
bg_style.border_width_top = val
var fg_style = get_fg_style_box()
fg_style.border_width_bottom = val
fg_style.border_width_left = val
fg_style.border_width_right = val
fg_style.border_width_top = val
func set_corner_radius(val:int):
corner_radius = val
# 设置StyleBox中的属性
var bg_style = get_bg_style_box()
bg_style.corner_radius_bottom_left = val
bg_style.corner_radius_bottom_right = val
bg_style.corner_radius_top_left = val
bg_style.corner_radius_top_right = val
var fg_style = get_fg_style_box()
fg_style.corner_radius_bottom_left = val
fg_style.corner_radius_bottom_right = val
fg_style.corner_radius_top_left = val
fg_style.corner_radius_top_right = val
# ========================= 加载 =========================
func _enter_tree(): # 替换原有的stylebox
# 背景
var box = create_styleboxflat(bg_color,border_color,border_width,
[corner_radius,corner_radius,corner_radius,corner_radius])
set("custom_styles/bg",box)
var fg_border_color = Color(0,0,0,0)
# 前景
var box2 = create_styleboxflat(fg_color,fg_border_color,border_width,
[corner_radius,corner_radius,corner_radius,corner_radius])
set("custom_styles/fg",box2)
func _ready():
percent_visible = false # 关闭百分比显示
size_flags_horizontal = SIZE_EXPAND_FILL
size_flags_vertical = SIZE_EXPAND_FILL
# ========================= 方法 =========================
# 增加血量值
func add(val:int):
var tween = create_tween()
tween.tween_property(self,"value",value + val,0.2)
# 减少血量值
func sub(val:int):
var tween = create_tween()
tween.tween_property(self,"value",value - val,0.2)
# ========================= 信号处理 =========================
func _on_HealthBar_value_changed(value):
if value == min_value:
emit_signal("dead")
if value == max_value:
emit_signal("is_maxed")
emit_signal("val_changed",value)
pass
# ========================= 底层方法 =========================
# 获取或创建背景所需的StyleBox
func get_bg_style_box() -> StyleBoxFlat:
var box
if get("custom_styles/bg"):
box = get("custom_styles/bg")
else:# 不存在
box = create_styleboxflat(bg_color,border_color,border_width,
[corner_radius,corner_radius,corner_radius,corner_radius])
set("custom_styles/bg",box)
return box
# 获取或创建前景所需的StyleBox
func get_fg_style_box() -> StyleBoxFlat:
var box
if get("custom_styles/fg"):
box = get("custom_styles/fg")
else:# 不存在
var fg_border_color = Color(0,0,0,0)
box = create_styleboxflat(fg_color,fg_border_color,border_width,
[corner_radius,corner_radius,corner_radius,corner_radius])
set("custom_styles/fg",box)
return box
# 动态创建StyleBoxFlat
func create_styleboxflat(bg_color = ColorN("white",1),
border_color = ColorN("gray",1),
border_width = 0,
corner_radius = [0,0,0,0],
content_margin = [5,5,5,5],
expand_margin = [0,0,0,0],
has_shadow = false,
shadow_size = 1,
shadow_color = ColorN("gray",0.5),
shadow_offset = Vector2(1,1)
) -> StyleBoxFlat:
var stylebox:StyleBoxFlat = StyleBoxFlat.new()
# 背景
stylebox.bg_color = bg_color
# 边框
stylebox.set_border_width_all(border_width) # 粗细
stylebox.border_color = border_color # 颜色
# 圆角
stylebox.set_corner_radius_individual(
corner_radius[0],
corner_radius[1],
corner_radius[1],
corner_radius[1])
# 内容边距
stylebox.content_margin_bottom = content_margin[0]
stylebox.content_margin_left = content_margin[1]
stylebox.content_margin_right = content_margin[2]
stylebox.content_margin_top = content_margin[3]
# 外边距
stylebox.set_expand_margin_individual(
expand_margin[0],
expand_margin[1],
expand_margin[2],
expand_margin[3]
)
# 阴影
if has_shadow:
stylebox.shadow_size = shadow_size
stylebox.shadow_color = shadow_color
stylebox.shadow_offset = shadow_offset
return stylebox
然后你就可以发现自己有了一个简单的参数化的血条组件。
当然你还要再做一件事情,手动连接一下value_changed
信号到脚本。
保存和实例化
为了实现复用,你需要将这个场景保存然后关闭,然后在其他场景中实例化这个组件。
比如我们创建有一个Control
根节点的场景,实例化一个HealthBar
组件。
通过参数快速调整样式
实例化后的HealthBar
组件就像Godot的原生控件一样,可以通过调整其属性来实现快速的样式改变。当然由于我们采用的是export var
的形式,也就是“脚本变量”,所以为了区别将其称为“参数”,也可以体现参数化的理念。
HealthBar
组件的“自定义属性”(或叫“参数”)只有5个,但是有于它本质是继承于ProgressBar
控件,所以ProgressBar
控件所拥有的属性、信号、方法都可以使用。
参数 | 值类型 | 默认值 | 说明 |
---|---|---|---|
bg_color | Color | Color(0.941176, 0.043137, 0.043137) | 背景颜色 |
fg_color | Color | Color(0.286275, 0.8, 0.258824) | 前景颜色 |
border_color | Color | Color(0.952941, 0.952941, 0.952941) | 描边 - 颜色 |
border_width | int,0,20 | 2 | 描边 - 宽度 |
corner_radius | int,0,200 | 2 | 圆角半径 |
通过这些参数的设定,你可以快速创建完全不同的颜色和描边样式。
方法
HealthBar
组件提供了两个基础的增加和减少血量的方法,并且通过Godot3.5新增的SceneTreeTween
实现了动效。
add(val:int)
当前血量增加给定的数值。变化过程有一个简单的动画效果(使用SceneTreeTween实现)。
并触发val_changed(value)信号,当血量达到最大值时,触发is_maxed()信号。
sub(val:int)
当前血量减少给定的数值。变化过程有一个简单的动画效果(使用SceneTreeTween实现)。
并触发val_changed(value)信号,当血量达到最小值时,触发dead()信号。
效果:
信号
HealthBar
组件自定义了三个信号,你可以在通过节点面板或脚本进行连接。
具体描述如下。
信号 | 描述 |
---|---|
dead() | 已经到达最小值时触发 |
is_maxed() | 已经到达最大值时触发 |
val_changed(value) | 值发生变化时触发,参数value 返回当前值。 |