Skip to content

Instantly share code, notes, and snippets.

@krazyjakee
Last active September 7, 2025 16:13
Show Gist options
  • Select an option

  • Save krazyjakee/6535e42b7e72a0b3c8cf249a847efb3c to your computer and use it in GitHub Desktop.

Select an option

Save krazyjakee/6535e42b7e72a0b3c8cf249a847efb3c to your computer and use it in GitHub Desktop.
AnimationTreePlus: A wrapper for the AnimationTree
## A wrapper around AnimationTree to add a more intuitive API
class_name AnimationTreePlus extends AnimationTree
var _param_cache: Dictionary = {}
func _ready() -> void:
_scan_parameters()
## Scans the AnimationTree's properties and populates the parameter cache.
## This is called automatically in _ready(), but can be called again if parameters are changed at runtime.
func _scan_parameters() -> void:
_param_cache.clear()
for p in get_property_list():
var param_name: String = p.get("name", "")
if param_name.begins_with("parameters/"):
var sub = param_name.substr(11)
if not sub.is_empty():
_param_cache[sub] = param_name
if has_meta("parameters/playback"):
_param_cache["playback"] = "parameters/playback"
## Converts a friendly parameter name (e.g., "MyNode/some_param") to its full path.
func get_param_path(friendly_name: String) -> String:
if friendly_name.begins_with("parameters/"):
return friendly_name
if _param_cache.has(friendly_name):
return _param_cache[friendly_name]
push_warning("AnimationTreePlus.get_param_path: unknown parameter '%s'." % friendly_name)
return ""
## Sets the value of a parameter using its friendly name.
func set_param(param_name: String, value) -> bool:
var path = get_param_path(param_name)
if path.is_empty():
if param_name.begins_with("parameters/"):
path = param_name
else:
push_error("set_param: cannot resolve parameter '%s'." % param_name)
return false
if not _has_property(path):
push_warning("set_param: property '%s' not found in AnimationTree property_list; attempting set anyway." % path)
set(path, value)
return true
## Gets the value of a parameter using its friendly name.
func get_param(param_name: String):
var path = get_param_path(param_name)
if path.is_empty():
if param_name.begins_with("parameters/"):
path = param_name
else:
return null
return get(path) if _has_property(path) else null
## Gets a node from within the blend tree.
func get_blend_tree_node(friendly_name: String) -> AnimationNode:
return tree_root.get_node(friendly_name)
func _has_property(path: String) -> bool:
return get_property_list().any(func(p): return p.get("name") == path)
## Gets the AnimationNodeStateMachinePlayback object from the tree.
func get_state_machine_playback(node_name: String = "") -> AnimationNodeStateMachinePlayback:
if node_name == "":
var path = get_param_path("playback")
if path.is_empty():
push_warning("get_state_machine_playback: playback not found on AnimationTree.")
return null
return get(path)
else:
return get(get_param_path(node_name + "/playback"))
## Travels to a new state in the root AnimationNodeStateMachine.
func travel_state(state_name: String) -> bool:
var playback = get_state_machine_playback()
if not playback:
push_error("travel_state: playback object unavailable.")
return false
playback.travel(state_name)
return true
## Gets the name of the current state in the root AnimationNodeStateMachine.
func get_current_state() -> String:
var playback = get_state_machine_playback()
if not playback:
return ""
return String(playback.get_current_node())
var cs = get_param("StateMachine.current_state")
if cs:
return String(cs)
return ""
## Fires a one-shot animation. The friendly_name is the path to the OneShot node.
func fire_oneshot(friendly_name: String) -> bool:
var param_name = friendly_name + "/request"
return set_param(param_name, AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE)
## Aborts a one-shot animation. The friendly_name is the path to the OneShot node.
func abort_oneshot(friendly_name: String) -> bool:
var param_name = friendly_name + "/request"
return set_param(param_name, AnimationNodeOneShot.ONE_SHOT_REQUEST_ABORT)
## Sets a one_shot fadeout and fadein time
func set_oneshot_fadetimes(friendly_name: String, fade_in_time: float = 0.0, fade_out_time: float = 0.0):
var node: AnimationNodeOneShot = get_blend_tree_node(friendly_name)
node.fadein_time = fade_in_time
node.fadeout_time = fade_out_time
## Returns true if a one-shot animation is currently active. The friendly_name is the path to the OneShot node.
func is_oneshot_active(friendly_name: String) -> bool:
var param_name = friendly_name + "/active"
return bool(get_param(param_name))
## Seeks to a specific time in an animation. The node_name is the path to the Animation node.
func request_timeseek(node_name: String, seconds: float) -> bool:
var param_name = node_name + "/seek_request"
return set_param(param_name, seconds)
## Sets the time scale (speed) of an animation. The node_name is the path to the Animation node.
func set_timescale(node_name: String, scale: float) -> bool:
var param_name = node_name + "/scale"
return set_param(param_name, scale)
## Gets the time scale (speed) of an animation. The node_name is the path to the Animation node.
func get_timescale(node_name: String) -> float:
var param_name = node_name + "/scale"
return get_param(param_name)
func _get_node_parameter_path(node_name: String, parameter_name: String) -> String:
var full_parameter_name = node_name + "/" + parameter_name
if _param_cache.has(full_parameter_name):
return _param_cache[full_parameter_name]
var parameter_path = "parameters/" + node_name + "/" + parameter_name
if _has_property(parameter_path):
_param_cache[full_parameter_name] = parameter_path
return parameter_path
push_warning("_get_node_parameter_path: parameter not found for node '%s', parameter '%s'." % [node_name, parameter_name])
return ""
## Sets the blend amount for a Blend2, Blend3, or BlendSpace1D node.
func set_blend_amount(node_name: String, value: float) -> bool:
var blend_amount_path = _get_node_parameter_path(node_name, "blend_amount")
if not blend_amount_path.is_empty():
set(blend_amount_path, value)
return true
var blend_position_path = _get_node_parameter_path(node_name, "blend_position")
if not blend_position_path.is_empty():
set(blend_position_path, value)
return true
var position_path = _get_node_parameter_path(node_name, "position")
if not position_path.is_empty():
set(position_path, value)
return true
push_warning("set_blend_amount: failed to set blend value for '%s'." % node_name)
return false
## Sets the blend position for a BlendSpace2D node.
func set_blend_position(node_name: String, value: Vector2 = Vector2.ZERO) -> bool:
var position_path = _get_node_parameter_path(node_name, "blend_position")
if not position_path.is_empty():
set(position_path, value)
return true
push_warning("set_blend_position: failed to set blend_position for '%s'." % node_name)
return false
## Linearly interpolates the blend amount for a Blend2, Blend3, or BlendSpace1D node.
func lerp_blend_amount(node_name: String, to_value: float, weight: float) -> bool:
var current_value = get_param(_get_node_parameter_path(node_name, "blend_amount"))
if current_value == null:
current_value = get_param(_get_node_parameter_path(node_name, "blend_position"))
if current_value == null:
current_value = get_param(_get_node_parameter_path(node_name, "position"))
if current_value != null:
var new_value = lerp(current_value, to_value, weight)
return set_blend_amount(node_name, new_value)
push_warning("lerp_blend_amount: failed to get current blend value for '%s'." % node_name)
return false
## Linearly interpolates the blend position for a BlendSpace2D node.
func lerp_blend_position(node_name: String, to_value: Vector2, weight: float) -> bool:
var current_value = get_param(_get_node_parameter_path(node_name, "blend_position"))
if current_value != null:
var new_value = current_value.lerp(to_value, weight)
var position_path = _get_node_parameter_path(node_name, "blend_position")
if not position_path.is_empty():
set(position_path, new_value)
return true
return false
push_warning("lerp_blend_position: failed to get current blend_position for '%s'." % node_name)
return false
## Gets the blend amount for a Blend2, Blend3, or BlendSpace1D node.
func get_blend_amount(node_name: String) -> float:
var value = get_param(_get_node_parameter_path(node_name, "blend_amount"))
if value != null:
return value
value = get_param(_get_node_parameter_path(node_name, "blend_position"))
if value != null:
return value
value = get_param(_get_node_parameter_path(node_name, "position"))
if value != null:
return value
push_warning("get_blend_amount: failed to get blend value for '%s'." % node_name)
return 0.0
## Gets the blend position for a BlendSpace2D node.
func get_blend_position(node_name: String) -> Vector2:
var value = get_param(_get_node_parameter_path(node_name, "blend_position"))
if value != null:
return value
push_warning("get_blend_position: failed to get position for '%s'." % node_name)
return Vector2.ZERO
## Requests a transition in the root AnimationNodeTransition.
func request_transition(node_name: String, transition_name: String) -> bool:
return set_param("%s/transition_request" % node_name, transition_name)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment