Hey everyone, just wondering what the coding is for calling all the objects in a given list. For example, I am using this list in my game:
prep_grunt_spawn = [i for i in scene.objects if 'prep_grunt_spawn' in i.name]
I have ten objects in the scene with “prep_grunt_spawn” in their name, and i want to use the list above to be able to add a grunt enemy at each of these spawn points. However, I don’t know how to tell Blender to add the objects at all of the objects in the list. I’ve tried adding [0,9] and [0-9] at the end of the definition, and the [0-9] added the object at one of the locations, but not at all of them.
You’re already done it once in that code! But it’s hidden among some of the other stuff, so I’ll filter it out.
If I re-wrote that code, it could be:
sceObj = scene.objects
prep_grunt_spawn = []
for i in sceObj:
if i.name == 'prep_grunt_spawn':
prep_grunt_spawn.append(i)
So sceObj is already a list, you’ve just narrowed it down.
You use the same method to go through the list:
for grunt in prep_grunt_spawn:
'''do stuff'''
print(grunt)
Your code that finds the grunts relies apon the object name. This isn’t always a good idea, it is better to use properties. To do this we add a game property, and then replace your code:
prep_grunt_spawn = [i for i in scene.objects if 'prep_grunt_spawn' in i.name]
with something very similar:
prep_grunt_spawn = [i for i in scene.objects if 'prep_grunt_spawn' in i]
Now instead of looking for the string ‘prep_grunt_spawn’ in the name, it will look for it the game properties.
This is useful if you want to build a list of all the enemies.
Yes, that’s exactly what I want to do! Basically, the way I was planning on using the list in my first post was like this:
scene.addObject('prep_grunt', prep_grunt_spawn)
The goal was to only have to use 1 enemy object, and simply spawn it at these different locations, instead of having to duplicate the enemy. Now that I think about it, I am going to go back and use properties instead of names, since this will let me spawn different types of enemies at the same spawn point.
I think you’ve misunderstood me. The objects that are in this list are empties that I am using to spawn my grunt enemies. As I said above, my goal was to only have 1 grunt enemy in a background layer of my scene, and then have it be spawned in multiple different places.
EDIT: Ok, I have gone back and set the list to properties and not names, and now I am getting an error that says that the scene.addObject command expects a KX_GameObject or a string for the second argument. Here is all of my current code:
The new list:
grunt_spawn = [i for i in scene.objects if 'grunt' and 'spawn' in i]
I am using two properties to tell it that it is a spawn point (‘spawn’) that is allowed to spawn grunt enemies (‘grunt’).
This is the scene.addObject command:
if message.positive:
scene.addObject('grunt_prep', grunt_spawn)
message is just a message sensor that activates the command.
To have it spawned in different locations you can just use empties with add-object bricks:
Message -> AND -> Add Object (grunt)
But I shall stop pushing that now.
In terms of the error it may be one of several things:
There may not be any with those properties. You may have made a typo
Have you tried printing the list so you can see what’s in it?
Is there any chance we could see the whole code? Or maybe a demo blend?
If I was going to use this in a game I would make it a callable function and pass parameters in such as what unit and what spawnpoint types. That way you could use the same code to spawn different units at different spawn locations or same location or whatever.
Let me know if you want me to update the blend to show that.
Here is a .blend that I have been using to try and get it to work. Would you mind looking at it, and seeing if you can figure out what is wrong? I’m sure this seems odd, since you just gave me a solution to my problem, but I want to use this as a learning experience, and I can’t learn if I don’t know what I did wrong.
I understand what you are trying to say, as far as doing it with logic bricks, but for some reason I want to figure it out in Python (probably something to do with the learning experience again ) Thank you for your help though
You can leave the 0 out as it is a default value.
The real issue was trying to use a List type when an Object or String (object name) type was required.
Thank you so much! That was exactly what I needed! However, I don’t really understand what that one line of code
for spawn in grunt_spawn:
does. I understand that it gives me the objects that make up the grunt_spawn list, but I’m not really sure how. If you could explain this to me, that would be very helpful
Looking at the code snippets above, grunt_spawn is a list consisting of all objects in the scene if they have the properties ‘grunt’ and ‘spawn’ in their objects. The line
for spawn in grunt_spawn:
Loops through each of these objects to perform a function on them all, namely spawning something at each of their positions, with their objects as the initial reference objects (the second argument in scene.addObject())
So, you’ve already met the datatype - list:
A list is one of many different data types which are “iterable”. If you’re interested, other examples can include dictionaries, tuples and sets.
So, what does an “iterable” object do? Well, iterable objects are datatypes which you can iterate through. this means that you can use a loop to cycle through the elements within the data object one at a time. So, you’ve already created a list “grunt_spawn”.
But, what if you want to use each object in the list. You don’t have to modify all the objects in the list at once. No, instead you can modify each element in the list as you cycle (iterate) through it.
How do we iterate through this data object? We use a “for loop”. A for loops comes typically in the following form:
for new_variable in iterable_object:
do_something()
You see the “for” keyword? this means that you’re defining a for loop. Next is the “new_variable”. This is the name of the variable that is set to the value of each element in the data type as you cycle (iterate) through it. So the first item in the list is the first value of the variable, and on the next step in the cycle, the second item (and so on.)
“in” is the keyword that defines that you’re looking “in” an iterable object. The variable following “in” is an iterable object, or a variable that references the iterable object (in your case - “grunt spawn”).
Finally, you have a colon which determines the end of the loop. Any code following the colon is executed within the scope of the loop - each time the for loop cycles through the iterable object that nested code is executed (nested meaning “indented due to the colon”).
Now how to handle all those spawned objects with collisions? Like for an example, assign each one of those objects with different hp and when shooting an object at one of them causes just that object that was hit to loose hp. If they all have the same property wouldn’t they all loose hp when just one was hit?
No, not if you change the HP value of the one that specifically was hit. Messages, as an example, can’t be directed, and even if they could, there’d be no way to know which enemy to subtract health from beforehand. With Python, you can get the hit (collided) object with a ray / near / collision / touch (I guess) sensor and subtract the necessary amount from its ‘hp’ variable.