[ home / board list / faq / random / create / bans / search / manage / irc ] [ ]

/agdg/ - Amateur Game Development General

AGDG - The Board

Catalog

8chan Bitcoin address: 1NpQaXqmCBji6gfX8UgaQEmEstvVY7U32C
The next generation of Infinity is here (discussion) (contribute)

You may buy ads now for any board, betakey is removed. Please contact ads@8ch.net for information or help with this service.
Name
Email
Subject
Comment *
File
* = required field[▶ Show post options & limits]
Confused? See the FAQ.
Embed
(replaces files and can be used instead)
Oekaki
Show oekaki applet
(replaces files and can be used instead)
Options
dicesidesmodifier
Password (For file and post deletion.)

Allowed file types:jpg, jpeg, gif, png, webm, mp4, swf, pdf
Max filesize is 8 MB.
Max image dimensions are 10000 x 10000.
You may upload 5 per post.


Welcome to AGDG, have you ever made a game?
See also: /ideaguy/ | /vm/

File: 1440689703450.webm (4.74 MB, 1920x1200, 8:5, CombatPrototypeVid4.webm)

17b9f5 No.21297

So I'm currently working on a 4x and have implemented A* pathfinding. The thing is that A* still is too slow on the maps I want to use because of their size. As the video shows it takes the algorithm over 20 secs to find the path from the bottom left to the top right which is totally unacceptable. So the question is how do I cut that down to < 0.5 secs hopefully on maps even larger than this?

Also I guess: Pathfinding general.

da8281 No.21300

>>21297

>As the video shows it takes the algorithm over 20 secs to find the path from the bottom left to the top right which is totally unacceptable

That's bullshit bro. Post your code.


17b9f5 No.21306

File: 1440704079729.jpg (48.92 KB, 620x620, 1:1, 1400418886305.jpg)

>>21300

If you say it like that I'm absolutely willing to consider I fucked up somewhere. I'm pretty new at this stuff.

The following code is not save for minors, the elderly, pregnant women or people with a weak constitution. Oh, it's also written in gamemaker's GML.

Part I:


//Establishing basics
var GoalXYZ = argument1
var UnitID = argument0
var arr_MovementCosts = UnitID.arr_MovementCosts
var UnitXYZ = UnitID.var_CubeXYZ
var arr_TacticalHexTerrain = var_CombatLoopID.arr_TacticalHexTerrain //Copy array once or ask combat loop every time?
var arr_TacticalHexCubeCoords = var_CombatLoopID.arr_TacticalHexCubeCoords

var CurrentHexXYZ
var PrevHexXYZ
var Terrain
var MCost
var PrevMCost
var TotalMCost
var Distance
var VisitedHexes = 0 //When searching in array with this var it must be decreased by one!
var CombinedString
var dsp_Frontier = ds_priority_create();
arr_Visited [2, var_GridHorz*var_GridVert] = 0 // X0=CubeXYZ, X1=Previous CubeXYZ, X2=TotalMovementCost //Delete array at end of script!
arr_Visited [2, VisitedHexes] = 0
arr_Visited [1, VisitedHexes] = UnitXYZ
arr_Visited [0, VisitedHexes] = UnitXYZ

//Start finding path
scr_HexNeighborsString(UnitXYZ)
for (var Neighbor =5; Neighbor >=0; Neighbor--)
{
if arr_Neighbors[Neighbor,0] != "a"
{
CombinedString = string(arr_Neighbors[Neighbor,0]) + "/" + string(UnitXYZ)
scr_SearchInArray(arr_TacticalHexCubeCoords, 0,0,var_GridHorz,var_GridVert,arr_Neighbors[Neighbor,0])
Terrain = arr_TacticalHexTerrain[var_ArrayX,var_ArrayY]
MCost = arr_MovementCosts[Terrain]
if MCost != -1
{
VisitedHexes++
Priority = MCost + scr_HexCubeDistance(arr_Neighbors[Neighbor,0],GoalXYZ)
ds_priority_add(dsp_Frontier, CombinedString,Priority)
arr_Visited [2, VisitedHexes] = MCost
arr_Visited [1, VisitedHexes] = UnitXYZ
arr_Visited [0, VisitedHexes] = arr_Neighbors[Neighbor,0]
}
}
}


