如何创建没有 setter 函数的 getter 函数?

2023-12-14

我的脚本中有多个导出的变量,每当更改一个变量时,我想调用一个通用的 getter 并让值自动设置

tool

export(float) var sample1 setget ,smthn_changed;
export(float) var sample2 setget ,smthn_changed;
export(float) var sample3 setget ,smthn_changed;

func smthn_changed():
    print("something changed!")

但这不起作用,我必须为每个变量创建一个设置器

有什么解决办法吗?


请注意您正在定义smthn_changed作为这些属性的吸气剂。当您尝试读取吸气剂时,而不是当您尝试分配它们时,将调用吸气剂。

好吧,假设您确实想知道变量何时被赋值。为此,您通常会使用设置器,如下所示:

export var property:bool setget set_property

func set_property(new_value:bool) -> void:
    if property == new_value:
        return

    property = new_value
    print("value changed") # or emit a signal or whatever

setter 将在任何时候从外部(或在内部)分配变量时被调用self.property = value,如果你不使用self您可以直接分配变量而不触发设置器)。

但是,由于您需要从 setter 中写入实际变量,这意味着为每个变量创建一个 setter(如果您对多个变量使用相同的 setter,您将不知道要设置哪个)。


您还可以尝试其他方法:_set。问题与_set是只会为脚本中未声明的变量调用。

所以,这是计划:

  • 我们将使用不同的名称声明支持变量,而不是导出它们。
  • 我们将使用_set and _set来处理它们。
  • 我们将使用_get_property_list导出它们。

让我们看看只有一个变量的情况:

tool
extends Spatial


var _x:String setget _no_set


func _set(property: String, value) -> bool:
    if property == "x":
        _x = value
        smth_changed()
        return true

    return false


func _get(property: String):
    if property == "x":
        return _x

    return null


func _get_property_list() -> Array:
    if not Engine.editor_hint or not is_inside_tree():
        return []

    return [
        {
            name = "x",
            type = TYPE_STRING,
            usage = PROPERTY_USAGE_DEFAULT
        }
    ]


func _no_set(_new_value) -> void:
    pass


func smth_changed() -> void:
    print("something changed!")

与简单的 setter 相比,这不值得付出努力。

二传手_no_set是一个不执行任何操作的设置器(甚至不设置变量)。我添加它是为了防止通过直接设置支持变量来从外部绕过该机制。您可以在那里添加警告,因为这不是您的代码应该做的事情。另一方面,您的代码不应该这样做的事实也可以被视为反对的论据_no_set.

但让我们看看它如何扩展到多个变量:

tool
extends Spatial


var _x:String setget _no_set
var _y:String setget _no_set


func _set(property: String, value) -> bool:
    match property:
        "x":
            _x = value
        "y":
            _y = value
        _:
            return false

    smth_changed()
    return true


func _get(property: String):
    match property:
        "x":
            return _x
        "y":
            return _y

    return null


func _get_property_list() -> Array:
    if not Engine.editor_hint or not is_inside_tree():
        return []

    return [
        {
            name = "x",
            type = TYPE_STRING,
            usage = PROPERTY_USAGE_DEFAULT
        },
        {
            name = "y",
            type = TYPE_STRING,
            usage = PROPERTY_USAGE_DEFAULT
        }
    ]


func _no_set(_new_value) -> void:
    pass


func smth_changed() -> void:
    print("something changed!")

仍然不太好,因为我们必须多次重复变量。我仍然希望有多个设置器,即使它们都有相同的代码。


任意一组属性的通用情况很棘手,因为调用get from _get, or set from _set, or get_property_list form _get_property_list以这种方式导致堆栈溢出将使 Godot 崩溃(并在打开项目时继续崩溃)。所以写这段代码的时候要小心。

我要做什么才能避免打电话get_property_list from _get_property_list就是把我们想要的属性放入字典中:

tool
extends Spatial


var _properties := {
    "x": "",
    "y": ""
} setget _no_set, _no_get


func _set(property: String, value) -> bool:
    if _properties.has(property):
        _properties[property] = value
        smth_changed()
        return true

    return false


func _get(property: String):
    if _properties.has(property):
        return _properties[property]

    return null


