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 = logic.keyboard.events
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
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.
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 !
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?
isn’t the near sensor a heavy one?
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.")
else:
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