Help with enemy patrolling to random coordinate

As the title says, trying to make my first game on here and have the enemy pick a random coordinate to patrol to when the player is outside its detection radius. It seems to be picking a coordinate and then not refreshing because it just floats to the bottom left corner whenever the player is too far away. Any help appreciated!

go.property("dir", vmath.vector3())
local reg_speed = 30
local radius = 100

function init(self)
	self.dir = vmath.vector3()
	self.speed = reg_speed
end

function update(self, dt)
	local p = go.get_position()
	local player_pos = go.get_position("Player")
	local direction = player_pos - p

	if vmath.length(player_pos - p) <= radius then
		if vmath.length_sqr(direction) > 0 then
			direction = vmath.normalize(direction)
		end
		go.set_position(p + direction * self.speed * dt)
	else
		local x = math.random(0,15)
		local y = math.random(0,15)
		local target = vmath.vector3(x,y,1)
		local distance = target - p
		if vmath.length_sqr(distance) > 0 then
			distance = vmath.normalize(distance)
		end
		go.set_position(p + distance * self.speed * dt)
	end
end

I see two issues:

  1. local x = math.random(0,15) – The values are pretty small.
  2. You are basiclly randomly pick new coordinate to go in each frame. Instead you should pick new coordinate and go to it until you reach the point (or certain proximity). Also I would expect that reaching the target point takes some time instead of instatly getting there, but maybe you had different idea?
2 Likes

Yea its just cause the map is 15 x 15 at the moment, i figured anything higher would cause it to go out of bounds. The aim is for it to gradually get there instead of teleport. Is it worth using some kind of true/false variable to keep track of whether its reached the target or not?

Game object positions are measured in pixels, not tiles (which is what I assume you are using for your map).

Is it worth using some kind of true/false variable to keep track of whether its reached the target or not?

Yes, exactly!

Typically should logic is like

function init(self)
    self.dir = vmath.vector3()
    self.speed = reg_speed
    -- Lets store the flag for target following:
    self.is_executing_route = false
end

--First  let's make some additional functions for more clarity:
local function move_closer_to_player(self, dt)
    -- Implement logic for moving closer to the player. Remember to move enemy just a little bit closer to player, not to player position! Also route execution flag should be set to false.
end

local function continue_route(self, dt)
    -- Implement logic for continuing the current route. Remember to move enemy just a little bit closer to target position, not immediately to the target pos! Also check if you have reached the target point here (or you are close enough).
end

local function get_new_target(self, dt)
    -- Implement logic for getting a new target. Just getting new target, you can also call continue_route() to move a little bit in the same frame. Dont forget to set the is_executing_route flag to true.
end

function update(self, dt)
    local player_pos = go.get_position("Player")
    local enemy_pos = go.get_position()
    local distance = vmath.length(player_pos - enemy_pos)

    local is_player_close = distance < 100

    if is_player_close then
        move_closer_to_player(dt)
    else
        if self.is_executing_route then
            continue_route(dt)
        else
            get_new_target(dt)
        end
    end
end

I have not tested the code above, I just writen it directly here, so there may be some mistakes, but I hope it gives you an idea what can be done.

Also as @Alex_8BitSkull mentioned, try using higher values for target coordinates. Maybe start with printing player coordinates when traversing map to get a grasp of range that interests you?