Pathing around other units using Jumper. [SOLVED]

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
NemoVonFish
Prole
Posts: 18
Joined: Sun Feb 24, 2013 7:48 am

Pathing around other units using Jumper. [SOLVED]

Post by NemoVonFish »

My problem, quite simply, is that I can't figure out how to make the entities path around each other. Here's what i've tried.

Code: Select all

function calculatePath(entity, target)
	local grid = Grid(mapCurrent.terrain)
	local sx, sy = worldToTile(entity)
	local ex, ey = worldToTile(target)
	local path = myFinder:getPath(sx, sy, ex, ey)
	if path then
		path:fill()
	end
	entity.path = path
end
There's the pathing code, and it works all fine, they run at you, etcetera, but i've made it so if they try to walk in to a space that contains another entity, it stops them. The downside to this, is they all stand in a straight line, since obviously they path with the shortest distance to the PC, then try to take the first step, but there's someone already there, so they just.. stop.

I tried doing this:

Code: Select all

function calculatePath(entity, target)
	mapCurrent.pathing = mapCurrent.terrain
	for i, v in ipairs(enemies) do
		mapCurrent.pathing[v.grid_y/tileSize][v.grid_x/tileSize] = 0
	end
	local grid = Grid(mapCurrent.pathing)
	local sx, sy = worldToTile(entity)
	local ex, ey = worldToTile(target)
	local path = myFinder:getPath(sx, sy, ex, ey)
	if path then
		path:fill()
	end
	entity.path = path
end
Essentially, generating a clean terrain map for them to path on, making all the tiles containing an entity unpathable, then generating a path, so they'll walk around each other. Then, something rather.. odd happens. Despite never drawing mapCurrent.pathing, or interacting with mapCurrent.terrain, the terrain changes, and they all leave behind unpathable tiles, and I have no idea why, or where that is even happening.
The second issue, is that the moment they can't path to the PC, because it would require stepping on one of these unpathable zones, the game locks up, most likely because it is forever their turn to act, and they can't.


Just as a warning, i'm rather new to programming, so my code may be frustratingly inefficient, and difficult to read. If so, I can copy+paste the relevant parts.
Attachments
MyRoguelike.love
Controls:
Numpad to move selection/PC
Numpad enter to select
(57.99 KiB) Downloaded 179 times
Last edited by NemoVonFish on Thu Dec 05, 2013 6:12 am, edited 1 time in total.
bekey
Party member
Posts: 255
Joined: Tue Sep 03, 2013 6:27 pm

[]

Post by bekey »

-snip-
Last edited by bekey on Fri Jan 24, 2014 1:59 am, edited 1 time in total.
User avatar
NemoVonFish
Prole
Posts: 18
Joined: Sun Feb 24, 2013 7:48 am

Re: Pathing around other units using Jumper.

Post by NemoVonFish »

bekey wrote:it just references it.
...That would explain a lot, hahahhahaah, ohh god, I have been wracking my brains on this for like, two weeks.
bekey
Party member
Posts: 255
Joined: Tue Sep 03, 2013 6:27 pm

[]

Post by bekey »

-snip-
Last edited by bekey on Fri Jan 24, 2014 1:59 am, edited 1 time in total.
User avatar
NemoVonFish
Prole
Posts: 18
Joined: Sun Feb 24, 2013 7:48 am

Re: Pathing around other units using Jumper.

Post by NemoVonFish »

bekey wrote:Either way, you should probably localize the temporary table, and then nil it at the end.
I don't quite get what you mean, or how the local variables work, really. When I do

Code: Select all

function calculatePath(entity, target)
	local mapCurrent.pathing = deepCopy(mapCurrent.terrain) --This is line 642
	for i, v in ipairs(enemies) do
		mapCurrent.pathing[v.grid_y/tileSize][v.grid_x/tileSize] = 0
	end
	local grid = Grid(mapCurrent.pathing)
	local sx, sy = worldToTile(entity)
	local ex, ey = worldToTile(target)
	local path = myFinder:getPath(sx, sy, ex, ey)
	if path then
		path:fill()
	end
	entity.path = path
	local mapCurrent.pathing = nil
end
It says "Syntax Error: main.lua:642: unexpected symbol near '.'" I assume i'm not localising the variable correctly?
bekey
Party member
Posts: 255
Joined: Tue Sep 03, 2013 6:27 pm

[]

Post by bekey »

-snip-
Last edited by bekey on Fri Jan 24, 2014 1:58 am, edited 1 time in total.
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

Re: Pathing around other units using Jumper.

Post by Roland_Yonaba »

