How to detect if a given object has a given property using Python?

How do I check if an object has a certain property when the player approaches it and presses a certain key, such as’ E "?
Thanks in advance for any help.

this may help while @Cotaks don’t comes in with a better solution( he is awesome with mechanics).

from bge import logic, events
key =
scene = logic.getCurrentScene()
#cont = logic.getCurrentController()

player = scene.objects["PlayerName"]

#someObject = scene.objects["objName"]
#owner = cont.owner # the object the script is in

#loop through all objects in the scene
for object in scene.objects:
    # check if object has the property
    if "given_property" in object:
        # get the distance from the player to the object
        dist = player.getDistanceTo(object)
        # check if distance is below 10 and if the 'E' key is pressed
        if 0.0 < dist < 10.0 and key[events.EKEY]: 
            #do something
            object.visible = False
1 Like

use a raycast with property set, and a keyboard brick with e key. all you need.

@Murilo_Hilas option is pretty bad. It gives the right idea but the setup is terrible. Also a raycast is the best solution with python.

def test(cont):
    own = cont.owner
    e_key = cont.sensors['e_key'] #keyboard brick called e_key
    if e_key.positive: #key is pressed
        distance = 2 # meters to check
        vec = own.worldPosition + own.worldOrientation.col[1] #0=x,1=y,2=z axis
        ray = own.rayCast(vec, own, distance)
        if ray[0] and ray[0] is not None: #ray hitted an object
            hit_obj = ray[0] #the object detected by the ray
            #here you can add a lot of options
            if 'some_property' in hit_obj:
                #do something
            elif 'another_property' in hit_obj:
                #do something else  
            elif 'and_another_property' in hit_obj:
                #rinse reppeat  

This way you can add lots of actions under the e_key, without hassle and you don’t loop trough all the scene objects, bge does not like to loop trough lots of objects. And you check the distance with the ray rather then checking it separate. You can still combine the two if you like.

1 Like

both methods are useful, it all depends on what you need, if all you need is proximity then calculate the distance is the fastest way to go, and if you also need it to be in line of sight, then the raycast method is what you want.

a side note:
looping over all the objects in the scene is a bad idia.

thank you guys! I just found that out ! :smiley:

But how to check if an object with specific property is within a distance regardless of direction without looping over all objects in the scene? :thinking:
isn’t the near sensor a heavy one? :face_with_monocle:

Perhaps, a List in the Global Dict, and use a small Script that adds his Owner into that, or remove. So just need to look inside this. But i think that makes only Sense, if there are not to many Objects writing at once.

For the Questioner: You can read from the Sensor like this:

import bge
Cont = bge.logic.getCurrentController()
Own = Cont.owner

NearSens = Cont.sensors["Near"]
KeySens = Cont.sensors["Keyboard"]

if KeySens.positive:
	if not NearSens.hitObjectList:
		print("No Objects here.")
		print("There are", len(NearSens.hitObjectList), "Objects arround.")

Thanks for the quick responses, friends. I adopted the @Cotaks implementation, as it seemed more direct.

you make a list out of the scene objects, then you loop trough that list.
A quick way to do that is:

def test(cont):
    own = cont.owner
    #true pulse or not run only once
    if not '__init__' in own:
        #put all objects with property 'enemy' in a list to be used lateron
        own['enemy_list'] = [obj for obj in own.scene.objects if 'enemy' in obj]
        own['__init__'] = True
    #if prop in own and list is not empty
    if 'enemy_list' in own and own['enemy_list']:
        #loop trough the list
        for enemy in own['enemy_list']:
            dist = own.getDistanceTo(enemy)
            if dist < 5:
                #do something with the enemy in range
1 Like