func _get_property_list() -> Array:
    if not Engine.editor_hint or not is_inside_tree():
        return []

    var result := []
    for property_name in _properties.keys():
        result.append(
            {
                name = property_name,
                type = typeof(_properties[property_name]),
                usage = PROPERTY_USAGE_DEFAULT
            }
        )

    return result


func _no_set(_new_value) -> void:
    pass


func _no_get():
    return null


func smth_changed() -> void:
    print("something changed!")

另请注意,我根据值报告类型typeof.

我将让您决定这种方法是否值得付出努力。例如,如果变量集可以改变,则可能是这样。我提醒你,你可以打电话property_list_changed_notify以至于戈多呼唤_get_property_list并使用新的属性集更新检查器面板。

尽管_no_set,字典仍然可以在外部读取和操作。所以我添加了一个吸气剂_no_get返回 null 来防止这种情况发生。如果您喜欢在您的_no_set,您可能希望在您的_no_get too.


Addendum:这是一个变体,它使用数组作为要导出的属性的名称。这样你仍然可以拥有常规变量而不用处理字典。您有责任保持阵列最新。

tool
extends Spatial


var _property_names := ["x", "y"] setget _no_set, _no_get
var _x:String
var _y:String


func _set(property: String, value) -> bool:
    if _property_names.has(property):
        set("_" + property, value)
        smth_changed()
        return true

    return false


func _get(property: String):
    if _property_names.has(property):
        return get("_" + property)

    return null


func _get_property_list() -> Array:
    if not Engine.editor_hint or not is_inside_tree():
        return []

    var result := []
    for property_name in _property_names:
        if not "_" + property_name in self:
            push_warning("Not existing variable: " + property_name)
            continue

        result.append(
            {
                name = property_name,
                type = typeof(get("_" + property_name)),
                usage = PROPERTY_USAGE_DEFAULT
            }
        )

    return result


func _no_set(_new_value) -> void:
    pass


func _no_get():
    return null


func smth_changed() -> void:
    print("something changed!")

请注意,我添加了一项检查以防止在没有支持变量的情况下导出,这也会发出警告。暴露它们并不是灾难性的,因为它们只会被视为空。

另请注意,我必须删除_no_set从这个版本中的变量。原因是我将它们设置为set,这会导致调用 setter,并且由于_no_set没有设置变量,结果是它没有保存值。


关于重置值的附录

如果您想添加该箭头来重置值,您需要实现几个(yikes)未记录的方法:

func property_can_revert(property:String) -> bool:
    if property in self:
        return true

    return false


func property_get_revert(property:String):
    match typeof(get(property)):
        TYPE_NIL:
            return null
        TYPE_BOOL:
            return false
        TYPE_INT:
            return 0
        TYPE_REAL:
            return 0.0
        TYPE_STRING:
            return ""
        TYPE_VECTOR2:
            return Vector2()
        TYPE_RECT2:
            return Rect2()
        TYPE_VECTOR3:
            return Vector3()
        TYPE_TRANSFORM2D:
            return Transform2D()
        TYPE_PLANE:
            return Plane()
        TYPE_QUAT:
            return Quat()
        TYPE_AABB:
            return AABB()
        TYPE_BASIS:
            return Basis()
        TYPE_TRANSFORM:
            return Transform()
        TYPE_COLOR:
            return Color()
        TYPE_NODE_PATH:
            return NodePath()
        TYPE_RID:
            return RID(Object())
        TYPE_OBJECT:
            return Object()
        TYPE_DICTIONARY:
            return {}
        TYPE_ARRAY:
            return []
        TYPE_RAW_ARRAY:
            return PoolByteArray()
        TYPE_INT_ARRAY:
            return PoolIntArray()
        TYPE_REAL_ARRAY:
            return PoolRealArray()
        TYPE_STRING_ARRAY:
            return PoolStringArray()
        TYPE_VECTOR2_ARRAY:
            return PoolVector2Array()
        TYPE_VECTOR3_ARRAY:
            return PoolVector3Array()
        TYPE_COLOR_ARRAY:
            return PoolColorArray()

    return null

