So in any type of game that spawns AI, sending any form of a message to a certain AI will result in the message being sent to all of them (since they all have the same name).
Is there some way of renaming an object after it is spawned?
Thanks
So in any type of game that spawns AI, sending any form of a message to a certain AI will result in the message being sent to all of them (since they all have the same name).
Is there some way of renaming an object after it is spawned?
Thanks
don’t use messages,
set properties directly using python
or use a global dictionary or ???
Freds[‘Target’]=Bob
Freds[‘NavigationRoute’]=navmesh.findPath(A,B)
etc
Monster often points out python id can be used in identifying an object, I think* instanced object should carry their unique id too
<b>############### getting the object id</b>
<b># get current controller</b>
controller = GameLogic.getCurrentController()
<b># get object controller attached to</b>
obj = controller.objects
<b># get objectID</b>
objID = id(obj)
<b>############### getting the object from object id</b>
<b># get current scene</b>
scene = GameLogic.getCurrentScene()
<b># get object list</b>
objList = scene.objects
<b># use the saved objectID to get game object</b>
obj = objList.from_id(objID)
copy and pasted from tutorialsforblender3d
If you need to rename them, than you can do:
if not "ini" in own:
own["enemyID"] = 0
own["ini"] = True
if enemySpawnRequest == True:
enemyAI = scene.addObject(your object spawn data)
enemyAI.name = "EnemyAI.{}".format(str(own["enemyID"]))
own["enemyID"] += 1
This is slightly simple method to approach what you asked for, but I doubt if this is the best one.
well this doesn’t exactly work if you are trying to set the position of an AI or if you are sending them a message to take damage.
I curious if you can send message using only the object id instead, but specified method should work for most situations
each time you spawn them in, save them on a list,
for objects in bge.logic.getCurrentScene():
if 'AddAiHere' in objects:
added=bge.logic.getCurrentScene().addObject('yourOriginalObject',objects,0)
own['LiveAiList'].append(added)
this is a ‘factory’
why send a message to give damage?
whatever sensor detects the projectile hit, or sensor collision etc.
if 'health' in sens.hitObject:
sens.hitObject['health']-=sword['Damage']
Actually, when you spawn and object, you can store it as a local or global variable. You can modify my script so that:
import bge
cont = bge.logic.getCurrentController()
own = cont.owner
if not "ini" in own:
own["enemyID"] = 0
own["ini"] = True
if enemySpawnRequest == True:
enemyAI = scene.addObject(your object spawn data)
bge.logic.globalDict["enemy{}".format(str(own["enemyID"])] = enemyAI
own["enemyID"] += 1
Now you have stored the enemy in globalDict as KX_GameObject(it’s original format) and you can acess it whenever you want(I hope so).
if you are detecting the actor in the first place, the sensor that detects to send the message of damage could just apply it…
why send a message to give damage?
Perhaps @Thatimster wasn’t actively detecting the AI with rays or sensors for damage but rather keeping a list of available AI and issuing commands through radio/messages to them “individually” without ever having any physical means of contacts/sights on them to identify them “individually”… just a guess
That is the problem though for example this:
ray.hitObjectList[0] ##this returns 'enemy' which the clones are also called
ray.hitObjectList[0]['health'] -= 20 ###will reduce the health of all AI since they have the same name
Well i was meaning for using rays as bullets, but as you said this has many different applications, for example having a target appear over the one AI.
Great this should work well, I will use this when spawning in AI. Have you tested if it works?
I have tested the object storage in variable when spawning it(
obj = scene.addObject(name, reference, time)
) that allows to access the exact KX_GameObject you just added through variable(obj in my example). I haven’t tested globalDict, but usually it should work.
ray.hitObjectList[0][‘health’] -= 20 ###will reduce the health of all AI since they have the same name
this will only hurt objects on the hitlist… which is generated by the sensor.
Well i was meaning for using rays as bullets, but as you said this has many different applications, for example having a target appear over the one AI.
I see, the more the merrier, try this method as well, it should work with message sensor once you convert the id into a readable string format
enemy = scene.addObject(enemy,spawn,0)
enemyID = id(enemy)
get_name = str(scene.objects.from_id(enemyID))
own.sendMessage('hit','',get_name)
#OR
if ray.hitObject:
enemy = ray.hitObject
enemyID = id(enemy)
get_name = str(scene.objects.from_id(enemyID))
own.sendMessage('hit','',get_name)
Every spawned object is an instance of the original object. They have the same name but they are not the same object. Changing a property on one won’t do anything to the others. HitObject[0] is a reference to that instance not the original object.
It’s not the best design to get objects by name, but rather get objects by reference.
I do not recommend to use the id of an object. This is low level programming and should not be needed.
The basic problem is you want to bind two communication partners together. That way the sender knows the recipient.
This connection might be already present via the event e.g. hitObject or via structure e.g parent, or children, or group object. If might be you need to establish the connection manually. In this case you can write your own custom registration function.
your example
looks correct as it interacts with one detected object. (I would deal with all detected objects rather than just one of them).
The problem here is that this code knows too much about the target. It should not reduce the health as it is not responsible to do that.
damage provider:
I suggest to provide the damage to the hit object. As there might be more damage within the frame adding it up can be a good idea:
for damageReceiver in hitObjectList:
damageReceiver["new damage"] += <whatever damage>
damage receiver:
The hit object needs logic to evaluate the “new damage”, calculate the change in health and reset the already processed damage. The advantage is that the damage provider does not need to care how and if the damage is processed, and you can have different kind of damage receivers.
receivedDamage = damageReceiver["new damage"]
damageReceiver["new damage"] = 0.0
damageReceiver["health"] -= receivedDamage * 0.2 # example damage formula
...
a property sensor in change mode observing property “new damage” should be enough to trigger this code.
Hi Monster, what about getPhysicsId()? Can we use it to id an object?
Edit: what I meant to ask is about the drawbacks from such design?
You do not need an id at all.
The point is, when you know the object, just use it. There is no need to search for it.
hitObject/hitObjectList gives you the object.
You only search if you do not know the object. In that case you need some criteria. Why should an id be such a criteria? Where is this id coming from? Only the object can give you that. So you already have the object = no need for ids ;).
Thanks Monster, I was thinking of sending message to one instanced object base on its id tag while avoiding other instanced objects to pick it up, I guess that was unnecessarily convoluted when you can reference that single object and it’s property all the while
The “problem” with messages is that they transport strings only. That can become a bit problematic when you want to transfer something else.
When you have such a case, you can store the data to be transferred in a shared container (e.g. a module) and provide enough information to retrieve the data. This is a sort of “indirect” data transfer on demand.
Real life example:
Imagine you get an email with an URL where you can download certain data. The email can be pretty short while the data can be huge.
Blender examples:
Constant (no key):
-> The sender stores the game object DemoCube in a module storage.py (via Python). Then it sends a message with the subject “demo data updated”.
-> The receiver gets the message “demo data updated” and retrieves the game object DemoCube from storage.py
Flexible (with key):
-> The sender stores the game object DemoCube in a module storage.py under key “demo key” (via Python). Then it sends a message with the subject “demo data updated” and the body “demo key”.
-> The receiver gets the message “demo data updated” and uses the key “demo key” to retrieve the game object DemoCube from storage.py.
One thing you need to care: the data might be invalid at the time you access the shared storage. E.g. the object was ended. Your solution should be robust enough to deal with missing data. As the data is expected, an error message should be good enough if it is not there. Either the sender send incorrect information, or the receiver worked too late, or something else manipulated the data (scene change). Either way this is a design issue and should be handled by adjusting the design (rather than hiding the error).
So yes the object id or the object physics id can be used as key - the match the requirement to be unique within the communication path. Other keys can do that as well. E.g. let the storage generate you a new unique key.