IndexError: list index out of range

I have run into an odd error going through some code…

“IndexError: list index out of range”

Now I have seen the common problem for this error is the object or property doesn’t exist.
But I have taken the exact same method used on a working script to detect invisible boxes to detect this characters collision mesh and the mesh is there and the name matches the code exactly ‘SolliusCol’… so if it’s saying that it doesn’t exist I don’t know why…

Only differences between this and the working script is that the working one has 6 objects in it’s “path”, their “sensor” type, and the SolliusCol mesh moves in the game engine.

Current Code…

import bge

cont = bge.logic.getCurrentController()

Flee = cont.actuators['Flee']

TrackPamr = cont.actuators['TrackPamr']

path = ['SolliusCol']
speed = [0,0,0]
point = cont.owner['point']
dir = cont.owner['dir']

if point+1 == len(path):
   dir = -1
elif  point == 0:
   dir = 1

if cont.owner.getDistanceTo(TrackPamr.object) <= 150:
   point += dir
else:
   speed[1] = 50
   
TrackPamr.object = path[point]
cont.activate(TrackPamr)
cont.owner['point'] = point
cont.owner['dir'] = dir
Flee.linV = speed
Flee.useLocalLinV = 1
cont.activate(Flee)

The error message also gives you line number which helps you pinpoint the cause.


path = ['SolliusCol']

TrackPamr.object = path[point]

This is what gives you the error. The first line makes a list of one entry, a string “SolliusCol”. The second line tries to read the n:th entry on that list where n is controller by integer called “point”. N is probably something bigger than 0 which would be the first entry so the list is not long enough. Thus why the error.

Yup thats the cause. Hmm… I have seen something like that as well… but where does it specify what N is? If it’s based of the “point” property it looks like it should start at 0… math just seems to show that it should go +1 along the path until it repeats… I don’t see a max or min number of “path” objects it should search for… Seems like it would search for SolliusCol then either run to it or run away repeating until it’s out of distance.

The node loop searches for the next node once he reaches a target but then it repeats… so maybe it’s looking for the next object rather then just repeating?

Anyway… any idea how to fix it? I just want to have it use that one mesh as it’s target object to flee from or attack when I’m in the distance of the Near sensor. Guessing my problem is with the math here:

if point+1 == len(path):
   dir = -1
elif  point == 0:
   dir = 1

I’ll look into it some more after dinner.

Edit: haven’t got the code working… but I see I have the option of just making an and controller connected to the near sensor and actuators, changing the motion to 180zrot and .7yloc. Then connecting a random sensor to my pathfinding script/actuators the AI goes back on track after leaving the near sensors distance. (all in state 4)

Pythons error messages usually show what the problem is. I found out that I simply interpreted them to much which causes confusion.

In your case your index to a list is simpy incorrect.

The code snippet you show in post #3 is not the cause as “dir” is no index to a list.

Try following:
A) name all variables that should contain an index in a way that you can recognize it as that e.g. fooIndex
B) add a print statement before the line with the error that you can see how the index grows e.g. print(“fooIndex:”, fooIndex)
C) think about why the variable gets out of bounds ( usually because a missing or incorrect relationship to the list length)
D) correct the code
E) remove the print statement

“name all variables that should contain an index” what do you mean by this?

“path” is my only variable that contains an index?

“point” is a variable to the index I believe…

if you mean all the variables that I want in my index [ex: ‘SolliusCol’] I know they are all labeled correctly…

Ok now how about this one.

I tried removing that piece of code from post #3 along with TrackPamr.object = path[point] from my “FleeAI” script and…

The object originally starts by following python script “PamrAI” (pathfinding script moving along path or [‘nodes1-6’]). Now when I go towards the AI object and activate the Near sensor it will switch to “FleeAI” script which now seems to work detecting and moving towards/or away from my character depending on the speed variable. But now at the same time it’s telling me that same “IndexError” is happening for the “PamrAI” script line 24 ‘track.object = path[point]’. The same script that works just fine when I start the game up has this error, so now when I move away from the AI he doesn’t go back to his path. Same code that has been working for the last 2 hours while I played with the “and” controller/“movement” actuator instead of the “FleeAI” script… no problems going right back to the “PamrAI” script and jumping right back on the “path” track for over an hour then boop magically has an Index error.

