Instancing

Hi,

I want to do something like this http://www.youtube.com/watch?v=3QzKkHi-0xo&feature=related, when i click play an animation (red arrows in this vid).

I frist did this:

from pandac.PandaModules import NodePath
from direct.actor.Actor import Actor

class Pointer:
    '''The Marker'''
    def __init__(self, render):
        # You probably want to use a different marker model
        
        self.render = render
        
        # Create a NP to hold the last clicked pos (maybe we'll need this later)
        self.PointerNP = NodePath('Pointer NP')
        self.PointerNP.reparentTo(self.render)
        self.model = 'ralph' #using ralphs model as placeholder
        
        # Create a list to hold the pointers     
        self.pointerList = []
        
    def getPos(self):
        return self.PointerNP.getPos()
    
    def point(self, pos): # this function is called when there is a click
        self.PointerNP.setPos(pos) # save the last pos in case of needing it
        
        a = Actor('models/{0}'.format(self.model),
                            {'run':'models/{0}-run'.format(self.model),
                             'walk':'models/{0}-walk'.format(self.model),
                            })
        a.loop('run')
        a.reparentTo(self.render)
        a.setScale(0.5)
        a.setPos(pos)
        self.pointerList.append(a)

        taskMgr.doMethodLater(5, self.fadeTask, 'fadeTask') # 5 secs only to test, its going to be less than .5

    def fadeTask(self,task):
        if self.pointerList:
            print ('Deleting: ' + str(self.pointerList[0]))
            self.pointerList[0].detachNode() #use detachNode() or removeNode()?
            self.pointerList.pop(0)
        
        return task.done
    

then I found this page http://www.panda3d.org/manual/index.php/Instancing and changed my code to:

from pandac.PandaModules import NodePath
from direct.actor.Actor import Actor

class Pointer:
    '''The Marker'''
    def __init__(self, render,loader):
        # You probably want to use a different marker model
        
        self.render = render
        
        # Create a NP to hold the last clicked pos (maybe we'll need this later)
        self.PointerNP = NodePath('Pointer NP')
        self.PointerNP.reparentTo(self.render)
        self.model = 'ralph'
        self.Pointer = Actor('models/{0}'.format(self.model),
                            {'run':'models/{0}-run'.format(self.model),
                             'walk':'models/{0}-walk'.format(self.model),
                            })
        self.Pointer.loop('run') # they are all animated at the same time.
        
        # Create a list to hold the pointers     
        self.pointerList = []
        
    def getPos(self):
        return self.PointerNP.getPos()
    
    def point(self, pos):
        self.PointerNP.setPos(pos) # save the last pos in case of needing it
        
 
        a = self.render.attachNewNode("Placeholder")
        a.setPos(pos)
        
        self.Pointer.instanceTo(a)
        #self.Pointer.loop('run') #if uncoment the animation is restarted when i click
        self.pointerList.append(a)
        
        taskMgr.doMethodLater(5, self.fadeTask, 'fadeTask') # 5 secs only to test, its going to be less than .5

    def fadeTask(self,task):
        if self.pointerList:
            print ('Deleting: ' + str(self.pointerList[0]))
            self.pointerList[0].detachNode() #use detachNode() or removeNode()?
            self.pointerList.pop(0)
        
        return task.done

With the first code all the animations are independent, but it is a little expensive if I click alot (I know that every actor will be deleted in less than 1s but isn’t expensive to load the actor every click? and i’m concerned if its going to be a problem when i get lots of things in the scene).

So, is there anyway to improve this code?

And another thing, should I use detachNode() or removeNode()?

Thx :slight_smile:

It doesn’t actually re-read the disk on the subsequent times you load the same model–it just loads it again from its in-memory cache. So it’s not as expensive as you might think. Still, it’s true that creating a new Actor requires a certain amount of setup operations, and this isn’t free. If you create many, many Actors in a short amount of time you will see the cost.

If this cost gets too much to bear, you could consider recycling your Actors in a pool–when you’re done with one, use detachNode() to remove it from the scene, and put it in a list of standby Actors. Then, when you want to create a new Actor, check the list first and take one from the list if there’s one there, instead of creating a new one every time.

The difference between removeNode() and detachNode() is mainly a question of whether you plan to use the model again. If you are not going to use it again, it doesn’t make a big difference, but you might prefer removeNode() to make your intentions clear. If you are going to use it again, you should use detachNode().

David

great idea :smiley:

just did that.