does Actor have specified anim?

I want to know if my actor has an anim bundle with the specified name.

I tried:

if actor.getAnimControl('anim') != None:
    print "Animation exists"

and got:

File "C:\Users\Hx\Desktop\test.py", line 1003, in myfunc
    if actor.getAnimControl('anim') != None:
  File "C:\Panda3D-1.8.0\direct\actor\Actor.py", line 1729, in getAnimControl
    assert partDict != None
AssertionError

Previously I thought this was the right way:

if actor.getAnimControl('anim').hasAnim() == True:

Anyway, what is the right way? And why doesn’t Actor just have a hasAnim(‘name’) itself?

I think that’s the right way to do it. The assertion error seems to imply that your Actor doesn’t even have a model.

David

Weird.
If I wouldn’t be able to find the issue, can I jut go with this instead?

if 'anim' in actor.getAnimNames():
    pass

Or is it for something else?

Sure, but I don’t see how that can work either, if your actor doesn’t have any model. Does it work?

David

Are you sure thats the only thing the error message can mean? Because I can see my actor in the scene.
When I do print actor.getAnimNames(), I get two animation names printed, while getting that error message when I use the AnimControl() method to check for the same thing.

Also, I’m pretty sure I do unloadAnims([‘animation1’, ‘animation2’]) before doing actor.getAnimNames(), but I still get the names.

The code is a bit big, so I tried creating a test scene instead to find the problem, but no luck yet.

The actor are stored in a list.
I do:

for i in actors:
    i.unloadAnims(['animation1', 'animation2'])

Before doing

for i in actors:
    print i.getAnimNames()

And I still see the names there.
However, I can’t reproduce it in my test scene.

I’ll search some more.
But if there is an obvious mistake you could spot, please tell me.

EDIT: OK, this is one problem to me:

from panda3d.core import *
import direct.directbase.DirectStart
from direct.actor.Actor import *

panda = Actor('panda')
panda.reparentTo(render)

panda.loadAnims({'anim': 'panda-walk'})
panda.unloadAnims(['anim'])

panda.loop('anim') # still works it seems

run()

unloadAnims() unloads the animation tables from memory, but it doesn’t delete them from the Actor. The next time you play it, it will just force the Actor to reload the animation from disk.

I don’t recommend using unloadAnims() in general unless you really understand what it is doing and know that you need it; it’s not likely that what it does is useful to you.

David

Yes, I really need that.
For one thing the animations are not even read from an egg file.

So what does this mean? You can’t really remove an animation if you have loaded it?

Personally, I think a better design would be an error message when someone wants to use something he has unloaded. What’s even worse to me is Panda tells you it’s there (if you use getAnimNames()). How am I supposed to know then?

I don’t think you yet understand what it means to “load” and “unload” an animation. It has nothing to do with whether the animation is associated with the Actor. getAnimNames() returns all of the animation names you have associated with the actor, not just the ones that are currently loaded. You can play any of them you like. There’s no easy way to ask which ones are actually loaded right now, and for the most part, it doesn’t even matter.

The method loadAnims() is misnamed–it doesn’t actually load animations. All it does is associate them with the Actor. The animations are actually loaded when they are bound, sometime later, usually when you play them for the first time (though you can force them to load earlier if you like).

There’s no way to disassociate an animation with an Actor. Once it’s been associated, it’s always there. (You can associate a new animation with the same name, though, and that will replace the previous association–but that would be a weird thing to do.)

The only difference between a loaded and an unloaded animation is whether it occupies space in memory. But modern computers have lots of memory, and unless you are running on a very low-memory computer, or if you have many hundreds of animations, that’s not going to make a difference to you.

Edit: note that the Actor interface was designed around the concept of loading animations from egg files. If you are constructing your animations directly in-memory and “loading” them by passing NodePaths, you can still use the Actor interface to play them, but the concept of loading and unloading doesn’t really work in this case.

David

I really don’t like this design of not being able to load something exactly when you want, especially when rest of the engine seems to work that way. But that’s just my opinion.

Either way, my question is unanswered. Is there no easy way, or is there no way at all?

I have few animations on my Actors which I freqently replace, and not always with the same amount of animations, sometimes I need to remove some instead of replacing. I often need to play one of them one after another, so I really need to know which animations are currently available. Right now, I see no way to know that.

Frankly, I’m not a huge fan of the Actor interface myself. It’s big and clumsy for what it does.

All of the functionality you’re looking for is possible with the lower-level Character/AnimControl interface. Maybe you should consider using that lower-level interface directly, or writing your own Actor-like replacement for your specialized purposes, instead of using the existing Actor code (which doesn’t seem like a good fit for what you are trying to do).

David

But still, is it not possible with Actor, or just not so easy as you said?
Because I already use Actor everywhere in my code and I wouldn’t want to rewrite everything for a single feature. Also, I use many other convenience functions of Actors, so dropping all of them and rewriting my own is undesireable as well.
And since Actor is a convenience wrapper, shouldn’t it keep the functionality of the lower level classes?

I’m unable to answer whether what you want to do is possible or not, because I don’t really understand yet what you want to do.

It is not possible to disassociate an animation with an Actor once it has been associated, except by associating a different animation in its place. But you keep using the word “unload”, and I don’t know what you mean by that, precisely. When you create the animation in-memory yourself, of course you become responsible for managing its memory thereafter.