Adding those lines of code back onto “FleeAI” script of course brings back the error there as well.

I’ll try that print before the error line but this just seems weird…

You know this issue is not all that hard. You made that script. What are you trying to do with these 2 lines?

 path = ['SolliusCol']
TrackPamr.object = path[point]

Because the first line there makes the “path” a list that from my understanding should contain all the waypoints, actually just contains only 1 piece of text saying “SolliusCol” and that is a piece of text, not a reference to the game object.

Now if you want to make the SolliusCol the point you flee from, you don’t need to worry about the path or point. Just have a script turn away from SolliusCol and move forward. I could try to modify what you have but here’s an example of how to make it from scratch without logic brick actuators:


#flee.py
#untested
import bge

#here you define the object script is linked to and the scene the usual way
cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()

#here you define threat object aka solliuscol
threat = scene.objects["SolliusCol"]

#here you get a vector from solliuscol to your own location, replaces trackto actuator
escapedir = threat.getVectTo(cont.own)
#here you turn to face the same direction as that vector, replaces trackto actuator
cont.own.alignAxisToVect(escapedir[1],1,1.0)

#here you move forward in local, replaces movement actuator
cont.own.applyMovement([0,50,0], True)

I’m not an expert on your entire setup but if you link that script to the near sensor you have for detecting solliuscol it should move away.

Ok, I tried again to understand your script and setup.

How would this work for a flee script in your setup:


import bge

cont = bge.logic.getCurrentController()
scene= bge.logic.getCurrentScene()

Flee = cont.actuators['Flee']

TrackPamr = cont.actuators['TrackPamr']

speed = [0,50,0]
dir = cont.owner['dir']

#if it's going to wrong direction uncomment the next line
#dir *= -1

#this actuator seems to actually take a gameobject and not an object name?
TrackPamr.object = scene.objects["SolliusCol"]
cont.activate(TrackPamr)
cont.owner['dir'] = dir
Flee.linV = speed
Flee.useLocalLinV = 1
cont.activate(Flee)

I meant, the name should reflect what the variable contains or should contain (the purpose).

“path” - indicates it contains some sort of Path. As it is not further explained it can be assumed there is only one path ;).
“point” - indicates some sort of … point. The open question is: what sort of point?

together with the context:

path = ['SolliusCol']

-> this shows it is a list of strings.

point = cont.owner['point']
...
point+1
...
point += dir
...
path[point]

this shows that point must be a number and is used as index into a list. As this is not obvious (you need to analyze the code first) it would be better to name for example “pointIndex”. This would allow such code:

point = path[pointIndex]

…assuming the path is a list of points. But I guess it is more or less a list of object names (representing the position to go to)…

targetName = path[pointIndex]

None of that will fix you problem, but it will help you understanding what is going on and why.

Obviously your path has exactly one item. This means the only valid index is 0.
As you get an IndexError your index is not 0. Try to find out under what circumstances this happens.
(Hint: find ALL circumstances. )

I assumed that it should be but I’m very new to scripting of any kind, just some basic python bge tutorials and VisBasic way back in school. I didn’t make this script exactly it was from a tutorial I referenced, I just plugged in the logic bricks and fixed errors found on the console for the original. Then trying to decipher the bits as I go along I tried altering it for another purpose.

path = ['SolliusCol'] 
TrackPamr.object = path[point]

Was to use the same path script that identified the target node objects to identify my new target object “SolliusCol”
“TrackPamr.object = path[point]” purpose was a little unclear to me, it seemed to be there to set the track object, maybe also to alter it along the path being effected by [point] in some way. As I read on to Monsters post I might get a better idea of whats going on here.

