flighting enemy (AI) simple?! custom path following?

HI,

I have an Basic Idea to realize a AI for my Game (a little Drone-demolish-derby) and want that my cpu enemy random follow me and attacks(bumped) me or try to kick me from the arena have try some sort of steering actuator-> not the result I want.

here is a little test code from my experimentation:


from bge import logic

def position(cont):
    own = cont.owner
    scene = logic.getCurrentScene()
    objList = scene.objects
    
    #ray_player = cont.sensors["Ray"]
    steering_act = cont.actuators["Steering"]
    settings = objList["settings_block"]
    player = objList["Player"]
    player_life = player["Life"]
    own_life = own["Life"]
    player_dist = (player.worldPosition - own.worldPosition).magnitude
    print(player_dist)
    obj_enemy = [o for o in scene.objects if "player_ai" in o]
    enemy = obj_enemy
    
    dist = lambda o: (o.worldPosition - own.worldPosition).magnitude
    object_distance = [(id(o), dist(o)) for o in enemy]
    object_distance.sort(key=lambda t: t[1])
    closest = object_distance[1][0]
    enemy_id = closest
    enemy_life = objList.from_id(enemy_id)["Life"]
    #print(object_distance[1], objList.from_id(enemy_id)["Life"])
    
    steering_act.navmesh = objList["Navmesh"]
    steering_act.behavior = logic.KX_STEERING_PATHFOLLOWING
    steering_act.pathUpdatePeriod = 0
    steering_act.velocity = 3.0
    steering_act.acceleration = 3.0
    steering_act.turnspeed = 120.0
    steering_act.distance = 1.0
    steering_act.selfterminated = False
    steering_act.enableVisualization = True
    steering_act.target = player
        
    #if settings["all_cpu_against_player"] == False:
    #    if enemy_life < player_life:
    #        attack(steering_act, player)
    #        steering_act.target = player
    #    else:
    #        attack(steering_act, objList.from_id(enemy_id))
    #        steering_act.target = objList.from_id(enemy_id)
    #else:
    #    attack(steering_act, player)
    #    steering_act.target = player

def attack(actuator, obj_to_attack):
    
    #actuator.target = obj_to_attack
    
    print("I current attack: " + str(obj_to_attack))

def enemy_position(cont):
    pass


is it possible to get all vertex, face-midpoints possible positions and get an own inGame navmesh and an custom path following?
this is the Arena:


Hello, I am a quite concerning programming who cannot help but point out this is not AI unless it iterates over it’s own decision making skill’s thus because it duz not realize that it’s ability for attack depends on it’s distance to the target it cannot adapt to you running backward’s and shootin, I had the same problem the second Time I played descent 3… so no worry’s I think you should write the code and then have it iterate through it’s own decompiled code via opcode.py in your Lib path and generate genetic signatures for efficiency… see my contest under member contests for more info soon.

Instead of dynamically generating navmeshes, try continuously changing steering_act.target to points you calculate in real time.

If you really wanted to play with changing navmeshes, you could alter the actual navmesh in-game by changing its vertex points/location. The AI will then adapt to the changing navmesh.

have try it but it’s not what I am looking for.

I think I will set up an track_to actuator to direct to points in navmesh but how can i get the closest vertex_point to reach the main player?

how can i get the closest vertex_point to reach the main player?

Mhm, ok. You can enumerate through the vertices of the navmesh with the example code here:
https://www.blender.org/api/blender_python_api_2_67_1/bge.types.KX_MeshProxy.html

