Some more python questions

Hello,I share with you these 5 lines of code to ask some questions.


1.cont = bge.logic.getCurrentController()
2.obj = cont.owner
3.act = cont.actuators["move"]
4.sens = cont.sensors["land"]
5.sens_2 = cont.sensors["bonus"]

Questions
1)In line 1,I understand that the variable cont is assigned a value of “bge.logic.getCurrentController()” which I guess is the python controller,so that I can use everything that connects with him in my script.Correct?
2)This code line,assigns the object(for example the cube that I am working on) to a variable.Is this correct?If yes,can you give me some examples as to where I can use this variable.Cause so far in my practise I have achieved all I want to do without having to use the “obj” variable.
3)In line 5,I assign to sens_2(variable) the result of the sensor which I have named bonus.This sensor belongs to another object,different from the cube that I am working on.However I want to use it in the script of my cube(which runs through the python controller that exists in the cube controllers).How can I do this?I guess I need to change something in line 1 at least.

I am gonna share with you the blend file in case you need it to understand or to comment on my beginner code for something important.
http://www.pasteall.org/blend/27117

1)Correct.

2)That line is for get the object owner of the controler.
You can use functions like:


obj.worldPosition = [0,0,1]

or:


obj.endObject()

For get other objects use this:


scene = bge.logic.getCurrentScene()
object = scene.objects["Cube"]

Is there much examples in this web, other link.

3)In the past I had tried to get the sensors or actuators of other object, and not work.
I was try something like this:


import bge
scene = bge.logic.getCurrentScene()
object = scene.objects["Cube"]
object.sensors[0]

Not appears errors, but looks like not work.

Many thanks,I am gonna try the 3rd example you gave me myself.
If anyone knows if and why this is doomed to fail,let me know. :slight_smile:

For #3

Controllers and game objects (the “cont” and “obj” variables in your script) only have access to sensors and actuators that are on the same object. In order to get a sensor that is attached to another object, you must first get a reference to that object. This can be done easily like this:

scene = bge.logic.getCurrentScene()
otherObj = scene.objects['otherObjectName']
otherSens = otherObj.sensors['sensorName']

Note that you can use an index instead of ‘sensorName’ to get the sensor like carlo did, but it’s better to reference the sensor by name. Otherwise your script will break if the order of sensors on the object is changed.

getting actuators from other objects is easy, and you can activate them from your scripts, however, getting sensors from other objects is not a very good idea. You first need a sensor to trigger your current object and then it needs to check every single frame to see if the other object sensor is active. That’s a huge waste of resources.

You should use messages instead, so “bonus” triggers a message actuator and your current object has a “message” sensor (maybe called “bonus_messsage” or whatever. when bonus is triggered it sends a message which your object picks up and then triggers “bonus_messsage”. Then you can have “if bonus_message.positive then do something”.

Another way to do it would be to have your bonus object get the current object from a the list of scene objects (as mobius and carlos said) and then set a property on that object, maybe you could have a property sensor to trigger your current object.

I think messages are the best way to start with as they are pretty easy to work with. Only use the second method if you want to start sending lists or dictionaries from one object to another.

I take issue with this statement for a couple reasons:

  1. No one said anything about checking the state of the sensor. There can be many different reasons for accessing a sensor other than just checking if it is positive. One in particular that comes to mind would be getting the source and direction of the ray cast from a mouse focus sensor

  2. Even if you are checking the state of the sensor every single frame, all that amounts to is 1 boolean comparison each frame. That is a far cry from “a huge waste of resources” as a boolean comparison is pretty much one of the simplest operations you can do. You would probably have to perform tens of thousands of them or more each frame before you would begin to see a performance drop.

I agree with this statement but for different reasons:

Separation of concerns.
First question to ask: Why should an object access the sensor of another one? You need a really good answer (“because it can” - is a not a good answer). If you do not have a good answer - there is probably a design issue.

Dependency
When you do this your code needs to know the implementation details of an object it does not belong to. This creates a strong dependency as if you change this other object, the owner of this code not work as expected anymore. This is more or less a guaranty for hard to find issues later.

Contra
Nevertheless this depends on the situation and there are situations when this is a good solution:

  • there is temporary relationship
  • e.g. you want to find all objects with a message sensor ;).
  • there is a strong dependency anyway
    e.g. a character consists of multiple game objects (collision box, armature, skin, bone hooks, sensor objects) the behavior of the character needs to get input from one of the connected sensor object - but the logic is established at a different part of the character.

Edit:
This went a bit off topic. To come back to the original request:
All of this five statements contain as last step an assignment operation (“=”).
You do not need to guess your can find all of these methods in the BGE API. Take your time to get used to this documentation. It is really worth.

