Track to nearest enemy. . .

Does anyone have a script that works in 2.6 that is able to track to spawned objects? :spin:


In the past I would already be giving you hints about how to achieve that; but now I first must ask:

1 - Do you desire only a completed script, or you accept some hints about how you can achieve that yourself?

2 - Are these spawned object, a copy of a single object, or different objects being spawned?

3 - Logic Bricks only or Python is an option to you?

1 - I am not really any good at python. So, completed? Tutorial maybe?

2 - The spawned objects would be one enemy on a different layer, being spawned in as many. . . If that helps. And there would be different types of enemies.

3 - Whatever I can change what property the object tracks to and is short!

Other can clarify/improve what I will say next, and I do not know if I will be of any help(as you prefer a Tutorial), but from countless possibilities I will present one:

Outside the player class you would do a python list containing all loaded enemies(it gets updated with each enemy death or creation); back to the player class you would do a constant python ‘For loop’(while the list was not empty), for each item in that enemies list, inside the for loop you would then do a bge/python math or bge function(I guess there is already one) to check for each enemy, the distance to the player and store them in a second list(enemy object + distance), which would be python .sorted and the lowest distance value would be chosen by the second list index(I guess the lesser value is 0 index), you would then use that retrieved enemy object(stored together with the distance) at a bge command(which I can’t recall) to make the player object point to the closest enemy; if the bge command does not work well for you, you will have to do bge math/python math to achieve the same.

For efficiency you could even make the player distance for loop only work below a certain distance value(a maximum distance check).

Also it seems(I’m not sure) objects spawned which are copy of a single object have the same object name to the bge(thought the bge threats them separately); but there is a way to workaround that.


I don’t really know, like, what to do. At all ~:\

my learning process would be to learn to track 1 enemy…then 2…then let it figure out which one is closest…then 3…4…a group…etc…one thing ive learned is that these things take ALOT of trial and error

For any AI that is capable of managing more than one target object (enemies, players etc) you have to have a way to pick the best one. This is a NP complete problem, meaning you have to check through every single target and evaluate it to see which is best.
First get a list of all objects in the scene with the required property with something like this:

def withProperty(property, sceneObj):
    '''Makes a list of objects with a particular property'''
    targets = [obj for obj in sceneObj if property in obj]
    return targets

btw, sceneObj could be bge.logic.getCurrentScene().objects
property is a string

Now you have them all in a list and go through them all and see which is best to select as a target. I use things like:

distanceTo = obj.getDistanceTo(tar)


def getAngleBetween(source, target, axis):
    '''Get's the angle between source and target'''
    dis, gvec, lvec = source.getVectTo(target)
    angle = lvec.angle(mathutils.Vector(axis),90)
    angleDeg = math.degrees(angle)
    return angleDeg

Line of sight

def hasDirectSightOn(source, target):
    '''See's if there's a direct line between the source and target'''
    hitObject = source.rayCastTo(target)
    return id(hitObject) == id(target)

Then you come up with some neat way of combining it in a single big function, that process it all and selects the best:

def getBestToTrackTo(obj, targets, maxAngle, angleScale, vector):
    #Run this for every object that it could track to
    lowestValue = 1000
    target = None
    if targets == None:
        return None
    for tar in targets:
        distanceTo = obj.getDistanceTo(tar)
        if distanceTo > 500:
        angleTo = getAngleBetween(obj, tar, vector)
        if angleTo > maxAngle:
        if not hasDirectSightOn(obj, tar):

        #Work out the "value" giving distance a pioritys based on "angleScale"
        value = distanceTo + angleTo * angleScale

        #See if it's the lowest value.
        if value < lowestValue:
            lowestValue = value
            target = tar
    return target

Before finally writing a script that does something with this target.

All that code above does one thing, selects the best enemy to attack. To use it I have the following code:

def trackToClosest(cont):
    '''This loop get's the angle and distance to any enemy with a certain property, and then compares it using a value set by the object. You need 3 properties: 
        trackName  - quite obviously the property in the enemy to track to
        maxAngle   - the angle that the missile can see. Enemies beyond the angle will not be targets
        angleScale - the ratio of distance to angle for picking enemies'''
    #Getting the object the script runs from
    obj = cont.owner

    #Getting properties and actuators
    trackTo = cont.actuators["trackTo"]
    trackTo.object = None
    trackName = obj["trackName"]
    maxAngle = obj["maxAngle"]
    angleScale = obj["angleScale"]
        levelObj = pyro.levelObj
        '''On the first frame it has to find the levelObj, and does not exits, this stops errors happening on the first frame'''
        levelObj = bge.logic.getCurrentScene().objects)
    targets = pyro.getObjects.withProperty(trackName, levelObj)
    target = getBestToTrackTo(obj, targets, maxAngle, angleScale, [0,0,1])
    trackTo.object = target

hope that was helpful. I’m hoping to do a full tutorial on this stuff sometime.

This code was quickly ripped from my project, and some aspects of the code may refer to functions that aren’t available without some of the other modules I have written. So, the code as provided probably won’t work properly, but you can base your own off it.

Well I made this demo long time ago. It’s solution wchich use only game logic. You can try it.

check out my solution. It’s primitive, but works.

I run the following script on all of the empties that spawn enemies. The objectLastCreated function adds each enemy to a GameLogic list that I then can iterate through.

spawn = own.actuators["AddEnemy"]
last = spawn.objectLastCreated


You can use the S2A it allows exactly that