Hi Nemo,

First of all, thanks using Jumper. I appreciate the feedback.
Now, let me highlight a few things:

First of all, when moving a team/group of units from a target to a destination, they will tend to lineup at the destination, causing a "stack".
That is totally normal, just because the path they following leads to the same destination.
I am very aware of that, though I won't pull any patch in the library code to "fix" this, mostly because it goes out of the scope of the original intent of Jumper.
But, if for some reason, you want to avoid that "stacking" problem, there is a couple of solutions.
The one you are using is not the best, and is not even suitable because it is quite costful. Indeed, there is nicer one that relies on steering behaviours. Basically, you have a team of units which are supposed to follow a path, but you want them to move in formation....In this case, steering is definitely the way to go, in my humble opinion.
Here is Craig Reynolds' original paper on the subject, followed with some slides. You might also be interested in this very straightforward tutorial series at tuts.plus. There are lots of behaviors, and they can be combined to create new ones. The one you might be interested in is crowding.
Also, I have been working myself on Steering behaviors, and I got pretty interesting code to show, although this experiment is paused at the moment.

Second, I noticed that you are doing something wrong, with Jumper. And actually, a lot of people do the same mistake.
You are not suppose to create a grid object each time you are requesting a path. This operation is quite costful (depending on the size on your map), but it is just irrelevant, since once the grid is create, it keeps internally a reference to the original map. Therefore, if you change something on this map, the grid object will be aware of that.

Code: Select all

-- only once, unless you change the table map with another table having a different size
local grid = Grid(map) 

function calculatePath(entity, target)
   local sx, sy = worldToTile(entity)
   local ex, ey = worldToTile(target)
   local path = myFinder:getPath(sx, sy, ex, ey)
   if path then
      path:fill()
   end
   entity.path = path
end
Do not hesitate if you have further questions, or if you want to expand on this.
User avatar
NemoVonFish
Prole
Posts: 18
Joined: Sun Feb 24, 2013 7:48 am

Re: Pathing around other units using Jumper.

Post by NemoVonFish »

Hello, once again!

Thanks for taking the time to help whenever I have an issue (which seems to be a lot), i've cleaned up the calculatePath function so it no longer creates a grid every time. Another issue i've found, which may help me fix the main one I have, is that entities will move diagonally perfectly fine, but if the terrain would force them to move diagonally, such as

Code: Select all

1 1 1 1
1 0 1 1
1 1 0 1
1 1 1 1
going from one zero to the other (assuming zeroes are pathable), Jumper (as far as I can tell) won't detect a valid path. That would explain why my method, as inefficient as it is, doesn't work when it would force them to move in to a diagonal-only space. I think I remember a setting somewhere about allowing diagonals, though I can't seem to find what i'm thinking of. Any chance you know what i'm talking about?
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

Re: Pathing around other units using Jumper.

Post by Roland_Yonaba »

NemoVonFish wrote:Any chance you know what i'm talking about?
Sure.
Actually, this is an expected behaviour and I set things this way on purpose. There is no real path from the first zero to the second. Jumper considers that a moving unit occupies (at the very least) a full tile. So, normally, it cannot "tunnel" through that diagonal wall.

As of v1.8.1 though, I introduced a feature called "tunnelling" which is supposed to fool the pathfinder in such cases and let it go through such diagonal walls. You just need to pass the boolean "true" as a fifth argument to pathfinder:getPath(...).

Assuming you have this minimal code base :

Code: Select all

--setup
local Grid = require 'jumper.grid'
local Pathfinder = require 'jumper.pathfinder'

local map = {
  {1,1,1,1},
  {1,0,1,1},
  {1,1,0,1},
  {1,1,1,1}
}

local grid = Grid(map)
local finder = Pathfinder(grid,'ASTAR',0)
Let's try to get the path from cell(2,2) to cell(3,3).
It fails naturally.

Code: Select all

local path = finder:getPath(2,2,3,3)
print('Path was found:', path~=nil) --> false
Now, passing a boolean to getPath(...) will trigger the tunnelling feature.
And in this case, a path is found.

Code: Select all

local path = finder:getPath(2,2,3,3,true)
print('Path was found:', path~=nil) --> true, a path was found.
User avatar
NemoVonFish
Prole
Posts: 18
Joined: Sun Feb 24, 2013 7:48 am

Re: Pathing around other units using Jumper.

Post by NemoVonFish »

Aha! Perfect! Thank you very much, i'm pretty sure i'm using an earlier version, so i'll get a newer one, give that a shot, and let you know how I go.
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 79 guests