I worked at BossAlien for three months over the summer of 2017. I had an amazing time there, the work was interesting and the team were so nice and helpful. I worked on the infrastructure team and learnt so much. I had little experience with AWS and cloud-based architecture so everything was very new but I managed to pick things up quite quickly and ended up working as a fully-fledged team member.
I worked as a full-stack developer and so used many different languages and systems: PHP, Unity C#, HTML, Javascript, CSS, JSON, AWS, Git, SVN and others.
My main accomplishments during the internship were:
BossAlien was an amazing studio to work at. It always had a great atmosphere and was very chilled and laid-back. I learnt a lot both technically and also about the structure/running of a game studio, it was really valuable experience. I want to thank BossAlien and Natural Motion for the opportunity!
I made this game for the 2nd round of the Sumo Digital Rising Star Competition. I was one of five finalists and came first in round two with this game.
For the second round of the Sumo Digital Rising Star competition, contestants were given a started unity project to build upon to make any game they wished. I created this game, Intersect and it came first in the round.
The games were marked by industry professionals and I received three pieces of feedback for Intersect:
I'd had the general ideas for the game in my head for a while. I remembered playing a flash game or something many years ago but I had no idea how I'd find it again to reference so I just worked from memory as to what the mechanics were, remembering more about separating the balls than taking area. Over time i realised I'd misremembered the mechanics and so began focusing more about the area capture mechanics over the separating balls mechanics.
The hardest part in making the game was working out how to calculate the area that the player has cordoned off each time they drew a line. In theory the player could draw polygonal areas with an arbitrary number of sides, correctly identifying the area they have created and colouring it in was quite difficult.
I spend a good few days near the beginning talking to friends to get ideas on how to accomplish this task. I ended up combining
several ideas together to create a general outline for how the algorithm should work.
I referred to the algorithm as the "Left-Right" algorithm due to how it checked the
left then right sides of the line.
/// <summary>
/// Finds the vertices that make up the area the new line is cordoning off. Implementing the Left-Right Technique I created
/// </summary>
/// <param name="startVertex">The start vertex of the line</param>
/// <param name="endVertex">The end vertex of the line</param>
/// <param name="newLine">The new Line</param>
/// <param name="lines">The list of all lines</param>
/// <param name="direction">The direction to be checking in relation to the new line. (perpendicular to the lines original vector)</param>
/// <returns>List of vertices</returns>
private List<Vertex> FindVertices(Vertex startVertex, Vertex endVertex, GameObject newLine, List<GameObject> lines, Vector3 direction)
{
// Define variables to help during the loop
List<Vertex> startVertices = new List<Vertex>();
startVertices.Add(startVertex);
GameObject startPreviousLineTaken = null;
bool startPreviousLineReversed = false;
List<Vertex> endVertices = new List<Vertex>();
endVertices.Add(endVertex);
GameObject endPreviousLineTaken = null;
bool endPreviousLineReversed = false;
bool updateStart = true; // Controls whether to update the start path or the end path this loop
int numberOfLoops = 0;
// Loop until the start and end point paths have met
while (startVertices[startVertices.Count - 1] != endVertices[endVertices.Count - 1])
{
if (numberOfLoops < 20) // Limit the number of loops to a reasonable amount
{
// Update the start and end paths on alternate loops
if (updateStart)
{
if (startVertices[startVertices.Count - 1] != null)
{
startVertices.Add(FindNextVertex(out startPreviousLineTaken, out startPreviousLineReversed, newLine, lines, direction, startVertex, startVertices[startVertices.Count - 1], endVertex, startPreviousLineTaken, startPreviousLineReversed));
}
updateStart = !updateStart;
}
else
{
if (endVertices[endVertices.Count - 1] != null)
{
endVertices.Add(FindNextVertex(out endPreviousLineTaken, out endPreviousLineReversed, newLine, lines, direction, endVertex, endVertices[endVertices.Count - 1], startVertex, endPreviousLineTaken, endPreviousLineReversed));
}
updateStart = !updateStart;
}
numberOfLoops++;
}
else break;
}
// Concat the lists after reversing the end vertices, removing the duplicate from the start of endvertices
List<Vertex> FoundVertices = startVertices;
endVertices.Reverse();
endVertices.RemoveAt(0);
FoundVertices.AddRange(endVertices);
FoundVertices.RemoveAll(x => x == null);
string logString = "Found Vertices: ";
foreach (Vertex vert in FoundVertices)
{
logString += "[" + vert.GetVector3().ToString() + "], ";
}
Debug.Log(logString);
return FoundVertices;
}
/// <summary>
/// Finds the next vertex in the given direction, a single step of the Left-Right technique
/// </summary>
/// <param name="lineTaken"></param>
/// <param name="newLine"></param>
/// <param name="lines"></param>
/// <param name="direction"></param>
/// <param name="originalVetex"></param>
/// <param name="fromVertex"></param>
/// <param name="towardsVertex"></param>
/// <param name="previousLineTaken"></param>
/// <returns></returns>
private Vertex FindNextVertex(out GameObject lineTaken, out bool reversedLineTaken, GameObject newLine, List<GameObject> lines, Vector3 direction, Vertex originalVetex, Vertex fromVertex, Vertex towardsVertex, GameObject previousLineTaken, bool previousLineReversed)
{
List<GameObject> intersectingLines = new List<GameObject>();
Vector3 towardsVector = Vector3.Normalize(towardsVertex.GetVector3() - fromVertex.GetVector3());
// Get all the lines that pass through this vertex
foreach (GameObject thisLine in lines)
{
if (thisLine != newLine && thisLine.GetComponent<LineScript>().PassesThrough(fromVertex))
{
intersectingLines.Add(thisLine);
}
}
// Find the line that moves most towards the towardsVertex after ensuring the line's directions move with the direction vector
GameObject smallestAngleLine = null;
float smallestAngleLineAngle = 360;
bool smallestAngleShouldReverse = false;
foreach (GameObject thisLine in intersectingLines)
{
bool shouldReverse = false;
Vector3 thisLineDirection = thisLine.GetComponent<LineScript>().GetNormalizedDirectionVector();
float angleTowards = Vector3.Angle(thisLineDirection, towardsVector);
// Only find whether to reverse direction on the lines we didnt take last time
if (thisLine == previousLineTaken)
{
shouldReverse = previousLineReversed;
}
else
{
// Find whether the direction of the line should be flipped
float angle = Vector3.Angle(thisLineDirection, direction);
float otherAngle = 180 - angle;
bool shouldReverseAngle = false;
if (otherAngle < angle)
{
angle = otherAngle;
shouldReverseAngle = true;
}
else if (angle == 90) // If perpendicular to direction, make sure we find out whether this line is pointing up or down
{
if (thisLineDirection != Vector3.Normalize(towardsVertex.GetVector3() - originalVetex.GetVector3()))
{
shouldReverseAngle = true;
}
}
// Get towards angles
bool shouldReverseAngleTowards = false;
float otherAngleTowards = 180 - angleTowards;
if (otherAngleTowards < angleTowards)
{
angleTowards = otherAngleTowards;
shouldReverseAngleTowards = true;
}
if (previousLineTaken != null)
{
// Take the shouldReverse of the smallest of the angles
if (angle < angleTowards)
{
shouldReverse = shouldReverseAngle;
}
else if (angleTowards < angle)
{
shouldReverse = shouldReverseAngleTowards;
}
}
else
{
shouldReverse = shouldReverseAngle;
}
}
// Check to see if this line has the smallest angle so far
if (shouldReverse)
{
thisLineDirection = Quaternion.AngleAxis(180, Vector3.up) * thisLineDirection;
angleTowards = Vector3.Angle(thisLineDirection, towardsVector);
}
if (smallestAngleLine == null || (smallestAngleLine != null && smallestAngleLineAngle > angleTowards))
{
smallestAngleLine = thisLine;
smallestAngleLineAngle = angleTowards;
smallestAngleShouldReverse = shouldReverse;
}
}
// Now i have the line to follow and the direction in which to follow it, need to get the next vertex on that line in that direction to return
Vertex nextVertex = null;
if (smallestAngleLine != null)
{
nextVertex = smallestAngleLine.GetComponent<LineScript>().GetNextVertex(fromVertex, smallestAngleShouldReverse);
}
if (nextVertex == null && smallestAngleLine != null)
{
smallestAngleLine.GetComponent<LineScript>();
smallestAngleLine.GetComponent<LineScript>().GetNextVertex(fromVertex, smallestAngleShouldReverse);
Debug.Log("UpdateArea: Couldn't find next vertex");
}
lineTaken = smallestAngleLine;
reversedLineTaken = smallestAngleShouldReverse;
return nextVertex;
}
One of the suggested features for the game was a leaderboard so the day before submission I decided to add one. I decided if I was going to have to faff around with reading a local file I might as well make a global leaderboard using a website api to add and retrieve. This feature ended up taking the entire day (which seems obvious in hindsight). I created a simple node.js app that would store the top 10 scores, storing them in a mongoDB database. The client would be able to get and post to the website to get the top 10 scores and post it's own score to the leaderboard if it beat one of the top 10.
Setting up the leaderboard server and web requests was relatively straightforward (I had done most of this a couple of years previous in my event planner project), so I managed to do it quite quickly. A large portion of the time to implement the leaderboard was spent struggling with Unity's GUI system. I had great difficulty making things line up nicely.
The global leaderboard functioned well and had the desired effect among my playtesters, many of them played the game multiple times in a row, trying to beat another person's score, adding additional replayability to the game.
I had two initial ideas for the music, one was a traditional approach - a calm, laid-back song playing in the background. The other idea was for the music to be created "live". To make the music to be based on what's happening in game by attaching the notes to the balls colliding with a wall.
I went with the second approach, but inn order for the music to not get boring I couldn't just use a single chord for the whole game. Instead I chose to have the chord change every time a line was successfully drawn. Whenever a ball collided with something it would pick a random note from the current chord to play and when a line was started or finished it would play the root of the current chord (though an octave down from the ball notes).
This system worked very well and was very pleasing. A nice upshot of attaching the notes to the balls is the relatively random timings you would get between notes. As you progressed through a level and cordoned the balls into smaller areas or played levels where the balls moved faster, they would collide more often and so the time between notes would decrease. This helped to increase the intensity of the music as you got to harder levels or got closer to finishing your current level which was a nice bonus.
I'd like to thank my friend cesque for providing the audio clips for the game.
I am currently working on my final year project at York, supervised by Paul Cairns. The project consists of a literature review, a experimental study, a presentation and a 55 page report.
The aim of the project is to research into how audio affects immersion by creating a game that can be played in multiple modalities (audio-only, video-only and both) in order to perform a study on how immersion is impacted by these different modalities. As part of this project, I am also writing a literature review as part of my project report which covers the current state of research into this field (including both examples of games that use audio as an important modality and formal literature).
The first thing to do was to prototype a few games that would work equally well audio-only and video-only. These three protypes were:
The idea behind Bat Pong was to create a pong-like game, adjusted so it can be played audio-only by making the bats and balls emit a constant sound with a pitch that varied based on the position of the object in the y-axis.
I decided to use Unreal C++ to prototype this to both gain experience with Unreal and because I could get low-level access to the audio buffer to send it generated sound data. I learnt a lot during creation of this prototype, having not used Unreal much before.
We decided not to pursue this game concept further due to the difficulty in audio-only play. In order to improve audio-only play, the video-only play would be severely hampered by a slow-moving ball or large paddle size, making the game too easy.
A rhythm game based on the Rhythm Heaven series of games. The concept is that the player must enter their input in-time with the music, as the ball reaches the centre.
I decided to make this in Unity C# due to time constraints. I am more familiar with Unity and it allowed faster iteration times.
The difficult part of this game and of the Simon game was in ensuring timing stayed consistent, the game needs to stay in time with the music. I used the dsp time that is provided by Unity, an integer that ticks up with the time of the audio driver. Using this value and a coroutine, actions could be reliably performed in-time with the music (as long as the beats per minute value was set correctly).
In order to orchestrate all the timings for when balls should appear and bounce etc. I decided to used a data-driven approach (something I hadn't done before). I used the ByteCode programming pattern from " Game Programming Patterns" to facilitate this. The whole game is run off a single CSV file that can be easily swapped out for different songs/ball timings. This system was robust enough that I prototyped the simon game using the exact same codebase. It also allowed me to easily adjust and change timings without recompiling/changing code.
Development on this game is currently in progress, improving the game to add menus, tutorials and more juice. Currently the music is from "Rhythm Heaven: Fever", this will be replaced later on.
One of my second year modules was a Software Engineering Project where teams of six worked to create three games over the course of the academic year which had to meet requirements given by the lecturers. My role in the team was as head of the programming sub-team, responsible for the development and design of the game I did over half the programming.
There were distinct phases of game development at the end of which teams had to present their game to the other teams and then had to take over the code and documentation of another team, and work on that for the next phase. Extra marks were given to teams whose code was chosen by other teams. Each phase lasted about 8 weeks.
Teams were free to use whatever tools/languages they liked to create the game with. We chose to use:
I created videos/trailers for each of the games that my team made. These were used in the presentations and can be viewed below:
The Brief we were given was that our game must be about a duck travelling across the University campus, encountering various obstacles and with various objectives.
Each team is to build a single-player duck simulator game, which must take place at the University of York. Ducks have objectives, and use their innate or acquired abilities to try to achieve those objectives. When an objective is completed, the duck is awarded points.
Your game must take place at the University of York, but you do not have to include the entire campus. It must include at least eight locations.
The game must support at least eight different objectives. You must support at least two different types of objectives.
The game must support at least five different types of obstacles, including at least one randomly allocated obstacle and at least one objective-specific obstacle .
The game must support at least three different Duck Special Powers. Ducks innately have the ability to waddle (fairly slowly), swim (fairly briskly), and fly (quickly).
Straight Outta Heslington is the first game we made. It is a JRPG modelled after final fantasy. We felt that it a JRPG would easily allow us to meet all the given requirements from the brief. Another good thing about choosing a JRPG is that we could split the programming evenly between the battle system and the overworld system allowing sub-teams to work on each part seperately- increasing our speed.
I worked primarily on the battle system, ensuring that the backend for the system was robust and easily expandable which was important as we wanted to get as many teams as possible to choose our code-base at the swap point. Development went pretty smoothly and our decision to separate the two systems (overworld and battle) proved successful as we were able to work quickly in our subteams without interfering with the other sub-team. The point where we linked the two systems went well which further showed our decision paid off.
We also created very high quality documentation for the game including requirements, system architecture, risk management and team management documents. The documents we created were very useful for ensuring the quality of our game and ensuring we met all the requirements given to us.
We had quite a lot implemented by the time we got to the end of the phase:
Three teams chose to take on our game for the next phase, the highest uptake of any of the games that were created. We got a mark of 76% for this phase.
For the second phase we took over a top-down shooter game. It was fairly basic but had a level system where you complete the objective to go to the next level. All the enemies were melee enemies but there was some AI to make them follow you implemented. There were some powerups implemented a form of flying.
We thought the basics of the game were good but it needed a lot of work to make it fun. We also heavily disliked the art-style
and decided to do a full art-pass on the game. One of my team
made a good sprite for the duck being a jedi and the star wars
theme took off from there (The Force Awakens had recently come
out). In the original game you could only face in four directions,
we upped this to eight to make the player feel more responsive.
Other changes we made:
We fulfilled all and surpassed some of the requirements for the end of the module phase. I think this game is the best one
we delivered of the three, I really like how cohesive the game
feels and when I was playtesting it I was surprised to find it
was actually a lot of fun- I wasn't sure if it would be fun to
play in the end.
The actual moment-to-moment fighting gameplay is fun but you
can blitz through the game by skipping most of the levels and
getting the flag immediately.
I am most proud of the boss fight. We had a couple of hours
left before our self-imposed development cutoff/feature lock
and we felt the end of the game was lacking so we decide to add
a boss. It took roughly two hours from having the first ideas
for the boss to having it fully implemented and playable. The
team really pulled together to do all the things necessary to
make it in that time and I find it one of the best bits of the
game, I am very glad we added it.
I believe our game was picked up by only one team - we were somewhat
expecting this. Our game wasn't as appealing to be taken on this
time round, part of this I think is that we were going to be
given requirements changes when starting the final phase and
our game probably didn't seem as easily extendable as other games.
However I am very confident in saying that our game was the most
polished/refined, actual game-like game of all those made for
that phase and that I am proud of.
We got a mark of
87% for this phase.
For this final phase we took on a game that had the same starting codebase that we had used in the second phase to create
The Empire Strikes Quack. The game we took on here was that original
codebase that had then been worked on by another team in the
previous phase.
We were given a change in requirements for this phase:
For the cheat requirements, we decided to follow the cheat methods in other older games, on the pause menu, if you enter
a certain key combination, the cheat is activated. We added two
cheats, one where an explosion graphics happens where your bullets
impact and the other which when activated causes a duck to bounce
around the screen, obstructing your view. The second cheat also
gives you a score multiplier while it is active to compensate
for the visual obstruction.
The harder requirement is the demented waterfowl. As far as
the player character randomness, it is inherently frustrating
and bad game design- having your player character ignore your
inputs every now and again is infuriating. I decided to try and
gamify the system instead- every now and again the player has
to press the key that appears above the character's head within
a certain amount of time else their movement controls will change
so the left key may move the player up etc. If they press the
key in time they get a powerup for a short while as a reward.
This system fulfills the requirements whilst adding another
mechanic to the game, ensuring the player has to pay attention
to their character regularly.
For the AI, we made an enemy that will walk up to you and explode,
shooting out damaging feathers in all directions - I think that
counts as random behaviour.
Other changes we made:
We successfully delivered on time, meeting all requirements both with documentation and with the game.
This was the last phase so teams didn't take over games from other teams. We got a mark of 90% for this final phase.
Pizzas Please is an asymmetrical multiplayer/party pizza making game written in C# using monogame during a 3-day gamejam. There are three different game roles:
Starting the server
To start a server you must run the game exe with the command line parameter "Server".
The default port is 4444, you can specify the port by adding it to the command line
parameters after "Server".
'PizzasPlease.exe Server <port>'
e.g. 'PizzasPlease.exe Server 4555'
Connecting to a server
To connect to a server and start a client you must run the game exe specifying the
IP address and port of the server as the command line parameters.
'PizzasPlease.exe <ip address> <port>'
e.g. 'PizzasPlease.exe 127.0.0.1 4555'
I made this game in Unity with two friends for Ludum Dare 37. The theme for the jam was " One Room".
None of us had very much Unity experience going into the jam -I had some experience with working in 2D in Unity- and no experience
creating VR games so the whole jam was a great learning experience.
The basic idea we had was to make a game where you are in a room full of different
things that you can interact with but basically anything that you do is narrated.
We were partly inspired by the website "
clickclickclickclick" which narrates everything you do on a simple webpage with
a button to demonstrate how much information can be gathered from your web browser.
Basic interactions
We started out learning how to to connect the Vive to Unity, getting the position
information of the head and controllers, then we moved onto allowing the user to
pick up objects and throw them. In order for the user to be able to throw objects,
we had to give the objects a force in the correct direction once the player let go
of them. This was because whilst being picked up by the player, the objects stopped
being physics objects.
Most of the first day was spent on this sort of thing, basic interactions.
Sound system
Once we had a reasonable system for allowing the player to interact with the objects
in the room, we worked on getting sounds to trigger. A single manager that was attached
to the headset prefab was created that would actually play the sounds. The main issue
would be playing the correct sounds at the correct time. So, playing the "
dropped the cube on the ground" sound when the cube is dropped and hits the ground.
For this, we created a generic state machine system which we then derived from for specific state machines. So there was a state machine for objects that could be picked up- grabbables. These had states for falling, grabbed, on the floor, on the table etc. Various actions would send signals to the state machine manager that would update all the state machines with the action, then state machines would signal that a sound for a particular event should play.
We had several voice lines recorded for each event, so picking up a cube may have " They pick up the cube" and " They grab the cube". Each voice line had a period given which was the length of time that the voice line cannot play again after being played. Voice lines and actions also had different priorities assigned to them so that voice lines for actions that occur less regularly would be able play straight away when signalled instead of voice lines that are more common.
Most of the rest of the time was spent improving the virtual play-space, adding new objects to play with, a light-switch to turn off the light, a picture to throw around, a poorly tuned piano etc.
State Diagram