Put Energy in your Maximo animations | time variation in Range/Upbge

Have you noticed that Maximo action animations (and many others) seem to have been recorded on clueless low-energy actors ? :stuck_out_tongue:
The character seems to punch, kick a ghost or some studio air… doesn’t look good.

Just speeding up the animation ? No , that doesn’t work. The speed is higher but constant.

BUT, by putting variations in the speed of the same animation, you can transform the pace and still keep the length of the animation.

d4cfb81543506c768ea2d860534917182919870f_2_690x367

The green line is the constant speed of your animation. The blue and orange are both slopes with different curvature and lag. The yellow one is a weighted mix of the 2 curves (75% goes to the orange, 25% to the blue) …

What does the yellow curve represents : it represents an animation that roughly plays in a smooth shape the 10 first frames at same speed than a constant … but … then holds a pause during ±10 frames in which the animation seems still … then then around frame 20, runs quickly exhaust the end of the animation (± 30 frames) in the time span of 20 frames.

→ So, to mark a pause in your animation around the frame 10 , you need to weight the blue one 25% (coz 25% of 40 = 10)

So typically, this is what u want for your “kick” or “punch” animations … you want the impact lasts for some time to emphasize the impact.

What to use ?

You can use the Logistic function

6f42e36c949c94189976ae00853af9a1b618e099

L = Length of your animation (in our example : 40 )
K = The shape of your Slope ( blue:1 , orange:0.5 )
T = x0 = The midpoint of the curve (blue : 5 , orange 25)
F = x = the time (expressed as the frame)
Y = f(x) = The position in the animations

Python code

    L = 40 ; F = player['frame_time']   ### F is typically the time 
    T1 = 5 ; T2 = 25 ; K1 = 1 ; K2 = 0.5   
    P = 10                              ### the moment the animation is still
    w1 = P/L ; w2 = 1-w1                ### 2 weights : 25% - 75% if L = 40
    
    noise = round(uniform(-1,1)/15,2)   ### why not create some noise ?
    bound = (T1 <  F < T2 )             ### noise time span 

    player["frame_pos"]  =   (noise*bound) +  w1*L/(1+exp(-K1*(F-T1)))  +  w2*L/(1+exp(-K2*(F-T2)))

So the time X is player[‘frame_time’] and the output Y is player[“frame_pos”]

Where to use ??

  • In Range 1.0 → … : you can use the Action Actuator with a Float property

image

  • In Range 1.6 → … : with this new feature you can feed the “Speed”

!! Actually use the SPEED (see post below) and not the POSITION

KX_GameObject.setActionLayerSpeed(Layer, Speed)
SetActionLayerSpeed

1 Like

Addendum

Previous Post was about computing the Position , if you want to calculate the Speed @ each frame, you can use its derivative

s1 = K1*L*exp(K1*(F-T1))/((1+exp(K1*(F-T1)))**2)
s2 = K2*L*exp(K2*(F-T2))/((1+exp(K2*(F-T2)))**2)
player["frame_speed"]  = w1*s1 + w2*s2

Green line is the constant speed of 1 Frame each time.

If you want to test in Range or Upbge : Animations functions with a Speed parameter

Range.types.KX_GameObject.html#KX_GameObject.playAction
Range.types.KX_GameObject.html#KX_GameObject.setActionLayerSpeed

1 Like