The achievements are another type of collectable that gives the player long term goals to work towards. I created an early version of the achievement system for the game shortly after developing the card unlocking and collection, and these were all about unlocking songs. After adding more features such as the outfits and quests, I decided to rework the achievement system, using the early prototype as a base I built upon.
Drawing images for all the achievements as well as the song cards would have been too much for my sister to do so I decided to repurpose some of her existing images for some achievements.
The achievement page has blank card icons when the player has not unlocked the achievement. Once the player does, a new gameobject with the achievement icon is enabled on top of the blank icon. Both the locked and unlocked achievement cards have an ID which is used to bring up the big card in the same way as song cards.
When the player views a locked achievement, it tells the player the goal they need to achieve to unlock it. The unlock achievement function looks at the threshold or checks the unlocked song list for all the relevant song IDs depending on the achievement type. There is an AchievementProcessed variable that is set to true when one of the achievements is completed. This means that only one achievement is completed at a time and all of them can be displayed.
In the old system, I put the achievement page as the last page of the collection, but I changed this to be its own tab as I wanted it to be a more prominent feature. The old system was focused on song unlocks, as they were all for unlocking a certain number of songs, or completing a group such as all vault songs and all track 1s. The new system has more variety in the achievement types and includes new elements added to the game since the first achievement system was created, like the outfits and quests.
I added a star ranking inspired by the quests in Clash of Clans, where quests have 3 levels that scale up in difficulty and the player is given a star each time they complete a level. Some of Swift Runner’s quests don’t have 3 levels as they are about completing one main objective, so when it is completed, the player receives all 3 stars to keep the achievement star counts consistent with each other. For each achievement, the number of stars enabled correspond to the saved progress value in the achievement array.
When I made the new achievement list, I decided to change some of them as the unlock requirements were similar. I had an achievement for completing quests, unlocking albums, which are done by completing quests, and unlocking new features, which have similar requirements to the previous achievements. I chose to keep the album achievement and changed the others to total elevation gain and collecting every song. I decided to make the achievement for collecting every song only count songs up until the current most recent album, so that the requirements didn’t change when a new album is released as that would feel unfair.
This achievement check works by using a list of all the card IDs for the songs and incrementing a counter when one of the unlocked songs matches an ID in the list. If the counter reaches 248, all the needed songs have been unlocked so the achievement is awarded.
A few quests required saving extra variables to track quest progress. I saved the total distance across all activities by combining the new distance from each activity and then adding that to the saved value. The total elevation is done the same way but using the elevation data, and when the player unlocks a new outfit, the variable storing the total outfit number increments by one.
I decided to add a secret final achievement once the player has completed all of the others. This is done by checking the array holding the data for the other achievements, and once all of them are fully completed, the final achievement is awarded. This is an extra way to reward completionist players.
Creating the achievements helped me to find existing bugs I was not aware of previously. During testing, I found that I was unlocking achievements for specific groups of songs seemingly at random. When I checked the song collection, most songs had been unlocked. I noticed that the unlocked songs would always be full albums and realised that this was happening because of the new way of buying songs.
When the game loads, it checks the remaining songs array and assumes any song not there has already been bought. However, when I changed the system, the remaining songs array only contains songs that are available to buy, and when the player unlocks more, they are added to the array. This meant that as the songs from future albums weren’t in the array, they were being unlocked automatically.
To fix this, I added a new array called remaining cards all, which contains every card the player still needs to unlock, including those that are not currently accessible. The game loads this array instead to check which songs have been bought.
When viewing a song card, the collection page is set to that song’s album so that viewing the collection is consistent with the songs. The achievement IDs changed the collection page as they used to be part of the collection, but it now set it to the wrong page as the achievements are separate. I changed this to default back to the first page of the collection if it was an achievement card so that it didn’t get set to the wrong page.
The achievement names display when the relevant achievement is viewed. They are Taylor Swift lyrics, or references and jokes within the Swiftie community that fans will recognise.
I adjusted the positions of the achievement stars to be in line with the achievement cards and added a background to the achievement name and description so it stood out from what was behind. When viewed from the achievement tab, the small stars in the background blended into the stars for the current achievement, so I changed them to only be enabled when not viewing a specific achievement.
When winning achievements, I found that there was an error when displaying the text for the last tier of an achievement. This was because the string was created using the tier to display the correct values, but the last tier was trying to display a value that didn’t exist. To fix this I changed the string generation to use the tier for the value if it wasn’t the final tier, but use the last value in the array if it was.