non-mouse 2D selection of 3D objects

I am currently working on (see abandoning my current attempt) a target/object selection system relative to the current target as seen from a third person/rpg type view that does not use the mouse. My first attempt was to use collision solids moving to scan the area. This seems inefficient, at least my approach does. I basically had vertical collision tubes attached to all targetable objects and used a collision segment to collide into them. If I moved the segment slightly each iteration of the search it gives the targeting system more precision but makes it horribly slow. If I increase the distance moved per iteration it has the tendency to skip over objects further from the camera. It was crude, but it “worked” for the purpose of learning how to use collisions to gain access to other nodes.

I was wondering if it would be “easier” (see simplified/more efficient/cleaner) to keep track of all possible targetable objects.inView() within X distance from the player. It would be ideal if I could get their 2D location (or to simplify it even more just along the X axis) as it appears from the cameraNode. The next target would just be what appears to the right of the current target no matter how close or distant it is from the player. I realize if there were a ton of objects.inView() efficiency would suffer, but there will probably be few circumstances in which there will be more than 20 max objects within range.

I would think (based upon my very very very limited knowledge and experience dealing with Panda) that I would have to use render2d for this, but I have even less knowledge and experience with render2d so I am not sure of what it is capable of.

I was looking at some of the bounding geometry, but they all appear to be based upon 3D coordinates relative to the world not the players view(camera/lens).

If anyone could point me in the right direction or suggest a simpler way to accomplish this type of targeting it would be much appreciated.

Thanks,
Brandon

No thoughts or helpful suggestions?

Disclaimer: I’m a bit tired, so forgive me if I misunderstood what you’re trying to do :stuck_out_tongue:.

[Drag Selecting multiple nodes)

The post linked above is actually meant for drag selecting, but it’s major component is what I think you’re asking for – finding out where on the screen’s surface a 3D object’s center is, if I can put it this descriptive way. If I understood you correctly, it should provide a nice foundation for you to work on.

That definitely gives me a starting point.

Thank you.

I finally got around to this again and this is what I came up with for my targeting system…

    def nextTarget(self, wrapAround, passes):
        objs = render.findAllMatches('**/target')
        targets = {}
        base2d = Point3()
        #If wrapAround is used then there were no possible targets to the right of the current target so nextTarget was called recursively
        if wrapAround:
            base2d[0] = -1
        #If player has no target, base2d is set to 0. This will line up with the center of the screen
        elif self.player.target == None:
            base2d[0] = 0
        #Else, this is the initial search and the player has a current target -- Find 2d xPos of the current target to use as base of target search
        else:
            base.camLens.project(self.player.target.node.getPos(base.camera), base2d)
            #Untarget the current target
            self.player.target.modelNode.hideBounds()
            self.player.target = None
            self.displayTarget(1)
        #Iterate through possible targets
        for x in objs:
            #If possible target isInView -- Calculate 2d xPos
            if base.camNode.isInView(x.getPos(base.camera)):
                pos2d = Point3()
                posConv = base.camLens.project(x.getPos(base.camera), pos2d)
                #If it is to the right of the base of the search -- add it to the targets dict, keep track of them by xPos as key
                if pos2d[0] > base2d[0]:
                    targets[pos2d[0]] = x
        #Copy keys to a list and sort -- targetlist[0] being the next target
        targetlist = targets.keys()
        targetlist.sort()
        #If targetlist is not empty then there are possible targets to the right of the base for the search
        #Find the target's ID and then find that ID in the npcDictionary
        if len(targetlist):
            tID = targets[targetlist[0]].getTag("ID")
            self.player.target = self.npcDictionary[tID]
            self.player.target.modelNode.showTightBounds()
            self.displayTarget(2)
        #ElseIf targetlist is empty then there were no possible targets to the right of the base for the search
        #Call nextTarget passing 1 for "wrapAround" so the search will start from the far left side of the screen
        #passing 1 for "passes" to flag that it has already wrapped around once
        elif not passes:
            self.nextTarget(1, 1)

This does exactly what I need it to do and it will be paired with a prevTarget method that will search to the left of the current target, but I am not terribly confident that this is a “good” way to go about this.

At the moment I am using showTightBounds to highlight the target and a simple OnscreenText to show the name. My game world is very simple at the moment, consisting of a very small terrain.egg and a few spawned NPCs. All of the NPCs/objects/etc that the player will be able to target have a NodePath(‘target’) attached to them.

Using “objs = render.findAllMatches(’**/target’)” seems like it could be terribly inefficient if the terrain was larger and there were hundreds of target NodePaths in objs. I was planning on implementing a heightmap terrain system later and only loading up sections of the map around the player (as is the standard I would assume). Is there any possible problem that I could run into later using render.findAllMatches like this?

Also any other criticism/suggestions about this in general would be appreciated as well.