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.
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).
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?
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
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.
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)
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
Once again you came to my rescue. 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.