Made in May 2024 using Unity and C#.
On this page
Game Page
Highlights
- Created in 24 hours as a submission to the Arcademia Game Jam held at the University of Lincoln in May 2024.
- Attempted to simulate the frantic experiences of university students towards the end of semesters.
- Fast-paced gameplay with procedurally spawned pickups and assessment list.
Description
'Assessment Training' is an attempt to put players into the shoes of a
university student who is stuck with a heavy workload and fast approaching
deadlines. The player must plan, manage, prioritise and strategise to
complete and submit their assessments by the due time.
This theme was chosen as the game was developed for the arcade machines at
the University of Lincoln, resulting in students making up the bulk of its
audience. Thus, a game centered around the experience of submitting
assessments, which is well-known to the student crowd, would feel more
interesting and relatable to play.
Technical Walkthrough
Assignment Generation
- As the game involves completing assignments by collecting the required number of its constituents, the first step was to develop an easily configurable system that could generate waves of assignments.
- For this, it was necessary to define how data for assignments and waves of assignments would be stored.
-
To begin with, an enum 'E_AssignmentFields' was created to describe the
constituents or fields that make up an assignmentL
[System.Serializable] public enum E_AssignmentFields { PRES_SLIDES, REPORT_PGS, VIDEO_DURATION, CODE_FILES }; -
This enum was used to define data for individual assignment fields in the
form of the structure 'S_AssignmentFieldData':
[System.Serializable] public struct S_AssignmentFieldData { public E_AssignmentFields field; public int minValue; public int maxValue; public int targetValue; //the value that should be reached to complete the assignment public int currentValue; //the current value of this field while the game runs } -
A list of assignment field data made up an assignment:
[System.Serializable] public struct S_Assignment { public List<S_AssignmentFieldData> fields; public int timeRemaining; //time remaining before this assignment's deadline } -
Finally, data for each wave was also stored a structure:
[System.Serializable] public struct S_AssignmentWaveData { public int numAssmts; //# of assignments to spawn in this wave public float assmtFieldMaxValModifier; //modifies the 'target value' of the field based on the wave's difficulty //minimum and maximum # of seconds to allow the player to collect 1 unit of the target public float minAssmtSecsPerTarget; public float maxAssmtSecsPerTarget; public string waveCompletionMsg; //message to display when player completes the wave } -
Making these structure serializable meant that they could be configured in
the Inspector:
-
Based on the above data, the AssignmentController.cs script generated new
assignments, added them to a list and updated the UI by initialising the
last unused assignment UI slot.
private void SpawnAssmtAndUpdateUI() { S_Assignment spawnedAssmt = SpawnAssignment(); assmtQ.Add(spawnedAssmt); assmtSlots[assmtQ.Count - 1].InitSlot(spawnedAssmt); } -
The UI consisted of a list of slots, each having UI elements like sprites
and text. Each slot had a script called AssignmentSlot.cs attached to it,
which took care of initialising its UI elements based on the assignment
data received from AssignmentController.
public void InitSlot(S_Assignment assignment) { GetComponent<Image>().enabled = true; fieldsPanel.SetActive(true); timerPanel.SetActive(true); for (int i = 0; i<assignment.fields.Count; i++) { fieldSlots[i].gameObject.SetActive(true); } UpdateAssmtSlotBGColor(assignment); UpdateUI(assignment); }
Pickup Spawning
-
The AssignmentPickup.cs class was a child of the abstract class
'Pickable.cs.' The parent class only checked whether the player collected
the pickup. The pickup behaviour after being collected was defined by its
children. This enabled me to add other types of pickups later, such as
powerups and power-downs.
public abstract class Pickable : MonoBehaviour { private void OnCollisionEnter2D(Collision2D collision) { if (!collision.gameObject.CompareTag("Player")) { return; } Pick(); } virtual public void Pick() { Debug.Log("Parent class pick method."); } } -
Assignment pickup, when collected, simply fetched the active assignment
from 'AssignmentController.cs' and updated its fields based on the picked
item's field and value:
public override void Pick() { var activeAssmt = assignmentController.GetActiveAssmt(); if (activeAssmt.fields == null || activeAssmt.fields.Count <= 0) { Destroy(gameObject); return; } for (int i = 0; i<activeAssmt.fields.Count; i++) { var currentField = activeAssmt.fields[i]; if (currentField.field == pickupField) { currentField.currentValue += pickupValue; currentField.currentValue = Mathf.Clamp(currentField.currentValue, 0, currentField.targetValue); activeAssmt.fields[i] = currentField; break; } } assignmentController.SetActiveAssmt(activeAssmt); Destroy(gameObject); } -
PickupSpawner.cs runs a coroutine at random intervals that spawns pickups,
powerups or power-downs/enemies based their spawn probabilities:
private IEnumerator SpawnPickupsRepeatedly() { while (true) { yield return new WaitForSeconds(UnityEngine.Random.Range(minSpawnDelay, maxSpawnDelay)); PickupSpawnPt randomSpawnPt = spawnPts[UnityEngine.Random.Range(0, spawnPts.Length)]; if (randomSpawnPt.CanSpawn()) { float prob = UnityEngine.Random.Range(0f, 1f); if (prob <= assmtPickupProb) { randomSpawnPt.SpawnPickup(assmtPickups[UnityEngine.Random.Range(0, assmtPickups.Length)]); } else if (prob <= assmtPickupProb+powerupProb) { randomSpawnPt.SpawnPickup(powerups[UnityEngine.Random.Range(0, powerups.Length)]); } else { randomSpawnPt.SpawnPickup(enemies[UnityEngine.Random.Range(0, enemies.Length)]); } } } } - The above two systems were the main components of 'Assessment Training.' Once these were implemented, audio and visual appeal was added to improve the game in terms of game feel.