In that case simply do not create this variable.
Thumb rule: create variables if you need them … shortly when you need them. Otherwise you are wasting your time and the time of the processor ;). Believe me I see unused variables very often (“because I might need them later” right response: “Then add them later” ;))

Why do you call the variable “sens_2” ? I mean there is a reason why you call the sensor “bonus”. Wouldn’t it be better to name the variable “bonus” too? There should be a reason for variable name. At least it should mean something ;).

See above … “first question”

Sorry, I didn’t phrase that well, but read what monster said, there are reasons not to do it like that.

is true but what other alternatives?
to manage these stuff should be a system message decent , but not there.

supposing a character with a sensor on the head,
there 10/20 characters (same name)

solution 1)
the box go to read the sensors of another object

solution 2)
???

The general idea is that you agree a protocol between objects. The more abstract the protocol, the easier it is to modify and to extend. Part of the SCA design means that it makes the most sense to have objects post the results of their sensors to a database and then to access that information elsewhere.

Sent from my Nexus 5 using Tapatalk

Great!Understood many things.Gonna put them into action now.Many many thanks! :slight_smile:

Yes, when you get better at python that is a great way to go.

For example I use a mouse sensor to find the place the player wants to send his character, then I use a pathfinder to calculate the route to that spot. Then I save that route to a global dictionary entry for the player and tag the player as “moving”. From there I have a action cue item which executes instructions in the right order. The action cue manager gets all its route info from the global dictionary and is activated whenever a new route or action is created, and then it deactivates itself once all actions have been executed. The action cue object works equally for players or monsters or whatever, as its only job is to execute actions, not to plan them or decide what kind of actions to take, that is the job of other scripts which can be tailored to the kind of agent in question.

But that’s quite complicated and not easy to do at first.

Better to work with messages, which although not perfect, are a great way to get used to the idea of remote access and execution.

Alternative: Look for a different solution ;). Usually there is more then one. Sometimes they are not obvious especially if you force your mind to look into a single corner only.

create inter-object logic brick connections.

As I wrote in this is a situation, when you already have a strong dependency.

Alternatives:

  • Object A can place the information in a property of its own and object B reads this property (“agreed protocol”) [dependency object B-> object A) - object A can sends a notification message to force object b to check the property

  • Object A can place the information in a property of object B and object B reads this property [dependency object A-> object B). No notification required as object B can sense a property change

  • Object A sends a message to object B only with the data. (This requires either only object B is listing to the message subject or the message is directed to object B only)

  • Object A stores the data in a agreed storage (e.g. object C) and object B reads from there. To force object B to read the data, object A can send a notification message (here it does not really matter if other s get the same message).

i want see if someone have a better solution .

in this blen this blend the main object(crux) grab the reference of the sensor of the children and read it “as a piece of itself”

a better solution will be that the sensor send a message to the parent , but with actual message system is impossible.
(since a sensor launc a message to ALL crux!)

maybe what say agoose is less invasive ?
but what mean make a database?

if someone has a better solution please post a blend with the “implementation” :yes:

PS:see right now the reply of Monster, now read…

Attachments

intrusiveReaderOfSensors.blend (87.7 KB)

Alternatives:

  • Object A can place the information in a property of its own and object B reads this property (“agreed protocol”) [dependency object B-> object A) - object A can sends a notification message to force object b to check the property

not seem different to read the sensor.
after all B “read” A
just rather than a property read a sensor, but is ever “read”, or not :rolleyes: ?

  • Object A can place the information in a property of object B and object B reads this property [dependency object A-> object B). No notification required as object B can sense a property change

this is instead write , seem a more “invasive”
EDIT: this really is not bad if is used ever a specific property(a sort of “protocol”)

  • Object A sends a message to object B only with the data. (This requires either only object B is listing to the message subject or the message is directed to object B only)

and this will be the better solution but not possible

  • Object A stores the data in a agreed storage (e.g. object C) and object B reads from there. To force object B to read the data, object A can send a notification message (here it does not really matter if other s get the same message).

if is a tird (3°) gameObject not see the difference , some obj write on some other object, and some other have to read some other object, seem a “multiplication of dependences”

unless that C is “global” … a global manager of messages …

It is functionally identical. But it means that you move as much code away from BGE API and so it becomes easier to manage. It’s also good practice as typically Python controllers should deal only with the state of their logic bricks.

I have some more questions,I ll type them here.

