Animation Blues: Controlling actions through Python

greets fellow blenderheads:

I’m trying to switch between two animations that run in slow and fast modes respectively (it’s essentially the same animation but in runs in a slow mode, over 800 frames and in fast mode in 80 frames).
Each animation has been setup in its own scene (see attached file).
To run the animation just press the fast button (red one). Once the other scene loads then it’s possible to switch between the two animations.
Pressing the spacebar also pauses the animation when in the slow scene.

I have run into a few problems and I’m not sure how to proceed. Heck, I’m not even sure I’m on the right path. Long story short:

#1. Seameless transition between the two modes. Is it possible in the BGE?
As it stands, the scene loads with the animation set to the first frame, then loads the stored value (if any) from a dictionary and continues from there. The current implementation is not elegant. Is there a more efficient way of achieving this?

#2. Assuming that you’ve swithced between fast and slow modes a couple of times, if you press spacebar the slow scene then the animation freezes as it toggles a property (PLAY). Pressing it again, however, restarts the animation but not from the desired frame. How do I proceed from here? Do I need to set up different functions?

#3. How am I supposed use the API documentation on this page:
https://docs.blender.org/api/blender_python_api_2_78a_release/bge.types.BL_ActionActuator.html#bge.types.BL_ActionActuator
I’ve tried to use some of the function arguments (e.g. frame, useContinue) but got errors ("‘frame’ is an invalid keyword argument for this function"). How am I supposed to use such methods from bge Python?

Any suggestions or recommendations are welcome.

Attachments

animationQuesttion.blend (980 KB)

forget the actuator. you can play an animation directly through python, and it has a play speed argument. Instead of having 2 animations that are the same you could have just 1 animation and change the play speed argument on the fly with a variable/property.

object.playAction(“name”, startFrame, endFrame, layer, priority, blendInFrames, mode, layerWeight, ipoFlags, speed)

you could also use variables/properties for your start and end frame. Making it restart from the beginning or saving the last frame played as a variable to pick up where you left off. Lots of possibilities. If you wanted to get real kinky, you could have it in its own function and pass the arguments you need in the function call.

http://bgepython.tutorialsforblender3d.com/Action/playAction

#1. Seameless transition between the two modes. Is it possible in the BGE?
As it stands, the scene loads with the animation set to the first frame, then loads the stored value (if any) from a dictionary and continues from there. The current implementation is not elegant. Is there a more efficient way of achieving this?

If you want seameless transition you need to change the animation layer for each action. Not only “blendin” and “continue” buttons.

#2. Assuming that you’ve swithced between fast and slow modes a couple of times, if you press spacebar the slow scene then the animation freezes as it toggles a property (PLAY). Pressing it again, however, restarts the animation but not from the desired frame. How do I proceed from here? Do I need to set up different functions?

Again, using different animation layers for the two different actions should also fix this.

I’m new to Blender 2.7+ but this is one of the first things I learned while converting my games. Or at least, this is how it works for me.

storing the last frame played when you switch then using that frame as a new first frame for 1 playout will make the transition part unnoticable…heres basic example, although my animation itself not real smooth.

animswap.blend (426 KB)

Edit: Sorry I just noticed Haidme’s post. Are you purposely wanting it to be 2 separate animations? I think I read your question wrong. I was reading that you were using 2 animations that were the same action, just a slow and fast version, and were wanting to switch between fast and slow without it restarting the animation. I just made it into 1 action, then used the playspeed argument to switch the speed of the action. The changing the startframe of the action to the lastframe played when you clicked for the rest of the action playout, then it resets the startframe to 1.

I had a look at your sample file. Currently I think this is an a bit to complex for the effects you want to achieve.

Why do you need two scenes?
Why you use an action for turning?

Using the actuators as GUI-Editor to setup the action parameters is a nice idea. But you do not benefit very much from it.

I understood your question similar to the other readers … one action played with slow speed and again with fast speed. This is indeed only possible via python as the action actuator does not support different animation speed yet.

While I appreciate you are using module mode, the code is not good to read.

There are various different styles of import.
There is unrelated code mixed into the imports (switching mouse cursor on should be done in the .blend or a separate python file).
The choice of variable names is very cryptic and not descriptive (e.g.: cont, lmb, mo, d, own).

Hint:


if booleanExpression == True:

is good to read, but does a double check. When you know an expression can only be boolean (True or False) you do not need to compare it again. You can shorten your code to this:


if booleanExpression:

Indeed the expression should be that much descriptive that a reader can guess what you mean.

e.g:


if isPlayingAnimation:

All of that does not help on your request, but it helps me to understand your current implementation.

Design
I think you had the correct idea to use the current frame of the current animation as start frame of the target animation. You do not need layers as just one action should play at the time (especially as you have two different objects).

I do not understand why your buttons do so much complicated things. They should simple send a message. Nothing more. The animated objects can care of what to do (playing stopping).

This way it is easy to reuse the buttons (which need a better clickable area btw.).

You need to ensure the timing:

  1. read current frame of the animation and stop the animation
  2. start the new animation set the current frame

this order needs to be preserved, otherwise the current frame is incorrect. This can happens when you use different objects to play the animations. In your situation this will not happen as the objects do not exist at the same time (due to the scene switch).

