I am making a game where you track a character to an object for interactions, but I am having a major error. When I go to call for several property values in an object so characters can “Interact” it keeps giving me an error saying that the argument of type ‘NoneType’ is not iterable. Now I sort of understand what this means, but I don’t understand why this occurs. However what baffles me even more is that somehow I know I had previously overcome this obstacle before with a virtually identical setup (Started with a normal cube, built a mesh, added game properties) However one object doesn’t come back as a NoneType, and my new object does. Now they both use the same script, and the same character has been used for testing. As far as I can see, the only difference is the mesh, and the names of the properties. I am not sure how I worked this out before, but if anyone can help, that would be great Thanks.
This code is being used to have units build/destroy houses and resources, as well as display their tools (Axes, pics, whatever) and send it between different states.
If you define a variable that contains hitObject I suggest to use it. You can use the original source but it is confusing when this is mixed together.
resource = sCollisionR.hitObject
...
if sCollisionR.hitObject == None:
#vs
if not resource:
I think this is the reason, why you did not see the situation MarcoIT describes.
Variables with a number suffix are usually a sign of dirty code (obj3). I recommend to think about a better name. According to your code “tools” would be a good name ;).
Further more your code becomes long. I suggest to extract the single code blocks into separate functions.
E.g.
...
sCollisionR = cont.sensors[SCollisionR]
resource = sCollisionR.hitObject
if not resource:
dealWithMissingResource()
elif "Wood" in resource:
dealWithWood(resource)
elif "Collected" in resource:
dealWithCollected(resource)
elif "houseHealth" in resource:
dealWithHouseHealth(resource)
This way you can focus on each single (and small) task
Additionally it enables you to access objects when they are needed (e.g. you do not need any actuator when resource is None.)
What means 0 in property “toolset” or in “steering”? I suggest you define some “constants” with names similar to the brick names. Or even better use a string e.g. “ultimate toolset”. So it is easier to debug.
true , but can be a bit annoyng “regenerate” all dependences.
to avoid this can be used a set of properties (obj[“prop”]) where each property contain a value(usually string) that mean a precise “command”
for the reader that can be the bricks or another gameobject.
advantage , is (should be) a lot flexible .
disadvantage is that the command can be executed in the current frame (if read from python) or the next.
but this is not really a problem if you know it.
(secondly is not “extremely” fast)
def dealWithWood(own, wood):
if wood["Wood"] <= 10:
own["toolset"] = 0 # the message for the children "tools"
own['steering'] = 0 # the message for the bricks (0=deactivate steering, 1=activate steering)
own["STATE"] = "state2" # the message for bricks (if STATE == "state2" -> and -> setState(2))
wood["Wood"] -= own["strength"]
own ["wood"] += own["strength"]
or at least is my more recent experiment as design
Ok, So I fixed my script, however my “House” is still a NoneType. I know my guy is colliding with the object in the game engine, so it’s not that he is colliding with nothing. But I don’t understand why this is still an issue. The code below is what I “fixed” with it, by updating it with Monster’s suggestions. I have two separate objects that have properties I can change and use, but I can’t access these ones. (And it works if I duplicate the objects and recreate the house with the same properties and settings) I don’t know if this is the cause, but the only differences in the meshes is that the House has separated parts, and the others don’t. But I don’t think that would cause that. If someone can tell me what cases other than No Object causes something to be returned as a NoneType object, maybe I can figure out what is going on.
I just assumed it all went into one script, but please do tell me if I am wrong.
Also, the [“Steering”] property is the “block” I am using to control which units are, and are not “Selected”. and the [“Tools”] tell what mesh the character’s tool is supposed to display, i.e. an axe = 1, or nothing = 0.
This might become handy to you. It encapsulates some often used access methods.
bgeUtils.py:
from bge.logic import getCurrentController
def getOwner():
return getCurrentController().owner
def getActuator(actuatorName):
return getCurrentController().actuators[actuatorName]
def activate(actuatorName):
getCurrentController().activate(actuatorName)
def deactivate(actuatorName):
getCurrentController().deactivate(actuatorName)
def allSensorsPositive():
for sensor in getCurrentController().sensors:
if not sensor.positive:
return False
return True
your code would look like this:
...
def takeResource():
if not allSensorsPositive():
return
resource= getActuator(SCollisionR).hitObject
if "Wood" in hitObject:
dealWithWood(resource)
...
def takeWood(wood):
worker = getOwner()
amount = wood["wood"]
chunkSize = worker["strength"]
if amount <= chunkSize:
chunkSize = amount
remaining = amount - chunkSize
wood["Wood"] = remaining
worker["wood"] += chunkSize
if remaining <= 0:
stopTakingWood()
def stopTakingWood():
heldTool = obj.childrenRecursive["tools"]
heldTool["toolset"] = 0
obj['steering'] = 0
activate(AState1)
# I think this is too much unrelated knowledge
# this code should simply notify the worker to stop taking wood
# how to do that - should be somewhere else
# e.g. in state 1
Seeming as I can’t get the attachments on here to work, I am using a link to a website I have seen several people suggest. I have scrapped down the file to what is required to run the actual game (i.e. no extra random meshes and codes)
I have continued to try to look into what exactly causes a nonetype object to occur without much luck. Maybe if you mess with my game you can find a solution. And no, the character is collecting the right ammount of wood because I am using a negative pulse mode inverted on my collision, and that is causing it to collect the right amount.
I can see there are clickable buttons. When I click them I get a house to place and a tree to place. This works pretty fine. But I do not see how the mentioned code fits into this. What do I need to do?