Is it possible to do string formatting in the property editor using an export variable?
I have a game with items that have different descriptions, and I’d like to use an export variable so I can quickly write them inside the editor. However, I’d also like to do string formatting, so I don’t have to rewrite it if something minor, like a number, changes. For example: "-%s Health to attacker when owner is attacked" % str(damage)
Currently, I set the description in the _ready(): function for descriptions with formatting, but I was wondering if there’s a way to do those in the editor instead?
## A common func to get the final text content
func fetch(content: String, dic_param: Dictionary = {}) -> String:
if dic_param:
return content.format(dic_param)
return content
# The definition of text with param, can be in editor
var some_text = '-{damage} health and...'
# Use fetch func to parse the final text
var damage = 300 # Get this value from other part
var final_text = fetch(some_text, {'damage': damage})
So you can define a string template with named parameters(0 to many, no matter the locations), and use a wrapper func to get the real string.
The con is all keys of dictionary must be spelled exactly right. So it’s just one way, and glad to see a better solution.
Here is one using setters/getters and expression evaluation. I added some code to print when message changes with signals which you can discard. Just set the @export msg string expression in the inspector and the new result will print. You dont need \" when you type it inspector.
extends Node2D
var damage=100
var message
signal message_changed
@export var msg: String = "\"%s health is \" % str(damage)":
set = set_msg
func _ready():
message = eval(msg)
message_changed.connect(Callable(self,"print_msg"))
message_changed.emit()
func set_msg(new_msg: String) -> void:
# You can add logic here to validate the value, trigger other actions, etc.
message = eval(new_msg)
message_changed.emit()
func eval(new_msg):
var expr=Expression.new()
var err=expr.parse(new_msg)
if expr.has_execute_failed():
print(err)
return
return expr.execute([],self)
func print_msg():
print(message)
Thanks a bunch! One downside is that I always have to put quotation marks around my string, even if the string doesn’t have any formatting, but it works great otherwise!
I think this has a lot of downsides for regular use. For one it is a entire expression, you could put any code inside the string, opening up potential security issues if this is somehow user-facing, and messing up could be much worse than a wonky string. Re-running this message string for say updating heath is more expensive than other operations.
@gamefang 's solution addresses these issues, here’s another example of how to use it
@export_multiline var message_raw: String = "-{damage} health to attacker with bonus {bonus_damage}x ({bonus_damage_calculated}) against {strong_type}"
func get_message() -> String:
return message_raw.format(get_parameters())
Then your objects/actors/players can define a function to get their parameters and the message can be supplied
# potentially overriden for each type of object you want to support
func get_parameters() -> Dictionary:
return {
"name": self.name,
"damage": self.damage,
"strong_type": self.strong_type,
"weak_type": self.weak_type,
"bonus_damage": self.bonus_damage,
"bonus_damage_calculated": self.damage * self.bonus_damage,
"durability": self.durability,
}