Here is a demo with two samples:

  • different scenes as you tried to do.
  • single scene - single object

I moved the buttons away into an own scene.
The objects are stateless. This means they do not care what they are currently playing (and if they do).
This means clicking the buttons multiple times resets the current animation (something you can try to work on ;)).

The python module contains three BGE callable functions “stop, playFast, playSlow”. The other functions encapsulate the lower abstraction code.

If by demo you mean a file, could you please re-upload it or attach it to your post?
Thank you.

In the meanwhile, I’m trying to digest all the responses…

Hi, are you wanting to change speed in your simulation?
You might be better off using transforms;

planets.blend (580 KB)

Here’s an example of a planetary sim which uses a timer to control speed. Use up and down arrows to increase or decrease speed. You can even make the animation run backwards!

Actions are best used for simple things like opening a door (even then I’ve found there are advantages to a good transform from a coding perspective) or very complex things like a rigged skeleton.

oups, the upload didn’t worked :eek:.Sorry, the file is on my other PC, I can upload it tomorrow again.

First off, many thanx to you folks for your suggestions which I found very informative.

Secondly, I’ve given it some more(?) thought based on the code samples and a little bit of googling.
I’m almost there, but still feel that I can’t put my finger on it.
If you check the attached blend file you’ll see that the only problem that remains is that upon switching scenes each animation assumes a resting (or initial?) position for a few milliseconds and then behaves as expected.
Why on earth is that happening? What am I missing?

ps: the code is certainly far from optimal (i.e. it’s not generic, needs refactoring etc) but will consider that once I know that this solution works.

Attachments

animationQuesttion-mod.blend (1.11 MB)

I’m sorry,I don’t have the answer but I just don’t get it…
Why on earth you are using two scenes for this? Is there something special you want to do later with these scenes? Also why are you using actual ipo/curves animation for a simple rotation, why just not do this with a simple script rotation and a speed property change?

P.S I guess your problem is in the switching between the scenes. I think scene must be initialized first and then it accepts your script. That is why you see the start position of the object every time you switch the scene. I may talk bullshit here, but this is what I came up with.

Here it is …

Attachments

animationAnswer.blend (1.02 MB)

It’s complicated…

Is there something special you want to do later with these scenes?

yep. Each scene (slow/fast) will have its own overlay scene (which will have to be in sync btw).

Also why are you using actual ipo/curves animation for a simple rotation, why just not do this with a simple script rotation and a speed property change?

Oh no particular reason, it seemed simple enough to do. I guess if it fails to work then I could always try controlling the rotation via a script instead of action

P.S I guess your problem is in the switching between the scenes. I think scene must be initialized first and then it accepts your script. That is why you see the start position of the object every time you switch the scene. I may talk bullshit here, but this is what I came up with.

Assuming that this is the problem any ideas of how to resolve it?

Thank you, checking it out atm

Just a quick note. When you switch scenes all objects will at the initial state. This will be visible at the first render.

I tried to hide that by covering the camera with a black (but disappearing) plane. Unfortunately I have the impression I still can see the initial frame when switching.

Ooops! Then switching scenes will most likely not work! :frowning:

Anyways, looking at your awesome coding solution, I wonder what exactly do the following functions do?


def allSensorsArePositive():
    for sensor in bge.logic.getCurrentController().sensors:
        if not sensor.positive:
            return False
    return True


def oneSensorIsPositive():
    for sensor in bge.logic.getCurrentController().sensors:
        if sensor.positive:
            return True
    return False

Does “Positive” in this context mean that the controller (i.e. empty) is running an action?
Thank you.

This is an equivalent to the AND respectively the OR controller.

As the names indicates:

if all sensors are positive:
if one sensor is positive:

You always need to ensure to avoid side effects when a sensor turns from positive to not positive. In this case the controller gets triggered too (not just when a sensor turns from not positive to positive).

I usually try to avoid hard-coded sensor names in my code. So I use these utility functions to check all. This way it does not matter if there is a keyboard, message or near sensor. The code can live with all of them.

The exception is when sensors provide additional information that is necessary within the code. E.g. you are interested in the hit object(s) of an near sensor, or the bodies of the message sensor.

Even than it can be pretty nifty to skip looking for that results as the not positive state already tells that there is nothing to find.

Finally it is a matter of taste and flexibility. It should not stop you from grabbing a sensor by name when you need it.

@Monster: thanx for the clarification.
Didn’t even know it was possible - much less desirable - in the BGE! :0

Here is a demo that included several matching options. The currently used one is the matching by name prefix. you can easily change that in getAnimationname() and getAnimationSpeed().

I set the play mode to loop as well. I guess this is always the same mode (according to the animations you have).

Additional a camera cover hides the “reset” when switching scenes. So you get a black flicker. As said, this is nothing you can prevent when switching scenes.

Basically this design combines various design elements:

  • mapping various objects to use the same animation
  • configurable animation speed by object
  • storing/restoring status information (current frame) which is a prerequisite of save/load

PS: I didn’t worked on the pause operation. This is up to you. It should basically work like stop.

Attachments

MAIN_SCENE_BASE_shot-03-01_several_options.blend (2.93 MB)