#here you define threat object aka solliuscol
threat = scene.objects["SolliusCol"]

I have been looking for something exactly like this to replace the path thank you very much.

#here you get a vector from solliuscol to your own location, replaces trackto actuator
escapedir = threat.getVectTo(cont.own)
#here you turn to face the same direction as that vector, replaces trackto actuator
cont.own.alignAxisToVect(escapedir[1],1,1.0)

#here you move forward in local, replaces movement actuator
cont.own.applyMovement([0,50,0], True)

This is all very interesting too.

Basically if you’re going to do python anyway, those couple of lines eliminate the need to pass all the information to actuators and activate them etc… might consider it as you get more familiar with python.

But if you just fix the path on the line “TrackPamr.object = path[point]” to refer to the SolliusCol gameobject like this "TrackPamr.object = scene.objects[“SolliusCol”] it probably works (although I didn’t check what the whole “dir” issue was) and you can move on with developing the script to suit your purpose :slight_smile:


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

And for this…
That script seems to work making him flee but he doesn’t stop outside of the Near sensors Reset distance for some reason…
Do you know why this might be? or have another option to correct his problem?

Thanks again for taking the time to teach me a bit.
Going to need some rest now I’ll have to get to Monsters post and more fiddling around in the morning before work.


Flee = cont.actuators['Flee']

Flee.linV = speed
Flee.useLocalLinV = 1
cont.activate(Flee)

Probably because the motion actuator you are connecting to will remain active until it’s told to deactivate.
So you need another script to deactivate the actuator or set the actuator values such as speed and dir right when the flee script is not being run.

Or edit the flee script so that it does another distance check and only flees if the distance is something a bit smaller than what you have in your near sensor that determines when the script is run.

So it would be like: (100 and 80 are just examples, I don’t know what distances you use)

If distance > 100 -> don’t run the flee script.
If distance < 100 -> run the flee script

the flee script always checks when it’s run:
if distance > 80 set motion actuator to no movement
if distance < 80 do everything you have working already

@monster

Thank you for the explanations…
I hadn’t really thought of changing… or didn’t feel safe changing those variables until I was positive of how everything was working in the code. Can see how that can help remind me and show others the variables and their functions though.

path = ['SolliusCol']

Just out of curiosity… What is it that makes this a list of strings?

x = ['y','z','a'] or x = ['']

this a formula to make a list of strings out of objects in the scene? What if I wanted properties or activators in a string list like this?

Thats what I was thinking point was for… Just hard for me to tell what number it starts at and what triggers causes it to add up, go down, or repeat.

Path is a list of object names to go to…
Aww the circumstances are what I was trying to pin point.
Looks like I had a pretty good grasp on my variables but thanks again for the explanations

@Kheetor

Alright this is something I came up with real quick.

import bge
import math

cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()

SolCol = scene.objects["SolliusCol"]

PCol = scene.objects["PamrCol"]

Flee = cont.actuators['Flee']

TrackPamr = cont.actuators['TrackPamr']

SolLoc = SolCol.position

PLoc = PCol.position

dist = math.sqrt( (SolLoc*2 - SolLoc*1)**2 + (PLoc*2 - PLoc*1)**2 )

speed = [0,-50,0]
dir = cont.owner['dir']

#dir *= +1

TrackPamr.object = SolCol
cont.activate(TrackPamr)
cont.owner['dir'] = dir
Flee.linV = speed
Flee.useLocalLinV = 1
if dist &lt;= 100: 
    cont.activate(Flee) 
else: 
    sys.exit

Currently getting an error with the distance formula

TypeError:unsupported operand type<s> for ** or pow<>: ‘Vector’ and ‘int’

Now I assume that means there are variables that are not understood in the formula… probably SolLoc/PLoc…

Am I not using the right function to pull up the objects positions?
Am I correct in looking for the objects position to get the distance?
Is the distance formula incorrect?