1)On my way to clear all the variables I faced this problem:
My player won’t move.I did small changes(I hope) from the .blend file in #1 post.
I dropped some print functions to see if there is a problem somewhere,and in lines 21/24/27/30/31 the cont.actuators[“move”].X[X] “variables” did not save the inputs I gave them.I checked the KX_objectActuator,and I think it should work.What am I doing wrong? The blend file is the same as #1,just paste the new code (without the lines I marked).Unless the mistake is obvious and you can point it out to me.

2)This script keeps running from start till the end all the time I am in “P-gameplay” mode?
So do I need to keep the lines:
cont.actuators[“move”].dLoc = [0.0, 0.0, 0.0]
cont.actuators[“move”].dRot = [0.0, 0.0, 0.0]
cont.actuators[“move”].linV = [0.0, 0.0, 0.0]
to get them back to 0 when the keys are not pushed?Also I tried without those lines and it seems it understands that if the keys are not pushed make them 0.Is it because of the logic bricks in blender?They have the default values( =0 ).

# Κάνε εισαγωγή την βιβλιοθήκη της bge.
import bge

# Αντιστοιχίζει μεταβλητές σε αισθητήρες,ελεγκτές και ενεργοποιητές..
# Επίσης παίρνει το αντικείμενο στο οποίο είναι αντιστοιχισμένος ο ελεγκτής.
cont = bge.logic.getCurrentController()
obj = cont.owner

# Φτιάχνω μεταβλητές-πινακες για να χρησιμοποιήσω στο όρισμα τιμών.
cont.actuators["move"].dLoc = [0.0, 0.0, 0.0]
cont.actuators["move"].dRot = [0.0, 0.0, 0.0]
cont.actuators["move"].linV = [0.0, 0.0, 0.0]

# Έτσι θα χρησιμοποιήσει τους τοπικούς άξονες.
cont.actuators["move"].useLocalDLoc = True
cont.actuators["move"].useLocalDRot = True
cont.actuators["move"].useLocalLinV = True

# Τι θα κάνει ο παίκτης;
if cont.sensors["w"].positive:
21    cont.actuators["move"].dLoc[1] = 0.05
    
if cont.sensors["s"].positive:
24    cont.actuators["move"].dLoc[1] = -0.05
    
if cont.sensors["a"].positive:
27    cont.actuators["move"].dRot[2] = 0.05
    
if cont.sensors["d"].positive:
30    cont.actuators["move"].dRot[2] = -0.05

if cont.sensors["spacebar"].positive and cont.sensors["land"].status == 2:
31    cont.actuators["move"].linV[2] = 5
 
 # Ενεργοποιεί τον ενεργοποιητή(δεν παίζει να είναι πλεονασμός :P).
cont.activate(cont.actuators["move"])

The comments are in greek,just for me.

Just found the solution to my problem.Gonna leave it here for future similar questions.

1)It seems that you can not change the value of 1 element of the list but you must change the whole list.
On the other hand you can read 1 element of the list with no problem.

So when I changed
cont.actuators[“move”].dLoc[1] = 0.05
with
cont.actuators[“move”].dLoc = (cont.actuators[“move”].dLoc[0], 0.05, cont.actuators[“move”].dLoc[2])

everything was back to good.

2)You need those lines,else the character won’t stop moving as soon as you give it motion.So i guess the script runs everytime a sensor changes in the background.

i agree, but “spaghetti bricks” here worse of 50 loops nested :smiley:

maybe a solution acceptable is that the sensors(children) write on a property of the “main object”.
since the task of the children is pretty simple he can also make some check before than write:


if own.sensors[0].positive:
  if own.parent:
    if "children_X_sensor" in own.parent:
      own.parent["children_X_sensor"] = True
else:
  if own.parent:
    if "children_X_sensor" in own.parent:
      own.parent["children_X_sensor"] = False

maybe add some print also , if there some error

and at the same time the parent(that usually has instead tasks more complex)
can read just its property


    if own["children_X_sensor"]: doSomething() #is supposed that the property exist..

a bit of dependence still but is more manageable…

-BUT-
the real solution is different

these tasks that cannot be function specific , should be solved with a generic (…generic but that work)
system of messages.

sendMessage() should be the “main tool to solve problems generics”

final usage, and solution at this problem
#sensor script


if sens.positive: #check ITS sensor and send message to the parent
  own.sendMessageTo(own.parent, subject="sensor children", body="positive", sender=None)

there just one dependence:
“own.parent”
eventually easy to check

if one want send message at all objects still perfectly doable:


for i in scene.objects:
  own.sendMessageTo(i, subject="sensor children", body="positive", sender=None)

no restrictions , just a upgrade

what you think? you are a developer :wink:
sendMessage() can still the same .

need own.sendMessageTo() , and own.readMessages() :wink: