Actors not acting (Yet Again)

In another game of mine, my actors aren’t acting. Code:

def checkMonsterDead(self, task):
        if self.monster.health <= 0:
            self.monster.actor.play("explode")
            self.monster.actor.cleanup()
            self.monster.actor.removeNode()
        
        return Task.cont

The code for monster:

class BabyMonster(DirectObject):
    def __init__(self, scale):
        self.actor = Actor("models/monster1.egg", {"attack" : "models/monster1-pincer-attack-both.egg", "explode" : "models/monster1-explode.egg"})
        self.actor.setScale(0.25, 0.25, 0.25)
        self.actor.reparentTo(base.render)
        self.actor.setPythonTag("monster", '1')
        self.actor.loop("attack")
        
        self.health = 4
        #self.health	
        
        monsterCenter = self.actor.getBounds().getCenter()
        monsterRad = 2
        monsterNode = CollisionNode("monster")
        monsterNode.addSolid(CollisionSphere(monsterCenter, monsterRad))
        monsterC = self.actor.attachNewNode(monsterNode)
        
        base.cTrav.addCollider(monsterC, base.pusher)
        base.pusher.addCollider(monsterC, self.actor)
        
    def update(self, player, dt):
        self.actor.lookAt(player.player)
        self.actor.setY(self.actor, dt * 5)

First of all, thank you for posting only the relevant code! It’s much appreciated–and I think that it helped me to quickly find the problem! :slight_smile:

As to that problem, you didn’t specify quite what was happening–does the looping of the “attack” animation work? Is it, as I’m currently guessing, just the “explode” animation that doesn’t work?

If so, what I think is happening is this:

In “checkMonsterDead”, you’re playing the “explode” animation–and then immediately destroying the Actor-object and removing its node. As a result, the animation never has a chance to play.

What I’d suggest is that you keep your Actors around until the “explode” animation has finished playing, and only then run the cleanup-and-remove code.

(You can check whether a given animation is playing by getting the “animation control” associated with that animation–by calling “getAnimControl(<name-of-animation-here>)”–and then calling “isPlaying” on that control.)

Only the “explode” isn’t playing. “attack” is looping.
Sow how do I solve the problem?

Okay; thank you for the clarification!

Erm… That was what my last two paragraphs above were describing: one way to solve this problem.

In short:

  • Keep the Actor around until the animation has finished playing.
  • Get the “animation control” for the animation in order to find out whether it’s still playing, or has finished.
    • (See the API and manual for details; I mentioned the relevant method-name in my previous post.)

Yeah, I understood but can you show me how am I supposed to do it. Give me a code snippet.

EDIT: Am I supposed to use if or while or something? I am confused in that.

What I’d suggest is simply storing the Actor somewhere, and checking on its animation in a task.

A “while” likely won’t work here: unless you get into asynchronous programming, a while-loop will presumably execute all of its iterations within a single frame; you want the animation to play out over multiple frames.

Can’t I do?:

while self.monster.actor.getAnimControl("explode").isPlaying():
    pass
else:
    self.monster.actor.cleanup()
    self.monster.actor.removeNode()

No, I’m afraid not.

Trace through with me how that would execute:

(I’m presuming that you would call self.monster.actor.play("explode") just before.)

The program would reach the “while”-statement. It would check the associated condition, which is whether the control is playing, and see that it is.

Since the condition is “True”, it would thus enter the “while”-section, encounter the “pass” statement, and move on.

However, this is a “while”-loop. Since the condition was “True”, it would return to the start of the “while”-loop. Once again, it would check the condition.

Now, all of this is happening in a single frame–since the program hasn’t yet moved on, the engine hasn’t yet had a chance to finish the frame and start the next one. As a result, the animation hasn’t yet updated at all–nothing has changed.

Thus the animation is still playing, and the condition is still “True”, and the program enters the “while”-loop.

And it’ll keep doing that until either the program is stopped, or the computer shuts down, I imagine.

So can you give the new code for the checkMonsterDead task and the other task you are talking about?

I mean, it’s saying that because you literally posted the same text twice. :stuck_out_tongue:

Honestly, how long have you spent trying to figure it out thus far? It’s been less than an hour, at least some of which was spent with one or the other of us typing responses.

Think about it some more, try and figure it out. I honestly think that you’ll learn more that way, and it’s good practice, and once again I feel like you’re asking me to do your work for you. Not to mention that I have my own work to attend to.

Because I have internet problem so It gets glitchy.

Fair enough! But that is why it’s saying that–the forum software doesn’t know about your internet trouble, after all. It just sees two messages posted by you.

(And I’m sorry to read that you have a glitchy connection!)

By the way, my “Beginner’s Tutorial” covers a bunch of the things that you’ve been asking about of late–off the top of my head: “pusher”-based collision; ray-collision with a queue; and the handling of enemy animations (as in this thread). Furthermore, it includes both description and code. I really do think that it might be useful to you.

If you’re interested, I’d suggest going through it from the start–even the bits that you’re already familiar with, so that you don’t inadvertently miss some item that you’re not familiar with.

You should find it here:

I tried what came to my mind. But I have 2 issues. If I don’t use the “explode” animation, it removes the node nicely. Issues:

  1. When I use the "explode" animation it still doesn't play
  2. Even though it doesn't play, the node is removed, but not properly. There is still collision detection for the monster
def checkMonsterDead(self, task):
        if self.monster.health <= 0:
          self.monster.actor.play("explode")
          if not self.monster.actor.getAnimControl("explode").isPlaying():
              self.monster.actor.cleanup()
              self.monster.actor.removeNode()

Ah, you’re on the right track, I think–good work! :slight_smile:

Okay, I think that what’s happening when you play the “explode” animation is a little non-obvious: I think that it is playing… but because you’re calling “play” on every frame after the monster “dies”, the animation is being reset to the beginning on every frame, and so appears to never play.

What I’d suggest is that you store a new value in your monster-class, something like “isAlive”, which is set to “True” when the monster is created, and which is set to “False” when the monster dies (i.e. just after checking that its health is less-than-or-equal-to zero).

You can then use this value to differentiate between a monster that has just died (because its value is still “True”) and one that died previously (because its value is already “False”). This way you can play the animation only for a monster that has just died, meaning that it shouldn’t be reset.

As to collision-detection, hmm, that’s odd! However, I do think that it’s probably good practice to remove collision-items from the traverser and pusher when they’re no longer being used anyway, and doing so might fix the problem.

And just in case you missed it, please see my previous post, above, about the tutorial.

I saw it.

1 Like

Actually, I just realized that the collision isn’t exactly working, If I click anywhere 10 times, the monster will die, so I will fix it.

1 Like

If I may add, this can also be handled using an Interval:

You could make a Sequence containing an Actorinterval and then a Func that will call actor destroy afterwards. So from that function you can just set up the Sequence and start() it and it’ll run on its own.

ActorInterval manual page:
https://docs.panda3d.org/1.10/python/programming/intervals/actor-intervals

Sequence manual page:
https://docs.panda3d.org/1.10/python/programming/intervals/sequences-and-parallels

3 Likes