Skip to content

Instantly share code, notes, and snippets.

@bruchmann
Last active November 9, 2025 19:36
Show Gist options
  • Select an option

  • Save bruchmann/b1e9bd8d9ff0416d0c6bc1a8cf9e0e9f to your computer and use it in GitHub Desktop.

Select an option

Save bruchmann/b1e9bd8d9ff0416d0c6bc1a8cf9e0e9f to your computer and use it in GitHub Desktop.
Intent system for Godot. (WIP)
class_name IdleIntent
extends Intent
class_name Intent
extends RefCounted
enum Priority {
LOW,
MEDIUM,
HIGH,
CRITICAL,
}
const COMMITMENT_MIN: float = 0.0
const COMMITMENT_MAX: float = 1.0
var accessor: String:
get = get_accessor, set = set_accessor
var commitment: float = COMMITMENT_MIN:
set = set_commitment
var priority: Priority = Priority.LOW
var _accessor_override: String = ""
var _derived_accessor: String = ""
func _to_string() -> String:
var script: Script = get_script()
var cls_name: String = str(script.get_global_name())
assert(!cls_name.is_empty(), "Intent must not be anonymous. Define a class name.")
var data: Dictionary = _serialize()
var stringified_data: String = ""
if !data.is_empty():
stringified_data = "#" + JSON.stringify(data)
return "<%s%s %d>" % [
cls_name,
stringified_data,
get_instance_id(),
]
func get_accessor() -> String:
if !_accessor_override.is_empty():
return _accessor_override
if _derived_accessor.is_empty():
_derived_accessor = _derive_accessor()
return _derived_accessor
func set_accessor(value: String) -> void:
_accessor_override = value
func set_commitment(value: float) -> void:
commitment = clampf(value, COMMITMENT_MIN, COMMITMENT_MAX)
func _derive_accessor() -> String:
var script: Script = get_script()
var cls_name: String = str(script.get_global_name())
assert(!cls_name.is_empty(), "Intent must not be anonymous. Define a class name.")
if !cls_name.ends_with("2D") and !cls_name.ends_with("Intent"):
assert(false, "Invalid intent name \"%s\". Must end with Intent or Intent2D." % cls_name)
var raw_name: String = cls_name.trim_suffix("2D").trim_suffix("Intent")
return raw_name.to_snake_case()
func _serialize() -> Dictionary:
var data: Dictionary = { }
for property: Dictionary in get_property_list():
if property.name == "priority":
data["priority"] = Intent.Priority.keys()[priority].to_lower()
continue
if property.usage != PropertyUsageFlags.PROPERTY_USAGE_SCRIPT_VARIABLE:
continue
if property.name.begins_with("_") or property.name == "accessor":
continue
data[property.name] = self[property.name]
return data
class_name IntentMap
extends RefCounted
var _intents: Dictionary[String, Intent] = { }
static func singleton(intent: Intent) -> IntentMap:
var map: IntentMap = IntentMap.new()
map.add(intent)
return map
func _get(property: StringName) -> Variant:
return _intents.get(property)
@warning_ignore("unused_parameter")
func _set(property: StringName, value: Variant) -> bool:
assert(false, "IntentMap is read only. Use IntentMap.add to add a new intent.")
return false
func _to_string() -> String:
var stringified_keys: String = ""
if !is_empty():
stringified_keys = " ["
for intent: Intent in values():
stringified_keys += str(intent)
stringified_keys += "] "
return "<IntentMap%s%d>" % [stringified_keys, get_instance_id()]
func add(intent: Intent, force_override: bool = false) -> bool:
if has(intent.accessor) and !force_override and !_can_override_intent(intent):
return false
_intents[intent.accessor] = intent
return true
func clear() -> void:
_intents.clear()
func has(intent: Variant) -> bool:
if typeof(intent) == TYPE_STRING:
return _intents.has(intent)
assert(typeof(intent) == TYPE_OBJECT, "intent must be an object.")
if is_empty():
return false
for value: Variant in values():
if is_instance_of(value, intent):
return true
return false
func is_empty() -> bool:
return _intents.is_empty()
func keys() -> Array:
return _intents.keys()
func values() -> Array:
return _intents.values()
func with_default(default_intent: Intent) -> IntentMap:
if !is_empty():
return self
return IntentMap.singleton(default_intent)
func _can_override_intent(new_intent: Intent) -> bool:
var old_intent: Intent = _intents[new_intent.accessor]
if new_intent.priority > old_intent.priority:
return true
return new_intent.priority == old_intent.priority and new_intent.commitment > old_intent.commitment
class_name MovementIntent2D
extends Intent
var direction: Vector2
@warning_ignore("shadowed_variable")
func _init(direction: Vector2) -> void:
self.direction = direction
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment