Action "blend-in" in GE

Having an issue with my FPS motion rig in blender. Not sure if it is my python script causing it or some issue with my logic bricks…



As you can see from the in game screenshot, I am having an issue where multiple actions are blending together. For example:

I can walk (W) then hold down Shift to run… the animation works fine. If I release the shift AND the W, then hit the W key again, the animation works fine.

BUT if I let go of the shift key, and still hold down the walk key (W) the actions sort of blend slightly. Then, if I iron-sight in while still holding the walk key, then iron sight out, I get the following in game screen. The actions are all blended together, and only fix themselves if I let all the keys go and it resets.

Here is my python:

from bge import logic as GameLogiccont = GameLogic.getCurrentController()
own = cont.owner


g1 = cont.sensors["g1"].positive
g2 = cont.sensors["g2"].positive
g3 = cont.sensors["g3"].positive
g4 = cont.sensors["g4"].positive
jump = cont.sensors["Space"]
fwd = cont.sensors["W"]
back = cont.sensors["S"]
slft = cont.sensors["A"]
srght = cont.sensors["D"]
shift = cont.sensors["Shift"]
lctrl = cont.sensors["Crouch"]
iron_sight_s = cont.sensors["Iron_sight"]


act = cont.actuators["floormove"]
crouch_d = cont.actuators["Crouch_D"]
crouch_u = cont.actuators["Crouch_U"]
idle = cont.actuators["idle"] #gun anim ipo
run = cont.actuators["run"] #gun anim ipo
walk = cont.actuators["walk"]
iron_sight_a = cont.actuators["iron_sight"]
#head_bob = cont.actuators["Head_Bob"]




ownc = crouch_d.owner




if ownc["cstate"] == 1: #If crouching, slow down
    speed = 1
else:
    speed = 2
jspeed = 0 #unless we press the jump button our jump speed will be set to zero.




sqrt2over2 = 0.70710678






if g1 or g2 or g3 or g4: #If any of the 4 ground sensors are within .54 BU from the ground, give user control over motion.  #If you change this, user could jump high, start walking far above the ground
    
    if lctrl.positive and ownc["cstate"] == 0: #If we hit crouch (tap sensor), and we are not already crouching
        speed = 1 #slow down
        cont.activate(crouch_d) #Activate our crouch down animation
        ownc["cstate"] = 1 #Set our crouch state to crouched
    else:
        if lctrl.positive and ownc["cstate"] == 1: #If we hit crouch (tap sensor), and already crouched
            speed = 2 #speed up
            cont.activate(crouch_u) #activate our crouch up animation
            ownc["cstate"] = 0 #set our crouch state to NOT crouched
    
    if shift.positive:#If holding down the run button, speed up
        speed = 3
        if ownc["cstate"] == 1: #If we are crouched and try to run, stand up and run
            cont.activate(crouch_u) #activate our crouch up animation
            ownc["cstate"] = 0 #stand up to start running
    
    if     iron_sight_s.positive:
        print("IRON_SIGHT")
        speed = 1
        cont.deactivate(run)
        cont.deactivate(idle)
        cont.deactivate(walk)
        cont.activate(iron_sight_a)
        
    
    fspeed = speed * (fwd.positive - back.positive) #fspeed, or forward speed, takes the walking/running/crouch speed and multiplies it by W key and S key pressure to equal our forward/backward speed
    sspeed = speed * (srght.positive - slft.positive) #sspeed or sidways speed, takes the walking/running/crouch speed and multiplies it by A key and D key pressure to equal our right/left speed
    
    if fspeed and sspeed: #if we are traveling sideways (Two keys held down) I believe attempting to slow the diagonal speed slightly.
        fspeed *= sqrt2over2 #variable set up as .707 in beginpning... unsure why that exact number?
        sspeed *= sqrt2over2
    
    if own["rel"] == 0: #Disables forward and sideways speed (appears to be used for disabling walking when jumping)
        fspeed = 0
        sspeed = 0
    
    if not jump.positive: #If we aren't pressing the jump button, the property jstate on our player will be set to 1
        own["jstate"] = 1
    
    if jump.positive and own["jstate"] == 1: #If we are pressing the jump button, AND we aren't already jumping
        jspeed = 2 #set our jump speed
        own["jstate"] = 0 #set our jump state BACK to "not jumping" (disables double jump)
        own["rel"] = 0 #disable movement in the air
        cont.activate(idle) #disables the walk/run anim in the air
        
        
    act.linV = [-fspeed, sspeed, jspeed] #act = cont.actuators["floormove"] Taking speed (Side speed (D and A)
    print(fspeed)
    if [sspeed, fspeed, jspeed] == [0, 0, 0]:
        print("zeros")
        cont.deactivate(run)
        cont.deactivate(walk)
        cont.deactivate(act)
        cont.activate(idle)
        #cont.deactivate(head_bob)
    else:
        if ownc["cstate"] == 1 and (shift.positive + jspeed) == 0:
            cont.deactivate(idle)
            cont.activate(walk)
            
        #else:
            #cont.activate(idle)
            #cont.deactivate(run)
        
        if speed == 2 and fspeed != 0: # If walking forwards or backwards or DIAG
            cont.deactivate(run)
            cont.deactivate(idle)
            cont.activate(walk)
            #cont.deactivate(head_bob)
            print("walk_activated")
        else: #If walking sideways only
            if speed == 2:
                print("Sideways")
                cont.deactivate(walk)
                cont.activate(idle)
        
        if speed == 3: #If running
            #cont.activate(head_bob)
            cont.deactivate(walk)
            cont.deactivate(idle)
            cont.activate(run)
            print("run_activated")


        cont.activate(act)
        print("activating else")
