Animation 1d and 2d blend trees

Hello,
Neither BGE, UPBGE nor Range have Animation blend trees.
It makes 1D/2D Vector based animations extremely difficult, if not impossible to get a clean animation.

Has there ever been a tool, addon whatsoever, or has anyone ever written a functioning blend tree script?

Since blendin doesnt work with property driven animations, the only way is to fiddle around with layer weight. That works fine for 1D blending but is almost impossible with 2D blending.

If someone has a solution I would highly appreciate it, as I have been struggling with this for ages.

Cheers

Hello,

Not sure if this would help, but if you use 2 action actuators on 'Property" mode , you can pretty do whatever u want. Other modes (play, LoopEnd, …) are just broken for proper animation mixing …

Indeed, the “BlendIn” option just use the last frame of the previous animation … so basically a mini-freeze … and the “layerWeight” cannot update its value during animation play time …

So play your animations frame by frame with the Property mode and update your mix choices each frame.

1 Like

Yes, that’s basically what I do. You gave me that advice some years ago and that is what I have been doing. But you need a lot of scripting to get it right. And if you mix in loads of animations it can get really complicated.
Here is a script of mine just for Idle and turning as an example:

Blockquote
def steering(self, stance):

    speed = abs(self.physicsObject.linearVelocity.y)
    speedFactor = min(speed / 5, 1.0)

    if abs(self.movementDirection[0]) > .1:

        turnFactor = self.movementDirection[0]  * 60  * speedFactor
        self.turnFrame = Database.lerp(self.turnFrame, turnFactor, .05)
    else:
        self.turnFrame = Database.lerp(self.turnFrame, 0, .05)

    if self.driftButton:
        self.driftTurnFrame = Database.lerp(self.driftTurnFrame, self.turnFrame, .05)
        self.steerToDrift = Database.lerp(self.steerToDrift, 0.0, .05)
    else:
        self.driftTurnFrame = Database.lerp(self.driftTurnFrame, 0.0, .05)
        self.steerToDrift = Database.lerp(self.steerToDrift, 1.0, .05)

    if speed < 1:#self.turnFrame > .5 or self.turnFrame < -.5:
        self.steerToDrift = Database.lerp(self.steerToDrift, 1.0, .5)

    if abs(self.turnFrame) > 1:

        self.setAnim("A_turn_"+self.stanceSuffix, self.turnFrame,self.turnFrame,2, 0,0,0,0)

        if self.steerToDrift < .95:
            if not Range.logic.globalDict["isDoingManual"]:
                self.setAnim("A_drift_"+self.stanceSuffix, self.driftTurnFrame, self.driftTurnFrame,3, 0,0,0,self.steerToDrift)
        self.resetIdle()
    else:
        self.object.stopAction(3)
        self.object.stopAction(2)

        if stance:
            self.setAnim("A_idle_regular", 0, 400, 1, 0, 5, 0, 0)
        else:
            self.setAnim("A_idle_switch", 0, 400, 0, 1, 5, 0, 0)

That’s why I was hoping for an easier solution.

Looks over-complicated … don’t know why you guys so obsessed to write walls of text whilst - for me at least - its just about scheduling some bricks with python after fetch a whole action record in an indexed table

[ [keys], “animation”,“length”,“loc”,“rot”, …] … then feed my hungry bricks

Just have to mix some values for the Motion actuator based on the value i set for the LayerWeight . I update the stuff each frame, but it can be lower pace

NB : i feed the Motion actuator with Delta Pos , basically speed . So from the original animation, i record the Position , then compute the Delta for X and Y (Z is often un-used unless your character fly :stuck_out_tongue: ) . Those computed and stored in a table .

def dX(x,r) :
	dx = [round(b-a,r) for a,b in zip(x,x[1:])]	
	dx.append(dx[-1])
	return dx

Can you change the layerWeight of a Actuator by script?
For the keys, do you have a state machine of some sort?
[ [keys], “animation”,“length”,“loc”,“rot”, …]

And what does this script do?

Blockquote

def dX(x,r) :
	dx = [round(b-a,r) for a,b in zip(x,x[1:])]	
	dx.append(dx[-1])
	return dx

yes, with
myactionactuator.layerWeight = value (a float value between 0 and 1 )

no, just sensor’s values, parameters … anything u want … i write the keys in the table, but you can use dictionnary if u prefer … really nothing hard here

as said, compute the delta of values of a list so i can feed my Motion actuator with Delta values … For the last element, i pick a guess on how/when the Motion actuator is operating. But i said that the last value might be the same than the one before

do a test

PosY = [0,2,4,7,11,10,11,11] 
DeltaY = dX( PosY , 0)
print(DeltaY)
>>>>  [2, 2, 3, 4, -1, 1, 0, 0]