Need advice on how to create instances.

Im working on getting my ship’s laser firing working. So i have my laser running a method whenever the mous ebutton is pressed. But now i need to somehow instance the laserbeams so that i can have more than 1 at one time from the player. So i need every laserbeam to have a different name but im not sure how to do this? does anyone know of something i can do?

Its called Dictionaries in python. Lets you name the object/list.

            #self.bullets = {}
            #self.NumberOfBullits = 0 

            #self.NumberOfBullits = self.NumberOfBullits + 1
            #self.bullets[self.NumberOfBullits] = loader.loadModel("towns/bullit")
            #self.bullets[self.NumberOfBullits].reparentTo(render)
            #self.bullets[self.NumberOfBullits].setPos(0,25,0)
            #self.bullets[self.NumberOfBullits].setScale(.05,.1,.05)

ok this would work but how do i remove bullets from the list once they hit somehting or have reached the limit of their range? Thanks :slight_smile:

You can Google the standard Python array-type structures (List, Dictionary, Tuple, …) and get all the access methods. Most have some remove-by-equality operation. If not, you may be able to give each shot a different name and key against shot name.

Python has no support for arrays built-in, only through external modules.
Usually you don’t really need them, lists and dictionaries are fine for most cases too.

To add a link to this…

python.org/doc/2.5.2/tut/node7.html

ok i made it sucessfully and i can see them being rendered but now i need to do a forloop to make them all move forward and this isnt working:

        for projectile in self.projectiles:
            projectile.setY(projectile, 10)

It gives me an error:

AttributeError: ‘int’ object has no attribute ‘setY’ :question:

means your projectile list is full of ints. Double-check how you’re filling it.

but it’s not full of ints lol… They are nodes because i can see them being rendered to the screen

Ah, there are nodes to be sure, but are they in your list? Panda will keep track of created nodes independently of you so long as they’re on the scenegraph, which is why it’s important to never lose track of your own handles to any nodes you may want to change/remove.

Here is how i create the items in the list:

if self.lastSideFired == "left":
                
                    self.projectiles[self.projectileCount] = loader.loadModel(self.weapon.projectileFilePath)
                    self.projectiles[self.projectileCount].reparentTo(render)
                    self.projectiles[self.projectileCount].setPos(self.weaponRight, self.weapon.projectilePos)
                    self.projectiles[self.projectileCount].setHpr(self.weaponRight, self.weapon.projectileHpr)
                    self.projectiles[self.projectileCount].setScale(self.weapon.projectileScale)
                    self.projectiles[self.projectileCount].setLight(self.area.starIlluminator)
                    
                    self.lastSideFired = "right"

                else:
                
                    self.projectiles[self.projectileCount] = loader.loadModel(self.weapon.projectileFilePath)
                    self.projectiles[self.projectileCount].reparentTo(render)
                    self.projectiles[self.projectileCount].setPos(self.weaponLeft, self.weapon.projectilePos)
                    self.projectiles[self.projectileCount].setHpr(self.weaponLeft, self.weapon.projectileHpr)
                    self.projectiles[self.projectileCount].setScale(self.weapon.projectileScale) 
                    self.projectiles[self.projectileCount].setLight(self.area.starIlluminator)
                    
                    self.lastSideFired = "left" 

Looks fairly straightforward, but if you “print self.projectiles” before your update loop, do you get a whole string of marginally comprehensible Panda node tagging, not just a list of ints?

Well after i fired a couple shots it printed this:

{1: render/laserBeam.egg, 2: render/laserBeam.egg, 3: render/laserBeam.egg, 4: render/laserBeam.egg, 5: render/laserBeam.egg, 6: render/laserBeam.egg, 7: render/laserBeam.egg, 8: render/laserBeam.egg, 9: render/laserBeam.egg}

oneKiltedNinja is right…

Whats happening is you are telling a int number to have this (the number/name of the object). The numbers alone arnt your objects, your objects are whats inside your list given that name, or self.projectiles, x being the name of the object.

so change it to…

        for projectile in self.projectiles:
            self.projectiles[projectile].setY(projectile, 10)

I a vise reading that link I gived you, it covers how to use list, arrys, so on.
python.org/doc/2.5.2/tut/node7.html

