This week my focus was to make the AI more coordinated in the sense that they should not clump together/obstruct the passing lane to another teammate. In addition to this, I also aimed to make players more position oriented than running all over the pitch to open up passing lanes. So I decided to go about implementing this sort of "coordination" through positioning where each player does not deviate too much from their respective anchor positions while moving to receive a pass, and eventually drifting closer towards that anchor position while out of possession.
I went about doing this by setting a repositioning timer every time a player repositions to receive passes, which once expired, runs the repositioning logic. The repositioning logic is essentially just an if check to see if the player has drifted a certain distance away from their anchor position (this distance is exposed to reflection so it can easily be tweaked), and if so calls the MoveTo function back to the anchor position. While they are within the certain distance around the anchor position, this MoveTo function can be overriden to move them to a better passing lane as before, so it looks much more natural and organic as opposed to robotically moving back to their anchor positions with no regards to the state of the pitch around them.
This seemed intuitive to me as most of the times players drift quite far away from their positions to receive passes/make runs but eventually drift back to their original positions after a certain period of not receiving the ball.
Timer based repositioning.
In addition to most of these changes related to positioning I also reworked some bits related to the AI coordinator and how repositioning positions are determined. I've now introduced a mechanism to return the angle formed between a player, opponent and the player with the ball, in addition to the bool being returned by the IsPassingLaneBlockedForPosition function.
If the bool is set to true (passing lane is blocked), we can also get the angle by which it is blocked and pass it into the FindOpenSpaceForPlayer and using it to make sure that they always move out of the blocked passing lane.
Reworked flow of repositioning logic for each player.
Another significant change I made this week was scaling the size of the pitch down to suit a 3v3 scenario and adding in the third opposition player. This was done intentionally as this meant that there is now less navigable spaces on the pitch to move into passing open spaces. This inevitably led to scenarios where the determined open spaces where outside the field and since they are non-navigable, the AI agents simply would not move. In order to address this I wrote a function that does a raycast from the player with the ball to the open space determined by the FindOpenSpaceForPlayer function (this entire line can be considered an open passing lane, not just that specific location), and if anything static was hit along the way (which can only be the walls surrounding the pitch), then get the point that is 8 tenths (arbitrary value I chose) along the length of the line formed between the player with the ball's location and the point of the raycast impact. If there is no hit, it simply returns the original open space, as it is already navigable. You will notice these modified points show up as red debug spheres in the video demo below.
Function that finds the furthest navigable point along a line as described above.
The culmination of all these individual components I worked on this week resulted in AI that is aware of it's surroundings and carries out repositioning behavior with respect to their original positions which are predefined. The players can now move around the other team's players into spaces while all trying to stick to their own positions when required, resulting in a more complex and realistic AI behavior, enabling the player to play quick triangles of passes, which is quite an encouraging sign for this project.
A video showing off the new positioning system.
Comments