这个想法是property_can_revert将返回true对于任何将具有重置箭头的属性。和property_get_revert将给出单击所述箭头时将设置的值。这必须在源代码因为它没有记录。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何创建没有 setter 函数的 getter 函数? 的相关文章

  • 【Godot】对 Godot 节点设计的思考

    对 Godot 中节点设计的思考 单个节点的功能设计的想法 xff0c 体会 Godot 的设计思想 低耦合 设计单个节点可复用的节点时 xff0c 调用方法尽量只对当前节点可获取到的变量或方法进行使用 xff0c 比如我写一个可以控制 K
  • 【Godot】行为树(一)了解与设计行为树代码

    行为树介绍 行为树是个节点树 xff0c 父节点通过不断遍历子节点 xff0c 根据不同类型的节点执行不同的分支 最终调用叶节点执行功能 行为树也不难理解 xff0c 他就像代码逻辑一样 xff0c 只是用节点的方式展现出来 xff0c 而
  • 【Godot 4.0】一个简单的匿名方法的使用lambda

    Godot 4 0 beta3 Godot 4 0 中添加了 lambda 表达式 xff0c 匿名方法等很多方便的特性 xff0c 这里我写个用于扫描目录下所有文件的功能 可以看到代码非常简洁 span class token keywo
  • Godot Engine:GDScript 4.X中语法的变化(2020年8月4日 更新)

    文章目录 4 X版 GDScript范例支持注解属性 xff08 Properties xff09 的定义格式await关键字代替yield加入super关键字去除了多级调用问题小结 4 X版 GDScript范例 支持注解 从4 x开始
  • Godot 4 应用 - 图形绘制

    花了两天时间 做了一个初步的图形软件效果 先占个坑 以后再叙
  • Godot 4 源码分析 - 文件读入编码处理

    今天需要读入xml文件进行处理 结果读入一个带中文的文件时 出错了 当然程序还能运行 但编译器一直报错 而且XML解析也不正确 单步调试发现读入的内容出现乱码 具体逻辑 String FileAccess get as text bool
  • 戈多3.2.1。刷新查询时无法更改此状态。使用 call_deferred() 或 set_deferred() 来更改监控状态

    在我的 2D 游戏中 玩家能够摧毁箱子 具有两种碰撞形状的物体 当被摧毁时 板条箱会产生也具有碰撞形状的物品 但是当调用以下函数时 Godot控制台中会显示许多类似的错误 Code func on Crate item dropped co
  • 如何创建没有 setter 函数的 getter 函数?

    我的脚本中有多个导出的变量 每当更改一个变量时 我想调用一个通用的 getter 并让值自动设置 tool export float var sample1 setget smthn changed export float var sam
  • 如何检测 Godot 中的碰撞?

    我有3个场景 一个名为 KinematicBody2D tscn 的 KinematicBody2D 节点 该场景是一个玩家在屏幕上从左向右移动 我还有一个名为 mob tscn 的场景 它是一个igidbody2d节点 这个场景只有精灵和
  • (Godot 引擎)用 Tilemap 瓷砖填充 2D 多边形

    我在 Godot 引擎中遇到一个无法解决的问题 怎么可能 在代码中 用图块填充 Polygon2D 区域 我尝试过获得点位置 使用 2D for 循环遍历线的顶点 但我无法理解这一点 这是我期待的结果的模型 我有解决方案 有一点 hacky
  • 在 Area2D 中覆盖 KinematicBody2D 运动?

    I m trying to create a windy area within which the player would be pushed continuously to the left lt 到目前为止 这就是我想出的Windy
  • 如何在Godot 4.0游戏引擎中实现可组合的角色/技能系统?

    我目前正在使用 Godot 尝试 MOBA 风格游戏的原型 我正在努力寻找一种管理角色及其技能的方法 所有角色都将具有相似的属性 姓名 生命值 奔跑速度 力量等 然而 所有角色的技能都会有所不同 尽管有些角色非常相似 例如基于投射物的技能将
  • Godot 监听来自同一场景的多个实例的信号

    我有以下场景 玩家 敌人 攻击 当攻击与敌人发生碰撞时 敌人会发出 onHit 信号 播放器监听该信号并反弹 这一切都运行良好 但现在如果我复制敌人 因此有多个敌人场景 我如何收听所有敌人的信号 有没有办法获取场景的所有实例并连接到它们的所
  • 在 godot 游戏引擎中使用不同的编程语言?

    我想要将不同的编程语言绑定到 Godot 游戏引擎 有关于这个主题的指导文件或视频吗 例如 这个项目是如何完成的 戈多锈 https github com godot rust godot rust 如果我能学习基础知识 我就能成功地用不同
  • 如何在 Godot 中将字符串转换为枚举?

    使用 Godot 3 4 我的枚举设置为 enum STRENGTH DEXTERITY CONSTITUTION INTELLIGENCE WISDOM CHARISMA 我希望能够使字符串 STRENGTH 返回枚举值 0 我希望下面的
  • 如何在戈多中使刚体跳跃而不赋予其飞行能力

    我本来会使用运动体 但我想将现实生活中的物理添加到我的 2d 对象中 但似乎我可以通过多次按向上键来飞行 extends RigidBody2D var velocity Vector2 ZERO const GRAVITY 35 cons
  • Godot:调用外部方法

    经过大量谷歌搜索 我仍然不明白什么可能是一个简单的解决方案 场景 主要 包含一个 TileMap Grid 并附有一个脚本 Grid gd 场景 玩家 包含一个 KinematicBody2D Player 及其附加脚本 Player gd
  • 如何克服 Godot 将按钮字体更改为默认颜色的问题?

    我正在使用 Godot 4 我在容器中手动创建了很多按钮 我在主场景中设置了一个颜色变量 tempcol 当我单击带有 tempcol 设置的按钮时 比如 Color Red 按钮的字体颜色更改为白色 似乎是默认字体颜色 但是当我单击另一个
  • 传递Physics2DShapeQueryParameters 层进行检查

    我目前正在为我的 2D 自上而下游戏开发一个构建系统 最后一步是检查是否有任何物体 例如树或玩家 阻碍了物品的放置 经过一些研究后 我发现使用Physics2DShapeQueryParameters 是正确的方法 我唯一的问题是我不知道如
  • 如何应用着色器并仅生成图像一次?

    我正在尝试将像素化着色器应用于我的纹理 并且我只需要将其应用一次 之后我可以一遍又一遍地重复使用我的着色器生成的图像作为纹理 而不必每次都进行计算 那么我如何拍摄一些图像 gt 应用着色器并在每次游戏加载时仅渲染它们一次 gt 并将它们用作

