Ok, I’ve got time to answer a few more questions. Been mountain hiking the last few days, but got some time now.
Sorry for the especially slow reply, @HuangNg. It seems that since your reply was your first, Epic held it for review so that I could not see it until later. Ok, to your question:
So, I try to explain how the grid is organized in some of my newest videos, which you have watched. I’ll reference these in my answer. GridLocations, GridEdges and GridUnits are the three most important TMaps for interacting with the grid. They store the actual world locations of each grid index (GridLocations), what tiles each tile is connected to for pathfinding (GridEdges) and what tiles are occupied by units (GridUnits). They can all be found in the variables of BP_GridManager (make sure you look at the real parent blueprint and not child actors like BP_GridManager_Hex). If your grid manager does not have these variables you are using an old version of the toolkit and I recommend you create a fresh project with the latest version.
If you understand how the grid indexes are related you should be able to create any arbitrary shape you want. As I explain in my tutorials each tile you go in the X-axis increases the grid index by 1000, while each you go in the Y-axis increases the index by 1. So if you wanted to draw a line of four tiles in the positive direction of the X axis from tile 4004, for instance you would want to get tiles 4004, 5004, 6004 and 7004. Add tile 7005 and you would have an L-shape. A diagonal would go 4004, 5005, 6006 etc. For a game like chess, where the movement of each pawn is limited and clearly defined you can get away with hardcoding these patterns. For a more complex games you might want to make your own functions for patterns of arbitrary size and direction. I don’t know what you are planning for your game, though. For this you would indeed want to create functions similar to what I do with GetIndexesInRange. There are many resources online for drawing various patterns on grids. If you understand my explanation of relative tile positions as described above and in my videos, applying these resources to my toolkit should hopefully be quite straightforward.
For a game like chess you probably don’t need to use the pathfinding functions at all, as the movement of chess pieces do not curve around and avoid obstacles. In such a game you could just get the tiles like described above, store them, and move the chess piece directly to the end location if a valid tile is clicked. You would do this in a similar way to how I set things up in BP_Ability. You would probably want to first create a generic chess movement ability based on BP_Ability (say BP_Ability_Chess). In the activation of this ability you would have a function that would find the appropriate tiles you can move to (perhaps FindChessMoveTiles?). In ServerInteract you would add a branch that checks if a clicked tile is in the array output by FindChessMoveTiles, which if true leads to an ExecuteAbility function which moves the chess piece and removes any enemy chess piece on the target tile. Then you could create ability child blueprints (say BP_Ability_Chess_Knight) which override the FindChessMoveTiles function with the specific movement pattern of that unit.
For your question on finding reachable tiles, you should use the RunPathfinding function from BP_GridManager. This function finds tiles in a specified move range from a specified starting point.
Though it is hacky, it is hopefully a good starting point. It might be a while before I get to improve it, as there are many other things that I want to fix before I revisit climbing. I’ll let you know if I think of any improvements.
Hey, not a stupid question at all. The way the toolkit handles this kind of stuff is fairly non-standard, so I understand if it takes some getting used to. If you have not done so already I recommend you watch my three videos on the Action System and my three videos on Custom Units. They cover the sort of stuff you are asking about here. If you look at the Event Graph of BP_Unit_Anim you’ll see that the animations are driven by input from an FAction struct. This struct can hold a vary large variety and number of variables and is used by the Action Systems (refer to the tutorial vids for details).
The FAction structs are set by the QueueAction macros you see all over the place in the toolkit. This system makes it simple to queue multiple animations after one another without relying on dozens of interface calls, event dispatchers and custom events. It also comes with the added benefit of making everything replicate easily. You have already seen ActionHitNotify stuff in the various attack abilties. You’ll see that in the ExecuteAbility functions for these abilities a QueueAction macro is called that is responsible for adding the stuff in the AnimateAction function of that ability to the ActionQueue. This is the macro where you should input your NumberOfAttacks variable. As I describe in my tutorials, do not use any outside variables within the AnimateAction events except those you get from the FActions struct or ones you are 100% certain will not change between the action being queued and animated.
Now that you’ve input the number of attacks into the QueueAction macro you can use them within the AnimateAction event. Within this event you can then call a new QueueAction event to animate the attack on the unit (as I do in the offensive abilities). Note that this queue must be set to immediate, as you cannot queue an action within another action. For this action you call on the unit you input the NumberOfAttacks variable you get from the FActions struct output of AnimateAction (it should be index 0 of the integer array). This is then passed along to the AnimateAction event of the unit, which is again passed along to the AnimateAction event of the animation blueprint (by default in BP_UnitAnim). Here you can use this variable to choose the number of attack animations you want to display.
Hope this makes sense. I know this can seem overly complicated to do something fairly simple, but once you get the hang of it you have a generic solution you can apply to a lot of things.
I hope my answer is sufficient for you as well, in that case ![]()