top of page
About
About Me
Hi I'm Benjamin Morris Bsc (Hons) a Postgraduate, Masters By Negotiated Study student, where I am currently researching Genetic Algorithms and their applications in game development. I am primarily a programmer with experience using Unity, The Unreal Engine's Blueprint scripting language, programming with C++ and using the DirectX 11 API.
Portfolio
Below is some of the projects I have been working on over the last two years, the examples show projects within Unity, Unreal Engine and C++ using DirectX 11, some of the examples are quite long so where possible they have been edited down to a snippet of gameplay in different sections.
Unreal Engine - Ai-ppliance Defiance
This is a vertical slice of a game created as part of a group work project for a University Assignment. For this project I acted as the group and programming lead alongside running our GitHub repository, merging the project and helping everyone linking and using it with Unreal.
During development my role was to help keep communication flowing throughout the different departments, help and give inputs with decisions and I also assigned tasks to developers using Jira - mainly to the programmers, and made sure people were updating and documenting their process. I also spent a lot of time with the junior programmers (level 5 programmers) helping them fix issues and bugs and teaching them good practises.
The game was programmed within blueprint. My contributions to the project were the Health Systems, Checkpoint System and all of the AI in the game. I made a lot of different AI for the game utilising the Behaviour Tree system, I expanded the functionality of the system to support randomisation of nodes using decorators and created randomised timers which could change behaviours after so long using simple parallel nodes, this allowed me to create for example attacking movements which could random between having the AI say move straight towards the player, move around them or wait based on different weighted odds. All of the blueprints that require tick use timers instead to reduce overhead and programming interfaces are used for any type of blueprint communication to reduce coupling.
During development my role was to help keep communication flowing throughout the different departments, help and give inputs with decisions and I also assigned tasks to developers using Jira - mainly to the programmers, and made sure people were updating and documenting their process. I also spent a lot of time with the junior programmers (level 5 programmers) helping them fix issues and bugs and teaching them good practises.
The game was programmed within blueprint. My contributions to the project were the Health Systems, Checkpoint System and all of the AI in the game. I made a lot of different AI for the game utilising the Behaviour Tree system, I expanded the functionality of the system to support randomisation of nodes using decorators and created randomised timers which could change behaviours after so long using simple parallel nodes, this allowed me to create for example attacking movements which could random between having the AI say move straight towards the player, move around them or wait based on different weighted odds. All of the blueprints that require tick use timers instead to reduce overhead and programming interfaces are used for any type of blueprint communication to reduce coupling.
Unity - Genetic Algorithm
This Genetic Algorithm was built within Unity to play a custom Lunar Lander framework based on Atari’s 1979 Lunar Lander. Both the framework and algorithm were developed for my master's degree research: Planning and Developing a Genetic Algorithm Within a Gaming Scenario.
The Genetic Algorithm attempts to evolve solutions to land the spacecraft, where it is required to land below a target speed, orientation and at a set landing pad. Chromosomes contain real values representing button inputs and the duration of each press - which controls the lunar lander.
To evaluate the fitness of each chromosome, the fitness function considers the speed, rotation and distance to the landing zone. Each component of the fitness score is scaled is based on a multiplier, the distance is scaled the highest, then the speed and rotation are scaled less; this is so chromosomes which are closer to the landing zone are favoured. The speed and rotation multipliers are scaled by the distance, so the closer to the landing zone, the more influence they have on the final fitness value.
The Genetic Algorithm utilises Roulette Wheel and Single-point crossover for evolution, and a mutation operator which randomly selects a chromosome then a random gene where the values within are regenerated. Elitism selection can also be used when set on the initial level load.
The algorithm is also capable of tracking when and if the population is stuck in local maxima and can reset half the population to attempt escape after so many generations when set. It can also output the current progress to a file to load later and output the current stats of the population to a .csv file for loading in Excel.
Issues that needed to be overcome when creating this system was creating a Genetic Algorithm that was adaptable, as the framework and system is intended for future use as a building block for further development. To make it adaptable and modular, chromosomes act mostly as a generic container class which contain objects of type T where T is a gene, as genes consist of an abstract base class with a small interface for creating random starter values; derived classes can then implement the required encoding. The main Genetic Algorithm class is also built using object orientation with an abstract base declaring the interface that all future algorithm implementations will need, alongside any common functionality. Derived Genetic Algorithm classes will only need to implement problem specific code such as what gene type the chromosomes require, what evolution operators to use and the fitness function. As a benefit of this design, it means that evolution operators can be part of a single library of code and can work interchangeably with any future system as the chromosome class is all that is required for selection and evolution; if specific functionality is required in the future for evolving chromosomes, then genes can have relevant interfaces placed into their derived classes if necessary.
The current implementation can generate successfully landing chromosomes at a varying rate between runs, but typically between 20-60 generations. Other operators such as Tournament selection and Two-point crossover have also been tested and they can result in faster generation between 10-50.
The Genetic Algorithm attempts to evolve solutions to land the spacecraft, where it is required to land below a target speed, orientation and at a set landing pad. Chromosomes contain real values representing button inputs and the duration of each press - which controls the lunar lander.
To evaluate the fitness of each chromosome, the fitness function considers the speed, rotation and distance to the landing zone. Each component of the fitness score is scaled is based on a multiplier, the distance is scaled the highest, then the speed and rotation are scaled less; this is so chromosomes which are closer to the landing zone are favoured. The speed and rotation multipliers are scaled by the distance, so the closer to the landing zone, the more influence they have on the final fitness value.
The Genetic Algorithm utilises Roulette Wheel and Single-point crossover for evolution, and a mutation operator which randomly selects a chromosome then a random gene where the values within are regenerated. Elitism selection can also be used when set on the initial level load.
The algorithm is also capable of tracking when and if the population is stuck in local maxima and can reset half the population to attempt escape after so many generations when set. It can also output the current progress to a file to load later and output the current stats of the population to a .csv file for loading in Excel.
Issues that needed to be overcome when creating this system was creating a Genetic Algorithm that was adaptable, as the framework and system is intended for future use as a building block for further development. To make it adaptable and modular, chromosomes act mostly as a generic container class which contain objects of type T where T is a gene, as genes consist of an abstract base class with a small interface for creating random starter values; derived classes can then implement the required encoding. The main Genetic Algorithm class is also built using object orientation with an abstract base declaring the interface that all future algorithm implementations will need, alongside any common functionality. Derived Genetic Algorithm classes will only need to implement problem specific code such as what gene type the chromosomes require, what evolution operators to use and the fitness function. As a benefit of this design, it means that evolution operators can be part of a single library of code and can work interchangeably with any future system as the chromosome class is all that is required for selection and evolution; if specific functionality is required in the future for evolving chromosomes, then genes can have relevant interfaces placed into their derived classes if necessary.
The current implementation can generate successfully landing chromosomes at a varying rate between runs, but typically between 20-60 generations. Other operators such as Tournament selection and Two-point crossover have also been tested and they can result in faster generation between 10-50.
Unity - Chroma
Chroma was made for a University Assignment to create a potentially publishable Indie Game. This Mega Man inspired game has the player traversing through 4 levels which can be selected in any order, with a 5th final level unlocking at the end.
Chroma's main mechanic is what I've coined the Paint Mechanic, this allows the player to 'paint' monochrome parts of the level. Monochrome tiles will damage the player on contact, 'painting' these tiles with a variety of weapons the game offers will provide score and a way to progress.
From a technical standpoint this game heavily utilises coroutines, they are used to split heavy processing such as the paint mechanics tile colouring, AIs behaviours and bomb hazards between multiple frames to reduce CPU overhead. Other tricks such as using triggers to enable enemies when the player gets in range, then checking to see if the player is within the trigger and the enemy on screen before disabling them again to optimise performance is used, these triggers are also used for all the level hazards and moveable platforms; this set up allows the game to have everything loaded but only processed when needed reducing memory allocation at run time.
Chroma's main mechanic is what I've coined the Paint Mechanic, this allows the player to 'paint' monochrome parts of the level. Monochrome tiles will damage the player on contact, 'painting' these tiles with a variety of weapons the game offers will provide score and a way to progress.
From a technical standpoint this game heavily utilises coroutines, they are used to split heavy processing such as the paint mechanics tile colouring, AIs behaviours and bomb hazards between multiple frames to reduce CPU overhead. Other tricks such as using triggers to enable enemies when the player gets in range, then checking to see if the player is within the trigger and the enemy on screen before disabling them again to optimise performance is used, these triggers are also used for all the level hazards and moveable platforms; this set up allows the game to have everything loaded but only processed when needed reducing memory allocation at run time.
Unreal Engine - Possession Prototype
This is a prototype game made for a University Assignment about creating possession mechanics in the Unreal Engine.
This game has the player control a single character starting off with 3 AI characters accompanying them, as the game progresses more AIs will join the players team to create a large attacking force; the player is able to switch between every AI and possess them whenever they want.
The aim of the game is to progress up the map and take over villages and castles, villages get taken by defeating the enemies that are present within them, castles require a flag to be captured by having friendly AI within a capture radius while being the majority team within it, while capturing waves of enemies will keep appearing based on time and how many enemies are currently in the castle, friendly reinforcements will also appear.
The game is won once all of the castles are taken over.
This game was developed utilising Blueprints and the Behaviour Tree system within Unreal for all of the AIs.
This game has the player control a single character starting off with 3 AI characters accompanying them, as the game progresses more AIs will join the players team to create a large attacking force; the player is able to switch between every AI and possess them whenever they want.
The aim of the game is to progress up the map and take over villages and castles, villages get taken by defeating the enemies that are present within them, castles require a flag to be captured by having friendly AI within a capture radius while being the majority team within it, while capturing waves of enemies will keep appearing based on time and how many enemies are currently in the castle, friendly reinforcements will also appear.
The game is won once all of the castles are taken over.
This game was developed utilising Blueprints and the Behaviour Tree system within Unreal for all of the AIs.
C++ - Behaviour Tree System and Editor
This is a Behaviour Tree and Editor made within C++ for my Final Year Project during my time on BSc (Hons) Computer Games Design and Programming.
The Behaviour Tree system consists of Composite, Action and Decorator nodes that can be utilised for AI decision making. The Composite nodes comprise of Sequence and Selector nodes for controlling the flow of execution through the tree. Decorator nodes allow for if/conditional checks and to loop behaviours for a set number of attempts. The Action nodes are up to the use case and requirement of the implemented project. The system also features a Blackboard system that can hold all inbuilt types and be accessed using a string key like how the Unreal Engine allows for Blackboard data setting/getting.
The Behaviour Tree Editor allows for the construction of the trees using a node graph utilising the ImGui and ImNodes Libraries. The editor works by having nodes attached to each other to form branches, the higher the node is in relation to its parent and other branches, the earlier it executes. Nodes can have decorators applied to them by right clicking and selecting the required one, from here the options for these decorators appear on the right-hand window allowing for its settings to be altered. Action nodes can be added by going into options and adding the correct Action node name - for it to be used in the editor, the editor only requires non decorator nodes name to function as they can be loaded from only the name in both the main system and in the editor. Action node names can be output to a file for loading in next time or across different projects.
The editor allows for having multiple windows and trees loaded at once, they can be accessed via the tab at the top of the editor panel, where they can then be dragged away to allow for multiple windows. Save files can then be created or loaded using the Windows file dialogue box for easy saving/loading for the user, with the save file acting as a single solution for both loading in the editor and in the behaviour tree system.
Issues that arose during this project mainly relate to limitations with C++ or issues with ImGui and ImNodes. The first issue was getting over the lack of reflection within C++ so classes cannot be loaded with just a name from a file. To resolve this a factory pattern was created, with classes registering themselves to a dictionary alongside a string name key which will allow them to be accessed, the factory method would return a new instance by a virtual function within all nodes which returned a new instance of the same type; this allowed for node names within files to load the correct node. ImNodes and ImGui had issues with UI widgets being used on nodes, ImGui widgets did not often scale properly to ImNodes widgets, this led to no selection and hover effects as these would fly off the screen instead of cutting off at the edge of the node. The decorators also had to be apart of a separate node which followed the main node around, with the decorators being represented by a string of text on the node, as having them on the decorated node would cause stretching and visual problems.
The Behaviour Tree system consists of Composite, Action and Decorator nodes that can be utilised for AI decision making. The Composite nodes comprise of Sequence and Selector nodes for controlling the flow of execution through the tree. Decorator nodes allow for if/conditional checks and to loop behaviours for a set number of attempts. The Action nodes are up to the use case and requirement of the implemented project. The system also features a Blackboard system that can hold all inbuilt types and be accessed using a string key like how the Unreal Engine allows for Blackboard data setting/getting.
The Behaviour Tree Editor allows for the construction of the trees using a node graph utilising the ImGui and ImNodes Libraries. The editor works by having nodes attached to each other to form branches, the higher the node is in relation to its parent and other branches, the earlier it executes. Nodes can have decorators applied to them by right clicking and selecting the required one, from here the options for these decorators appear on the right-hand window allowing for its settings to be altered. Action nodes can be added by going into options and adding the correct Action node name - for it to be used in the editor, the editor only requires non decorator nodes name to function as they can be loaded from only the name in both the main system and in the editor. Action node names can be output to a file for loading in next time or across different projects.
The editor allows for having multiple windows and trees loaded at once, they can be accessed via the tab at the top of the editor panel, where they can then be dragged away to allow for multiple windows. Save files can then be created or loaded using the Windows file dialogue box for easy saving/loading for the user, with the save file acting as a single solution for both loading in the editor and in the behaviour tree system.
Issues that arose during this project mainly relate to limitations with C++ or issues with ImGui and ImNodes. The first issue was getting over the lack of reflection within C++ so classes cannot be loaded with just a name from a file. To resolve this a factory pattern was created, with classes registering themselves to a dictionary alongside a string name key which will allow them to be accessed, the factory method would return a new instance by a virtual function within all nodes which returned a new instance of the same type; this allowed for node names within files to load the correct node. ImNodes and ImGui had issues with UI widgets being used on nodes, ImGui widgets did not often scale properly to ImNodes widgets, this led to no selection and hover effects as these would fly off the screen instead of cutting off at the edge of the node. The decorators also had to be apart of a separate node which followed the main node around, with the decorators being represented by a string of text on the node, as having them on the decorated node would cause stretching and visual problems.
Unity - AI Techniques
This is a project consisting of AI techniques created for a University Assignment. The project features a variety of steering behaviours which apply to a character through a force accumulation model.
There are two pathfinding algorithms showcased; A* and Dijkstra, these are both also capable of perpendicular only movement and not cutting corners when required.
Finally to show these off in a practical example a finite state machine AI had been set up utilising different steering behaviours and pathfinding. The state machine works by having the AI look for the player, alerting other AIs if any are within the radius then returning to where they first found the player. The AIs will enter a fight state when close enough to the player where they have a chance to either attack or dodge. When an AIs health is low it may run away to find health, in this instance if they locate an idle AI they will alert that AI of the players position which if they are not on low health will run to where the AI last saw the player. Once the evading AI has health it too will move back to the location it last saw the player.
These AIs will switch between steering behaviours and pathfinding if there is no line of sight to their target location.
In this project the players health is capped at 1 as the AIs behaviours alter slightly when the player is on low health. The AIs attacking and dodging odds will change to make them appear a bit more erratic and they have a chance to not run away and look for health while the players health is low when fighting.
There are two pathfinding algorithms showcased; A* and Dijkstra, these are both also capable of perpendicular only movement and not cutting corners when required.
Finally to show these off in a practical example a finite state machine AI had been set up utilising different steering behaviours and pathfinding. The state machine works by having the AI look for the player, alerting other AIs if any are within the radius then returning to where they first found the player. The AIs will enter a fight state when close enough to the player where they have a chance to either attack or dodge. When an AIs health is low it may run away to find health, in this instance if they locate an idle AI they will alert that AI of the players position which if they are not on low health will run to where the AI last saw the player. Once the evading AI has health it too will move back to the location it last saw the player.
These AIs will switch between steering behaviours and pathfinding if there is no line of sight to their target location.
In this project the players health is capped at 1 as the AIs behaviours alter slightly when the player is on low health. The AIs attacking and dodging odds will change to make them appear a bit more erratic and they have a chance to not run away and look for health while the players health is low when fighting.
C++ DX11 - Advanced Graphics Assignment
This project is using C++, DX11 and HLSL to create graphics rendering techniques for a University Assignment.
This project features normal mapping, simple parallax mapping, parallax occlusion mapping and self shadowing, a render to texture to produce an object textured with the scene, the render to texture is also used for a screen quad for post process effects; a depth of field blur and a screen tint.
This project features normal mapping, simple parallax mapping, parallax occlusion mapping and self shadowing, a render to texture to produce an object textured with the scene, the render to texture is also used for a screen quad for post process effects; a depth of field blur and a screen tint.
C++ DX11 - Further Games and Graphics Assignment
This project utilises C++ and was my first introduction to using DirectX 11 and HLSL which was made for a University Assignment.
This project features a per pixel lighting local illumination model, a camera class which is capable of linear interpolation around set points, rotating around and zooming into targets, alpha clipping and blending is present as is billboarding, finally cell generation to create a grid of a set size has also been implemented.
This project features a per pixel lighting local illumination model, a camera class which is capable of linear interpolation around set points, rotating around and zooming into targets, alpha clipping and blending is present as is billboarding, finally cell generation to create a grid of a set size has also been implemented.
C++ DX11 - Further Games and Graphics Physics Assignment
This is a physics framework made for a University Assignment.
The framework features a point mass physics system with a thrust force, friction with laminar and tubular flow resistance alongside gravity. Rotational physics have been implemented using a quaternion based system, this features angular drag and acceleration.
Collision is also present with a narrow phase implementation featuring a axis aligned bounding box and a bounding sphere, when two objects collide an impulse will occur with the forces taking into account the speed, weight and normal of the collision.
The framework features a point mass physics system with a thrust force, friction with laminar and tubular flow resistance alongside gravity. Rotational physics have been implemented using a quaternion based system, this features angular drag and acceleration.
Collision is also present with a narrow phase implementation featuring a axis aligned bounding box and a bounding sphere, when two objects collide an impulse will occur with the forces taking into account the speed, weight and normal of the collision.
bottom of page