Character distance with object and picker class

Hello, am developing a game where the moving character in 3d world needs to click on objects to activate appropriate actions. I have successfully used the functions in the picker class in the tutorial. But i want my character to be able to click an object once he is close enough to it… is it possible to modify the functions inside the picker class to implement this?

You can subtract the character position and the collision point (the result of both must be at the same coordinate space). Subtraction of 2 points yields a vector, so you can get the distance by using length(). Then check if this distance is reachable or not.

Ok thanks, that should be a better way… i was thinking of doing it by getting the coordinates of the model picked and then of the character and use square root to find the length.

ANother thing… when i click on the object… it returns me the name of the model. But i am placing several instances of the same model, is it possible to retrieve the instance name instead of the model name??

The result of the collision is a geom. Depends on your model’s hierarchy, you can get the parent and check the name.

I have another big problem

Let’s say i need the x position of an object clicked. that will be :

tx=self.pickedObj.getX()

but if ever the user clicks on an object that returns “None”, it won’t have any tx and thus the program will crash. To prevent it from happening, i have tried:

if self.pickedObj!="NoneType":

and

if self.pickedObj!="None":

without success.

I also need to compare individual objects. for example, i need to chk whether object clicked is

if self.pickedObj=="render/myobject.egg":

But it’s not entering the if condition in this case. I firstly need to know how i to detect the “NoneType” and secondly checking which object is selected by comparison

I have been able to figure out the solution :smiley:

self.pickedObj needs to be converted to string first b4 comparison!

How do chk the name with self.pickedObj as the object?

There is no need for any conversion.
Simply

if self.pickedObj!=None:

does the job.

You said it clearly : the NAME.
I assume, you had named each parent of your instances before, perhaps something like this :

char1=render.attachNewNode('instance1')
model.instanceTo(char1,0)

so that the model now is a child of char1.

Assuming the collision model (trapped in self.pickedObj) is the child of model, to get the parent (char1) name :

self.pickedObj.getParent().getParent().getName()

Thanks

I have another problem with the picker class.

My game is networked. When i click on an object in the client, after a certain period of time, another object is loaded exactly at that position, and this is reflected on the server. But when i click on that new object now from the server, it remains undetected, though everything has been defined and there is no networking problem.

In short, is it normal in panda that when an object, defined to be pickable, is replaced by another object exactly of the same size at the same position, panda cannot detect the latter?

I never do network.
Are you sure your new obj is pickable even if it’s loaded since the beginning ?
Are you using the same picker class like –THIS– ?

YEs, i think my guess was right. I lost several hours in trying to find a bug in my program. When i displaced the position of the new object which should replace an existing object, it is pickable again. But when i place it the same position as the previous one, it is not

So what’s picked then ? The old one ? Shouldn’t you remove it before placing the new one ?
The collision entries are sorted based on distance from the ray, so if your old obj is still there and it’s bigger (at the collision position) than the new one, than the old one will get picked.

Nah… when my code remove the old object and places the new one there… and i clicked on the new one, “None” is returned. However if i place the new object slightly at a different location and click on it, the new object is returned successfully.

hey… that’s funny enough to make me laugh.
ok, to see the whole thing clearly, try this :

  1. show() your new collision object
  2. showCollisions(render) the collision traverser
  3. create a new task to do these things :
    a. put the ray to follow the mouse
    b. traverse() the collision traverser
    c. print whatever the intonode

something like this :

        taskMgr.add(self.followMouse,'mouse chasing')

    def followMouse(self,t):
        if base.mouseWatcherNode.hasMouse():
           mpos=base.mouseWatcherNode.getMouse()
           self.pickerRay.setFromLens(base.camNode, mpos.getX(),mpos.getY())
           self.picker.traverse(render)
           if self.queue.getNumEntries() > 0:
              self.queue.sortEntries()
              print self.queue.getEntry(0).getIntoNodePath()
        return Task.cont