As part of the Game AI module I took at Goldsmiths University on February 2017 it was needed to design, implement and playtest an AI-based game. There was no technichal constraints or limitations. The idea was making something that could be useful later for my research and, as I need to use the GVGAI Framework, I opted to use it in order to get familiar with it. Valve’s Portal series are in the top of my favourite games list (check them out if you haven’t), so I decided to make my game based on them.
The GVGAI Framework it is a JAVA-based open source framework used for the General Video Game AI Competition.
It supports arcade-style 2D games built in VGDL language. These (1 or 2 player) games can be easily set up to be played by a human or a controller. Because of the GVGAI competition, the framework is fully documented and there are lot of games an sample controllers available.
For the assessment, I simply forked the framework in my own repository to easily create a new game and a controller for it.
The Video Game Definition Language (VGDL) was initially implemented in python and ported to JAVA to be used in the framework for the competition. To create a game, it is just needed to declare two files:
Game description file. In this file it is declared the termination rules, objects, their interactions and how they should be mapped when defined in the level description file.
Level description file. This file should contain a 2D matrix of symbols corresponding to the elements defined in the mapping section of the game description file.
As a detailed explanation about the language can be found in the framework wiki I will not get into details in here. An easy example, taken from the Framework, are the description files for the game Sokoban. As shown, just a couple of lines of code are enough to create a very simple game, pictured below.
BasicGame key_handler=Pulse square_size=40
SpriteSet
floor > Immovable img=newset/floor2
hole > Immovable color=DARKBLUE img=oryx/cspell4
avatar > MovingAvatar img=oryx/knight1
box > Passive img=newset/block1 shrinkfactor=0.8
wall > Immovable img=oryx/wall3 autotiling=True
LevelMapping
0 > floor hole
1 > floor box
w > floor wall
A > floor avatar
. > floor
InteractionSet
avatar wall > stepBack
box avatar > bounceForward
box wall box > undoAll
box hole > killSprite scoreChange=1
TerminationSet
SpriteCounter stype=box
limit=0 win=True
wwwwwwwwwwwww
w........w..w
w...1.......w
w...A.1.w.0ww
www.w1..wwwww
w.......w.0.w
w.1........ww
w..........ww
wwwwwwwwwwwww
The game I created for the assessment is based in Valve’s Portal where 2 different player have to reach a different goal in order to win:
Human (subject). Their goal is collecting the cake avoiding being killed, either being shot by the other player or steping into the traps allocated around the level. The player is allowed to move up, down, left or rignt and shoot to create Portals in the walls (one orange & one blue). It is possible to teleport between the Portals created in order to reach different areas of the level.
Turret. Its goal is killing the subject before they collect the cake. The player is allowed to move up, down, left or right and shoot a laser that immediately kills the other player.
Other elements needed to implement the game are:
Below it has been included a screenshot of the game created containing all the elements described: The turret has shot a laser trying to reach the human player, who has moved down to avoid it. The human player has created two Portals to be able to move to the area below (from the blue Portal to the orange Portal) without stepping into the traps in order to be closer to the cake.
As part of the assessment, it was needed to include some kind of AI in the game. It was decided to develop a controller for the turret, focused on finding and killing the human. An overview of what it was implemented for the AI behaviour is:
To allow an efficient way to move around the map, it was decided to use the A* algorithm, considering every move with cost 1 and having the distance between the Start and Goal positions as the heuristic.
In order to implement the algorithm, it was needed to identify the navigation matrix (valid positions for the turret), which would be used to identify the valid neighbours on-the-fly when the algorithm was run. For the level created, the navigation matrix is marked in orange-colour in the image on the right.
Once the A* algorithm returned the list of positions that should be followed to reach the desired position, it was needed to convert these into valid actions to be followed by the turret. In the example below, as the turret is orientated to the right and the desired movement implies going down, it is needed to add an “extra” action to turn and face the desired orientation:
If the human is in-sight, the logic is adapted to enter this state and plan the list of actions to kill them. If the turret has a list of actions already planned but the previous state was not targetting the previous plan of actions is unrelevant as this is the most important status.
When the human is not in-sight, it is needed to find the best spot to be able to target them. The pathfinding algorithm is called and the actions planned to reach the desired position. If, while these list of actions are being carried out, there is no change of status, the turret would keep following them.
It was needed to take into cosideration the existance of different areas in the level, which are those limited by walls and traps where the human is forced to use a Portal to move between them.
It was included an interruption in the seacrhing plan for the special case of the human not being the same area as they were when the pathfinding algorithm ran. If it is detected that the human has changed from an area to another, a new search is run to update the movement-actions plan in order to get closer to the player.
To check if the human is in sight, the visible spots in-line with the current position of the character are identified (marked in blue colour in the image below).
Once these spots are identified, it is checked if the agent current position corresponds with one of those or not.
When the human is in sight, the agent should shoot in the correct direction. In order to achieve this, it should change its orientation if it is not facing the human and shoot once the orientation is the correct one.
The best spot of the agent is the closest from where the human is in-sight at the moment. The spots previously identified are used, taking the one of those closest to the turret as goal for the pathfinding algorithm.
When the AI was implemented and the game was tested, most of the feedback received was that the AI was too quick and it was impossible too difficult to win the game. Because of this, it was decided to add some doNothing actions when planning the actions to carry out. As a result, even when the logic is the same, it looks like the agent is slower and the player is given a chance to reach the cake before being killed by it.
Below it is included a gameplay for a fully working game, where the turret (Player 1) is controlled automatically by the implemented AI and the human character (player 0) is controlled by a person:
As mentioned before, the framework was forked into my own repository, where I created the game and implemented the AI logic. Some bugs were found during the playtesting session (they have been fixed) so the last up-to-date version can be found in the Portal2D-improvements-and-fixes branch.
The files created for the game can be found at:
To run the game, it is suggested to follow the instructions provided in the framework wiki.
Thank you for reading, I hope you enjoy the game! And don’t forget to give Valve’s Portal games a try because they are really good!! Just bear in mind that…