For every vertex you obtain, you can use AI.getDistanceTo(VertexPoint) to store in a variable with the shortest distance information (enumerate, and have a list called ‘shortest’ or something to keep track of what vertex has the shortest distance so far. Don’t forget to also store in the vertex.
You can refer to the documentation for getDistanceTo():
https://www.blender.org/api/blender_python_api_2_78a_release/bge.types.KX_GameObject.html#bge.types.KX_GameObject

I’m assuming you want to gather a lot of points for the navmesh anyway, so I think gathering distances
through brute force might be an ideal solution for your case. Hope that helps.

I create an test area but the track to is not working any solutions?Enemy_track_to_fail.blend (614 KB)

@Mirror
I will think about brute force thanks

you can but ,


is just a piece of code necessary.i use empties parented to the navmesh obj as “waypoints” … waypoints = [i for i in navmesh.children]

[some problem with format] :wink:


def get_faces_position(mesh):
    positions = []
    for pn in range(mesh.numPolygons):
        poly = mesh.getPolygon(pn)
        mn = poly.getMaterialIndex()
        verts = []
        for pvn in range(poly.getNumVertex()):
            vn = poly.getVertexIndex(pvn)
            vertex = mesh.getVertex(mn, vn)
            verts.append(vertex)    
        if verts:
            position = Vector([sum(values) for values in zip(*[v.XYZ for v in verts])])/len(verts)
            positions.append(position)
    return positions

local_points = get_faces_position(navmesh.meshes[0])
global_points = [navmesh.worldTransform*lp for lp in local_points]

Try this: Enemy_track_to.blend (680 KB)

Basically, your code didn’t work because you didn’t cont.activate() the actuator
when you changed the targeting object. Also, if you put the ‘player_ai’ variable
for your tracking object, it will measure the distance to itself, which will be
a distance of 0.0.

Brute force may or may not be required. This depends on what is desired.
There are many methods other than simple brute force.

Good luck!

@MarcoIT
your code looks a little familiar to other thinks I have done before spawn Player at Vertexpoint (not the same but I know how to do it)

I think about KDTree / BVHTree or maybe something from this mathutils.geometry

@Mirror
forgot to set it to active <-- ok
distance to itself <-- no, this line “object_distance[1][0]” is the second object that is near to itself (first is it self) by “player_ai”

distance to itself <– no, this line “object_distance[1][0]” is the second object that is near to itself (first is it self) by “player_ai”

Oh, my mistake, thanks.

Please let us know if you need more help :slight_smile:

ok, I get all Vertex points from mesh and but have some trouble to get the nearest vertex point to the interpolated midpoint/s didn’t know if this work anybody has some experience with KDTree -> find-n(co, n)


from bge import logic
from mathutils import Vector

def get_possible_points(navobj):

    position_list = []
    mesh = navobj.meshes[0]
    got_last_v = (mesh.getVertexArrayLength(0)-1)
    
    for v in range(mesh.getVertexArrayLength(0)):
        if v != got_last_v:
            vert = mesh.getVertex(0, v)
            vert_position = vert.getXYZ()
            position_list.append(vert_position)
        else:
            return position_list

def near_vertex_points(startpoint, endpoint, inpo_num, possible_position):

    #dist = lambda o: (startpoint - endpoint).magnitude
    #object_distance = [(id(o), dist(o)) for o in possible_position]
    #print(object_distance)
    #point = object_distance.sort(key=lambda t: t[1])
    #closest = point[0][0]
    #print(closest)
    #possible_position
    
    
    
        
def main(cont):
    own = cont.owner
    scene = logic.getCurrentScene()
    scObj = scene.objects
    destination = scObj["Player"].worldPosition
    now_position = own.worldPosition
    points = get_possible_points(scObj["Plane.001"])
    accurate = 2

    near_vertex_points(now_position, destination, accurate, points)
    
    
    
    #print(points)
    


the code sniped from MarcoIT is great but it will not produce the vertex list I want because
“for pn in range(mesh.numPolygons):” this range is every time = 0 so I got only the last vertex position.

i tried it in different conditions and it work ever.

try to open a new blend, copyu and paste this code in script mode (always without true)
it should add the object visualizer for each face of the obj “own” , own just must be a mesh object (it can be also a navmesh obj)


import bge
from mathutils import Vector


def get_faces_position(mesh):
    positions = []
    for pn in range(mesh.numPolygons):
        poly = mesh.getPolygon(pn)
        mn = poly.getMaterialIndex()
        verts = []
        for pvn in range(poly.getNumVertex()):
            vn = poly.getVertexIndex(pvn)
            vertex = mesh.getVertex(mn, vn)
            verts.append(vertex)    
        if verts:
            position = Vector([sum(values) for values in zip(*[v.XYZ for v in verts])])/len(verts)
            positions.append(position)
    return positions




cont = bge.logic.getCurrentController()
own = cont.owner
navmesh = own


local_points = get_faces_position(navmesh.meshes[0])
global_points = [navmesh.worldTransform*lp for lp in local_points]






name_obj_visualizer_face = "Icosphere"


for point in global_points:
    obj_point = own.scene.addObject(name_obj_visualizer_face, own)
    obj_point.worldPosition = point
    obj_point.setParent(own)
    
    
    

i use blender 2.74 (a bit old)

@MarcoIT
thanks,
that is my new prototype (not finished):


from bge import logic, render
import mathutils
from mathutils import Vector

def get_kd_tree(own, obj):
    
    if 'init' not in own:
        size = obj.meshes[0].getVertexArrayLength(0)
        mesh = obj.meshes[0]
        
        kd = mathutils.kdtree.KDTree(size)
        
        index=0
        for pn in range(mesh.numPolygons):
            poly = mesh.getPolygon(pn)
            mn = poly.getMaterialIndex()
            verts = []
            for pvn in range(poly.getNumVertex()):
                vn = poly.getVertexIndex(pvn)
                vertex = mesh.getVertex(mn, vn)
                verts.append(vertex)
            if verts:
                point = Vector([sum(values) for values in zip(*[obj.worldTransform*v.XYZ for v in verts])])/len(verts)
                #global_point = obj.worldTransform*point
                kd.insert(point, index)
                index+=1
        
        kd.balance()
        
        own['init'] = True
        own["kd_tree"] = kd

def main():
    cont = logic.getCurrentController()
    own = cont.owner
    scene = logic.getCurrentScene()
    scObj = scene.objects
    obj = scObj["Plane.001"]
    
    get_kd_tree(own, obj)
    
    startposition = own.worldPosition
    endposition = scObj["Player"].worldPosition
    findpoint = (startposition-endposition)
    #track_to = cont.actuators["track_to"]
    co_find = findpoint
        
    kd_tree = own["kd_tree"]
    
    for (co, index, dist) in kd_tree.find_n(co_find, 1):
        #print("    ", co, index, dist)
        
        new_posi = own.getVectTo(co)
        print(new_posi)
        own.alignAxisToVect(new_posi[1],0,0.1)
        render.drawLine(startposition, co, (1.0,0.0,0.0))
        
        #cont.activate(track_to)
        #track_to.object(co)
        #own.worldPosition = co
 
 

if you have an improvement please let me know

have override this line:

“findpoint = (startposition-endposition)”

to this line:

“findpoint = startposition.lerp(endposition, 0.2)”