Please help with my targeting system.

Ive got my targeting system pretty much perfect to my liking except 1 thing. I cant get my target script to jump through my targets in range.


import bge
from bge import logic
from bge import events
cont = logic.getCurrentController()
s = logic.getCurrentScene()
o = cont.owner
me = cont.owner
range = 100
key = logic.keyboard.events
TAB = key[events.TABKEY]
if TAB == 1:
    for o in s.objects:                         #get objects in scene
        if "targetable" in o:                       #check if 'targetable' prop is in objects
            distance = me.getDistanceTo(o)        #get distance from US to target
            if distance <= range:                         #if in range
                me['target'] = str(o)                    #set target

                targetPosX = int(o.position[0])
                targetPosY = int(o.position[1])
                targetPosZ = int(o.position[2])
                print("Now targeting", target,"at")
                print(targetPosX,"X")
                print(targetPosY,"Y")
                print(targetPosZ,"Z")
            if distance > range:
                me['target'] = ""

Console gives me 2 different targets from the print()s when in range of 2 targetable objects, but only 1 will ever show up in me[‘target’]

You are over writing the value in me[‘target’] when you use the assignment operator (=), instead add the new value to the end of it. e.g:

me['target'] += ' ' + str(o)

Since you are adding to the end of it you’ll also need to clear the string near the start of the script, add this before the for loop:

me['target'] = ''

You’ll also need to remove

if distance > range:
    me['target'] = ""

Alright now me[‘target’] gets filled with both? How can I get it to choose the one closer? or choose a different target in range?

Do you want to store all the targets or only the closest target?

The following will only select the closest target.

me["target"] = sorted([ob for ob in o.objects if ob.get("targetable", False)], key=lambda ob: ob.getDistanceTo(me))[0]

Is there a way to get it to cycle through all in range, one at a time? E.g. I press tab first time,target cube1 at 35m, press again target cube2 at 45m, keep pressing, they keep changing through any in range one at a time.

If anyone ever played SWG you know the targetting system Im aiming for :slight_smile:

You’d have to control that youself, my first step would be to make an array of all objects to be considered (perhaps you’ve done this already). Next sort this based on range with some simple iteration:
declare an empty array
declare a variable, prevdistance orsomething, make it 0.
declare another variable, call it index and make it 0.
have a for loopto iterate oer the elements in the list.
using another for loop inside this(again, for all the elements in the list), for each object you should use the getDistanceTo function, and compare this with the prevdistance value, if it is larger, assign the prevdistance to the value, and assign the index value to the “index” variable. then place the element at the index value at the end of the initially empty array and remoe the element from the previous array.
after the for loops, reverse the list order, as this will order them in descending order, IE, furthest first.
you will now have a list of the objects, closest first, you could use a property to access an element, and increment this when tab is pressed.
I would write the code, but I don’t knowyour setup, and it will probaly help more in the long run to give you an idea of how to do it. ifyou need any help,just ask.

The code I posted at the top is 95% of my system, the other 5% is inside a BGUI setup for my game, that setup just assigns the textstring from me[‘target’] to a on screen text display, then I use the string in me[‘target’] to get target’s health.

Im really confused on arrays, Ive though about


targets = []
for o in s.objects:
    if distance <= range:
        targets.append(o[0])
        targets.append(o[1])
        me['target'] = targets[0]


Im probably all sorts of wrong haha, I ask for wisdom of much wiser gurus. :slight_smile: Im gonna keep researching these array things lol

Here’s my system

This is my target grabbing script.


import bge
from bge import logic
from bge import events
cont = bge.logic.getCurrentController()
s = bge.logic.getCurrentScene()
o = cont.owner
own = cont.owner
range = 35
key = logic.keyboard.events
TAB = key[events.TABKEY]
if TAB == 1:
    for o in s.objects:                         #get objects in scene
        if "targetable" in o:                       #prop health is in objects
            distance = o.getDistanceTo(me)        #get distance from US to target
            if distance <= range:

                own['target'] = o

                own['tmana'] = o['mana']*100/o['manaMax']/100
                own['thealth'] = o['health']*100/o['healthMax']/100
                own['tenergy'] = o['energy']*100/o['energyMax']/100

                targetPos = o.position
                print("Now targeting", o,"at ")
                print(targetPos[0],"X")
                print(targetPos[1],"Y")
                print(targetPos[2],"Z")

This is the part of the gui that uses the info provided via target script


if own['target'] == "":
                    self.target.text = ""
                    self.tgthealth.percent = 0.0
                    self.tgtmana.percent = 0.0
                    self.tgtenergy.percent = 0.0
                else:
                   self.target.text = str(own['target']
                   self.tgthealth.percent = own['thealth']
                   self.tgtmana.percent = own['tmana']
                   self.tgtenergy.percent = own['tenergy']

I did think of a way to use andrew-101’s post.


if own['targetnum'] == 1:        
          own["target"] = sorted([ob for ob in .objects if ob.get("targetable", False)], key=lambda ob: ob.getDistanceTo(me))[0]
if own['targetnum'] == 2:
          own["target"] = sorted([ob for ob in s.objects if ob.get("targetable", False)], key=lambda ob: ob.getDistanceTo(me))[1]

and so on until I cap targetnum at a max number of targetable objects at a time.
This is turning into a huge post but I also figured out a way to get properties from whatever own[‘target’] equals, that Id like to be able to keep using with an array.


target = str(own['target'])
target1 = s.objects[target]
distance = own.getDistanceTo(target)
own['targMana'] = ((target1['mana']*100)/target1['manaMax'])/100
own['rng2targ'] = int(distance)