Game Development Community

SetActionThread() and smooth transitions

by Rubes · in Torque Game Engine · 05/23/2007 (8:43 am) · 9 replies

Incredibly verbose question for those in the know:

I have an NPC character in my game who needs a lot of different animations. I start him out with a "root" animation, which is just him sitting in a still position. This root animation is just a short non-looping, non-blended 3-frame animation of him in his root position, with no movement.

Once the game begins, he then performs an "idle" animation when he is not engaged by the player. It is a looping, non-blended full-body animation of him sitting on a bed skinning a rabbit with a knife. He starts and ends this sequence in the root position mentioned above, so it loops continuously from this root position. I use setActionThread() to play it, and it works fine.

When the NPC is engaged by the player, I want to stop this idle animation and play a different one, which I call the "rest" animation. In this sequence, the NPC moves from the root position to a resting position and stops. I want him to hold that position until he is no longer engaged. At that point, I want him to return to the root position, and then restart the idle animation.

If I use setActionThread() to play the rest animation, it plays fine but then the NPC immediately (and smoothly) transitions right back to the root position. I need him to hold the final position, though.

Now, if I call setActionThread() using "true" for the hold parameter, it nicely plays the rest animation and stops it at the end, just like I want. The problem, however, is that I want to be able to have him later return to his root position on command. If I call setActionThread() using the root sequence, however, he snaps back to the root position, instead of smoothly transitioning back to the root position.

I find this odd, because as above calling the "rest" animation without specifying the hold parameter as true causes him to play the rest animation and then smoothly transition back to the root position right away. It's also frustrating because switching between these sequences in ShowTool always produces a nice, smooth transition.

So, the question is: is there a way to have him smoothly return to the root position, after holding the rest animation at the end for a period of time?

If it helps at all, here is a Google video showing the NPC performing his idle animation (skinning the hare). I don't show the rest sequence, however. And sorry about the crappy sound levels.

#1
05/25/2007 (12:22 pm)
Just a friendly bump...
#2
05/28/2007 (7:01 am)
Try playing around with the transitionToSequence method of the TsShapeInstance class, maybe it'll help. If you need any more details, don't hesitate to ask.
#3
05/28/2007 (3:33 pm)
I've looked into that, but the problem I'm having is that the transitionToSequence method is already being called when I call setActionThread. But for some reason that I can't figure out, instead of doing the smooth transition from the end position of one sequence to the beginning of the next, it just snaps to the beginning.
#4
05/29/2007 (12:46 am)
Rubes: are your .dsq files generated with the "blend" flag enabled? Are the animation threads you use set to use blending?

I am actually having a similar problem and I'm also looking into it. The way I'm doing it is I have the "main" thread playing and idle animation loop on my NPC character, and a secondary thread playing occasional random animations. Both threads are controlled by the same shape instance of the player and transitions happen smoothly because the first and last frames of my animation are close to the idle position of the NPC.

My problem is that, if a random animation runs before the other is finished, they do not blend together and the animation jumps to the first frame of the new one.

The generated .dsq files do have the "blend" flag enabled, I enable blending on both animation threads, and I use transitionToSequence with blend percent 0, 0.5 or 1.0 depending on the animation, transition time always 1.0 seconds and continuePlay always set to true.

If anyone has some insight it is more than welcome.

Rubes: I will update if I find a solution, and hope you will doi the same on your end if you do.
#5
05/29/2007 (8:29 am)
@Yves: Thanks for the good response.

The DSQ files I reference above are not generated with the blend flag enabled, since I don't expect these to be blend animations. These are full-body animations that do not require any blending with other sequences.

I am also doing this all from script, and I'm not sure how to enable or disable blending for a particular thread from script. Are you doing that from the engine code?

I'm wondering what calls you are using to play the idle animation loop and the random loops. Are you using setActionThread or playThread?
#6
05/30/2007 (1:25 am)
I'm using neither. All my calls are done through the engine code and I use the TsShapeInstance of the player to play the threads. The idle animation is loaded into the main animation thread of the shape instance, it is the "root" animaition of the player which is loaded by default by the engine.

For the random animations, I start a new animation thread using:
myThread = mShapeInstance->addThread();
mShapeInstance->setSequence( myThread, someSequence, 0 );
mShapeInstance->setBlendEnabled( true );

When I play one of the animations I use:
mShapeInstance->transitionToSequence( myThread, someSequence, blendPercentage, 1.0, true );

Then on each tick, I update my animation threads in the Player::udpateAnimation method
mShapeInstance->advanceTime(dt, myThread);


But, like I said, if I let an animation play its course, it transitions smoothly from and to the "idle" animation, but if I start a new animation while another one is playing, the player just snaps to the first frame of the new animation. And I have no idea how to solve this particular problem.
#7
05/30/2007 (9:22 am)
Ah, I see. I basically try to stay away from the engine code when possible, so I'm not sure how much help I can be.

Is it possible for you to reset the model to the root position before calling the new animation? Transitioning back to the root position should occur smoothly, and then the new animation should play smoothly as well.

But this might not be possible depending on your setup. This is essentially how I get past this problem, but my game is set up to allow this without looking forced.

Alternatively, if you don't want the random animations to play while another animation is currently playing, then you can just insert a check to see if the model is currently in the middle of a sequence.

[Edit for typos.]
#8
05/31/2007 (12:19 am)
I think I'll try and accelerate the current animation until its end (which is always the root position) before blending over to the new one. Hope it'll fix the problem. Now to see how to accelerate it cleanly :)

I cannot check for other currently playing animation because my animations aren't exactly random, they are in reaction to certain events which can happen well, randomly! I do not want to do this workaround but would rather find a more elegant solution.

[edit] Tried the acceleration thing. Works like a charm on short animations, but I get a "Benny Hill" effect on longer ones :) So I guess I have to see how to cleanly blend 2 completely random animations.
#9
06/04/2007 (2:32 am)
Quote:
Rubes: are your .dsq files generated with the "blend" flag enabled? Are the animation threads you use set to use blending?

Here's the problem right there! transiotionToSequence() only works with non-blend animations!! Saw the info in this thread, regenrated the animations without the blend flag, and bingo it works!