else:
    cont.deactivate(act)
    own["rel"] = 1





Usually having actions blend together is a desirable property. If they don’t, your character will suddenly “jump” to a new pose when changing animations rather than moving to the new pose smoothly.

But as for your problem, I would suggest looking through you logic to make sure the run action deactivates as soon as you lift up the shift key. Right now it looks like you deactivated it based on speed conditions, not on the state of the shift key.

Yes, I suppose “Stuck-in” is a better word, I do have blend-in on these animations already, and that does work correctly.

So I rewrote my script, and it still has the exact same issues? Any other ideas? Does this script look correct?

from bge import logic as GameLogiccont = GameLogic.getCurrentController()
own = cont.owner


g1 = cont.sensors["g1"].positive
g2 = cont.sensors["g2"].positive
g3 = cont.sensors["g3"].positive
g4 = cont.sensors["g4"].positive
jump = cont.sensors["Space"]
fwd = cont.sensors["W"]
back = cont.sensors["S"]
slft = cont.sensors["A"]
srght = cont.sensors["D"]
shift = cont.sensors["Shift"]
lctrl = cont.sensors["Crouch"]
iron_sight_s = cont.sensors["Iron_sight"]


act = cont.actuators["floormove"]
crouch_d = cont.actuators["Crouch_D"]
crouch_u = cont.actuators["Crouch_U"]
idle = cont.actuators["idle"] #gun anim ipo
run = cont.actuators["run"] #gun anim ipo
walk = cont.actuators["walk"]
iron_sight_a = cont.actuators["iron_sight"]
#head_bob = cont.actuators["Head_Bob"]




ownc = crouch_d.owner




if ownc["cstate"] == 1: #If crouching, slow down
    speed = 1
else:
    speed = 2
jspeed = 0 #unless we press the jump button our jump speed will be set to zero.




sqrt2over2 = 0.70710678






if g1 or g2 or g3 or g4: #If any of the 4 ground sensors are within .54 BU from the ground, give user control over motion.  #If you change this, user could jump high, start walking far above the ground
    
    if lctrl.positive and ownc["cstate"] == 0: #If we hit crouch (tap sensor), and we are not already crouching
        speed = 1 #slow down
        cont.activate(crouch_d) #Activate our crouch down animation
        ownc["cstate"] = 1 #Set our crouch state to crouched
    else:
        if lctrl.positive and ownc["cstate"] == 1: #If we hit crouch (tap sensor), and already crouched
            speed = 2 #speed up
            cont.activate(crouch_u) #activate our crouch up animation
            ownc["cstate"] = 0 #set our crouch state to NOT crouched
    
    if fwd.positive or back.positive or slft.positive or srght.positive:
        print("Walk")
        cont.deactivate(run)
        speed = 2
        if (fwd.positive or back.positive) and not (slft.positive or srght.positive):
            cont.activate(walk)
            
        if (slft.positive or srght.positive) and not (fwd.positive or back.positive):
            print("sideways")
            cont.activate(idle)
        
        if (fwd.positive or back.positive) and (slft.positive or srght.positive):
        #cont.deactivate(run)
        #cont.deactivate(idle)
            cont.activate(walk)


    if shift.positive:#If holding down the run button, speed up
        print("Run")
        speed = 3
        cont.activate(run)
        if ownc["cstate"] == 1: #If we are crouched and try to run, stand up and run
            cont.activate(crouch_u) #activate our crouch up animation
            ownc["cstate"] = 0 #stand up to start running
    
    if not shift.positive:
        print("Not_RUN")
        cont.deactivate(run)
        cont.deactivate(idle)
        cont.activate(walk)


    if     iron_sight_s.positive:
        print("IRON_SIGHT")
        speed = 1
        cont.deactivate(run)
        cont.deactivate(idle)
        cont.deactivate(walk)
        cont.activate(iron_sight_a)


    fspeed = speed * (fwd.positive - back.positive) #fspeed, or forward speed, takes the walking/running/crouch speed and multiplies it by W key and S key pressure to equal our forward/backward speed
    sspeed = speed * (srght.positive - slft.positive) #sspeed or sidways speed, takes the walking/running/crouch speed and multiplies it by A key and D key pressure to equal our right/left speed
    
    if fspeed and sspeed: #if we are traveling sideways (Two keys held down) I believe attempting to slow the diagonal speed slightly.
        fspeed *= sqrt2over2 #variable set up as .707 in beginpning... unsure why that exact number?
        sspeed *= sqrt2over2
    
    if own["rel"] == 0: #Disables forward and sideways speed (appears to be used for disabling walking when jumping)
        fspeed = 0
        sspeed = 0
    
    if not jump.positive: #If we aren't pressing the jump button, the property jstate on our player will be set to 1
        own["jstate"] = 1
    
    if jump.positive and own["jstate"] == 1: #If we are pressing the jump button, AND we aren't already jumping
        jspeed = 2 #set our jump speed
        own["jstate"] = 0 #set our jump state BACK to "not jumping" (disables double jump)
        own["rel"] = 0 #disable movement in the air
        cont.activate(idle) #disables the walk/run anim in the air
        
        
    act.linV = [-fspeed, sspeed, jspeed] #act = cont.actuators["floormove"] Taking speed (Side speed (D and A)
    print(fspeed)
    if [sspeed, fspeed, jspeed] == [0, 0, 0]:
        cont.activate(idle)
        #cont.deactivate(head_bob)
    else:
        if ownc["cstate"] == 1 and (shift.positive + jspeed) == 0:
            cont.deactivate(idle)
            cont.activate(walk)




        cont.activate(act)
        print("activating else")
