Aloha!
After a quick break over the weekend we’re back to continue developing the 2D project as a part of GameDevHq’s game development course. The focus for today was finishing the proper set up for using Git to back up the project to Github as well as adding even more mechanics to the game through free form challenges.
To start with Git the biggest challenge was learning that Git has issues with transferring larger files to Github due to the system being primarily made to store script files that are text files that do not take up much memory. This meant that folders that contained large files sizes had to be added to a .gitignore file to specify to Git which folders to exclude from the repository. These usually involved larger local files such as sprites and the asset folder that provided from Filebase for this course. Once the .gitignore was properly set up I could then store the base version of the project that was created through following the tutorial videos to a main branch. This branch is where all finalized changes will eventually be pushed to but for the time being will be our backup repository for a clean 1.0 version of the project that we can revert to if there turns out to be problematic changes to the project when developing the features covered in the course section titled “ Phase I: Framework”.
With the main repository established the next step in development was to continue fleshing out the mechanics of the game to make it more challenging and engaging. One of the ways to create challenging gameplay to provide the player with a mix of restrictions and advantages that they have to manage to find eventual overall success in their gameplay performance. Sort of like writing a good story there usually needs to be some form of challenge whether big, like attempting to win a match in a competitive multiplayer game, or small, such as catching a fish in Animal Crossing, where the player can potentially feel a sense of success for overcoming the challenge. However tuning gameplay mechanics is a fine balance and if the gameplay is difficult to the point of feeling unfair the player may feel frustrated and stop playing. On the other hand if the gameplay is too easy or lacks any sort of aspect to its presentation that compels the player to want to see what’s next, they may get bored and also drop the game. If this gameplay loop is tuned right you have the formula for a good game that can keep people coming back to during their leisure time.
In this framework phase of the course we were given a set of features that we are to implement and are given free reign to figure out how to do so. This contrasts to the previous features where we were walked through their implementation via the video lectures. For today I aimed aimed to complete the first half of the eight features that were given to complete. These four features were as follows:
- Thrusters — Increase player speed when holding down the shift button and reset back to normal speed when the button is released.
- Shield Strength — Allow the player shield to absorb three hits before expiring. Show the amount of hits left via UI text, shield color, or any other method.
- Ammo Count — Set a limit of 15 for the total amount of shots the player can fire before their attack is disabled. Display this count on the screen via the UI.
- Ammo Collectable — Create a powerup that refills the ammo count allowing the player to fire again. Update the UI when ammo is refilled.
IMPLEMENTING THRUSTERS AND OPTIMIZING KEY HOLDS
To break down each one we can start with the implementation of the thrusters. This method was a simple addition that allows the player to speed up as long as the left shift key is held down. The first attempt involved using the Input.GetKey() function which is a function that is used in the Update block of a script and will constantly send a signal every frame as long as the chosen key is held down. This function was implemented in the Player() script and basically switched out the _speed value used in the player speed calculation:
transform.Translate(direction * _speed * Time.deltaTime);
with a faster value declared by the variable _boostSpeed. This method did work in that it did speed up the player whenever the shift key was pressed, however because this method resulted in a constant check and call every frame there were noticeable performance issues and stuttering when testing the function. This means that while this did meet the requirements of the assignment there should be a better, less-expensive way to optimize the script and still meet the goals of the assignment. The solution to this was through using the functions Input.GetKeyDown() and Input.GetKeyDown() alongside a boolean switch. The difference between these functions and Input.GetKey() is that they only send their signal once rather than every frame. This means that the new structure is as follows:
The way this works is that once the left shift key is pressed it will send a single signal to turn the boolean _sprintActive from false to true. As long as _sprintActive is set to true the player movement speed is calculated suing the value from the variable _boostSpeed. Once the player releases the left shift key Input.GetKeyUp() will send a single signal to switch _sprintActive back to false and revert the player movement back to its regular speed. This trial an error scenario works as a good example of how there are multiple ways to achieve a single goal in coding but the results may not be as clean as others when it comes to things such as performance optimization. This is an important aspect of programming for games as optimizing for a stable framerate is an important part of of the presentation and playability of your game. If the game is poorly optimized and slows or hitches to the point of being unresponsive or being hard to look at this can put a player off of the game and make the experience as a whole not very fun to engage with.
STRENGTHENING THE SHIELDS
In this goal the aim was to allow the player with an active shield to receive three hits from enemies that deal no damage before losing their shield. This part of the behavior is simple as all that is needed is to create a value that tracks the amount of hits the shield can take and subtract from that amount whenever a hit is taken until the total equals 0 at which point the shield is disabled.
The interesting challenge of this goal was attempting to provide the player with a visual indicator of the amount of hits they have left by dynamically changing the color of the shield every time a hit is taken. This was handled by accessing the Sprit Renderer component of the Shield game object and changing its color every time a hit was taken. This was a simple implementation but I found it interesting as it was a feature that I had not worked with before so it was a nice skill to learn.
AMMO RESTRICTIONS AND BUSTING OUT PHOTOSHOP
With the last two features both being centered around giving the player an ammo mechanic I figure we can cover both of them here for the wrap up. Providing the player with an ammo restriction is an example of providing the player a challenge in the mechanics that they can fail or succeed at and works to grab their attention. This feature when fully implemented provides the player with 15 shots to fire at enemies, once those shots are expended the player can no longer attack until they pick up an ammo refill powerup. This restriction changes what is the most effective behavior that the player can take to succeed at the game. In the basic version of the game the lack of any type of restriction on player shots besides fire rate means that the most effective behavior for the player to take is to endlessly fire in the chance that they can potentially destroy an enemy the second it enters the screen. This makes the strategy of the game simple and prevents certain features like the ability for multiple enemies to be present on screen easily countered. Adding an ammo restriction requires the player to conserve their shots and be more methodical in their behavior otherwise they may run out of shots and be left defenseless until an ammo refill spawns, meanwhile the amount of enemies they have to dodge continues to grow as older ones aren’t destroyed.
Adding an ammo restriction was similar to adding shield health in that a new integer variable was created to track the total amount of shots the player has at any given time. Every time a shot is fired this value is decremented by 1 and the text on the UI updates with the new total. Once all of the player’s shots are expended a boolean switch flips that disables the ability to run the FireLaser() function in the script until the amount of shots available is made greater than 0 again when the ammo refill powerup is collected.
For the ammo refill powerup the implementation of the code part was also straightforward in that it had to be added to the table of possible power up spawns and then its behavior was simply to change the value of the variable _ammo in the Player() script to equal the maximum possible amount of 15.
The part of implementing this new powerup was actually the visual side of creating a custom icon for it since all three of the other powerup icons we were given were already used for other functions. After some searching I found an ammo box icon at the site favpng.com that fit the bill.
This image did require some editing as having an black colored icon on a mostly black background would not work. To fix this I flipped the color on the icon using Photoshop, removed its background, then imported it into Unity and converted it into a sprite.
This process was successful and I was able to get a new working powerup sprite into the game. If I have more time I would want to add a slight glowing animation to it but for now this method will work for the time being.
That’s the wrap up for my progress for today. The aim for tomorrow is to start, and hopefully finish, the second half of the required functions for this phase which include:
- Health Collectibles
- Secondary Fire Powerup
- Thruster: Scaling Bar HUD
- Camera Shake
These all sound like interesting features to try and solve but in the meantime here is a shot of the game with the new functions currently implemented. Mahalo for reading and keeping up with my journey through this program.
— Kurt