Enemy wander scipt issues

hay guys! in need of a little help I am, hhhmmmmm.
so I am trying to set up a script to make an enemy wander around semi randomly. I have an empty with the property ‘empt’ as a child of the enemy, and a cube on an inactive layer. there is also a nav mesh with the property ‘nav’.
the idea is to have the script get the enemies location, adjust the x and y coordinates by up to 4units. shift the z up a bit, and use these new coordinates as the origin for a raycast.

the raycasts down to see if it hits an object with the ‘nav’ property (the navmesh) and if so, returns hit location. the child empty is placed at that location, and a raycast is cast from about the point of the enemies eyes to the empty to see if it with its ‘empt’ property is the 1st thing hit. if so, the enemy has sight of that location and then sets an added copy of that cube from the other layer, to the location of the empty. the cube is set as the target for a steering actuator, and the enemy ‘wanders’ to it.

my code looks as fallows:

import bge
import logic
import mathutils
import vector
import random

cont = bge.logic.getCurrentController()
own = cont.owner
pos = vector(own.worldPosition)
node = scene.objectsInactive[‘Cube’]
targ = scene.addobject(node,pos)
target = none
targetfound = false

#get the enemies child empty for use in target checking
for ob in own.children
if ‘empt’ in obj: child = obj

myx = pos[0]
myy = pos[1]
myz = pos[2]

eyez = myz + 0.2

'# wander destination finding module

while targetfound == false

'# think I made a mistake here, this setup might cause coordinates that are not within 4 of the enemy right?
testx = random.randint(0,4)
testy = random.randint(0,4)
testz = myz + 2

inver = random.randint(0,1)
if inver == 0
testx += myx
else
testx += -myx

inver = random.randint(0,1)
if inver == 0
testy += myy
else
testy += -myy

reypos = vector(testx,testy,testz)

newz = myz - 1
dest = (testx,testy,newz)

obhit, hitloc, fase = ray_cast(dest, reypos, 3, nav, 0, 1)

if obhit != none
child.location(hitloc)
else
continue

reypos = (myx,myy,eyez)
obhit, targloc, fase = ray_cast(hitloc, reypos, 5, empt)

if obhit == none
continue
else
targ.location(targloc)
targetfound = true

cont.actuators[‘wand’].target = targ

can anyone tell me what I’m doing wrong? I think that when the cube from the inactive layer is made the value of a variable at the top of the script, that the cube would be added to the active layer at that point. that or the cube would be added whenever the variable is called? but the cube does not appear and the enemy never moves from where he starts. I’m not sure what part isn’t working. thank you in advance. :slight_smile:

good habits : comment your code (even if it seems unecessary) and test it with the console mode open.
You didn’t tell us what is your bug/problem.

you are welcome to look at this or take whats useful, it’s and old test i made to test roaming monsters.

monster-ai-test.blend (683.5 KB)

1 Like

thanks, I actually removed several comments because they were for bits of code I planned to add in places later on that I realized weren’t necessary. also I’ve no clue how to test this in the console.
I haven’t the slightest idea what the bug/problem is, but I press play and nothing happens.

I’m still a newb to coding in blender and python, and in games. so there are a bunch of new and unfamiliar things I’m trying to learn and my programming is rusty. I use to just code in eclipse or visual studio, and if something didn’t work after hitting run it’d tell me what line and some vague description of the error. running scripts in blender doesn’t seem to do that. in the console you can’t enter more than one line at once right?

I’ll look at the example here in a few and see what I can gleam from it.

it’s a nice system, but I was hoping to have my enemies wandering around without pre-set way points. I feel when AI travel between way points it seems too mechanical and systematic. it’s easy for players to see where the way points are as the AI moves around. even if the enemy or npc randomly selects way points in their vicinity, the player can memorize way point locations and predict where AI are going based on location and direction.

it works well for guards and other patrolling units, because then having per-determined travels points is natural and expected. but for monsters and animals that are suppose to just be roaming about, way points seem to robotic.
but I thank you for the example and I’m sure I can use it at some point.

so how does one test a script in the blender console? I’ve looked over that script time and again, but I’m not sure why it isn’t working. maybe an error from the console would help me solve it.

If you want stuff calculated behind the scenes & shown use this :arrow_down:

print()

facepalm how did i forget something so simple? thank you.

1 Like

Glad I could help.

i[^.^]i

1 Like

alright, so I extended the text editor window and found the “run script” button, which gave me errors I could use to solve some of the scripts issues. mostly syntax errors for not having “:” at the end of the while, if, and else statements.
but after fixing all that it just says “error” and “look at console” but the console hasn’t updated or changed at all. how do I run my script in the console? I have added several “print” commands on various lines to help me find where the problems were occurring, but haven’t been able to make use of them because I don’t know what to type into the console to run the script from there.

you need to put a python brick on an object connected to an always sensor. then run the gane.

theres a “toggle console” in the window menu at the top of the ui, next to file. or just run the the game in standalone

1 Like

I think you are having typo errors :wink:

Try this on any object with a simple python controller set to script :arrow_down:

import bge

def main():

  print("THIS IS A PRINT FUNCTION")

main()
1 Like

it wil for bge code always give errors, that button is there to test addons or bpy script created for blender.
so ignore that button.

instead go to window -> toggle system console.
this will open another window that hold errors that you may get/have.

the print() option will also output to that window.

put logic bricks on an object:
always -> python -> scriptname

or using module mode
always -> python -> scriptname.function you want to run. and set the script (in the python brick) to mudule. and don’t forget to let your script end with .py, so scriptname.py

now simply start the engine, by pressing start/run in the render panel, best is to use the standalone button

1 Like

