top of page

Learning Unity - Obstacle Course

  • Writer: Jason Warrick
    Jason Warrick
  • Mar 28, 2022
  • 7 min read

The next section of the 3D course is dedicated to the creation of a simple sandbox obstacle course game.

The section starts off with some notes on game design and how to approach a game before ever developing it. Things to consider include the player experience (How should the player play/feel? What experience do you want to create for the player?), core mechanic (What is the main action the player will execute?), and the game loop (What are the goals/objectives?). The first challenge for this lesson was to give the player a name, just for fun more than anything, so I named mine Skip!


The first challenge of the lesson was to set up the scene with a plane as the ground and a cube, named Skip that is, for the player character. Then we had to create a script and attach it to the player.

Using the script we wrote (seen below), the player character now moves 0.01 units in the positive x-direction every frame.

This was the code that allowed Skip to move as they did, and it's pretty simple! It was mostly used as a way to exemplify the differences between Start() and Update() (Start() runs its code once when the scene loads, Update() runs its code once every frame that the game is running). Just like before, it went off basically without a hitch but was still useful to complete.

The next lesson was on variables, so we updated our code to utilize them, and also alter the values to make the player fly straight up in the air. Still pretty basic stuff so there isn't really much to report here.

In the following lesson we got started on materials, as well as using SerializeField. The materials were pretty simple so far, and not too difficult as I've used them plenty in Godot. It's definitely easier to use here and I really like them so far.

As I mentioned before, we also learned about SerializeField, which allows variables to be accessed and tweaked in the Unity editor. A strange aspect of this is that the changes in Unity are local, so the code will remained unchanged. I feel like this is something that could definitely lead to some confusing errors or bugs in the future so I'll have to be sure to keep this in mind.

Getting player input from the keyboard was the next step in creating our obstacle course. I like the way that Unity handles keyboard inputs a lot more than Godot. It's pretty clean and simple, and it seems like there is a lot more customization in regards to how you want the keypresses to feel, which I appreciate.

Given that the original, raw input movement from above was incredibly fast, we worked on fixing it using Time.deltaTime. Multiplying the speed by this value (How long it took to execute each frame) normalizes the speed of the object across every level of hardware. The resulting movement was incredibly slow, however, so we also added a speed variable to allow us to customize the player movement. Here is what the movement looks like after those changes:

The next topic was a big one, Cinemachine. Not big in terms of difficulty or anything, but definitely a fundamental component of 3D game development in unity.

This is what the project looks like now with Cinemachine implemented. We haven't really delved into many of the settings or intricacies yet, those will come later, but so far it seems pretty easy to use at a base level, and was definitely easy to set up. It was really just attaching the Cinemachine brain to the main camera, make a virtual camera and point it to follow the player, and then just tweak the translation and rotation properties as I saw fit.


This is how the movement looks now with the Cinemachine follow camera added. The smoothing on it is pretty heavy, but for a first use I'm not bothered by it. I'm really looking forward to learning the intricacies of this utility and getting as good as I can at it.

The next step in the tutorials was to get the basic collisions working. This was done by creating the walls like we did with the floor and player character, and then adding a RigidBody to the player character and unchecking the "use gravity" property. The BoxCollider components on both the player and the walls give each object a shape, and the RigidBody on the player lets Unity know that there should be collisions between the two.

Here's what the collisions look like now. I was having an issue with the walls so I added a mesh collider to them, but I've since realized that the issue was that the walls were labelled as triggers, so they weren't registering any collisions.

Methods were the next topic of discussion! With my extensive coding experience I kind of breezed through a lot of this lesson as it's aimed at introducing new programmers to the subject. It was a nice refresher though, as I've been coding in GDScript a lot lately and that has a relatively different structure for declaring methods.

Here's what the console looks like after running that new code with the refactored methods.

This was a pretty quick lesson, we just covered how to use OnCollisionEnter which, if Godot is anything to go by, is a very important function. I plan on doing some research into callbacks, as in Godot their available to implement through the GUI, whereas they're all just functions called within the text editor here.

Here's what the console output on collisions look like!

This is the updated OnCollisionEnter function that is attached to the walls, and now changes the color of the walls when a collision occurs. It was pretty simple, only one line, but I do want to look into how to make a custom color instead of just the premade red.

As expected, this is what that looks like! This is one of those things that, even knowing how simple it is to implement, it still feels so cool. Any sort of dynamic change of an object at runtime will always be so fun to me.

The next lecture mostly consisted of using skills we already know to add some functionality to the game, in the form of a score counter that tracks how many collisions are made. This was done by attaching a new "Scorer" script to Skip (our player character) that increments and prints out an integer that tracks the number of collisions made.

And here's that script in action! As you can see there's a new, albeit a little boring, obstacle added, along with a new debug message that displays our score!

Time.time was the next topic of discussion, and was pretty brief. This is a new script that we attached to a floating block (that will eventually fall after a given time) that simply prints out the elapsed time of the running game.

Here's what the console log looks like with that in action. You can see the shadow of the floating block since I altered the lighting to point straight down in order to accurately express that objects position.

In the next lecture we covered if statements, and altered the script on the (eventually) falling block to print a message when 3 or more seconds have elapsed.

Here's a quick video showing that in action! As a side note, the falling block is now a prefab so I'll be able to duplicate it as much as I want and retain all of its original properties.

This was probably the most interesting lecture so far as the game is now becoming much more dynamic. We used cached references to store and reference the MeshRenderer and RigidBody of the falling block, and then adjusted its properties after a certain time to make it visible and start its falling.

Here is a video of the aforementioned falling!

Next, we implemented tags to both the player, as well as to an object once it's been hit by the player. This is done to prevent repeat hits being counted, as well as further organize and structure the project

Here's a quick demo of the new collision scripts. The collision in general is still pretty wonky, but especially with the RigidBody cube, which I'm hoping is something that the course addresses soon. If not, I'm sure there's plenty of documentation on collision handling that I would be happy to look into.

This lesson was another quick and fun one, implementing the spinning game objects! The method for it is pretty much what I expected, just altering a property over time, but much like the changing of the material on hit, it's so much fun to see it in action and be able to play around with it.

Here's that spinning object in-game! It might be a little fast, but since it'll pretty much just be me playing it I'd like it to be pretty difficult. Also, the instructor mentioned the buggy collisions and alluded to the fact that they'll be covered in a later section of the course, nice!

Before finishing out and designing the rest of the obstacle course, there was a lesson on organizing your projects (making prefabs of any repeated obstacles, organizing folders and empty objects, etc.), as well as making ramps for small ball obstacles to roll down. A pretty short lesson but a nice reminder nonetheless!

At last! The full course is finally done! I tried to strike a balance of different challenges (Precision navigation at the start, dexterity and reactions with the spinners, balls, and blocks, timing and more precision with the archways) while still making everything fun and it's pretty fun if I do say so myself!

Here's me playing through the course without hitting anything, which admittedly took a few tries. I'm pretty happy with how this section of the course went! I completed all of the challenges given pretty easily and I experimented as thoroughly as one can with my current skills! Given that the tools I learned about in this class aren't super extensive, I might hold off on any independent projects until I finish the next session as I want to be able to use as may of my skills as possible.

Comments


©2025 by Jason Warrick. Proudly created with Wix.com

bottom of page