Download

[SUPPORT] Advanced Turn Based Tile Toolkit

After playing for some time with this great toolkit I have small problem with making roads.
I was thinking to make default tile cost 2 to be able to place tile_cost_1 as roads but now I have to place all tiles as tile_cost_2 and then tile_cost_1 as roads because they need separate mesh. Is there better way to do this? Or where can I look to change default tile cost from 1 to 2?

Second and more complicated thing would be to have separate cost to enter tile, based on vehicle type. For example truck should not be able to enter forest (without road) and boat should not be able to enter land. And plane should always have tile cost 1. I think It would require much more work, is there any chance it will be added to toolkit any time soon?

Another small tip/request would be to change Can_attack_with_0_move to “Attack cost” instead because some units should be able to attack few times in one turn or be able to move after attack. And maybe separate option for “attack ends turn” for that unit.
I would try to add all this to the toolkit somehow but I’m afraid how I will update it to new version without losing any changes.
Thanx and keep up great work!

Lots of stuff to reply to :slight_smile: Sorry for the late reply. I worked all of yesterday preparing a lecture for work.

No worries! I will want to do a lot more bug testing, cleaning up and commenting before I release the update, and I would not feel comfortable sending out early updates before this was mostly done. I’ll consider it when I get there, though.

Looks awesome! Glad you managed to solve your fog of war problem.

Hmm, I need more info to understand what is wrong here. How are you detecting what tile has been clicked and if it is a friendly unit? Are you using the default On Click nodes in ATBTT_Player_Controller or are you doing something else? Pathfinding should always run at the beginning of a unit’s activation, before input is enabled. Have you made any changes to the Activate Unit part of the player controller that could affect this?

Hi tutkarz. For your first question I agree that setting the default tile cost to 2 would probably be the easiest way of achieving this. This can be done in the grid manager when the edge array is originally filled, but adding the roads afterwards is a bit more complicated. The toolkit is built on the assumption that the default tile cost is the lowest, and the default Spawn Tile function ignores the edge costs of an added tile if they are lower than the current costs. It is certainly doable, but I will need to play around with it a bit. I’ll report back with my results when I have something :slight_smile:

Separate pathfinding for different sorts of units can be done in a few different ways, and the best implementation depends on the desired results. For units ignoring movement cost (such as your plane), there is such a pathfinding type implemented by default which you can select in the pathfinding type public variable of unit_parent. For the differing pathfinding of trucks and boats the easiest way to do this would be to add another such custom pathfinding (expanding the pathfinding type enum as necessary). This can be done by modifying the use custom pathfinding macro inside the pathfinding function in BP_GridManager. During the search step of a unit with pathfinding set to, say, truck, after checking if a tile has not already been added to the CanMoveTo array you would check if that tile was a forest, and if it did you would not add this tile index to the Open List or CanMoveTo array. You would create a similar branch to the custom search step for boat units to check if the considered tile was an ocean tile. To do this efficiently you would want to create an array where you can easily look up what terrain is contained in each tile. I would use an array of enums the size of the grid (GridSizeX*GridSizeY), with the enums designating terrain type. For terrain tiles I would create a new actor based on Tile_Parent with an enum variable designating its terrain type. On Event Begin Play, after resizing your new terrain enum array in BP_GridManager to the size of your grid I would loop through all actors of your new custom tile type and set the array elements of your enum array to the value contained in your custom tile blueprints at the grid indexes corresponding to the tile actors’ index variable values. Hope that makes sense.

As for the attack cost stuff, this is something I am slowly implementing, and the example game in the coming update will have something much closer to an action point system (though it is not fully realized yet).

I just added a branch to the pre-existing click event for when you click an allied tile. I didn’t change anything with pathfinding, etc. I simply turned the Boolean to true when switching to the proper ability.

On true it goes into the nodes for when you click an enemy.

6d38f70f8c900369dc6bee5263a2b08c888cc06a.jpeg
6cfa41d2d8e6ce464b9b539361890ea8e29b6e2d.jpeg