Edit: woot found a tut: http://www.youtube.com/watch?v=5MH4cDe682M

import bge
import math
scene = bge.logic.getCurrentScene

cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()

PCol = scene.objects["PamrCol"]
SolCol = scene.objects["SolliusCol"]

distance = PCol.getDistanceTo(SolCol)

print(distance)

Flee = cont.actuators['Flee']

TrackPamr = cont.actuators['TrackPamr']

SolLoc = SolCol.position

PLoc = PCol.position

speed = [0,-50,0]
dir = cont.owner['dir']

#dir *= +1

TrackPamr.object = SolCol
cont.activate(TrackPamr)
cont.owner['dir'] = dir
Flee.linV = speed
Flee.useLocalLinV = 1
if distance &lt;= 100: 
    cont.activate(Flee) 
else: 
    sys.exit

No errors here but

else:
    sys.exit

Doesn’t seem to be working out. When the objects reach a certain “distance” the script will end. But once again my random sensor applied to reactivating my state one script doesn’t get triggered and the object ends up just sitting there or sometimes (about 2/10 times) endlessly runs.

It is a list of strings as you fill the list with strings. It is just that simple ;).
No it is not a list of strings out of (game) objects in the scene. ‘y’ and Co. Are strings. They might match the name of game objects but this relationship is not established by code.

This is a " know how" situation :):

Get the actuators ( or whatever object) and add them to the list.


first = scene.objects[0]
cube = scene.objects["Cube"]
target = trackToActuator.object

myGameObjects = [first, cube, target]

As they often come as a collection already, all you need to do is to filter this collection by your needs. E.g.


...
   myGameObjects = findObjectsByProperty(scene.objects, "node")
...
def findObjectsByProperty(gameObjects, propertyName):
   return [gameObject for gameObject in gameObjects
            if propertyName in gameObject]

I hope it helps

Basically this makes it a list
and this makes what you put inside a string ’ '.

For example:
a list of integers:


 intList = [7, 8, 9, 11]
sum = intList[0] + intList[2]
print(sum)

The script understands these as numbers you can use to count, for example sum = intList[0] + intList[2] would mean sum = 16

a list of strings:


strList = ["7","8","9","11"]
sum = intList[0] + intList[2]
print(sum)

Strings aren’t understood as numbers, rather just text, in this case individual characters. Sum = “79” which is formed by simply putting the strings together. The result will also be a string that you can’t use for counting.

Note that this means list of strings isn’t good for much. A string is just a piece of text and you can’t use it to refer to objects directly.

dist = math.sqrt( (SolLoc2 - SolLoc1)**2 + (PLoc2 - PLoc1)**2 )

 

It’s good you know the math behind finding distance but you don’t need to make things the hard way. In BGE there is functions like getDistanceTo() and getVectTo() and many other making everyday operations like this easier. You should perhaps skim through this list for an idea what kind of functions you can do with GameObjects: http://www.blender.org/documentation/blender_python_api_2_68a_release/bge.types.KX_GameObject.html


dist = PCol.getDistanceTo(SolCol)

TypeError:unsupported operand type<s> for ** or pow<>: ‘Vector’ and ‘int’

Type error means you are trying to input wrong type of arguments to functions. The error you get is because of the distance formula you are doing. SolLoc = SolCol.position which is a vector which means it is basically a list of float numbers. It looks like [1.0, 0.0, 0.0]. So while you can multiply it using *2, you can’t add it to power of 2. Vectors are also little bit different from standard list of 3 float numbers but there’s no need to go in-depth about that here.

What I think you should do is use print() more. Print() prints whatever you want during the script to the console. If you’re not sure about what causes the error it is good way to print the variables you are using just before the line that causes the error. Since there is no breakpoint and variable table debugging in BGE (AFAIK?) this is one of the basic ways of debugging you can always do.

Try adding


print(SolLoc)
print(PLoc)

Just before the “dist = …” line to see what I mean.