else:
    cont.deactivate(act)
    own["rel"] = 1





Does anyone know of a FPS template that has arms/gun with multiple animations that I can at least look at? I’m out of ideas at this point, and apparently no one else knows either… Seems like this would be something that someone would run into a lot…

The only other thing I can suggest is removing the blend-in frames on the walk animation. I suspect that the run animation is stopping correctly, but leaves the armature stopped in a running animation pose. The armature then blends from this pose to the walking animation.

If you want more control over when your actions use blend-in and when they don’t, I would suggest using the playAction method instead of the action actuator.

I would also suggest using the playAction method to play animations as opposed to the action actuator, since you’re already using Python for your character’s movement. It’s a bit difficult to diagnose a problem looking at just logic bricks and a script. Posting the blend file would be helpful.

I did set the blend-in to zero, it made no difference with that issue…

I uploaded my new re-written python script .blend file to:
https://docs.google.com/open?id=0Bz170qNApm2AeHIteng4NEhRamc

I also just realized there is another bug where if I jump while running it appears to keep running… not sure if that was in my old script or not…

Also, if someone could point me to an in-depth explanation of the priority feature of the action actuator that would be great, because that does not do even close to what I expect, just now using trial and error to get that working.

Thanks for the playaction method, I have just started with python so haven’t much of a clue what python stuff is available.

This “stuck-in” frame issue will correct itself if I let off of all of the keys, or jump… is there a way that perhaps I can simulate that? I’m afraid I didn’t write most of this script, just editing an existing fps template I found, so not that knowledgeable.

I took a quick look at your file and it seems that the run action has key frames on bones that the walk action doesn’t have key frames on. This means when you switch from the run action to the walk action, the bones that don’t have key frames in the walk action won’t “reset” to the position you want them to be in. Make sure you put key frames on all the bones you want to position in each action.

Wow… thanks, I just added key frames at frame 1 for all the bones and it works fine, thank you so much, can’t believe that was the issue…

As you can tell, I haven’t been using blender very long, thanks for your help.

to me the script is to restructuring.

you have start to use some states but here not fully integrated and seem more a exception at moment
i suggest to expand it as first statement ,(before the states , then the keyboard)
this way should still more easy , and easy to debug

somenting like this
pseudocode:








newState = curState = own["STATE"]






if curState == "run" :
    if not keyShift : 
        newState = "walk"
        cont.deactivate(curState)
        cont.activate(newState)
    else:
        x, y = 0, 0
        if keyW y = 10
        if keyS y = -5
        if keyA x = -5
        if keyD x =  5
        own.localLinearVelocity.xy = x, y
        if not y and not x:
            newState = "walk"
            cont.deactivate(curState)
            cont.activate(newState)
        
        
        
elif curState == "walk" :
    if keyShift : 
        newState = "run"
        cont.deactivate(curState)
        cont.activate(newState)
         
    else:
        x,y=0,0
        if keyW y =  5
        if keyS y = -2
        if keyA x = -2
        if keyD x =  2
        own.localLinearVelocity.xy = x, y
        if not y : 
            newState = "idle"
            cont.deactivate(curState)
            cont.activate(newState)

I will take a look at this… but not sure how that would be better… When I hit the shift key, I want to come out of a crouch and start running, OR go from a walk to a run… if I am stuck in the state based setup won’t that require a ton of duplication? Since I will have to test for shift.positive if I am in the crouch state AND if I am walking as well… and so on… Of course, not an expert, so I may be missing something…