Help with Lock-on

I’m trying to make a decent lock-on that can cycle through enemies. If anybody could take a look at my blend I would be super grateful. I’ve been trying, with little luck, for almost a week:( If some enemies are out of range I need the cycle to go to the farthest enemy that is still in range and if only one enemy is in range it needs to not be able to cycle. Thank you in advance.

Ctrl to lock-on MouseWheel to cycle enemies

Attachments

Lock-On_Attempt.blend (482 KB)

import bge
cont= bge.logic.getCurrentController()
scene= bge.logic.getCurrentScene()
own= cont.owner
sens=cont.sensors['Delay']
if 'enemyList' not in own:
    own['enemyList']=[]
if sens.positive:
    for objects in scene.objects:
        if 'Enemy' in objects:
              if objects not in own['enemyList']:
                   own['enemyList'].append(objects)

this will build a list of objects with the property enemy,

you will need a method to remove enemies from the list as they die.

either using object.invalid or a message upon death,

cycling the index will cycle through the enemies,

look into the list.sorted function,

It already builds a list of objects with ‘enemy’ property and uses radar sensors on enemies to find others near and can cycle through accordingly. My problem comes when you’re locked-on to one and some are out of range, if you cycle it tries to lock on one out of range and ends the script or if only one enemy is in range and you cycle it still looks for other enemies but since non are in range it raises an index error.
I didn’t even think of what to do when the enemy dies:o ,trying to get the cycle to work right,I’ll probably just have it switch the lock to enemy closest or if there aren’t any enemies set ‘lock-on’ property to False and end script.

you can use list.length I think?


if index + 1 < list.length:
    index=0
else:
    index+=1

there is also Mod operations

If at all possible could you post a blend of a working lock-on, or something similar, that I could study\learn from or if you know of any tutorials that aren’t just implementations of track to actuators, although that could work if you can set specifically which object to track with a cycle. e.g. mouse wheel up = track to closest enemy left of currently tracked enemy.
Any more help would be most appreciated!

just a experiment
should work but not necessarly “worth” :slight_smile:


import bge






class Nears:
    def __init__(self, sensor):
        self.sensor = sensor
        self.owner = sensor.owner
        self.index = -1
        self._make_list()
        
    def get_previous(self):
        return self._get_item(self.index-1)
    
    def get_next(self):
        return self._get_item(self.index+1)
    
    def _get_item(self, index):
        self._make_list()
        if not self.lst:
            return None
        self.index = 0 if index < 0 else len(self.lst)-1 if index >= len(self.lst) else index
        return self.lst[self.index]
        
    def _make_list(self):
        self.lst = sorted(self.sensor.hitObjectList, key=self.owner.getDistanceTo)




        






def Lockon_Object():
    
    cont = bge.logic.getCurrentController()
    scene = bge.logic.getCurrentScene()
    own = cont.owner
    
    wup = cont.sensors['wheelup']
    wdown = cont.sensors['wheeldown']
    
    if not "nears_instance" in own:
        own["nears_instance"] = Nears(cont.sensors["Near"])
        own["near"] = None


    nears = own["nears_instance"]
    
    if wup.positive:
        own["near"] = nears.get_next()
    elif wdown.positive:
        own["near"] = nears.get_previous()
    
    if own["near"] and own["near"].invalid:
        own["near"] = None
        
    ob = own["near"]
    
    if ob:
        scene.objects['Lock_Indicator'].worldPosition = ob.worldPosition
        scene.objects['Lock_Indicator'].visible = True
        scene.objects['Lock_Indicator']['lock'] = True



So after much trying and failing I could not get the functionality I’m looking for out of the code that MarcoIT posted. I’m probably just not smart enough:o I could not get it to lock-on when initially told to do so and also I need to be able to control the order in which it cycles through enemies. Is it at all possible to divide the near sensors sphere in half, essentially making two near sensors out of one. I tried using radars for each side but I don’t know how to compare two lists to check if an object is on both. Maybe I’m biting off more than I can chew but a lock-on script shouldn’t be so difficult.

i can be also written some code useless (can be) but is the kind of logic that allow to this code bad .
there 2 type of code , the one that do miracles with 2 lines , and one that do nothing with 50 and still prone to error.
this is the second one.
is a collection of exceptions that require a bunch of check .

but as sayd , maybe i m wrong the method

I’m sorry, I in no way meant to imply that your code was “bad”. Essentially it does the same as mine in much less and neater code.
Also I would like to thank you very much. I was able to learn a little from your code and I think I figured out a way to do what I am trying to accomplish, as long as I can find a way to compare two lists.

I would have 1 list ,

if you see it, add it to the list,
if you see it while its on the list renew it,
if its not seen in x frames pop it from the list

if object not in list:
    list.append([object , time])

else:
       lookUpIndex
       list[index][1]=renewedTime

and you can loop through the list, and reduce each time value each frame,
so when it reaches zero pop it from the list.

no problem :wink:
i mean the bad code(for me bunch of code is bad code) is due to the “bad elements”
my code is also semplificated since the “index” is semi-static .

i guess what you want require to know the index “on the fly” (ie, get the index from the item)

supposing you had already the target and the target exist also in the new list, the index in the list sorted by distance is:
sorted_enemies = sorted(sensors[“Radar”].hitObjectList, key=player.getDistanceTo)
index = sorted_enemies.index(player[“target”])

#where index+1 is the one a bit more far (if exist in the list)
:wink:

I decided to mark the post as solved because I got it working almost perfectly.
The only issue is at certain angles it doesn’t cycle enemies properly. In a game this shouldn’t really matter because enemies likely wont be lined up in this way, at least not for very long.

I’ll post the blend file for anybody who wants to use it.
I’m sure it’s in need of optimization but is the best I could do.
If anybody is able to optimize it or makes any useful changes please post it back here.

Thank you Marco and BPR for your help and insight.

Attachments

Lock-On.blend (518 KB)