Hi,
A quick question:
I know I can get an object by doing this:
scene = logic.getCurrentScene()
cube = scene.objects['cube']
But how to get the cube if it is not sure if its name is ‘cube’, ‘cube.001’, ‘cube.002’ or ‘cube.003’ etcetera?
And to prevent issues with the fact there may be more than one object with cube in its name, I have only 1 object with cube in its name.
I’m asking this because my game contains more scenes and the character is called ‘archer’ but in another level it is called ‘archer.001’ because it is duplicated.
I know I’m not an expert in explaining things but I hope you understand my question.
I hope you can help me.
Thanks
Well for example I have a empty that has properties like the health of the archer.
When I want the archer to walk, a script (activated by a keyboard sensor of the archer) will first check if the health is greater than 0 before it actually starts to walk.
For that, the script needs to acces the empty its property ‘health’.
But the empty its name can be empty.001 , empty.002 etcetera…
Yes yes… I know this can be done very easily with logic bricks but this is just a simple example. I want this also in more complex things that are not easy to do with logic bricks.
if you don’t keep your object names tidy don’t expect to have great results by name searching.
Also names are not great way of referencing objects anyway.
I suggest keeping a dictionary of python references to the objects.
You can even store health and other things there.
Also why has a empty the properties of a separate object?
Why can’t the archer himself have them?
Also why has a empty the properties of a separate object?
Why can’t the archer himself have them?
Yup I agree… I’ll give another example:
My game has a lot of enemies walking around. They all run a script that checks if the archer is alive because when the archer is not alive they are not going to attack anymore… How they get the archer when it is not sure if the archer is called archer.001 , archer.002 etcetera…
I would suggest wrapping objects in classes at the start of each level. You can create your own Archer class that inherits from KX_GameObject and keeps track of things like their health. At the start of the level, you can run something like the following to wrap all the archer objects and save them to a list:
import bge
# global list of archers
ARCHERS = []
class Archer(bge.types.KX_GameObject):
def __init__(self, obj):
self.health = 100
# any other stats, states, etc. you need to track can go here
# example method you might want an archer to have
def shoot(self, target):
# fire an arrow at target
# initialize all archers in the scene
def init_archers():
scene = bge.logic.getCurrentController()
for obj in scene.objects:
if obj.name.startwith('archer'):
ARCHERS.append(Archer(obj))
EDIT: If you only have one archer at a time, you can do pretty much the same thing. Just use a single global variable or a class attribute instead of a list. Alternatively, you could save the Archer as a property on an object or in the global dict. You can even make the first method robust against the archer object changing in the middle of the game (due to it dying for example) by creating function for retrieving the archer, similar to the bge’s getCurrentScene() or getCurrentController() methods:
If the above code is in a module called archer.py, enemies and other objects can get the reference to the current archer by calling the getCurrentArcher() method like this:
from archer import Archer
# enemy code...
def move_towards_archer():
# get reference to current archer
currentArcher = Archer.getCurrentArcher()
# make sure it isn't None in case there is no archer
# or it hasn't be initialized yet
if currentArcher is not None:
# do stuff
dont have the enemies know anything about the player unless they see him, check to see if they see him every so many frames, spawn them all in a frame off or in little groups.
I use rays, but you can also use a radar sensor or a collison sensor etc.
this also opens up things like multiplayer,
you don’t want the enemy to only attack the player sometimes either
you want all living objects to have a property ‘side’
if own[‘Side’]!=sens.hitObject[‘Side’]:
attack!
then you can ‘charm’ or hack a enemy to the player side
Since your ‘suffix’ is always a decimal point followed by three digits, you know you can always slice off the last 4 ‘entries’ (if you’re treating the string like a list) and get the base name. Unless you have more than 999 scenes planned, this would work. EDIT: Just make sure you put a 4-digit suffix after the “archer” (like .000), or it will read it as “ar”
Mweh… nevermind… I really appreciate all your help guys! Thanks! But I think nobody really understood my question. My fault, because I’m always a bit vague… Now I think I can solve my problem with globalDict, but I hoped someone got a better idea…
Nevermind, Thanks everyone, you’re all awesome
Is it a single object in the scene?
Does it consist of several objects?
Is it a property?
Is it a Python object?
A mixture of that?
Your archer should know if it can perform a requested operation or not. E.g if something want the archer to walk, the archer will ignore it when in state dead, sleeping or fixed otherwise he can walk. Why should the requesting instance need to know he is dead or not? It makes more sense to give the requester the information, which entities are able to walk, rather then which entities are not dead. These are two complete different informations.
So I think the real question is: how to find objects that can perform a specific operation e.g. Walking?
Answer: ask all objects if they can ;). This might be inefficient. So you can implement any short-cut you like e.g. Mark obuects that can perform operations at all. Mark objects that can perform specific operations. Maintain lists of such objects …
I hope I can make it more clear now:
I have a game, it contains 10 scenes, each scene has an ‘archer’ object. All those different scenes are copies of the orginal scene.
In the orginal scene the archer object its name is ‘archer’. But in another scene it is ‘archer.001’. That is because when you copy a scene all names will get .001, .002 etc. behind its name.
Now I have got a script runned by the camera that needs to set a property that belongs to the archer object.
scene = logic.getCurrentScene()
archer = scene.objects['archer']
archer['a property'] = True
But this script does not work anymore in another scene because the name of the archer is not ‘archer’ anymore but it is for example ‘archer.001’.
I hoped someone got a simple solution to this, but nobody can give me that when I’m not clear enough so sorry for that.
But now after some thinking, I think a solution could be this:
when the game starts the archer object will run this code:
logic.loadGlobalDict()
cont = logic.getCurrentController()
logic.globalDict['name of the archer object'] = cont.owner
And then I can replace the first piece of code in the beginning of this quick reply with this:
scene = logic.getCurrentScene()
archer = scene.objects[logic.globalDict['name of the archer object']]
archer['a property'] = True
If you must have multiple scenes (which requires you to judge if having multiple scenes is a workaround / inefficient (are you trying to have levels?)), then give the archer a property instead (“archer”) and search for it in the scene.
def do_something(cont):
own = cont.owner
scene = own.scene
archer = next(o for o in scene.objects if "archer" in o)
Using your solution (provided you handle cases with multiple archers in different scenes), is more efficient, and also works.
Thanks but it should also work with other objects so not always the camera.
for GameOb in bge.logic.getCurrentScene().objects: if 'Tag' in GameOb:
own['Target']=GameOb
I already used this method, but Monster said to me that it is not good using this when you have a lot of objects in your scene, and since I make a 2d pixel game with a lot of objects I started this thread to get an good alternative.
Now I use the method I described above with globalDict, it works fine, so yeah…
I think the method @Mobious described is also good, but since I’m not very good with python I didn’t know how to use it.
import bge
cont = bge.logic.getCurrentController()
own = cont.owner
if 'TargetObject' not in own:
for objects in bge.logic.getCurrentScene().objects:
if 'Tag' in objects:
own['TargetObject']=objects
Actor = own['TargetObject']
and it will only look it up 1 time and store it forever.
I think you need to look at your architecture with a different perspective.
At one level you know you switch between scenes. That mean everytime you swith, you work with a different set of game objects. The previous set is gone at that time.
At the scene level, you know that it contains an object ( or more ) that have a specific purpose e.g. act as archer.
Know you connect these knowledge:
Everytime you switch the scene … you search the game objects for the puposes you are looking for. To be efficient, you store the search result in a way that you can have fast access. When you switch the scene again, the stored data gets invalid and must be refreshed.
Now your question makes sense, if your assumption is there is only one archer in the scene. According to your question you identify the object(s) by prefix.
def findByPrefix(prefix):
return [object for object in bge.logic.getCurrentScene().objects
if object.name.startswith(prefix)]
Example to store in an property
def refreshArcher(objectProvider):
archers = findByPrefix("Archer")
if len(archers)!=1:
... Whatever you want to do in this case e.g raise an error
objectProvider["archer"] = archers[0]
Remember, you do nit search all the time. You search after you switched scene. By your contention, the prefixes of the objects need to match. Other options are suffix, property names, property values, positions, parent child relationships …