I have assets that I create and animate in Blender. So I want to be able to import them into Godot and have the work with AnimationTrees in a semi automated way. Meaning I don't really want to have to create the inherited scene for every asset and then add an animation tree etc etc.

The steps I have seen using the GUI are basically

  1. Create AnimationTree
  2. Create a AnimationNodeBlendTree on #1
  3. Configure the AnimationTree with the right AnimationPlayer
  4. Add a BlendSpace1D in the AnimationNodeBlendTree
  5. Configure that BlendSpace1D with the animations (in my case "idle" and "walk")
  6. Connect the BlendSpace1D to the Output
  7. Later update the parameters of the AnimationTree to get the blended animation

It seems like this is somewhat supported, you basically have to create an AnimationTree, AnimationNodeBlendTree, AnimationNodeBlendSpace1D and then just configure them all and then finally add the AnimationTree to the hierarchy. But it doesn't seem to work for me.

var animationTree := AnimationTree.new()

func setup_animation_tree():
	var idle = self.animationPlayer.get_animation("idle")
	var walking = self.animationPlayer.get_animation("walk")
	var blendTree := AnimationNodeBlendTree.new()
	var blendSpace := AnimationNodeBlendSpace1D.new()
	var inputName = "IdleWalkInput"
	blendTree.add_node(inputName, blendSpace, Vector2(100, 100))
	blendTree.connect_node(inputName, 0, "Output")
	self.add_child(self.animationTree)
	self.animationTree.set_tree_root(blendTree)
	self.animationTree.set_animation_player(self.animationPlayer.get_path())
	blendSpace.min_space = 0
	blendSpace.max_space = 1
	blendSpace.add_blend_point(idle, 0)
	blendSpace.add_blend_point(walking, 1)

Later when we want the blended animation (this examples sets the walk animation with (1):

self.animationTree.set("parameters/IdleWalkInput/blend_position", 1)

The above example assumes there is an idle and a walk animation on the model (Which I verified was the case in my test code).

My one thought here is the step where you connect the node to the output. I am really not sure if that API works at all, or is it just impossible to connect the blendspace1D to the output programmatically? It seems impossible to find the name of the Output or verify it even exists when created programmatically. So I really wonder if connect_node is working, though it does not assert.

    graggu
    I played around a bit more and figured out that it does respond true to blendTree.has_node("output") so it seems the output is lowercased. However the connect function still appears to have no effect when given a lowercase string.

    I also don't seem to get anything from setting animationTree.active = true

      graggu

      Actually I see some errors now

      1. First of all it seems to always assert when I try to add the animation to the blendSpace. Nothing I do to make sure the AnimationTree, BlendTree or BlendSpace to a parent first seems to resolve this. Should I be adding these as nodes in other ways than I am already?

      Doing this:

      blendSpace.add_blend_point(idle, 0)

      Gives this error

      E 0:00:00:0532   BasicCharacter.gd:46 @ setup_animation_tree(): Condition "p_node.is_null()" is true.
        <C++ Source>   scene/animation/animation_blend_space_1d.cpp:132 @ add_blend_point()
        <Stack Trace>  BasicCharacter.gd:46 @ setup_animation_tree()
                       BasicCharacter.gd:16 @ _ready()

      Because of this https://github.com/godotengine/godot/blob/ee865051367a78bf20f50500520af13ef8f1097b/scene/animation/animation_blend_space_1d.cpp#L132

      1. The other problem is that it asserts if you even try to output the to the output node programmatically.
        https://github.com/godotengine/godot/blob/ee865051367a78bf20f50500520af13ef8f1097b/scene/animation/animation_blend_tree.cpp#LL1146C16-L1146C29

      Doing this

      blendTree.connect_node(inputName, 0, "output")

      Error:

      E 0:00:00:0532   BasicCharacter.gd:48 @ setup_animation_tree(): Condition "p_output_node == SceneStringNames::get_singleton()->output" is true.
        <C++ Source>   scene/animation/animation_blend_tree.cpp:1141 @ connect_node()
        <Stack Trace>  BasicCharacter.gd:48 @ setup_animation_tree()
                       BasicCharacter.gd:16 @ _ready()

      So it just seems like it's not possible to set up an AnimationTree programmatically at all.

        graggu Okay so I figured out some more. Firstly you can't set an Animation to a BlendSpace you have to set a AnimationNodeAnimation instead. But ultimately it looks like it's impossible to programmatically connect the output node inside a BlendTree which seems kind of weird to me.

        Here is the final code, but I had to create a scene where I already created a blendTree and connected the output

        func setup_animation_tree():
        	self.animationTree = self.preloadAnimationTree.instantiate() as AnimationTree
        	self.add_child(self.animationTree)
        	self.animationTree.set_animation_player(self.animationPlayer.get_path())
        
        	var blendTree := self.animationTree.tree_root as AnimationNodeBlendTree
        	var blendSpace := blendTree.get_node("BlendSpace1D") as AnimationNodeBlendSpace1D
        	blendSpace.min_space = 0
        	blendSpace.max_space = 1
        	var idleAnimation = AnimationNodeAnimation.new()
        	idleAnimation.set_animation("idle")
        	var walkAnimation = AnimationNodeAnimation.new()
        	walkAnimation.set_animation("walk")
        	blendSpace.add_blend_point(idleAnimation, 0)
        	blendSpace.add_blend_point(walkAnimation, 1)
        	self.animationTree.set("parameters/BlendSpace1D/blend_position", 0)
        	self.animationTree.active = true
        8 months later

        graggu blendTree.connect_node(inputName, 0, "output")

        Actually, it's possible to connect. The problem is in parameter order. The "output" should be in input parameter)
        blendTree.connect_node("output", 0, inputName)
        This happens because first two function parameters describe target node - thing which get data as input