Strings in Python 3?

I am working on a simple hint dialogue where the player would click on an object, which would send a message with a common subject, but an object-specific body text, to the hint text. This makes it so I don’t need more than one text object. Here is the code:


import bge
cont = bge.logic.getCurrentController()
pC = cont.actuators["propChange"]
mess = cont.sensors["mess"]
#Properties
pink = "The box looks like it is pink"
blue = "The text is an overlay"
yellow = "Animations are optional"
red = "The box appears to be red"
green = "The text is customizable"


def main():
    if mess.positive:
        typeSent = mess.bodies[0]
        if typeSent=="red":
            pC.value = red
            cont.activate(pC)
        if typeSent=="green":
            pC.value = green
            cont.activate(pC)
        if typeSent=="yellow":
            pC.value = yellow
            cont.activate(pC)
        if typeSent=="blue":
            pC.value = blue
            cont.activate(pC)
        if typeSent=="pink":
            pC.value = pink
            cont.activate(pC)
        else:
            pass


The message interprets okay, but when it activates the string I get this on my text object:
[[The not found…]]
It’s saying that it can’t find the variable that I’m pointing to. I’m not using a variable, it is a text string. What am I doing wrong?

UPDATE: It’s not Python, it’s blender. Using print(pink) works fine. It also works when I put a number instead of text. What is the deal here?

Have you tried printing out “mess.bodies[0]” to see if it matches any of your if statements?

-edit-
I think I misunderstood before.

Try setting the property like this:


own = cont.owner
own.text = green

It matches each of my statements, that I’m sure of. The text object will change to the correct string, but the script will not read the string correctly.

Any reason you can’t just get the text object and then set its text property?


text_obj = scene.objects["Text"]
text_obj["Text"] = "Whatever string you want here"

I think it’s more efficient to do it my way, but I will try it anyway. BRB :wink:

I feel like an idiot. I added these lines to my code:
scene = bge.logic.getCurrentScene
text_obj= scene.objects[“hint text”]

Then when the message is received an interpreted and so on, this was added:
text-obj[“Text”]=“The box appears to be red”

It spits out that the scene variable has no attribute ‘objects’. Groans loudly

Just hit F5 and saw TheDave’s edit and I got it working now! Thanks!

Forgot the parentheses(). scene = bge.logic.getCurrentScene()

The Property Actuator interprets the value field. This way you can use property names and operators too (e.g. “a + b + 3”).
To tell the interpreter you mean a string constant you need to surround the string with “”.
Example:


myPropertyActuator.value = ' "this " + "is " + "a " + "string" '

in your case:


propertyChange.value = '"' + red + '"'

In the above example I see no reason to avoid writing directly into the property.

On a side note, own[‘Text’] or own[“Text”] are current usage I think. Don’t forget the capital letter if you’re setting a text object to display text.

That’s for font maps. OP is using text objects which don’t use visible “Properties” as you know them in the Blender interface.

Both methods are working with KX_FontObjects.

The property access makes the code compatible with KX_FontObject and bitmap text.

anyway if you had write all code should not work correctly

if is a script mode lack “main()” at the end.
in this caser should make nothing

if is module mode (i suppose) it should work correctly only one time.

with module mode the code should be written in this way:


import bge

#Properties
pink = "The box looks like it is pink"
blue = "The text is an overlay"
yellow = "Animations are optional"
red = "The box appears to be red"
green = "The text is customizable"


def main(cont): #<- the "hook updated"
    pC = cont.actuators["propChange"]
    mess = cont.sensors["mess"]
    if mess.positive:
        typeSent = mess.bodies[0]
        if typeSent=="red":
            pC.value = red
            cont.activate(pC)
        if typeSent=="green":
            pC.value = green
            cont.activate(pC)
        if typeSent=="yellow":
            pC.value = yellow
            cont.activate(pC)
        if typeSent=="blue":
            pC.value = blue
            cont.activate(pC)
        if typeSent=="pink":
            pC.value = pink
            cont.activate(pC)
        else:
            pass


with script mode in this way:



import bge
cont = bge.logic.getCurrentController()
pC = cont.actuators["propChange"]
mess = cont.sensors["mess"]
#Properties
pink = "The box looks like it is pink"
blue = "The text is an overlay"
yellow = "Animations are optional"
red = "The box appears to be red"
green = "The text is customizable"


def main():
    if mess.positive:
        typeSent = mess.bodies[0]
        if typeSent=="red":
            pC.value = red
            cont.activate(pC)
        if typeSent=="green":
            pC.value = green
            cont.activate(pC)
        if typeSent=="yellow":
            pC.value = yellow
            cont.activate(pC)
        if typeSent=="blue":
            pC.value = blue
            cont.activate(pC)
        if typeSent=="pink":
            pC.value = pink
            cont.activate(pC)
        else:
            pass

main() #<<< need explicit call


strange noone had noticed

what about this?




import bge




DATA =  {
"pink":     "The box looks like it is pink",
"blue":     "The text is an overlay",
"yellow":   "Animations are optional",
"red":      "The box appears to be red",
"green":    "The text is customizable",
        }


def main(cont):
    
    mess = cont.sensors["mess"]
    if mess.positive:
        typeSent = mess.bodies[0]
        if typeSent in DATA:
            pC = cont.actuators["propChange"]
            pC.value = DATA[typeSent]
            cont.activate(pC)



(module mode) :wink:

Thanks, I’ve always used a dictionary call before, rather than a class property.

A little Off topic, I’ve often wondered why BGE swapped from using class type properties to using dictionary type ones… it used to be own.health but became own[‘health’].

In my own projects I’ve noticed a few times when the second one would be better, but I just wondered.

I never saw an explanation of this decision. And yes it felt really strange at the beginning. But if you look at this it was a natural decision as it prevented the usage of property style attributes (KX_GameObject.worldPosition vs. KX_GameObject.getWorldPosition()).

Additional benefits of dictionary style access:

  • property names can contain spaces, numbers special characters
  • no naming conflicts (e.g. .state vs [“state”])
  • dynamic property name processing (e.g. “myprop” + str(index))
  • getting a list of all current property names

The attribute KX_FontObject.text is a natural part of this object (it already existed in the Blender world). The additional “Text” BGE property was introduced to support the GUI (logic bricks) which is based on BGE properties.