So I'm making an RTS type game, just for practice and exercise, but when I send someone somewhere, I want them to know when they need to stop. I decided this could be done by having the marker that they go to send them a message when they're near it. How can I make the message send only to the guys that are within, say, 3BU from it?
2 Answers
You need logic set up like in the image below on each of your markers.
It is just an Always sensor, set to True level triggering; and a Near sensor. Those two are plugged in to the python controller, which will activate the message actuator. The property in the Near sensor is not needed, that is only to limit what objects get the message.
The script will send a message to every object that is near (3 units or closer) the marker.
import bge
cont = bge.logic.getCurrentController()
list = cont.sensors['Near'].hitObjectList
if cont.sensors['Near'].triggered:
message = cont.actuators['Message']
for obj in list:
message.propName = obj.name
cont.activate(message)
- The script gets all the objects that are near the marker and stores it as the
list
variable (line 5). - The if statement works like this, when anything is near the marker, the near sensor is triggered, thus it is True.
It then loops through the list of objects that are near, and sets the message actuator's "To:" field to one of the objects. (message.propName = obj.name
) - The last line still part of the loop, activates the actuator - sends the message.
-
$\begingroup$ with two monkeys, your system doesn't work. one of them stops moving but the other keeps spinning around the marker. $\endgroup$– ruckusCommented Sep 11, 2015 at 19:55
I do not recommend to use the "To:" parameter at all. It creates a direct dependency to a single object.
One of the biggest advantages of messages is that you do not get such a dependency. Beside of that you couple the actuator to a single object which is contradictory to your requirement to interact with multiple objects.
Suggestion
I suggest to use a different architecture.
- Identify the objects within range
- Set according properties of the identified objects.
- Objects with that property sense if the property value changed
1) Can be done with a near sensor. It serves several purposes. You set up the detection range, you set up the property name (A) and it senses the objects within that range.
2) Can be done with a Python controller. Due to its dynamic nature there are no sufficient build-in logic bricks. Python controllers do not have additional configuration parameters. So we can use a little trick to setup the value we want to send without hard-coding it. We use a connected message actuator and setup the value of the subject field (B) [The actuator will not be activated]. This looks pretty similar to your proposed idea.
The code retrieves the found objects and sets the property value for each of them:
notifier.py
import bge
def subjectToNotification():
hitObjects = getHitObjects()
if not hitObjects:
return
property = getPropertyName()
value = getPropertyValue()
for hitObject in hitObjects:
hitObject[property] = value
While this describes the basic operation we want to achieve, it misses some details. You can use your own flexible implementations of the details. Just in case you have no plan, here is a simple implementation to be appended to notifier.py:
def getHitObjects():
sensors = bge.logic.getCurrentController().sensors
sensor = sensors[0]
return sensor.hitObjectList
def getPropertyName(): # (A) and (C)
sensors = bge.logic.getCurrentController().sensors
sensor = sensors[0]
return sensor.propName
def getPropertyValue(): # (B)
actuators = bge.logic.getCurrentController().actuators
actuator = actuators[0]
return actuator.subject
3) The sensed objects need to check if they are sensed. As we know the property value gets set, we can use a property sensor to check the property (C). Example:
Be aware this will not detect subsequent notifications of the same value. If you need it that way you should explicitly reset the property after it changed.
I hope it helps
PS: With the above implementation (A) and (C) should have the same property name.