Hi NemoVonFish,
Nice project going on. I took a look at your code, and I can provide some interesting ideas.
Well, the lag that occurs is quite normal, here, because you are putting a very high load on the pathfinding.
First of all, let us consider this portion of our code:
Code: Select all
for i, v in ipairs(enemies) do
if v.energy >= 1000 then -- Is it their turn?
aggroProximity(v) -- Aggro them if they're within range.
if v.aggressive == true then ... end
end
end
And this, given that:
Code: Select all
function aggroProximity(foo) -- The pathing function.
local walkable = 1
local Grid = require ("libs.jumper.grid")
local Pathfinder = require ("libs.jumper.pathfinder")
local grid = Grid(mapCurrent)
local myFinder = Pathfinder(grid, 'JPS', walkable)
local startx, starty = foo.grid_x/16, foo.grid_y/16
local endx, endy = player.grid_x/16, player.grid_y/16
local path = myFinder:getPath(startx, starty, endx, endy)
if path then
if path:getLength() < foo.sense then
foo.aggressive = true
end
end
end
This is truly where the lag comes.
Is it really needed to pathfind for each ennemy before
trying to guess if the ennemy is close enough to the player to attack him ?
I would suggest a different approach.
Since each ennemy has a "sense" area, you can loop through the collection of ennemies, and calculate the actual distance between
the ennemy and the player, and compare it to that "sense" value. As such, you can mark the ennemies that are "close enough" to
the player and let them use pathfinding. Here is an example, assuming "sense" is the radius of a circular area around the ennemy (in pixels, not in tile units).
Code: Select all
local function squareDistance(entityA, entityB)
local dx = math.abs(entityA.x - entityB.x)
local dy = math.abs(entityA.y - entityB.y)
return dx*dx + dy*dy
end
for i, ennemy in ipairs(ennemies) do
if v.energy >= 1000 then
-- if the player is close enough to the ennemy
if squareDistance(ennemy, player) <= (ennemy.sense*ennemy.sense) then
calculatePath(ennemy, player)
end
end
end
Note: I am comparing the square distance to the square of square (since
math.sqrt is a costful function). Tricky, but valid, since
a = b also means a*a = b*b.
EDIT: You can also try a
lineOfSight algorithm. This will tell if the ennemy sees the player. It is a bit more expensive than the above, but still less explensive than performing a pathfinding request, actually. This feature is actually included in the latests commits of Jumper, but still in development.
The
calculatePath function will actually do a similar job to what the old
aggroProximity() was doing, but with a major difference.
You do not have to require the library, init a grid object and a pather
each time. Just do that once, at the top of your script:
Code: Select all
local walkable = 1
local Grid = require ("libs.jumper.grid")
local Pathfinder = require ("libs.jumper.pathfinder")
local grid = Grid(mapCurrent) -- mapCurrent has to be defined
local myFinder = Pathfinder(grid, 'JPS', walkable)
Even if the world changes (for instance a tile/ a group of tiles becomes switches from
walkable to
unwalkable, Jumper will accomodate with that, so that to don't need to recreate a new grid.
That way, the
calculatePath function will look like:
Code: Select all
local function worldToTile(entity, tileSize)
return math.floor(entity.x/tileSize)+1, math.floor(entity.y/tileSize)+1
end
function calculatePath(entity, target)
local sx, sy = worldToTile(entity,16)
local ex, ey = worldToTile(target,16)
local path = myFinder:getPath(sx, sy, ex, ey)
if path then
path:fill() -- the path filling you need, since you are using Jump Point Search finder
end
entity.path = path or false -- saves the path when found, false otherwise.
end
Note: The
worldToTile function performs conversion from world coordinates to tile coordinates. Since your tile coordinates start at 1,1 (but not 0,0), you will have to add +1 in tile units to perform a correct conversion.
You can commit those changes, and see how the speed improves. Jumper was designed to provide different flavors of algorithms and speed for pathfinding on large grids. But, as you said, you are not tight to it, there are lots of implementations for pathfinding out there.