The trackTo actuator and object instances

The following issues are not only valid for the TrackTo Actuator. They belong to ALL logic bricks with Object references (TrackTo, AddObject, Steering, Camera etc.)

I add new instance objects but the object with the trackTo actuator tracks the position of master object on the hidden layer. How to solve this?

I will try to explain

  • how the trackTo actuator works
  • why this happens and
  • how to fix that.

How does the trackTo actuator work?

The trackTo actuator rotates the object it belongs to until it points to the position of the tracked object.

The trackTo actuator’s tracked object can be configured in two ways:

  • at design time you can enter the name of an object in the OB: field
  • at runtime you can set the KX_TrackToActuator.object via Python
    While 1. is “startup” configuration, 2. can change the trackTo actuator multiple times at any time.

The trackTo actuator tracks when

  • an object is configured
  • the configured object exist
  • the actuator is active
    is one of the above condition false, the trackto does not track (but might still be active).

Why does it track the master object?
Short answer: Because you told it to do so.

See it in Detail. This happens at startup:


The trackTo actuator is configured to track an object with the name “Cube”. The only known object with that name at startup is Cube at the hidden layer. The actuator will track this object and nothing else (assumed the actuator is active).

Later on an instance object is added (a copy of the master):


Now there are two objects with the name “Cube”. But we nobody told the actuator to look for another one. So it will still track to the masters position.

Lets add another instance object:


The same here we have three objects named “Cube”. But nobody informed the actuator.

How to solve that, see the next post.

How to fix that?

first of all do not configure the trackTo actuator to track to the master object if you do not want that. Just leave the “OB:” field empty:

Now if you want the actuator to track something, then tell it. At runtime the only option is to do it by Python. In this example, if a new object is added the trackTo actuator should track the new object:

Lets add another new object:

Here you see the trackTo actuator gets a new tracked object. The old one will be ignored.

To track another object simply assign the reference (or the name) of the new target object to the trackTo actuator:

It is up to you when this happens and what object you select.
Here are some examples:

  • when another object is closer to the tracking object then the tracked object
  • when the tracked object disappears
  • when a new “target” appears
  • when the distance to the tracked object is over a certain limit
    Important is you have to implement this logic. The trackTo actuator does tracking targets - but does not select targets.

What happens if the tracked object disappears?

The trackTo actuator does not track anymore and the tracking object remains at the rotation it has. To track something, assign an existing object (on an visible layer).

For more details see the Game Engine API.

I hope it helps

Here is an example to let an object track to the objects under the mouse:

# Demo module to track to the object under the mouse
import GameLogic
#required Sensors
SMouseOver  = "sMouseOver"
#required Actuators
ATrackTo = "aTrackTo"
def trackToMouseOverAny(cont):
 sMouseOver = cont.sensors[SMouseOver] 
 if not sMouseOver.positive:
  return
 
 aTrackTo = cont.actuators[ATrackTo] 
 aTrackTo.object = sMouseOver.hitObject
 cont.activate(aTrackTo)
 
def showMouse(cont):
 import Rasterizer
 Rasterizer.showMouse(1)


Attachments

TrackToMouseOverAny.blend (138 KB)

Very informative and useful monster! I learned something today!

So, how would you manually assign a specific object?

Example, I have 1 master cube on an invisible layer. I spawn 10 instances in my visible layer.

I want the trackto actuator to ‘see’ the nearest spawned cube object and track it. If it moves away further, or another cube moves closer, switch and track to that one?

I worked out something myself, but I have to keep track of the python id(Cube) to see the difference in objects, is there an easier way?

Hi azure_infinity,

I just added S2A.py - the Sensor-To-Actuator library .

It contains a function that does what you need. Look for S2A.closestHitObjectToObject.

  • have a near sensor in True pulse mode (optional set the property field)
  • connect it with a Python controller in Module mode calling S2A.closestHitObjectToObject
  • connect it with an TrackTo actuator without the OB: field set.

I hope it helps

Hehe, thanks, very nice tutorial, thanks for teach us!
Coooool!

Another solution:

The S2A.py - the Sensor-To-Actuator library provides you with two functions to change the trackTo’s object:

  • hitObjectToObject
  • closestHitObjectToObject

This is very useful!!!
However, I am having problems, can you make the script so that the arrow tracks the latest added objects with an ‘always’ sensor? I tried changing the script but I have basic knowledge with python. Its an important feature I need to get working in my game, any help will be appreciated :wink:

An always sensor makes no sense. It would waste processing time for nothing.

