@AdventPalace: Ok, it seems I misunderstood you then. Thankfully Selentic understood perfectly and gave a great solution. Having thought it through I really think this is a great way to make a unit spawner, so I would go with Selentic’s method. @cbdeakin: I’m glad you like the toolkit! I’m modeling the skill system in this game example after XCOM, so you can indeed choose between several skills from an UI menu. The UI is pretty basic, but functional. This is how it looks:
I’m not sure if taking screenshots of parts of the skill blueprints will make much sense in a vacuum. They are all dependent on a lot of parented functions and interactions with the HUD and Grid Manager, so I would need to post a whole lot for it to make sense. If you have any specific questions about the skill blueprints I can answer them more easily.
The way the skills interact with the unit blueprints is that the units have an array of skill classes which decides what skills each unit has. At the start of the game each unit spawns a child actor of each skill class. On the start of a unit’s turn the UI is updated based on the current unit’s array of skills and each button in the HUD gets passed a reference to each of the skill blueprints. When a skill button is clicked, the activate skill event is called in the skill, which sets it as the current unit’s active skill, enables its tick and opens gates to enable mouse hover and mouse click events.
The AI works differently and has a separate decision tree for each skill. At the start of an AI controlled unit’s turn it cycles through all of its available skills and runs The AI Check Value event, where it considers all possible targets for its skill and assigns a value depending on the likely outcome. Then it chooses the skill with the best predicted outcome and executes it. Work on AI has been by far the most time consuming part of work on this update, but I feel a skill system would be half baked if the AI units could not also utilize it well.
I just found a bit of a glitch, or maybe I just missed a step, but when I added empty tiles to the basic toolkit and turned off collision plane walkable, the range trace meshes, and path line didn’t show up. I think they are hidden below the new tiles? I can walk around, I just can’t see where I can walk to.
Huh, odd. It seems like the Static Mesh of Tile_Hex_Empty was set to 0.5 unreal units above its CustomGridAnchor, meaning it occludes the marker meshes. Set it to 0 and it should be fine. I’ve now fixed it for the in-progress version for the next update. Thanks!
I’ve now come far enough with the update, that I’m pretty confident I will be able to release it around the same time as UE4.15 is out, by the way.
Hi ,
Thanks for your helpful reply. I’m pleased to see how much progress you’ve made with the UI and skills. I’m sure I’ll be able to learn a lot from the AI trees you are making as well. Is there anyway we can try out the additions you’ve made to skills and the UI in our own projects, before the next version is officially released?
So I have a working bubble shield (protects allies) that I can currently only place on the ground or on an enemy. However, I want to only be able to place it on empty tiles (already working) and Friendly units, while NOT being able to place it on enemies.
Currently, I added two new booleans: CanTargetFriendlies and CanNotTargetEnemies. With the first boolean I placed a CanTargetFriendlies branch after clicking a tile of a unit in the player’s faction or allied faction. On true it goes straight to the first node in the, “Attack clicked target if within reach, or move towards it if it is not,” comment box. However, right off the bat, something is wrong. It seems that the cost of the move, and the path-finding are not set, since it either uses the previous path-finding results or sends the unit to grid index 0, but the movement cost prints as 0. I have implemented the CanNotTargetEnemies bool, by placing a branch right after it checks the faction (working as intended).
This would be a very helpful feature for including friendly abilities, like shields and healing abilities.
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 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
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.
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 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.
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
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:
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:
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:
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:
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:
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 !
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.
Hello ! Long time no see 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.
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.
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?