David

It’s simple:

I asked if I can know what animations I have loaded with loadAnims() and how can I properly unload them. You explained that “loading” is not the right term here, it only “associates” the animation and loads it later.
Obviously what I want to know then is, can I know which animations have been “associated” with loadAnims() and can you disassociate them? You say it’s impossible to disassociate an animation from an Actor, so that answers it.

I don’t understand why you can’t disassociate an animation from an Actor, though. Can I ask for a function to be added which does that? Because I see no point in restricting us of doing that. I mean in most cases people might not care, but here is a real example that someone needed it. And I already explained why.

Maybe at least a hack like actor.loadAnims({‘anim’: None}).

You suggest maybe I shouldn’t use Actor at all, but I have no idea what I need from other classes, I found only few methods listed for the class Character, but most importantly, like I said I use Actor everywhere else in my project and use it here because it has so many helper functions. So dropping it and rewriting lots of code would be the last thing I’d want to consider.
And on the other hand I want to see a better Panda, so if a simple additional function could make the Actor class be more “general” (if I can say so) I don’t see why it shouldn’t be.

I agree that we should all strive to make Panda the best it could be. As always, we’re happy to accept patches. :slight_smile:

You’ll find that Actor.py is entirely written in Python and should be reasonably straightforward to extend as you wish.

David

I understand that there are some people who do patch stuff which they had problems with, but I’m not that kind of guy who knows enough to do that.
I think this is not the first time we talked about this.
No really, I tried:
I think self.__animControlDict is what holds all the associations, but that’s as far as I got.
Is there nobody in the dev team who could do that? Doesn’t seem like it would be much for those familiar with the code.

Just saying, I think its good to just ask people if they would be willing to contribute a fix or feature themlseves, because they often do, but sometimes it might give the impression that there is nobody else to do it (developers) and people wouldn’t want to use an engine if they need to fix stuff themselves, because most can’t or don’t have the time (maybe that’s why they are using an existing engine in the first place). Don’t want to sound harsh, I love Panda. I just think that suggestion seems like a double-edged sword. Don’t get me the wrong way.

Anyway, Actor module is pretty big and uses bunch of Panda classes which I’ve never encountered, so it’s not as simple as just reading some Python code, so like I said it’s too difficult to understand for me.
As for not using Actor, no idea what other classes to use then to achieve what I need.

Let me dissuade you from the mistaken belief that Panda is a commercial product with a team of active developers. It is not so. Panda is developed entirely by volunteers. There is a small bit of financial backing provided by Disney, and CMU keeps the lights on for this website, but for the most part we depend on our users to contribute code, the same as just about any other free product you’ll find out there.

As to extending or reimplenting Actor:

There are only a handful of classes that are involved in the lower-level implementation of Actor. You have PartBundle, which is the root of the model’s bone hierarchy, and AnimBundle, which is the root of a corresponding hierarchy of animation tables.

All you need to do is get the PartBundle for your model and bind it to the AnimBundle for your animation, using PartBundle.bindAnim(). The return value of this call is an AnimControl, which represents the bound animation. You can control the animation (play, stop, pose, whatever) with the AnimControl. If you drop the AnimControl and let it garbage collect normally, the animation is automatically unbound.

To get the PartBundle, you find the model’s Character node, which is the root node of the model you loaded from disk. Character inherits from PartBundleNode which provides an interface that allows you to query the PartBundle(s) within it. Usually there is exactly one PartBundle corresponding to a model.

To get the AnimBundle, you find the animation’s AnimBundleNode, which is the root node of the animation file you loaded from disk.

So: load a model, find its PartBundle, load an animation, find its AnimBundle, bind them, and save the resulting AnimControl. That’s all that really matters. Everything else that Actor does is just cruft.

David

1 Like

I know, but some open source projects have few “developers”, as in “long term” volunteers and the actual creators of the library (who might leave at some point, like Sinbad and I think Niko of the OGRE and Irrlicht 3d engines respectively).
But regardless, I think not everyone really gets how community projects work, so it might seem that the project is half-dead to them. Like I said, not for me, all I’m saying is maybe there is a better way to express this as it might cause some people to stop using Panda, because they didn’t know better.

And thanks fo the info. Reading the code I found a function which seems to do what I need: removeAnimControlDict(), because I need to disassociate all of the anims on my Actors at once, before loading new sets.
I think we could have something like diassociateAnims(), to disassociate only the ones we need. I’ll update this thread when I have it working and after doing few tests.
Maybe I’m just too frustrated to contribute bad code I guess.

Hm, what if the animations are not read from disk? I experience the same issue with AnimBundleNodes I generated myself.

What issue is it that you’re referring to? The only thing reported in this thread is a misunderstanding about the Actor interface: the function called “unloadAnims” doesn’t (and was never intended to) disassociate animations.

We can debate whether this is a good design or whether it should be changed, and whether there ought to be a function that does disassociate animations; but if you’re asking about the way it is now, that’s the answer. So, what’s the issue?

David

Okay, my issue is I create animations myself and don’t want to use this “caching” system, as I need to know exactly which of my animations are currently associated with the Actor, not which have also been associated at one point. I understand Actors are meant for egg files and here it makes perfect sense to do this.

Anyway, I found a solution:

actor.removeAnimControlDict()

But this only works if you want to remove (disassociate) all animations at once and luckily that’s the case for me.