When clicking an allied unit with this ability, it successfully places a shield around the allied unit, but the unit that places it, either follows the wrong path-finding or will teleport to index 0. Sometimes it seems to work correctly. I should also mention this seems to only happen when show all possible visible tiles is set to True. I also noticed it will use the path from the last time it displayed a path while hovering.

I will send you a video.

Per-Unit edge costs

I have seen some mention of this before. Just wondering at current best practices. Say you have a forest tile where it costs an infantry unit 1 point to move through it, but a vehicle takes 2.

Would it be better to keep separate edge cost arrays for each unit type and then use custom pathfinding or just update the one edge cost array when the unit selection change to a new unit type? The second option seem simpler, but I’m unsure if there would be a real performance cost.

Thanks.

We have to make this flexible enough so when we make a game that will allow players to create their own units, they will have to be able to specify cost to enter for each tile for their unit. This makes choosing pathfinding method useless. I don’t think there is any other method that will be better than making an array of movement types for each terrain type. Because even if we will come with some kind of modifier for difficult terrrain it still will be limited and will create other problems for unusual units.

Btw is this really important to have cost to enter neighbor tiles saved as array in each tile? In my previous game I had cost to enter tile as number in that tile. So when you wanted to enter neighbor tile you were asking it how much it will cost to move there. I don’t know why current solution is better, maybe I am missing something.

Maybe we could do something like this: leave current array with entering neighbour tile cost but change it for cost multiplier and add base tile cost for each movement type for that tile. That way if in base tile cost will be 1 as default then old mechanic will be saved and by changing it to other numbers we could have plenty of flexibility. For example:

right now
(base tile cost that is hardcoded) 1 x 2 edge cost N = 2 cost to enter forest north tile

new solution
(value stored in tile for each move type) base tile cost for forest 2 x 1 edge cost changed to multiplier = 2 cost to enter forest
but it is possible now for example to do
base tile cost for forest 2 x 1.5 edge multiplier cost when moving NE = 3 cost to enter NE tile

I don’t know if this is making any sense :wink:

Okay, I figured out the problem. You need to also modify the nodes in Display Path on Hover as well. Add the following:

SRmN3iX.png

Since you are modifying the very core of the pathfinding it is worth thinking about performance. The Search And Add Adjacent Tiles function is repeated a ton of times during pathfinding, so it pays to keep it as efficient as possible. I have worked hard to make it as efficient as possible, so you should be able to add a lot to it without noticing any frame dips for most games, but you should still try to be smart about it. The simplest and most efficient way I can think of is to add new custom Search And Add Adjacent Tiles functions and add them to the Custom Pathfinding macro and use these in conjunction with a new grid sized array for terrain.

First create a new enum for terrain, including the terrain types you wany (I added none, forest, ocean and mountain). Then create a new actor parented to GridActor (which has code for getting the correct index based on its placed location), maybe called GA_Terrain. Add a terrain enum variable to this class. Make a separate child actor of this actor for each type of terrain and add meshes/sprites to those (for my tests I just used a text render).

Then in BP_GridManager add a new array of terrain enums called Terrain Array (or whatever) and resize this to be the size of the grid. This probably makes the most sense to do in the Generate Gameplay Grids function. Like so:

7a86ea6caa2a6ce11353c0d2c2c8518a76f0e478.png

In the Add Viewport Terrain to Arrays function add the terrain enum values of the terrain tiles you have placed in the world to the Terrain Array at the appropriate indexes like so:

4rmosmU.png

Next expand the PathfindingType enum and add names for the various movement setups, like infantry, naval and heavy. For planes you can just use the Ignore Difficult Terrain pathfinding type. Duplicate the Search And Add Adjacent Tiles function and follow the example of implementation of other such functions in the Custom Pathfinding macro in BP_GridManager. Like so:

C7110A0.png

In these custom functions add a switch on the enum of the tile edge to be checked and set a terrain cost/refrain from adding the tile to be searched in the open list based on the terrain enum value of the Terrain Array at the grid index you are considering. Also, replace connections from the the EdgeArray ForEachLoop with a terrain cost based on the result of the switch. Like so:

a065ebb653d4964e9eab535426dbb1d9afef469b.png

