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.