随机推荐

  • 如何将字体与我的 .net winforms 应用程序捆绑在一起?

    我想为我的 net 3 0 Winforms 应用程序使用非标准字体 该字体可能安装在我的某些用户的计算机上 但在其他一些计算机上显然会丢失 如何将字体与我的程序一起发送 我需要安装字体吗 如果是这样 缺乏管理员权限会成为问题吗 您必须使用
  • html标签“/href”和navlink或Link之间的区别

    html标签 href 和react router提供的用于导航页面的navlink有什么区别 我可以使用两者来将页面导航到不同的 URL 那么为什么需要引入 Navlink 或 Link The href属性将触发页面刷新 从而重置应用程
  • Yii2 Pjax 和 ActiveForm beforeSubmit 重新加载后不起作用?

    我正在提交按钮上创建一个加载指示器 并使用 registerJs 函数将 开始 过程附加到 beforeSubmit 事件 第一次它可以正常工作 但是在重新加载 Pjax 容器后 再次提交表单时该事件将不会触发 我将整个视图文件包含在 Pj
  • C++ 极小极大函数

    我已经在 Google 和 Stackoverflow 上搜索了这个问题 但我仍然不明白 minimax 函数是如何工作的 我发现维基百科条目有该函数的伪代码版本 function integer minimax node depth if
  • 需要 ext-mongodb ^1.5.0 symfony

    我安装了 ext mongodb php ri mongodb php ri mongodb grep 版本 MongoDB extension version gt 1 5 1 libbson bundled version gt 1 1
  • Cassandra CQL - 将 system.local 表中的 release_version 列转换为 int

    我正在 cql 中编写一个查询 检查 Cassandra 的发行版本是否大于或等于 3 11 10 select from system local where release version gt 3 11 10 由于release ve
  • 在 C++ 中使用布尔值按位运算符

    在 C 中是否有任何理由不使用按位运算符 和 来表示 bool 值 有时我会遇到这样的情况 我希望两个条件之一恰好为真 XOR 所以我只是将 运算符放入条件表达式中 有时我还希望对条件的所有部分进行评估 无论结果是否为真 而不是短路 因此我
  • 区分磁盘模型的类型

    Tensorflow有几个模型格式的类型 TensorFlow SavedModel 2 Frozen 模型 3 会话捆绑包 4 Tensorflow Hub 模块 如何在磁盘上区分它们 稍后与tensorflowjs converter一
  • 如何在C中的UDP客户端/服务器中向sento和recvfrom添加延迟

    对于学校的编程项目 我们必须使用 tcp 协议和 udp 协议设计基本的客户端 服务器设置 我已经使用 C Socket 库中的 read 和 write 使 TCP 正常工作 我现在需要创建一个 可靠的UDP 系统 例如 当服务器收到长度
  • Java中如何在一定时间后停止执行?

    在代码中 变量计时器将指定结束 while 循环的持续时间 例如 60 秒 while timer run terminate after 60 sec long start System currentTimeMillis long en
  • Xcode 屏幕截图 EAGLContext [重复]

    这个问题在这里已经有答案了 可能的重复 如何从EAGLView获取UIImage 所以我只是想知道是否有人知道如何将 EAGLContext 中存储的内容保存为 UIImage 我目前正在使用 UIGraphicsBeginImageCon
  • 我正在尝试将 Sequelize 与 Next JS API 路由一起使用

    我正在尝试将 Sequelize 与 Next JS API 路由一起使用 但我几乎在第一个障碍处就跌倒了 无论我做什么 我似乎都无法将模型导入到我的route js 文件中 import nextConnect from next con
  • C++ 的 C 包装器:如何处理 C++ 模板?

    早些时候询问如何为 C 类编写一个 C 包装器 C 的 C 包装 基本就清楚了 但还有一个问题 如何处理 C 模板 假设这是我的课 template
  • 使用要显示最后一个活动的活动组在选项卡之间切换 - Tab ActivityGroup

    我已经为我的 Android 应用程序编写了选项卡 我的问题是使用它想要显示最后一个活动的活动组在选项卡之间切换 我想在导航选项卡时显示上次打开 访问的屏幕 我的方法是转到第一个屏幕 我需要在浏览选项卡时显示上次打开的屏幕 选项卡 1 gt
  • 立即更新 CALayer 子层

    我有 UIView 其结构如下 UIView layer CALayer depthLayer CALayer bodyLayer CALayer For layer我设置 needDisplayOnBoundsChange true 当我
  • react-native启动报:Error: UNKNOWN: 未知错误,打开...\.babel.json

    我在Windows 7上有一个RN开发环境 它运行得很好 直到昨天我运行 react native start后突然报错 错误消息 2016 12 26 09 58 17 HMR Server listening on hot React
  • 在java中将文件重命名为另一个文件

    我有一个文件需要重命名为现有文件的名称 这是对现有 JAR 文件的复制 修改 替换原始操作 我已经完成了前两个步骤 我只需要更换原始位的帮助 将新版本的 JAR 重命名为旧版本的最佳方法是什么 旧 JAR 不需要保留 而且我不想保留新 JA
  • 在 Either 中指定 Case 对象的类型

    如果我有一个对象如下 case object Foo 我尝试创造这样的价值 Either Foo B 我收到编译错误 指出找不到 Foo 但如果我这样做 Either Foo type B 它编译 我的问题是这样做是否正确 每当你想声明一个
  • 如何根据执行程序/子安装程序的过程结果重新启动 Inno Setup 安装程序

    我有一个安装过程 如果未安装子 exe 则执行该安装过程 如果是这样 我想要最终的 启动我的应用程序 末尾的复选框将替换为 重新启动计算机 复选框 我怎样才能做到这一点 我尝试使用NeedRestart 并使用全局布尔变量 但我似乎无法让它
  • 如何创建没有 setter 函数的 getter 函数?

    我的脚本中有多个导出的变量 每当更改一个变量时 我想调用一个通用的 getter 并让值自动设置 tool export float var sample1 setget smthn changed export float var sam