In the function I made for infantry above I set cost to be 1 if no terrain is specified, 2 for forest and impassable for ocean and mountains. For naval units I only proceeded with the function if the terrain was ocean. Heavy is the same as infantry, but without proceeding with the function if the terrain is forest. You would add more such types of pathfinding is necessary. There are more elegant ways to do this where you can contain everything in one function, but it will be less efficient. If you have a limited amout of such movement classes this would be my recommended solution. Here is a screenshot of Mr. unit_boat being a boat:

fd6f7d9bb12463b30930c48a81eebfc964598e09.jpeg

If the method above is not flexible enough (though I think it should be in most cases) you could add a terrain array and a cost array to Unit_Parent. Then you would get a reference to the current unit during Search And Add (make sure to set this up early in the pathfinding so you do not need to cast every loop), and check the cost value of the unit’s cost array against the terrain type of the tile being entered. It would be a lot less efficient, though. If the first method is impossible and you need to do something like this instead I’ll try to think up a more efficient solution.

For most games it does indeed not make a difference, but I’ve always strived to make the toolkit as flexible as possible and having the possibility of having various costs for entering the same tile from various directions can be utilized in some games. You could for instance set things up so that it costs more to walk up, but not down a slope, have rivers that slow you down when you walk upstream, but speed you up downstream etc.

I hope my answers have been helpful and that they will help you add the features you need.

Been a while since I posted on here!
Hope you are doing well Monokkel!

Debating a new type of map for my game, *sorry if this issue has come up previously
The map would basically be an ocean, but platforms where the units can walk.
Now as it stands the grid doesn’t need a mesh to be there for units to walk (so by default they could walk in the air)
So I was trying to think of the best way to check where there are spaces, or rather not spaces, and make those tiles impassable.
Just did this with a plane -400 from the grid and a extra linetrace in the “Add Viewports to Array” function.
Here i checked visibility, if the hit location Z = X make that tile impassable, which worked too well and now ALL tiles are impassable.

Any suggestions?
Screenshot 2017-02-01 22.58.22.png

Hello LDodds! Long time no see :slight_smile: The sort of functionality you are describing is included in the toolkit by default. If you disable collision plane walkable and make sure your bridge tiles block PathTrace and your water does not it should work automatically.

This is awesome. Thanks. It looks like it will let me do what I want. I think my only suggestion would be find some way to make the custom pathfinding a proper function for overriding… As it is, you have to alter the base class to make this work which will make it more difficult to integrate any future updates you release.

Thanks again.

Yes, they did. Thank you for your time and waiting for new version so I can start making changes there.

No problem! I had been wanting to test something like this out for a while. I agree that it would be much more elegant to use some form of function that can easily be overridden. However, in this particular part of the toolkit I am even less inclined than usual to sacrifice performance for elegance. But if I think up a better solution I’ll make sure to post about it here. I’m also open to suggestions.

For the most part the new update is fairly close to the current version and most of the new features are contained in child blueprints of the various standard toolkit blueprints. I have still done quite a few minor alterations and fixes on the standard blueprints, but it is close enough that you should not worry too much about adding your changes now. Just make sure to mark them clearly so they are easy to port over once the new update is out.

Alright I’m working with this part again. I’m running into an issue where pawns will go to index 0 when an enemy target is within movement range, but inaccessible do to the available spaces being occupied by either impassable terrain or other enemies. I’m not sure whether the issue stems from this fix, or something I changed elsewhere, but you may want to check into it.

I’ll let you know if I find the solution myself.

I found the issue, and I can reproduce it in a blank project.

https://dl.dropboxusercontent.com/u/3332789/asdfgaseds.jpg

Just do this, set default pathfinding to pass through friendlies.

https://dl.dropboxusercontent.com/u/3332789/dsgasd.jpg

This is why. The AI sees that tile as visible even though there’s no tile it can actually attack it from

You can also reproduce this with player units, they’ll run to index 0 as well, but properly path there atleast.

