Get an object when it is not sure if there is for example '.001' behind its name.

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

who needs to target him and when?

you can use a ray and get the ray.hitObject

you can have a empty spawn the archer at runtime, and then set the
archers game object as a property, or add a property to a list?

be more specific and I will write you a snipet.

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?

ok, you mean you want the player to control the archer,
if the archer dies, you spawn another?

obiects name is not what you want to use

will there ever be more then 1 archer the player controls?

Archer= bge.logic.getCurrentScene().addObject(‘yourArcher’,own,0)
bge.logic.getCurrentScene().objects[‘Controller’][‘player’]=Archer

on adding the new archer, swaps out the object your player controller is targeting, to the new archer.

when moving him (in the controller)
Archer=own[‘player’]
Archer.applyForce etc.

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:

class Archer(bge.types.KX_GameObject):
    currentArcher = None

    # ...

    @classmethod
    def getCurrentArcher(cls):
        return cls.currentArcher

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

Side note, clever ai,

if you see a living being, and its side is your own,
if he is targeting a enemy, follow him…

this makes mobs seem really smart…

if the Being your following stops, and is targeting, try and ? (shoot over him, or go above him or?)

with a few of these simple rules your enemies can seem quite intelligent,

If you really need to, you can slice off the ‘.xxx’ at the end of the string you are looking at in your search.


"archer.001"[:-4]
>>>
"archer"

"archer.314"[:-4]
>>>
"archer"

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” :stuck_out_tongue:

Just a more robust solution if you decided to go with Nines’s method. Strings have a handy split() method.

'archer.001'.split('.')
> ['archer', '001']

'archer'.split('.')
>['archer']

'archer.002.123'.split('.')[0]
>archer

As you can see, you can safely get the first part of the object’s name without having to worry if it has a suffix or not.

Ahh, I was not aware of the split() method. That is a nice trick!

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 :wink:

The question is what is the archer?

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 :wink: 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

I’ll try to be more clear next time

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.

ok,

have your camera use

if ‘Archer’ not equal empty---------python

have the camera start with the property empty

have

always(one time)------python
in the archer

import bge
cont = bge.logic.getCurrentController()
own=cont.owner
camera= bge.logic.getCurrentScene().active_camera
camera[‘Archer’]=own

then

camera[‘Archer’]= your archer…

I also included a system to look up the property ‘Tag’ in game objects (like Agoose Suggested)

Attachments

PassGameObjectToCamera.blend (452 KB)

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.

you can do

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 :smiley: 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 …

I hope it helps