The instructions for this assignment were to create a simple game where players can interact with elements within the game world, within the Unity Engine. This included accumulating experience points (XP) from these interactions and levelling up. We were guided through the project in class, learning some of the basics of coding along the way.
When I first began this project, I had never used Unity before and was totally unfamiliar with writing code. We learned how to create objects in the 3D space, including a basic player character. Using a template provided for us, I was able to import a C# script allowing the player character to rotate and move around.
Phillips, P. (2022). Newbie's first player controller script [Lecture document]. SAE Creative Media Institute. https://sites.google.com/sae.edu/gad170onlineguide/campus-schedules/perth/week-1
The next step was to create a series of collectible coins, which the player could use to gain XP and level up. We added another C# script, this time to the coin object, allowing it to spin on the spot. Additionally, I added a rigidbody physics simulator to the player character and a spherical collider to the coin. This meant that when the player entered the collider zone, the coin would generate XP for them and then disappear. The player character script also got an update. With some guidance, I was able to modify the script to have the player gain this XP.
I also added a jumping mechanic, using the same player controller script as before. Part of the XP mechanic was that, as the player levelled up, their turn and movement speed would increase by 10%. I modified the script to include the jump height in this.
The final segment of my project was to add a series of unlockable chests, from which the player would gain another coin. The mechanic here was to have a lock-picking skill that would automatically upgrade as the player levelled up. The success or failure of the action would be determined by a random d6 dice roll, and the chances of succeeding in opening the chest would increase with level-ups. By then end, I had created four levels with different layouts that tested the player's level with a number of obstacles.
Early draft of the level designs I would use.
I wasn't happy with the default commands for player movement (originally, one had to use the arrow keys to move the player character around the scene), so I managed to change them. Now, the player can use the WASD keys to move.
I had a problem with the apple GameObject at one point, because it had somehow lost its assignment tag in the Inspector. By reassigning it to the object and replacing the apple prefab, I was able to fix the issue. The next roadblock was getting the snake's body segments to follow the head as it moved.
The reason that the snake's body didn't follow the head properly was because the script was applying the 'follow' code to the snakeBody array. The head was not part of this array, and therefore not being counted. I got this sorted by adding separate movement code for the head.
In the original template, the snake moves direction when the player presses the arrow keys, but I changed that to the WASD keys.
I had a really hard time with this assignment. I can barely follow what's going on in class, and nothing really sticks for me. I'm extremely concerned about how I'm going to pass this unit. By the end of this project, I had successfully gotten the snake's body to follow its head properly, and got the the apple to respawn within the bounds of the screen after being collided with. However, I couldn't get the snake to teleport to the opposite side of the screen.
The process of recreating Snake is detailed in my Week 9 Learning Journal page.
Possible map (Storgård, 2022)
Storgård, A. (n.d.). 15 by 15 Orthogonal Maze. Maze Generator. Retrieved August 11, 2022 from https://www.mazegenerator.net/
(There is more documentation at the bottom of the page.)
Enemies patrol back and forth until interacted with. Upon player's victory, the enemy is destroyed.
The number of keys required for the level is predetermined, and spawn in random locations on start. This prevents the player from memorizing the path and increases re-playability.
Ideally, the maze would be procedurally generated so that it is new every time, but for this project I will stick to a set map.
1. I started the PlayerController script from scratch, using the simple template for player movement from Brief 1. I wrote out the definitions for moveSpeed and turnSpeed manually to get a better feel for writing code myself, and it didn't initially work.
2. The problem was that I wrote 'public class int...' where I didn't need that element. I copied and pasted that section of the sample script to compare the two and look for differences. After making sure the issue wasn't with Unity, I was able to fix it by rewriting those lines.
4. I sorted it out by rewriting the movement scripting. I erased the lines denoting to rotation and replaced them with duplicates of the movement lines. After that, I just changed the key codes and direction. Unfortunately, the player character only moved left.
6. Inspector view of Key GameObject, including the gold material.
8. [Glenn helped me write this script] I created a script for patrolling, AI-controlled enemies. Before this, I added a NavMesh so that the AI works by itself. We set up a list of two waypoints for the enemies to move between, instead of trying to create 'detect and turn' scripts for bouncing off walls. The wayPointSwapDistance was originally 0.1f, but the enemy GameObject wasn't ever reaching it because of the internal maths of the NavMesh going "close enough" too soon. Added a Debug.Log to make sure that the enemy was actually hitting the waypoint and doing what it needed to do.
11. The waypoints are simply 3D gameObjects that have no collider or physics applied, and function as points between which the AI patrols. These are grouped under an empty game Object called GuardPatrol.
13. I decided that I wanted the player to be able to rotate the camera around their character as they move. I did this by writing code for rotating, under the update function. I used the code from Brief 1 to do this.
15. I created a very basic User Interface containing the title of the game and a slider (see Learning Journal Week 13 for how to do so). I coloured it green My intention is to disable the slider's interactivity in-game and attach a script to it, so that it displays the character's current health meter.
17. One of my classmates, Fraser, had gotten a working Enemy AI script where the enemies would chase the player for a while, until no longer in range. He helpfully shared this script with me, but when I tried to implement it I got several errors. His script was attempting to reference others that I didn't have in my project yet. I figured out that it was looking for an EnemyVision script (the template for which is below) but when I wanted to assign it to my Enemy GameObject, it didn't want to work on the basis of a missing script class.
18. I got the assignment and referencing issues fixed with Glenn's help. I was referencing the wrong function in the Enemy script, and I had somehow managed to accidentally delete where it was assigned to the GameObject before changing the EnemyVision class. I'm not entirely sure what was wrong and how we got it sorted, but it works now so I can move on to fixing the Key problem.
19. The next bug I had to contend with was my Enemy GameObject not patrolling. Basically, none of the scripts attached to it are working. The error message is that the object reference is not set to an instance. I thought this meant that it was looking for the waypoints code, so I wrote it back in (see steps 8 and 9). Unfortunately, it still doesn't work.
Glenn was able to help me get the Enemy chasing the PlayerCharacter by cleaning up the Enemy script and making some adjustments. Now the enemy chases, but the player clips through the floor plane and cannot move fast enough to test the chase range. I worked out that I only have this problem after the Enemy chase is triggered. I believe this is because of the way destination is defined in the Enemy script; that it's attempting to bring the player's vertical position down to match it's own but the PlayerCharacter's rigidbody component is trying to prevent this. Neither removing the rigidboy component or changing the player's vertical position helped.
22. I followed @CodingInFlow's tutorial (2021) about adding audio to a game, and was able to get the sound on the key to play correctly when the PlayerCharacter entered the collision zone. However, I now have the problem where the key isn't destroyed and I get another error telling me that something is null (second image).
25. This is the 'Bite' script. It is attached to the Enemy GameObject and delivers damage to the player on collision.
26. After the Events system was working, we also quickly fixed the problem of audio on the Key. I had too many scripts attached to it, which was confusing Unity, and the syntax to make the audio play before the object is destroyed was wrong. The highlighted sections are what was added, and the commented-out section was how I had originally written it out. I have yet to test the sound, as I didn't have compatible headphones with me in class, but the previous errors I'd been having are no longer popping up.
Map with objects and some direction
3. When I attempted to test the movement, the player could move forwards and backwards without issue, but trying to move left and right didn't work. Instead, a weird rotation happened and the player capsule fell over.
5. I attempted to fix this by switching 'transform.right' to 'transform.left' but that didn't work. However, I noticed that I had two instances of move left. By changing one minus sign to a plus I could get the script to work.
7. The simple script attached to the Key GameObject. It was supposed to make the key rotate on the spot and then disappear when collected. When the player enters the collider on the key, it would be 'picked up'. When I tried to play test this, it didn't work. The key didn't move or disappear, and the collider wasn't working on it. As it turned out, I had just forgotten to apply the script to the GameObject.
9. In Update, instead of having the entire function written out, having just the function name is better. This makes the logic easier to follow when reading over the script. The long version can be placed outside the Update box. By checking the distance to the waypoint, the enemy can determine how far away it is and how much further it needs to move before turning around. Again, the Debug.Log was implemented to monitor what the AI was doing.
10. This script gave us some issues, because no matter what we tried and changed, the enemy moved to the first waypoint and stopped. We thought it might've been the colliders on the waypoints acting up but disabling these didn't work. Eventually we realised that Glenn had accidentally disabled the waypoints altogether. By re-enabling them, the script started working properly.
12. Video example of the Enemy AI working between two brightly-coloured waypoints, with a key rotating in the foreground.
14. The working script for the Enemy AI. This script gave Glenn and I some serious trouble, and took nearly three weeks of class-time to fix. No matter what we tried, the Enemy would only ever chase the player or patrol blindly. When chasing the player, the stopping distance wasn't functioning and the Enemy would not return to its patrol path. Eventually, we had to remove the patrolling element to make the chase element run properly. Although the distanceToTriggerPlayerChase and followStopDistance variables are set in the code, they must be changed in the hierarchy menu to take effect.
16. I tried getting the PlayerCharacter to pick up the key, and then log or keep a record of having got it (similar to that of gaining XP). Above is what was added to the end of the PlayerCharacter script, and below is the new version of the Key script. This didn't work but also broke the 'destroy' command. I'm not sure what to do about this.
20. By replacing the Key script with Brief 1's coin script and readjusting it, I got the key to work again. I noticed that it was being picked up from too great a distance, which I realised was the PlayerCharacter's box collider getting in the way. What appears to have happened was that the Key script was counting it as collected when the player's collider entered the key's collider, instead of the actual player GameObject. I disabled the box collider and it's fine now.
21. At home, using the instructions given in Week 14's first class, I downloaded and added a simple audio clip to my game. I want to have it so that the key makes a little noise when picked up. When I assigned the Audio script and tried to play-test it, I got an error message that disabled audio cannot be played. I double-checked that the audio was enabled in the inspector window, which it was.
23. In the meantime, in order to have a functional sound in my game, I added an empty GameObject to the scene. I gave it an audio source component and imported an atmospheric clip that would play for long enough to not have to loop. When I tested it out, it didn't work but as I played around with the settings I realised that Spatial Blend was the issue. By changing the value to zero, I got the audio working.
24. In our second class of the week, Glenn helped me get my Events system set up. I had been trying to follow the instructions in CampusOnline, but got confused when I tried to create a UI button. I found out that creating a button and having a take-damage event are two different things, and not steps leading into each other. As a result, I didn't have to worry about the button at all. This is the new script we created to run the system. All it does is note the damage taken and spits out the player's remaining health in a UI overlay.
27. A clip of the functioning game so far. It has the title and remaining health in the UI bar up the top, which updates when the player takes damage. The Enemy does not patrol just yet, but the key appears to be working and the Player can move out of range of the Enemy. It deals 5 damage every time it hits the Player. I will increase the turning speed a little, as it still feels a bit slow.
28. I realised at the last minute that a particle system is a required element for this unit, so I quickly put one together at home using the instructions from Week 14. It's not very pretty, but I plan to remove it once I've submitted this unit because I don't really know how I'd implement it in my game in a way that's not too advanced for me. I had some difficulty assigning a particle material and couldn't figure out how to change the shape of the particles. I attempted to assign one of the default Unity materials, but it just rendered my particles invisible.
The 3D-modelled maze, before and after vertical extrusion. I created this at home in Blender3D, and I plan to add an interesting stone or brick texture to it before importing it into my Unity project. It isn't yet to scale.
CodingInFlow. (2021, June 17). Sound Effects & Background Music | Build a 2D Platformer Game in Unity #11 [Video]. Youtube. https://www.youtube.com/watch?v=J77CMuAwVDY&ab_channel=CodinginFlow
Project Reflection:
The questions of what went well, what didn't and how I handled that are already worked into my process log. I've let go of the idea to have a trail behind the player, partly because I ran out of time and partly because I'm still not certain I even want it. Over the break, I do plan to continue working on this project for myself, so hopefully I'll be able to learn some more coding along the way.
What could I do differently in future?
Next time, I will try to do more on my own; I have very little confidence in programming, so trying to script anything myself is very daunting. Now that I know my way around Unity a little better, I'll most likely follow a few tutorials during the break to try to understand coding a bit better. Also, I feel that I could stand to be less ambitious about how I want my projects to turn out, especially since a few of my desirables didn't get met this time. I wanted the enemy to patrol and chase the player, to have keys spawned in random locations, and to have a whole maze laid out with doors and levelling up. I would also liked to have created an inventory system of some kind to keep track of how many keys the player had picked up, in order to have the mechanic where they must have the right amount in order to open doors.
Now what do I need to learn?
Without a doubt, I need to get a better understanding of programming basics. I'm still very shaky with it, and struggling with Unity syntax. I've tried using the online directory but it's confusing and feels a little above my level. As mentioned in my Final Reflection, I learn best by doing but unfortunately it hasn't worked quite so well with this assignment. I think a glossary of coding terms and how to use them would be very helpful. Another area that could use improvement is my time management. Instead of spending weeks fruitlessly trying to get a complex mechanic to work, such as the two-fold Enemy AI, I could've shelved it earlier and spent the time getting other parts of my game functioning. I think this problem comes down to my need to get everything perfect before moving on.