New Advanced closest function.

This is a python function that gets the nearest object.

To use it, all you have to do is place the following code into your script, then call on the function called getNearestObject()

Using this (almost) all purpose function you can get a series of different things.



##Gets nearest object (replaces near sensor) If you just want to get the nearest object leave prop as None##
def getClosest(obj,prop=None,maxdist=None,dynamicOnly=0,ignore=set()):
	closest = None
	closest_dist = maxdist
	objects = GameLogic.getCurrentScene().objects
	ignore = set(ignore)
	ignore.update([obj, objects["____default_camera____"]])
	
	for ob in objects:
		if (not prop or prop in ob) and (not dynamicOnly or ob.mass > 0) and ob not in ignore:
			dist = obj.getDistanceTo(ob)
			if closest_dist is None or dist < closest_dist:
				closest_obj = ob
				closest_dist = dist
	
	return(closest)


^This function was contributed by supersocks. I also made one, but his was better. :wink:

When you use the function, there are a series of parameters you must enter.

This is the function line that you should be entering into your code to get the nearest object:

getClosest(obj,prop=None,maxdist=None,dynamicOnly=0,ignore=set())

Parameters:
-obj = The target object (where you want to search from/in realation to)
-prop = The properties the objects must have. Leave as None or just close the bracket to just find the closest object.
-ignore = A list of objects that should be ignored by the function
-dynamicOnly = 1: only get dynamic objects, 0: get all objects
-maxDist = the maximum distance to look for an object.

Note: obj is the only parameter that you MUST enter.

Hope thats enough info. Comment if you need anything else.


def closest(obj, prop=None, maxdist=None, dynamiconly=False, ignore=set()):
    closest_obj = None
    closest_dist = maxdist
    objects = GameLogic.getCurrentScene().objects
    ignore = set(ignore)
    ignore.update([obj, objects["__default__cam__"]])
    for scene_obj in objects:
        if (not prop or prop in scene_obj) and \
           (not dynamiconly or scene_obj.mass > 0) and \
           scene_obj not in ignore:
            dist = obj.getDistanceTo(scene_obj)
            if closest_dist is None or dist < closest_dist:
                closest_obj = scene_obj
                closest_dist = dist
    return closest_obj

EDIT: Nevermind. I figuered it out. Thanks for the new function. Yours is much simpler than mine and it is quite elegant as well. :smiley:

I just have one question:

What does this line do?

ignore.update([obj, objects["__default__cam__"]])

Well, can you, please, make a Logic Brick too?..or at least, some “how to use it” examples? :wink:
Thank you!
Bye

Haha. Sorry OTO. Didn’t think of that…ummm. okay. I will make one.

EDIT:
Hmmmm. Its not working. I can’t isolate a problem. Here is the blend I made, but it only returns None for some reason.

getClosest Example.blend (195 KB)

Check lines 18, 28 and 31 and you’ll notice something.

ignore.update([obj, objects["__default__cam__"]])

Made a mistake here. Forgot default__cam exists only when view is not set to any camera object (which in games usually happens only in some rare debugging cases) so the script won’t run correctly. For a general use it should be simply:

ignore.add(obj)

or if you want to make it foolproof:


ignore.update([obj, objects.get('__default__cam__', None)])
ignore.discard(None)

So a Logic solution using track to actuator:


# closetracking.py

import GameLogic

def trackToClosest(controller):
    try:
        actuator = controller.actuators[0]
    except KeyError:
        return
    owner = controller.owner
    get_prop = owner.get
    prop = get_prop("closest:prop", None)
    maxdist = get_prop("closest:maxdist", None)
    dynamiconly = get_prop("closest:dynamiconly", False)
    ignore = get_prop("closest:ignore", set())
    if ignore:
        get_obj = GameLogic.getCurrentScene().objects.get
        ignore = set([get_obj(i.strip(), None) for i in ignore.split(",")])
        ignore.discard(None)
    closest_obj = closest(owner, prop, maxdist, dynamiconly, ignore)
    actuator.object = closest_obj
    if closest_obj is not None:
        controller.activate(actuator)
    else:
        controller.deactivate(actuator)

def closest(obj, prop=None, maxdist=None, dynamiconly=False, ignore=set()):
    closest_obj = None
    closest_dist = maxdist
    objects = GameLogic.getCurrentScene().objects
    ignore = set(ignore)
    ignore.update([obj, objects.get('__default__cam__', None)])
    ignore.discard(None)
    for scene_obj in objects:
        if (not prop or prop in scene_obj) and \
           (not dynamiconly or scene_obj.mass > 0) and \
           scene_obj not in ignore:
            dist = obj.getDistanceTo(scene_obj)
            if closest_dist is None or dist < closest_dist:
                closest_obj = scene_obj
                closest_dist = dist
    return closest_obj


Properties:
closest:prop – property to search for
closest:maxdist – maximum distance from object
closest:dynamiconly – search only dynamic objects
closest:ignore – comma separated list of object names to ignore

.

OR a Properties only version:


# closetracking.py

import GameLogic

def alignToClosest(controller):
    owner = controller.owner
    get_prop = owner.get
    axis = get_prop("closest:alignaxis", 1)
    factor = get_prop("closest:alignfactor", 1.0)
    prop = get_prop("closest:prop", None)
    maxdist = get_prop("closest:maxdist", None)
    dynamiconly = get_prop("closest:dynamiconly", False)
    ignore = get_prop("closest:ignore", set())
    if ignore:
        get_obj = GameLogic.getCurrentScene().objects.get
        ignore = set([get_obj(i.strip(), None) for i in ignore.split(",")])
        ignore.discard(None)
    closest_obj = closest(owner, prop, maxdist, dynamiconly, ignore)
    if closest_obj is not None:
        vect = owner.getVectTo(closest_obj)[1]
        owner.alignAxisToVect(vect, axis, factor)

def closest(obj, prop=None, maxdist=None, dynamiconly=False, ignore=set()):
    closest_obj = None
    closest_dist = maxdist
    objects = GameLogic.getCurrentScene().objects
    ignore = set(ignore)
    ignore.update([obj, objects.get('__default__cam__', None)])
    ignore.discard(None)
    for scene_obj in objects:
        if (not prop or prop in scene_obj) and \
           (not dynamiconly or scene_obj.mass > 0) and \
           scene_obj not in ignore:
            dist = obj.getDistanceTo(scene_obj)
            if closest_dist is None or dist < closest_dist:
                closest_obj = scene_obj
                closest_dist = dist
    return closest_obj


Properties:
closest:prop – property to search for
closest:maxdist – maximum distance from object
closest:dynamiconly – search only dynamic objects
closest:ignore – comma separated list of object names to ignore
closest:alignaxis – object axis to align the closest direction (0:x, 1:y, 2:z)
closest:alignfactor – the fraction to rotate object per logic tick (0.0 - 1.0)

.

In both examples omit property to use the default value.

Awesome! Here is the finished example.

getClosest Example.blend (195 KB)

Dear supersocks
you’re a true gentleman!
Thank you for the effort!
And thank you Sunjay03 for the nice example!
Bye