3D AI Pathfinding

Is there anyway that I can make an entity continuously follow the player around and also make it stop following the player if they are a certain distance away from the player???

Thanks in advance :slight_smile:

Yes, probably several ways. A simple one is to have a desired distance from the player, and a distance beyond which the player is ignored. Get the distance between player and entity. If it is greater than the “beyond” distance, do nothing. If it is greater than the “desired” distance, move a bit in the direction of the player. If it is less than the desired distance, either move away or stand still, whichever you prefer.

A question will arise: what is “toward”. If movement is free, that is the entity can move in any direction (as opposed to just N,E,S,W, for example), then the direction toward the player is the normalized value of the vector (playerPosition-entityPosition). That vector has length 1, so you can multiply it by any convenient number to pick how far to move. Multiply it by 2, the entity will move two units toward the player.

In general, of course, there may be obstacles in the space, walls or such. I prefer to handle those similarly for both player and entity. When either tries to move in some direction, if there’s something in the way, I don’t let them move. A more sophisticated approach might be, for example, if the entity is trying to move 2 units but there is a wall at 1.5, let it move 1.5 and bonk into the wall.

It seems that in your game you are trying to use physics to do the moving. I’ve not done that but the same principles apply.

@RonJeffries, I will try your two options and see what works.

If (the distance between the entity and player) < agroRange)
Move towards player

@Jarc, thank you for that help. I don’t however, know what to write in order for the enemy to move towards the player. Could you possibly show me an example??

Thanks :slight_smile:

@Creator27 Try this example. The right sphere will move towards the left sphere as it falls and bounces.

viewer.mode=FULLSCREEN

function setup()
    assert(OrbitViewer, "Please include Cameras as a dependency")
    fill(255)
    scene = craft.scene()
    skyMaterial=scene.sky.material
    skyMaterial.sky=color(0, 62, 255, 255)
    skyMaterial.horizon=color(99, 255, 0, 255)   
    scene.sun.rotation=quat.eulerAngles(20,45,-30)
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 100, 0, 200)
    v.rx,v.ry=20,20
    createRect()
    s1=createSphere(-10,30,0)  
    s2=createSphere(-4,30,0)
end

function draw()
    update(DeltaTime)
    scene:draw()    
    text("Drag your finger on the screen to rotate the cube",WIDTH/2,HEIGHT-100)
    v1=s1.sphere1.position-s2.sphere1.position
    s1.ss.linearVelocity=-v1*3
end

function update(dt)
    scene:update(dt)
end

function createRect() 
    diff=8
    c1=scene:entity()
    w=c1:add(craft.rigidbody,STATIC)
    w.restitution=.6
    c1.position=vec3(0,-10,0)
    c1.model = craft.model.cube(vec3(25,10,10))
    c1.model:position(5,-5,diff,5)
    c1.model:position(18,-5,diff,5)
    c1.model:position(10,-5,diff,5)
    c1.model:position(9,-5,diff,-5)
    c1.model:position(14,-5,diff,-5)
    c1.model:position(19,-5,diff,-5) 
    c1:add(craft.shape.model,c1.model)
    c1.material = craft.material(asset.builtin.Materials.Standard)
    c1.material.map = readImage(asset.builtin.Surfaces.Basic_Bricks_AO)
end

function createSphere(x,y,z)
    local sphere1=scene:entity()
    local s=sphere1:add(craft.rigidbody,DYNAMIC)
    s.restitution=1.5
    sphere1.position=vec3(x,y,z)
    sphere1.model = craft.model.icosphere(.5,5)
    sphere1:add(craft.shape.sphere,.5)
    sphere1.material = craft.material(asset.builtin.Materials.Specular)
    sphere1.material.diffuse=color(255,0,0)
    return({sphere1=sphere1,ss=s})
end

@dave1707, thank you very much, it works perfectly. Just one problem. Say I wanted 2 red spheres to follow me, when I spawn one sphere, it works fine. But when I spawn another sphere, the first sphere that was spawned stops following me, but the second sphere takes it’s place instead. It also doesn’t allow me to spawn more than one sphere at a time. Is there anyway that I can make every spawned sphere follow, regardless of how many there are and make it so that I can spawn as many spheres as I want??

Thanks :slight_smile:

You have to put the spheres that are supposed to follow the first sphere in a table so you can calculate the linearVelocity of each sphere individually.

@dave1707, I’ve tried doing what you said, but it still isn’t working. Every time I try to calculate the linear velocity, it just does the same thing. Could you possibly show me an example of what you mean???

Thanks :slight_smile:

Here’s a version that uses a table. Tap the screen to cause the red spheres to follow the green sphere. Tap again to unfollow.

viewer.mode=FULLSCREEN

function setup()
    tab={}
    assert(OrbitViewer, "Please include Cameras as a dependency")
    fill(255)
    scene = craft.scene()
    skyMaterial=scene.sky.material
    skyMaterial.sky=color(0, 62, 255, 255)
    skyMaterial.horizon=color(99, 255, 0, 255)   
    scene.sun.rotation=quat.eulerAngles(20,45,-30)
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 100, 0, 200)
    v.rx,v.ry=20,20
    createRect()
    s1=createSphere(0,30,0,1) 
    for z=1,5 do
        table.insert(tab,createSphere(math.random(-10,10),math.random(20,35),math.random(-10,10),0))
    end
end

function draw()
    update(DeltaTime)
    scene:draw()    
    text("Drag your finger on the screen to rotate the cube",WIDTH/2,HEIGHT-100)
    if follow then
        for z=1,#tab do
            v1=s1.sphere1.position-tab[z].sphere1.position
            tab[z].ss.linearVelocity=v1
        end
    end
end

function update(dt)
    scene:update(dt)
end

function touched(t)
    if t.state==BEGAN then
        follow=not follow
    end
end

function createRect() 
    diff=8
    c1=scene:entity()
    w=c1:add(craft.rigidbody,STATIC)
    w.restitution=.6
    c1.position=vec3(0,-10,0)
    c1.model = craft.model.cube(vec3(25,10,10))
    c1.model:position(5,-5,diff,5)
    c1.model:position(18,-5,diff,5)
    c1.model:position(10,-5,diff,5)
    c1.model:position(9,-5,diff,-5)
    c1.model:position(14,-5,diff,-5)
    c1.model:position(19,-5,diff,-5) 
    c1:add(craft.shape.model,c1.model)
    c1.material = craft.material(asset.builtin.Materials.Standard)
    c1.material.map = readImage(asset.builtin.Surfaces.Basic_Bricks_AO)
end

function createSphere(x,y,z,c)
    local sphere1=scene:entity()
    local s=sphere1:add(craft.rigidbody,DYNAMIC)
    s.restitution=1.5
    sphere1.position=vec3(x,y,z)
    sphere1.model = craft.model.icosphere(.5,5)
    sphere1:add(craft.shape.sphere,.5)
    sphere1.material = craft.material(asset.builtin.Materials.Specular)
    if c==1 then
        sphere1.material.diffuse=color(0,0,255)
    else
        sphere1.material.diffuse=color(255,0,0)
    end
    return({sphere1=sphere1,ss=s})
end

@dave1707, thank you for that code. Once I figure out what I’m not doing that stops from your example working in my game, everything will work fine.

@dave1707, everything works fine. Your creativity is incredible, and I am so grateful that you help me out as much as you do :slight_smile:

@dave1707 I hope this is ok: I modified your demo to have a floor and walls, so that the spheres stay on screen longer, and I made the balls a scootch bigger, so they’re easier to track visually, and I made a little .zip of it for people to be able to instantly open. It’s still fully credited to you.