thank you @Cotaks , @RandomPerson , and @Daedalus_MDW .
I have had an always sensor connected to a python controller with the script in it, so the script was getting run whenever I’d start the game. I just had no idea how to see the console output of the script. till now I’ve been referring to splitting a blender window and setting it to python console. that console wasn’t showing anything and I thought everyone was saying to use that.

now that I’m aware of the “toggle console” option, I’ve been able to see the print statements and more of the errors. I’ve fixed most of them, down to the “obhit, hitloc, fase = ray_cast(dest, reypos, 3, nav, 0, 1)” part. I’ve opened another thread a while back about understanding the ray_cast function, and I’ve been refferencing that thread and other sources to try and work out the problem, with no luck.

i thought the problem with this line is that the default ray_cast is object.ray_cast, which I guess is used only by mesh objects? where as this script is being used by the enemies armature as it parents the mesh. but I’ve saved the child mesh in variable ‘mesh’, and used mesh.ray_cast, with no luck.
the error is as fallows:
"attribute error: ‘kx_gameobject’ object has no attribute ‘ray_cast’ "

1 Like

i think you are looking for

hit = own.rayCast( start.worldPosition , end.worldPosition, 0.0, “”, 1, 0, 0)

that did help alot, thanks :slight_smile:
that solved the console error I was getting, and after some time I managed to find that the reason the ray cast wasn’t finding the nav mesh was because nav meshes are non-collision objects, which ray casts don’t work with. (which also means the child empty couldn’t be used for ray casting either, for line of sight checking. more on that inna few.)

I solved this issue by making a copy of the nav mesh, set it to static and ghost (because ray casts do work with ghosts) and then the 1st ray cast in the script could find it and set the cube copy (because the empty is no good with ray casts.) where the ray hit.

the cube is intended to be used as a target for a steering actuator (because a vector wouldn’t work right?)
and I figured I could use it as the target for a line of sight check using a ray cast. after over an hour of tinkering I can only conclude that an object that has been copied in from an inactive layer cannot be detected by ray casts. is this correct or am I doing something wrong?

own = cont.owner
node = scene.objectsInactive[‘Cube’]
targ = scene.addObject(node,own)

'#spot is destination vector where the 1st raycast determined that the nav mesh is present there, but is shifted up on the z slightly to avoid having the cube in the ground or blocked by the nav meshes static ghost copy. reypos is the origin vector, ‘tar’ is a property of the cube.

targ.worldPosition = spot

obhit, hitloc, fase = own.rayCast(spot, reypos, 5, ‘tar’)

I have an “if obhit == None:” setup with print statements so I’ll know if the ray reaches/detects the cube or not, and the cube is visible as the game and script are running so IK where the cube is and if it should hit or not, but it fails every time.

I should also note that the furthest random coordinate from the enemy that the script is now set to generate (found and error in my original coordinate assignment setup), is +/- 3x, and +/- 3y. so where ever the cube is placed should be within 5 units from the enemy. but even when the cube is clearly within 1 or 2 spaces from the enemy on any side, the ray cast fails to find the cube.

and again guys, I really appreciate all the help and support you all have given me, thank you :slight_smile:

evaluations are if x == y:

https://docs.python.org/3/library/stdtypes.html#comparisons

correct, sorry. I was alittle lazy when writing it in my last post, that was my bad.

it seems copies are not detected by ray casts. I gave the enemy a mesh object (ico sphere) and made that object invisible and a ghost, and that works with raycast, and then used the cube for destination navigation. finally, then enemy does now wander as intended. :smiley:

thank you all vary much for all the help and advice you have provided. and for anyone interested. my final script looks as fallows:

import bge
import mathutils
from mathutils import Vector
import random

print(“imports done”)

scene = bge.logic.getCurrentScene()
cont = bge.logic.getCurrentController()
own = cont.owner
pos = Vector(own.worldPosition)

print(“pos set”)

node = scene.objectsInactive[‘Cube’]

print(“node set”)

targ = scene.addObject(node,own)

print(“targ set”)

target = None
targetfound = False

for ob in own.children:
. if ‘kid’ in ob:
. . child = ob

print(child)

myx = pos[0]
myy = pos[1]
myz = pos[2]

print(myz)

eyez = myz + 0.4

'# wander destination finding module
print(“looking for a nice destination…”)

while targetfound == False:

. testx = random.randint(0,4)
. testy = random.randint(0,4)
. testz = myz + 2

. inver = random.randint(0,1)
. if inver == 0:
. . testx = myx + testx
. else:
. . testx = myx - testx

. inver = random.randint(0,1)
. if inver == 0:
. . testy = myy + testy
. else:
. . testy = myy - testy

. reypos = Vector((testx,testy,testz))

. print(reypos)

. newz = myz - 1.5
. dest = (testx,testy,newz)

. print(“checking a spot”)

. obhit, hitloc, fase = own.rayCast(dest, reypos, 3, ‘nav’, 0, 1)

. print("1st hitloc = ", hitloc)

. if obhit != None:
. . print(“spot found, checking availibility”)
. . x = hitloc[0]
. . y = hitloc[1]
. . z = hitloc[2] + 0.15
. . spot = Vector((x,y,z))
. . child.worldPosition = spot
. else:
. . print(“nothing here, lets try another…”)
. . continue

. reypos = (myx,myy,eyez)

. obhit, hitloc, fase = own.rayCast(spot, reypos, 5, ‘kid’)

. print("2nd hitloc = ", hitloc)

. if obhit == None:
. . print(“no good :(”)
. . continue
. else:
. . print(“prefect! :D”)
. . targ.worldPosition = spot
. . target = targ
. . targetfound = True

cont.actuators[‘wand’].target = target

this is a bit more rough and simple then what I intend for it to eventually be, but this is what I was looking for as a 1st step. sorry for lack of comments in the code.