17b9f5 No.21307

>>21306

Part II:



while ds_priority_empty(dsp_Frontier) = false
{
CombinedString = ds_priority_delete_min(dsp_Frontier)
scr_Separate2XYZStrings(CombinedString)
CurrentHexXYZ = var_StringXYZ1
PrevHexXYZ = var_StringXYZ2
scr_HexNeighborsString(CurrentHexXYZ)
for (var Neighbor =5; Neighbor >=0; Neighbor--)
{
scr_SearchInArray(arr_TacticalHexCubeCoords, 0,0,var_GridHorz,var_GridVert,arr_Neighbors[Neighbor,0])
if arr_Neighbors[Neighbor,0] != "a"
{
Terrain = arr_TacticalHexTerrain[var_ArrayX,var_ArrayY]
MCost = arr_MovementCosts[Terrain]
scr_SearchInArray(arr_Visited, 0,0,0,VisitedHexes,CurrentHexXYZ)
PrevMCost = arr_Visited[2, var_ArrayY]
TotalMCost = PrevMCost + MCost
if MCost != -1
{
scr_SearchInArray(arr_Visited, 0,0,0,VisitedHexes,arr_Neighbors[Neighbor,0])
if var_ArrayY != -1
{
//Old Hex already in the array
if TotalMCost >= arr_Visited[ 2, var_ArrayY] {/*Previous path was shorter, do nothing.*/}
else
{
//New path is shorter, replace old path
CombinedString = string(arr_Neighbors[Neighbor,0]) + "/" + string(CurrentHexXYZ)
Priority = TotalMCost + scr_HexCubeDistance(arr_Neighbors[Neighbor,0],GoalXYZ)
ds_priority_add(dsp_Frontier, CombinedString,Priority)
arr_Visited [2, var_ArrayY] = TotalMCost
arr_Visited [1, var_ArrayY] = CurrentHexXYZ
arr_Visited [0, var_ArrayY] = arr_Neighbors[Neighbor,0]
}
}
else
{
//This is a new hex
VisitedHexes++
CombinedString = string(arr_Neighbors[Neighbor,0]) + "/" + string(CurrentHexXYZ)
Priority = TotalMCost + scr_HexCubeDistance(arr_Neighbors[Neighbor,0],GoalXYZ)
ds_priority_add(dsp_Frontier, CombinedString,Priority)
arr_Visited [2, VisitedHexes] = TotalMCost
arr_Visited [1, VisitedHexes] = CurrentHexXYZ
arr_Visited [0, VisitedHexes] = arr_Neighbors[Neighbor,0]
if arr_Neighbors[Neighbor,0] = GoalXYZ {ds_priority_clear(dsp_Frontier);break}
}
}
}
}
}

scr_SearchInArray (arr_Visited,0,0,0,VisitedHexes,GoalXYZ)
dsl_Path = ds_list_create()
ds_list_insert (dsl_Path,0,GoalXYZ)

do
{
CurrentHexXYZ = ds_list_find_value(dsl_Path,0)
scr_SearchInArray(arr_Visited,0,0,0,VisitedHexes,CurrentHexXYZ)
if var_ArrayY = -1 {show_message("No Path possible!");var_Goal = "a";break;}
PrevHexXYZ = arr_Visited [1, var_ArrayY]
ds_list_insert (dsl_Path,0,PrevHexXYZ)
}
until (UnitXYZ = ds_list_find_value(dsl_Path,0))
ds_list_delete(dsl_Path,0)