Hey Selentic, I’m looking into this. I’m only able to reproduce it if I also set “square visibility” to false for the unit. If this is also the case in your project I know the reason for the issue, as the diagonal tile from the target is incorrectly thought of as adjacent during pathfinding if Pass Through Friendlies is true. I’ll get right on finding a fix, but could you confirm that you are not seeing this bug if square visibility is set to true?

This is correct. I use diamond visibility.

Ok, so diamond visibility was not really the cause of the problem (though it was necessary to reproduce the bug with the exact setup you pictured). The problem is that the AI naively assumes that any unit it finds during pathfinding can be reached and attacked from an adjacent tile. Normally this holds true. However, if the unit can pass through friendly units the pathfinding will find units that might be surrounded by other friendly units, meaning there is no unoccupied tile from which to attack. Sorry that you have been a bit of a guinea pig for the “pass through friendlies” option, as it is not something I have tested as much as units with standard pathfinding.

The good news is that all this is fixed in the coming update. I have made big changes to the AI controller which makes it quicker, less convoluted and more stable, and in the process I also solved your problem by accident. However I’m hoping you can live with this issue until the update is out. I could certainly think up a solution within the current framework, but it would be outdated as soon as the update is out.

My AI controller is significantly extended from the original, so it’d be preferable to know what I need to change to solve the issue with the system I have now, unless it’s something that I can easily integrate afterwards into my system.

Also isn’t the issue in pathfinding, since it affects players as well?

It should be something that is easy to integrate. It is a combination of several functions I now use to determine what units are reachable by the AI. These should be easy enough to replace with the old ones, but it will take some time to post all the nodes related to these new functions in this thread. Therefore I hope you can wait until the update is done. If you feel after the update is out that you will not want to use the new nodes for whatever reason I’ll think up a custom solution for you.

Well yes, sort of. It is a problem with what units the pathfinding considers to be reachable. This could be fixed within the pathfinding function itself. However, that would require taking all units reached by the pathfinding and for each of them look at all surrounding tiles to determine if at least one of them is reachable and unoccupied (which is expensive). This can be done much more efficiently in the AI and Player controllers where it is possible to narrow down the amount of units you want to check. I would still prefer the Reachable Pawns Array to only contain the units which are actually reachable, though, so I will give this some more thought.

As long as it’s simple enough to integrate then it shouldn’t be a problem. That begs the question though, how long until you release the update?

The issue for me is that I would prefer the visible tiles to be rendered accurately.

Unfortunately, the pathfinding and visibility functions are one of the things I’m not really familiar with at this point, but it’s my understanding that visibility is calculated after pathfinding, using the reachable tiles as a base to calculate what’s visible using the unit’s range value. Would it be possible to simply remove occupied tiles from that list for calculating visibility, and then add them back in afterwards?

My aim is to release it along with UE4.15. They seem to be making quick progress, though, so maybe I’m a bit optimistic :stuck_out_tongue:

You are absolutely right. I realized this shortly after my last post. I went to bed (it is pretty late in Norway), but kept thinking about it and then I came up with a solution. Couldn’t sleep without implementing it first, so here is my solution. I’ll show the nodes without explaining too much as I need to get up for work early tomorrow. I’ll explain then if you have any questions. There might also still be problems with this solution I have not seen yet, as I’ve only had time for limited testing:

In Pathfinding (yes, that is a new function. I’ll get to that next):
H96R038.png

New function (left side):
dXXG8OT.png

New function (right side):
NQj9zuH.png

In Player Controller (in Event Graph. Under Display Path On Hover. Bottom pretty par right):
6GtLFO3.jpg

Also in Player Controller (by the Initialize Movement - Step 1 custom event)
74c7169da62c58b8bdc3d566893719021ba5d4ab.png

AI should work with this solution without modification, even in the old version. Let me know if it solves your problems. I won’t respond for at least another six hours, though :stuck_out_tongue:

Edit: the function above can possibly be made slightly more efficient for this specific purpose by limiting the tiles checked to the ones surrounding the potential targets. Getting these indexes requires using one of the visibility functions, though, so it would probably only be better for large movement ranges. This function also has other uses as a more efficient way to get all possible targets within range compared to the old version for the AI which is what I originally made it for)