游戏开发分享

[Godot] C# 两种状态条实现

2025-03-22
2 分钟270 字

实现效果


实现方法

基础场景

我们在场景中添加了一个Label用来显示文本,两个按钮绑定了信号,用来控制数值的增加


第一种实现

在场景中创建一个进度条节点(ProgressBar或者TextureProgressBar),并根据需求调整所需要的样式,而我们代码控制的属性在Range一栏

大家可以悬停查看属性的功能,我们可以通过修改Value的值来决定进度条的值

现在我们编写脚本,代码如下

using Godot;
using System;
 
public partial class NumSider : Node2D
{
    public int Num = 10;
 
    private Label T_Num;
    private ProgressBar S_Num;
 
    public override void _Ready()
    {
        T_Num = GetNode<Label>("./Num");
        S_Num = GetNode<ProgressBar>("./S_Num");
    }
 
    public override void _Process(double delta)
    {
        UpdateUI();
    }
 
    void UpdateUI()
    {
        T_Num.Text = $"Num:{Num}";
        S_Num.Value = Num;
 
        if (Num > 10)
            Num = 10;
        else if (Num < 0)
            Num = 0;
    }
 
    public void Add()
    {
        Num++;
    }
 
    public void Sub()
    {
        Num--;
    }
}

保存代码,运行场景,简单的状态条就实现了


第二种实现

我们可以在场景中添加HBoxContainer或VBoxContainer节点,这个节点可以让子节点 横/竖 向排列,我们可以通过修改Theme override中的Constants/Separation属性来设置子节点之间的距离

有一点需要注意,添加的子节点可能因为一些原因导致显示不正常,我们可以修改节点中的Custom minimum size来控制子节点的最小长宽

还有一种办法,比如我的子节点用的是TextureRect,我们可以看情况设置子节点的Expand mode和Expand mode属性,来控制子节点的缩放模式等

总之,大家按照自己的使用情况设置

我们创建一个子节点的场景,我简单的用TextureRect显示了一个子弹的图像,之后,大家可以尝试把这个子节点场景添加到容器中,来查看是否能正常显示

之后,我们写出控制容器子节点数量的代码

using Godot;
using System;
 
public partial class NumSider : Node2D
{
    [Export] private PackedScene bullte;    //子节点场景
 
    public int Num = 10;
 
    private Label T_Num;
    private HBoxContainer Boxs;
 
    public override void _Ready()
    {
        T_Num = GetNode<Label>("./Num");
        Boxs = GetNode<HBoxContainer>("./Mag");   //获取容器
    }
 
    public override void _Process(double delta)
    {
        UpdateUI();
    }
 
    void UpdateUI()
    {
        T_Num.Text = $"Num:{Num}";
 
        if (Num > 10)
            Num = 10;
        else if (Num < 0)
            Num = 0;
 
        UpdateMag();
    }
 
    void UpdateMag()
    {
        foreach (var i in Boxs.GetChildren())
        {
            i.QueueFree();    //删除容器的所有子节点
        }
 
        for (int i = 0; i < Num; i++)
        {
            var node2D = bullte.Instantiate();
            Boxs.AddChild(node2D);    //按照Num数值来创建相应数量的子节点
        }
    }
 
    public void Add()
    {
        Num++;
    }
 
    public void Sub()
    {
        Num--;
    }
}

我们简单粗暴的删除了容器的所有子节点,然后又重新按照值添加了对应数量的子节点,大家在实际使用中可以换其他的办法,我这样写还是太草率了

保存脚本,在引擎中构建一下代码,然后把子节点场景文件放到检查器的脚本中(当然你也可以在脚本里面直接获取子节点场景)

现在我们可以运行场景,看看效果

当然我们也可以简单的实现下面的效果

大家应该也能看出来是怎么实现的,定义一个最大的数量,然后在生成数值相对的子对象后,再生成最大数量减现有数量的另外一个作为空的子对象

void UpdateMag()
    {
        foreach (var i in Boxs.GetChildren())
        {
            i.QueueFree();
        }
 
        for (int i = 0; i < Num; i++)
        {
            var node2D = bullte.Instantiate();
            Boxs.AddChild(node2D);
        }
 
        for (int i = 0; i < MaxNum - Num; i++)
        {
            var node2D = bullte0.Instantiate();
            Boxs.AddChild(node2D);
        }
    }

总结

在实际开发中,可能会出现各种问题,大家可以按照自己的需求来实现功能,我这里就简单的写了一个实现方法给大家作为参考,而且尽量不要频繁调用,在值更改的时候调用一下即可

许可协议: CC BY-SA 4.0 。转载请注明出处,允许商用;改编/转载须以相同许可(CC BY-SA 4.0)发布。如有问题请联系我。