If you want the code of any of the scripts just tell me.


da8281 No.21324

>>21306

>Oh, it's also written in gamemaker's GML.

Fug. I've never used that, so I can't really say much for sure. 20 seconds does seems excessive compared to a python implementation though. If I were to guess it would be the searchInArray calls that were slowing it down, just going by the name. Why is it called in each step/what does it do?

Also, have you tried just using a breadth first search, just to compare?

(Also, to answer the original question, have you considered precomputing paths when you generate the map? If you don't have rules like 1UPT it might work).


95d923 No.21327

>>21324

I have the hexes in 2d arrays layered on top of each other to make a 3d array (as GM doesn't support them natively). What I do there is I search for the XY of the hex's coordinate in the array that saves those and then feed that into the terrain array to find out what terrain the hex has.

The SearchInArray script is pretty basic.


var_ArrayX = -1
var_ArrayY = -1
for (var Y = argument4; Y >= argument2; Y --)
{
for (var X = argument3; X >= argument1; X --)
{
if argument0 [X,Y] = argument5
{
var_ArrayX = X
var_ArrayY = Y;
X = -1;
Y = -1;
}
}
}


95d923 No.21328

>>21327

Oh and to explain the script a little:

argument0 = the array to search in

argument1 = top-left x of the region to search in

argument2 = top-left y of the region to search in

argument3 = bottom-right x of the region to search in

argument4 =bottom-right y of the region to search in

argument5 = what is looked for in the array


da8281 No.21339

>>21327

> What I do there is I search for the XY of the hex's coordinate in the array that saves those

Shouldn't they be at X, Y?

Also what is VisitedHexes for? It looks like you're storing stuff in the order you process them but I'm not sure why.


95d923 No.21341

>>21339

>Shouldn't they be at X, Y?

I meant that.

>Also what is VisitedHexes for? It looks like you're storing stuff in the order you process them but I'm not sure why.

VisitedHexes is just a counter so I know the Y in the array arr_Visited I have to save new hexes to. In arr_Visited I have the hex, the hex that the algorithm came from and the movement cost up to this point.


ba8dce No.21360

>>21306

Does gamemaker have profiling tools?


a15c54 No.21361

>>21297

what are u use game engine ?


307322 No.21367

File: 1440857480415-0.png (360.19 KB, 1040x634, 520:317, 001.png)

File: 1440857480415-1.png (360.39 KB, 1028x639, 1028:639, 002.png)

>>21360

scr_FindPath is the two part block of code I posted in the beginning of the thread. scr_HexNeighborsString determines the coordinates (fast because simple math) and terrain. Finding the terrain involves scr_VariableToArrayXY which is an older version of scr_SearchInArray that just always has the top-left corner of the search region at 0,0.

The code up there is not entirely what I use anymore because I noticed while looking at it that I'm searching for terrain twice there. Both in scr_HexNeighborsString and scr_FindPath. Stopping scr_FindPath looking for terrain itself and using the array provided by scr_HexNeighborsString cut the time the pathfinding runs in half basically but it's still too slow. The second path I generated in the vid still takes 10+ seconds.

>>21361

Gamemaker

>>21324

>Also, have you tried just using a breadth first search, just to compare?

BFS + terrain was my first implementation. It was way slower.

>Also, to answer the original question, have you considered precomputing paths when you generate the map? If you don't have rules like 1UPT it might work

Tricky. I'm planning to have both a world and a combat map like Master of Magic or Age of Wonders. Combat is obviously going to be 1UPT but world will also limit UPT.

But yeah that was basically the point of the thread. Asking fellow anons where the biggest gains might be and then dig for some guides and implement whatever you guys recommended.


600642 No.21382

I can't say much about the posted code, since I neither have an abundance of A* knowledge, nor GML experience.

However, I have implemented pathfinding algorithms in other languages and can say that it's possible to incorrectly implement A* such that it finds a path but horribly inefficiently. One suggestion I have to you is to render the paths that your algorithm is calculating. This can help you to determine if your implementation is correctly ignoring bad choices.

Another suggestion, is to change that map generation code. Real land doesn't have scattered, densely packed lakes blocking movement so ubiquitously.

Already mentioned is the possibility to precalculate and store paths. This is a good idea if you know the pathfinding won't later be affected by terrain changes (or if you know such changes are rare enough to simply re-calculate affected paths). I wouldn't say, though that you should store a path for every tile moving to every other tile. I'd group the terrain into logical areas, then come up with some paths between those areas if this is your goal.

Finally, there are some optimizations of A* that can provide even more of a speed boost in pathfinding, such as the Jump Point Search algorithm. A google search will give you details on that. JPS specifically works best if the map has certain qualities (though I forget exactly what), and it needs a little adjustment if your terrain has varying movement costs, iirc.


600642 No.21383

>>21367

I'd look to see if you can optimize your SearchInArray function, or better yet, figure out how to get rid of it altogether. From what I see, you seem to be calling that function up to twice per hex in the search. and each time it is called, it seems to look through an array of, apparently, ever growing size.


739058 No.21385

File: 1440879679013.pdf (1.28 MB, search.pdf)

I have pdf about search functions. That might be able to help.

I'm not sure if I can share it since it's from a class.


307322 No.21388

First thanks all for helping me out here.

>>21383

I'll look at the other stuff you suggested later. It's getting late over here. But are you sure SearchInArray is the culprit here? The profile says it's using around 10% of the resources that scr_HexNeighborString or more specifically the script VariableToArrayXY called within it does. And I don't have any idea how I'd get a hex's terrain without looking it up in the corresponding array one way or another.

The "ever growing array" you mention is the array I save each hex into so I can reconstruct the path when I finally find GoalXYZ. I can't imagine how, but if I can do without it please tell me.

And map "generation" is randomly assigning each hex a terrain type when I set up the map. It's basically just so I have something to test on and in no way close to what I want to have in the end. The end goal is continents, islands and big oceans.

>>21385

Will look at when I wake up.


600642 No.21389

>>21388

Well, earlier, you said that scr_VariableToArrayXY is an older version of scr_SearchInArray, and your code above makes no mention of VariableToArrayXY, so I assume that it was simply replaced by scr_SearchInArray calls. The profile results you posted more clearly point to VariableToArrayXY as being the location where most of your pathfinding time is spent, about 44% of the application's time. The rest of your pathfinding code accounts for about 4% of the application's time. You also mentioned that you're doing some array searches because GM doesn't support 3d arrays, and I suspect that that may be related. The way you are using SearchInArray seems to be an attempt to get around the apparent lack of custom data structures in GML? I don't know, like I said, not sure what GML can and can do, since I have no experience.

A better way to get around this would, I think, be to create a Map (the data structure, not a traditional map) for every hex, containing all of the details for that hex. You'd have a key value pair for the hex's terrain, visited state, each coordinate, it's movement cost, and the current lowest cost to get to the hex in your current pathfinding search. That's only 7 items to search for per hex.

Using an array for each of those 6 or 7 values you need to track will only get continually worse as the number of hexes visited increases.

Again, I'm not familiar enough with GML, but if you can make an array of maps (or an array of pointers to the maps for each hex), that should be far more efficient. Not quite as efficient, I think, as using a more capable language, but still far better than using arrays the way you are doing.

Another recommendation is to see if there are pathfinding extensions available that will do all of this for you. I quick google search for gamemaker pathfinding showed a result of exactly that type from 2013. Not sure if it is still usable/updated, etc., but it might be worth checking out so you can avoid re-inventing the wheel (unless of course you are intrigued with this particular wheel, it's a fun wheel to figure out!).


307322 No.21390

File: 1440886138409-0.png (343.81 KB, 1638x1071, 26:17, 003.png)

File: 1440886138413-1.png (399.82 KB, 1893x1085, 1893:1085, 004.png)

File: 1440886138415-2.png (317.23 KB, 1376x1087, 1376:1087, 005.png)

>>21389

I couldn't sleep so implemented the visualization you recommended. All hexes with numbers were checked. The number is their y in the array, thus the order in which they were first searched. Is this how it's supposed to look?


600642 No.21391

File: 1440887509484.gif (49.71 KB, 210x210, 1:1, Astar_progress_animation.gif)

>>21390

I think, probably not; however, the fully random nature of your map generation may be interfering a bit.

In general, though, the A* algorithm tends to swiftly hone in on the goal the moment a straight line to it is available.

However, from what I see, once your implementation gets to the spot labeled 656, it should immediately make a bee-line for the goal. Instead, it searches another neighbor of the previous hex, then moves forward, then searches two hexes nowhere near the path first, all the way over to the east of the goal.

Honestly, it looks almost like a simple breadth first search, for that reason alone. In general, an A* search tends to make a bee-line towards the goal, then fills in around that beeline until it circumvents the obstacle. It tends to continue that until it reaches the goal, or fills up all accessible spots of the map. In general, it rarely searches further away from the goal unless an obstacle forces it to. The animation posted gives a sense of how it moves when coded properly (from wikipedia).


600642 No.21392

>>21390

Adding to that, one thing I would definitely look into is how your algorithm works with no obstacles at all. It should follow two straight paths, unless the goal can be reached with just one.


307322 No.21393

File: 1440889833903-0.png (24.03 KB, 689x893, 689:893, 006.png)

File: 1440889833914-1.png (23.17 KB, 1653x118, 1653:118, 007.png)

File: 1440889833915-2.png (213.25 KB, 1817x997, 1817:997, 008.png)

File: 1440889833915-3.jpg (6.08 KB, 246x205, 6:5, CommitSudoku.jpg)

>>21392

Okay, I 100% fucked up somewhere. Anyway, I'll be off to bed. Thanks again for helping me.


600642 No.21399

>>21393

Well, I had a bit more time to take a look at things. I'm going to have to implement some sort of A* pathfinding myself sometime soon, so why the hell not, eh? Your results for a clear, uniform field aren't entirely odd, though the third one is a little more random than I was expecting. It could be that A* acts a little less consistently on a hex grid, but the odd shape of the northeast side of the searched area is... odd. The resulting path was optimal enough due to symmetry of movement.

I'm used to the terminology used on wikipedia's explanation and pseudocode, so my questions are going to use that terminology.

Why are you concerned about 3D? All I see here is a 2D hex grid. While there are technically three dimensions of movement on a hex grid, that's not at all important to implementing a search. The only thing that is important is to know what any hex's neighbors are.

You're using the variable name dsp_Frontier... is that equivalent to the open set? I think it is, but I want to be certain.

What represents the closed set? arr_Visited?

Is the use of CombinedString your way of keeping track of the parent of a hex? I'm pretty sure that's the case, but again, wanna be certain. I don't think this is causing speed problems, but I would not at all do this this way. I'd use ds_map_create to create a map to store this data. From the warnings in the GML documentation, though, it sounds like their implementation of maps is inefficient, but I bet you'd not notice that except maybe on full map crossings if you can fix the major slowdown.

In your section commented with "New path is shorter, replace old path", you don't actually replace the priority of the value, you actually are adding a new value/priority pair to the priority queue without removing the old one. Not sure if this will cause issues (in fact, I suspect it wouldn't do anything but maybe slow things down a bit), but if you ever need to squeeze every last bit of speed out of things, fixing this might help.

I still think scr_SearchInArray is your biggest problem. If anything I would suggest creating three maps (ds_map_create); one to which you add closed hexes (things that are in the closed set), one to which you add hexes that are in the open set, and one final one which would store the parent of the hexes (rather than using your combined string approach). Doing this, might just solve the last two issues, also. Again, it sounds like GM's map data structure implementation isn't quite efficient, but I'd still wager to say this would be the better way to do things. It might be worth it to see if there is a better map data structure implementation available as an extension to GM.

Finaly, one thing that bugged me, When you are testing to see if the previous path is shorter, you can instead test if the previous path is longer and get rid of that empty { } code block. I have no idea if GML will optimize that empty code block away, and I kinda doubt that it would.basically, change:


if TotalMCost >= arr_Visited[ 2, var_ArrayY] {/*Previous path was shorter, do nothing.*/}
else

with


if TotalMCost < arr_Visited[ 2, var_ArrayY]


8f52b9 No.21408

File: 1440927769695-0.png (241.9 KB, 1916x989, 1916:989, 009.png)

File: 1440927769696-1.png (202.06 KB, 1916x1063, 1916:1063, 010.png)

>>21399

>Your results for a clear, uniform field aren't entirely odd, though the third one is a little more random than I was expecting.

I'm somewhat sure it isn't supposed to look like that. Especially since there are sometimes holes in the checked hexes. The results have always been optimal though so until I see it bug out I'll assume they always come out correct. This is after dozens of tests mind you as I pretty much always had an eye on the pathfinding and most of the time threw in a path or two when testing other stuff.

Which brings me to the most important issue. I'm convinced that checking a few hundred hexes less isn't going to really fix my issue. What's truly broken is that I'm searching the entirety of a pretty big array 6 times every time I'm checking a new hex. The way to fix this is to rewrite the way I store the hexes so their X,Z coordinates are the same as the array's X Y. That's likely to take a day+ and generate tons of bugs. But afterwards I can just find the hexes via math and plug their coords into the array without searching. Which I presume is going to speed up pathfinding by a factor of ten at least.

>Why are you concerned about 3D

Hex grids are complicated because you can't easily find their neighbors if you just dump them into an array. That's because every second line is offset. However hexes have 6 neighbors just like cubes and share a lot of other similarities with them as well. So if you instead use cube coordinates for them finding their neighbors becomes pretty trivial and a lot of math for AoE or LoS gets tremendously easier as well.

>You're using the variable name dsp_Frontier... is that equivalent to the open set?

That's the priority queue, yes.

>What represents the closed set? arr_Visited?

If I don't misunderstand the wiki article then yes.

>Is the use of CombinedString your way of keeping track of the parent of a hex?

The use of CombinedString was needed in a previous much worse version of the script. It currently serves no purpose and its removal is already on my to do list. I'll do that after I rip the very core out of everything i did until now and then somehow try to make what I didn't replace work with the new storage system. Oh happy day.

>In your section commented with "New path is shorter, replace old path", you don't actually replace the priority of the value, you actually are adding a new value/priority pair to the priority queue without removing the old one

I don't think I am doing that. The old priority queue entry gets deleted when I initially read it. That's what CombinedString = ds_priority_delete_min(dsp_Frontier) at the beginning of the while loop does. What actually gets replaced is the entry in the array. If you look at the code I'm replacing the line where I found the hex instead of adding a new one.

>get rid of that empty { } code block

I remember I did that deliberately when coding it but I can't quite remember why. Might just have been readability with the intention of changing it later. I'll mull it over and if I can't think of a good reason I'll change it.


c43cf7 No.21435

>>21297

>So the question is how do I cut that down to < 0.5 secs hopefully on maps even larger than this?

>Also I guess: Pathfinding general.

This is above my pay grade, but I heard about GPU pathfinding using the parallel processing to run concurrent algorithm. Not sure how much shiny graphics need to be sacrificed for better AI responsiveness.


8f52b9 No.21438

File: 1440980790851.png (69.64 KB, 1885x811, 1885:811, 011.png)

Happy news. I changed my coord system so I don't have to search Cube coords in arrays anymore. That reduced the time the pathfinding script runs by roughly 85% or ~93% if you count from the first version shown in the webm.

Also I'm pretty sure I found out what fucked up my A*. No idea how to really solve it right now, though. Basically what happens is that when two entries in a priority queue have the same priority Gamemaker picks the newest one. The behavior A* needs is for the oldest one to be picked instead. Now I have a workaround but it involves searching the priority queue two times more per while loop. Viable for testing but in practice this shows very mixed results in terms of speed.

When I tried it out with no obstacles A* looked like it was a Greedy Best-First Search algorithm in regards to how many hexes it checked and the solution was instantly there even on a 111x70 map. However on one of my randomly generated maps it checked basically the same amount of hexes as what I had before.

As a side note: Does anybody have an idea how to make the heuristic play nice with wrap around maps?

>>21435

With Gamemaker you are pretty removed from the hardware. I think it's very likely it does this on its own or not at all. My tip is on not at all.


600642 No.21440

>>21408

>>21438

>That's because every second line is offset.

That's the hard way to do it. The easy way is to just be consistent, and make each row down be offset to the right half a hex. If you're doing wraparound, everything works out just fine with no additional considerations. If not, just do X coord modulus map width, you'll get the correct X to use no matter what. And the end result is that the neighbors are consistent, as are the directions.

>when two entries in a priority queue have the same priority Gamemaker picks the newest one.

Hmmm. If GML allows real values as the priority for your priority queue (it ought to), and if your costs will always be integers (Easy to design), then you can accumulate the costs, then add a fractional value to sort out hexes the way you want them sorted. Kinda roundabout, but if you just keep a count of the number of hexes visited, you can use that times something like 0.00001. Add or subtract it from the priority depending on the sort order needed.

>However on one of my randomly generated maps it checked basically the same amount of hexes as what I had before.

Yeah. That's pretty expected in "porous" maps. Which is the best way I can describe a fully random map like that. Which is also the reason I suggested not testing on them. lol

>Does anybody have an idea how to make the heuristic play nice with wrap around maps?

Calculate two distances along the X axis. The first is if you go east only. The second is if you go west only. Use the smallest distance. If you want the Y axis to wrap too, do the same calculation with the Y coords.

function xDistance(startX, goalX)
if goalX > startX then
eastDistance = goalX - startX
westDistance = mapWidth + startX - goalX
else
eastDistance = mapWidth + goalX - startX
westDistance = startX - goalX
end
if eastDistance > westDistance then
return westDistance
else
return eastDistance
end
end


d92398 No.21449

File: 1441017184370.png (17.45 KB, 1443x967, 1443:967, 012.png)

>>21440

>That's the hard way to do it. The easy way is to just be consistent, and make each row down be offset to the right half a hex.

Yeah, it also plays nicer with the storage of hex data and makes some math easier. I'm already using a rhombus. It's why I was asking about wrap around stuff.

>add a fractional value to sort out hexes the way you want them sorted.

Worked like a charm. Should have thought of that myself.


c43cf7 No.21589

File: 1441338022659.jpg (13.08 KB, 117x120, 39:40, threat_nonstandard_spaceti….jpg)

>>21438

>With Gamemaker you are pretty removed from the hardware. I think it's very likely it does this on its own or not at all. My tip is on not at all.

I guess that goes back to the old question of whether to build game on top of graphics library or build on top of game engine.

>>21382

>(or if you know such changes are rare enough to simply re-calculate affected paths). I wouldn't say, though that you should store a path for every tile moving to every other tile. I'd group the terrain into logical areas, then come up with some paths between those areas if this is your goal.

Pardon me for cutting in, I'm curious about more information and details in that. In what metric can the map be divided into areas? Is the area-level path used for trimming out all the tiles not in the area-level path? How much hierarchy should a map have by grouping tiles into areas, areas into districts, districts into regions, regions into departments, departments into zones, zones into theaters, etc.? How often should higher-level paths be updated with regards to fortification and canals being captured? So yeah, pathfinding general...


1213f4 No.21611

File: 1441374379471.png (33.72 KB, 346x193, 346:193, 1437376768321.png)

>>21297

20 seconds for map this little? Man, I made same crap in a fucking game maker and it finds the path in under 50 ms.

I don't claim to be an expert, but so it happens that I'm the fucking expert. Feel free to ask.


34de66 No.21622


860963 No.21640

>Game Maker

Oh boy. And I'm not saying that to be a programming elitist, but for large-scale pathfinding, you're going to want to seriously optimize that shit.

I can't really contribute and don't feel like reading the thread, but a depth-first search is probably your best approach. Civ V is probably a good game to copy it from since the pathfinding is pretty fast and its modern, which means documentation - you can probably find some post mortems or papers written about certain aspects of the game (I found something once about how the terrain textures were procedurally generated, for example). Also, because the map in that game is immutable (the base terrain type, anyways), pathfinding can easily be broken into graphs based on island groups.

This is a good website for pathfinding in general

http://www.redblobgames.com

If I were to implement it, my first naive approach would probably be to have each cell act as a node with an edge connecting it to other cells/nodes, with a cost associated with it. Then, it simply becomes a matter of traversing the graph efficiently and favoring low-cost nodes first (although this might fail if it runs into a "pocket" where a low cost is surrounded by high costs)


860963 No.21641

File: 1441402392549.jpg (207.94 KB, 1920x1080, 16:9, asdf.jpg)

>>21622

Bookmarked fucking hard


da8281 No.21670

>>21622

It looked incredibly neat, but he didn't say much about handling potential obstacles like units. With A* / dijkstra you can just make the tile have infinite cost, but that wont work when you've precomputed a ton of things.


600642 No.21688

>>21589

the metric would depend on the map. if bottlenecks are common, I'd search for bottlenecks and separate areas by those bottlenecks. Another way might be to randomly choose centers around the map to use for a voronoi diagram to separate out map tiles. another possibility is to calculate the number of tiles within a distance of each tile that can be reached, then use the tiles with the highest number as the centers for voronoi diagrams. Your map generation system might help with this too.

I don't think I'd use more than two levels for this in anything Civilization-like. Lowest level would be for the actual tiles, the highest level would tell you what areas' tiles to use for the lower level pathfinding. You want the difference between pathfinding tiers to be large, so the upper level(s) can prune away unimportant areas while still allowing the A* algorithm to shine in the lower level. The effectiveness of two tiers like this would be tricky if your players ever have a chance to build high speed roads in circuitous routes that would circumvent pathfinding like this.

As for updating, I wouldn't see much need to update the higher level structure unless somehow you can completely eliminate the links between areas or greatly decrease the potential costs to move from one area to another. You'd want to be sure you don't update things so often that you lose any benefits of a high level structure, You'll probably have to test this as you go, so it would be a good idea to make this a configurable value you can update as you work on the game. One big issue with a two tier system like this will be how to calculate the heuristic cost of moving from one area to another, and how expensive it is to calculate that cost.

That expense of updating the costs of the higher tier areas can be reduced by having the areas be smaller, and by updating during player turns (since in civ type games, the game waits on the player to decide things quite a lot). Again, you'll have to play around with this to see how it works. Also, you'll have to decide how to calculate the costs. should it be the highest possible cost of a path from one to another area? The average cost over all possible combination of tiles (could get incredibly expensive to update)? The cost to go from the center-most tile of one area to the center-most tile of the next area (would ignore possibly more efficient corner paths)? All of this is stuff you'll have to play around with if you want to see if it will work for you.




[Return][Go to top][Catalog][Post a Reply]
Delete Post [ ]
[]
[ home / board list / faq / random / create / bans / search / manage / irc ] [ ]