ok thank you i fully understand now what was going wrong. Thanks for your help :slight_smile:

Yeah- it wasn’t at all evident that self.projectiles wasn’t a list. The ‘in’ operator on lists just returns the list content values in index-order, but on dictionaries and more complex maps, it looks like it returns key:value pairs, or just keys. Unless you have need for actively discontiguous key ranges, if you’re using integers as keys you’re probably better off just using lists from the start.

ok i have the shooting working perfectly and i even have a crosshair to show where the lasers are going to go but now i need to delete them after their time runs out (so there isnt 1000 of them being rendered at once) so i made a seperate dictionary to hold the times they were fired at but now i need help deleting them:

    def projectileUpdate(self, task):
        global timeSecond
        for projectile in self.projectiles:
            self.projectiles[projectile].setY(self.projectiles[projectile], self.weapon.projectileSpeed)
            
            if timeSecond -  self.projectileTime[projectile] > self.weapon.projectileRange:
                self.projectileCount -= 1
                del self.projectileTime[projectile]
                del self.projectiles[projectile]

i have that but when i shoot a laser after its range time (5 seconds) the game crashes and gives me the error : RuntimeError: dictionary changed size during iteration i think this means that when i remove one of the keys all the others fall back one key so their numbers all get mixxed up. Does anyone know of a way i can fix this?

My usual method is to use a List kept sorted by time and just pop (from the tail) any instances that have aged out. This won’t immediately purge shots that have collided with something before timing out, but presumably those have already been remove()d from the scene (which you need to do anyway, again objects exist in the scenegraph regardless of whether you’ve kept track of them), and are just waiting to be forgotten about, which would happen in due time as long as they continue to age until they’re ready to be popped.

Alternatively, rather than using for…in loops, use some while…contains logic plus a search for the first valid instance. This will be slower (possibly exponentially) but removes the need to keep track of ordering, and should let you use Dicts or Lists. Iirc, Python has first/last-instance-of accessors for lists and dicts, so all you’d need would be a little creativity/sensibility in your keys and/or equality test.

Method 3 is to rebuild your list every frame: for each element of your original list/dict, if it’s staying, put it in a new structure, if it needs to be purged, put it in a second new structure. When you’ve traced all the way through your first structure, set the variable for your old structure to your new keeper-structure and if necessary iterate through your reject-structure and remove the nodes in it from the scene. This method puts a lot of faith in the Python garbage collector. In almost any other language you’d need to explicitly deallocate your original structure and reject-structure afterwards.

Dicts are unordered. Unless I’m mistaken, there is no simple accessor for the first and last values in a dict – and even if there was, it wouldn’t be of much use since they may not be the values you were expecting.

Another way of going about this would be to use object-oriented programming. Here is a rough example:

class Ship(object):
    
    def __init__(self):
        self.laser1 = Laser()
        self.laser2 = Laser()
        
    def update(self, time):
        self.laser1.update(time)
        self.laser2.update(time)

class Laser(object):
    def __init__(self):
        self.bullets = []
    
    def addShot(self):
        #create a new bullet and attach it to the scene
        bullet = Bullet()
        self.bullets.append(bullet)
        bullet.node.reparentTo(render)
    
    def update(self, time):
        #update all the bullets this laser is currently firing
        for b in self.bullets:
            b.update(time)
            if b.dead:
                self.bullets.remove(b)
        
class Bullet(object):
    def __init__(self, lifespan=500):
        self.lifespan = lifespan
        #do all your node stuff here
        self.node = None#...
        self.dead = False
    
    def update(self, time):
        #update the node position and check to 
        #see if the bullet is dead (i.e. it has hit an object
        #or it has reached its lifespan), then set dead to True
        #...

Yes, but as he doesn’t seem to be putting much weight on keys/order to begin with, and as long as the keys/values in the dict are differentiable by equality, it should be possible to grab a first-found-to-match value from a dict, whatever the search order of the unordered structure is. I’m almost certain dicts have some sort of .contains functionality, which makes me think they also have some get-by-value method to circumvent regular key-based lookup.

But yeah, if your shots are all self-updating, self-cleaning objects, there isn’t much need to even track them by hand at all. You can even set up collision handlers to have the shots let you know when they hit something so you can just create them and forget about them unless they ask for attention.