What you can do is to send a message when you add a new object. Any tracking object could update it’s targets when receiving such a message.

There are multiple options, none of them work without Python.

The simplest is to update all trackTo Actuator after adding the object. The disadvantage is, you need to know which one should be updated.
updater.py:


'''
updater.py
==========
Allows to register objects and retrieve the reference to
this objects later. Objects will be registered by a key.
'''
__version__ = "1.0"
__author__ = "Monster"
import bge

Pkey = "key"
''' The property with the name of the registry key.'''

registry = {}
#--- BGE entry points
def register(cont):
  '''
  Registers an object under the registry key defined in property key.
  If the property "key" is not present the object gets registered
  und its object name. 
  Already registered objects with the same key will be removed from registry (not from scene).
  To be called by a newly added object (within the first frame).
  '''
  if not allPositive(cont):
    return
  newObject = cont.owner
  key = newObject.get(Pkey, newObject.name)
  registry[key] = newObject
  activateAll(cont)

def registeredToObject(cont):
  '''
  To be called by the object wich need the 
  object references at the actuators.
  Places the registered game object reference in the object
  parameter of all connected actuators. Actuators are not activated!
  '''
  if not allPositive(cont):
    return
  objectHolder = cont.owner
  for actuator in actuatorsWithObject(cont):
      registeredObject=findRegisteredObject(cont, actuator)
      if registeredObject is None:
          continue
      
      actuator.object = registeredObject
      cont.activate(actuator)

#--- internal
def findRegisteredObject(cont, actuator):
  if actuator.object is not None:
      registeredObject=registry.get(actuator.object.name)
      if registeredObject is not None:
          return registeredObject
  
  key = cont.owner.get(Pkey)
  if key is None:
      return None
  
  registeredObject=registry.get(key)
  return registeredObject
    
    
def allPositive(cont):
  for sensor in cont.sensors:
    if not sensor.positive:
      return False
  return True

def activateAll(cont):
  for actuator in cont.actuators:
    cont.activate(actuator)

def actuatorsWithObject(cont):
  return [actuator for actuator in cont.actuators if hasattr(actuator,"object")] 

You need this at the added game objects:
Properties:
“key” string value: a registry key [if it does not exist the object name is used]
Always sensor (sInit) no Pulses
–> Python Module: updater.register
-----> Message Actuator subject:“Cube added”

You need this at the tracking objects:
Properties:
“key” String value: object name of the added object [if not present the name of the objects in the actuators is used]
Message sensor True Pulse Subject “Cube added”
–> Python Module: updater.registeredToObject
----> TrackTo Actuator

Remarks:
If you skip the “key” property at the tracking object and the last tracked object ends, the actuator looses its name. That means the updater will not find the key anymore. The tracking will work exactly once (until the tracked object ends).
Better explicit set the key property.

Thank you so much for explaining this! I was stuck a while ago on just this problem so this was very useful!

Nice. Hopefully the odd question “why is my player not tracking added Objects?” will not appear anymore in the future…:wink:

Sorry for the late reply :frowning:
Thank for the script! It helps sooo much! :yes:

hi ^^

i need that my Zombie track (in Only 2d, Z axys locked for avoid tilt of skeleton) to nearest Survivor.

How i can lock the Z axys in this very useful code?

import bgedef trackNearestProperty(cont):
debug=True
if not ‘target’ in cont.owner:
if debug:print(‘No property called “target” found, please specify target property’)
return
property = cont.owner[‘target’]
objects = sorted([[ob,cont.owner.getDistanceTo(ob)] for ob in bge.logic.getCurrentScene().objects if property in ob], key=lambda x:x[1])
if objects:
if objects[0][0] == cont.owner:
objects.remove(objects[0])
cont.owner.alignAxisToVect(cont.owner.getVectTo(objects[0][0])[1],1,1)
return
if debug:print(‘No Objects with Property:’,property)

update: Solved with S2A.py 1.8

thank you so much!!

new problem: If the object is under the effect of an Actuator of “Action”, the auto-tracking is lost.

how i can set the priority of tracking over the Action rotations?

errata corridge of first request: the only axys that should change is the Zaxys (like a compass) but my objects change their tilting ! i need only the ground orientation! ^-^ ty for response

actions move the armature not the origin, just track a object parented to the root bone?

Once again you came to my rescue.:slight_smile: I’ve been trying to rewrite a python 2.6 (2.49) Track-to-closest-object scropt for the newer builds, (2.74) (with no luck) this will help. :slight_smile:

Thank you Monster.