Learning Unity - Water You Doing
- Jason Warrick
- May 15, 2022
- 8 min read
Created by following and expanding upon a GameDev.tv tutorial
Moving onto the next section of the boot camp, we are developing a physics based movement game.
Play the game here!
The first lesson was just an overview of the design of the game, which will consist of a few levels, with an emphasis on precision movement and mastery. As part of the lesson the instructor made a challenge for us to come up with our own theme for the game, as well as a new name. To differentiate my project I went with a water-jetpack theme, and the name "Water You Doing?" (very funny, I know).
As a part of the challenge in the next lesson, we have to list out the first 3 most important features in our game, in order of importance. Here are the 3 most important features of Water You Doing?:
Physics based movement
Moving / dynamic environment
Good difficulty curve / strong level structure

As you can see, the first lesson in Unity was pretty much just a project setup. I've got a player character, ground, and launch/landing pads all prefabbed, and then made some materials for all of them and organized the project structure.
The next lecture was just a briefing on what classes are and how they work, so I mostly skipped over it, as I'm very familiar with classes.

Setting up and debugging inputs were the next items on the list, with the above code being the final version within the lecture. I worked well and was responsive enough for tutorial purposes, but it bugged me a little that the left input was favored so heavily, which would make the game feel sticky and unresponsive, in my opinion at least.

This itch for a better input system led me to the above code. I'm pretty sure there's a cleaner way to do this, and if I find it before finishing the game I'll be sure to make an update, but for the moment this is what I'm going with, and it plays exactly how I want to. It successfully gets rid of the left input taking over, and now you can swap between the two dynamically, and the most recent button press gets the input. This was the first time I really experimented with my programming in Unity and it was so much fun, I can't way to get way deeper into gameplay programming, as it's the subsection of game development that I'm the most interested in at the moment.

With our new and improved inputs, we then learned how to apply thrust to an object! It's pretty simple really, just a single line that applies a set force in the up direction (relative) to the newly added RigidBody every time we press space.
The thrusting is currently way too strong and super floaty, but it works!

The next lecture was just reminding us to make a thrust variable, and then make it time independent as well. This helps a LOT with tweaking and testing, which will still need quite a bit because the rocket is feeling super floaty!

The rotation has been implemented! The first version in the lecture was pretty simple but a little tedious, so the instructor showed off some pretty useful refactoring and organization tricks to make it cleaner and easier to use. The "Extract Method" function wasn't something I'd seen before, but most certainly will be something I'll use frequently from now on!
While it doesn't feel as fast and responsive as I'd like, it's not bad and, most importantly, it works! And works well at that!

This next lecture was a super useful one! We fixed the buggy rotation collision with this little addition to the rotation code which is one of those things that I would never have even thought of to do or learn, but makes so much sense now that I have.

The next step was to make an obstacle to fly over (and under as I've made it) and to adjust the constraints, drag, and gravity. We've done constraints before, but the drag and gravity were both super helpful in making the game feel better to play. To compensate for the new, heavier gravity of -15 I boosted the thrust as well.
And here's the new movement, brought to you by the newly learned "Maximize on Play" button! As you can see, it's a lot snappier than before, which is exactly how I like these kind of games to be.

The next lecture was semi-conceptual, covering source control and tasking us with backing up the project to GitHub, which I've done plenty of times before.
Check out the GitHub here!

Audio was the next step in the process! There wasn't much covered here, as a lot of it was about how to source audio and download it, but what we did in Unity was pretty straightforward.
Fair warning, the audio is probably pretty loud (Sorry if you already played it and it was too loud!), but as I said, this was all just the basics so we haven't tuned anything yet besides "Play On Awake".

The audio now only plays when the thrust is pressed! I pretty much knew the general approach to doing this, but it was good to hear that it's the best way to do it from a professional! I feel like I'm getting into a pretty good groove with the references to objects and whatnot and the general Unity workflow which is nice!
Here's that sweet, sweet lawnmower thrust doing its thing!

Switch statements! This is one I've been waiting for! I use switch statements a LOT, like probably more than I should at the cost of optimization, but they're just so clean. Anyways, this was pretty standard in terms of switch statements, so not too much to report aside from the fact that we're getting close to an actual game loop, which is exciting!
Here are those collisions printing out with the switch statement, pretty straightforward!

This was a pretty crucial lesson, as it covered scene handling. If my Godot experience taught me anything, it's that loading / freeing scenes is massively important to game development, so I made sure to make some notes to help me along through this lesson. In actuality it's relatively simple, if a little verbose.
What that mysterious code above was doing was this! The game now reloads the level when an obstacle (not the start, "fuel" orb, or finish) is hit. Now it really is becoming a game!

We now have not only multiple (2) levels, but we also have a way to switch between them! This was another jump up in complexity, but still very manageable, just new information. I'm actually a little proud of myself because my method of determining the next level actually requires less lines and calculations than the instructor's, but is probably a little more confusing, which is something I'm sure he's trying to avoid.
I've made some visual changes as well since the last update, including switching to an orthographic view and adjusting the lighting. The orthographic view makes it MUCH easier to see where the corners are, as you couldn't in the perspective view, and the lighting changes are just a result of the new view style. Also, as you can see, I separated the first level into two different ones for the sake of testing!

The next step in polishing our level system was to add a delay whenever the goal or an obstacle is hit, which was done using Invoke. I know, I know, trusty Rick Davidson brief me on the pitfalls of using Invoke (relies on string references, other / better ways of doing it), but he appreciates its simplicity for our current use cases. Another added feature is that when you hit anything that triggers a reload, you briefly lose control of your character. And again, I know, it's a big no-no to take away the player's control, but I feel line in this case it helps to delineate the playing from the lose or win conditions.
As advertised, here's that delay in action! Pretty sweet right?

So I forgot to update this after the last lesson, but that's not a huge deal as they were both covering audio. We have a new and improved audio system that works by caching references to audio clips, then swapping them in and out as different events occur. This is done for the win and lose states, as well as the thrusting noise, which is also updated to be less annoying and more water-esque!
And here's a quick demo of those new sounds!

Here's our fancy new player character! It's a little simplistic, but that's what I'm going for! The "lore" for this character is that they're really into outdoor housework and made this chair out of a lawnmower engine and a power washer, with the original intent of reaching gutters more easily, but then fell into a cave exploration career using their new technology.

Onto particles! Rick so kindly provided a package of particles for us to use, so it was really just a matter of attaching them to the player prefab, and then calling the play function on them from code.

Here is said code, which used cached references to the win and crash particles (Thrust particles coming soon!).
And here are said particles doing their thing! I actually really like how they look, at least for a simple game like this.

Continuing the particles section of the tutorials, we then got particles working on the player whenever they thrust. As you can see in the screenshot, there's particles for the bottom "main" booster, and two side ones for the rotation.

These are done as you would imagine, just by triggering them on button press, and then turning them off on button release, pretty simple!
Don't they look nice? I'm eventually going to change them to blue (if I can) to fit with the power-washer theme, but this'll do for now!

The next lecture was just a quick refactoring challenge, so now here's my nice, clean new code!

From there we implemented some debugging tools in the form of a next level button and a collision disabler button, as seen above! The collision disabler required the GetKeyDown function that way the boolean would only change once, but since the next level happens immediately it didn't require it. The collision disabler works like you would assume, it just toggles a boolean which, if true, will prevent the collision sequence from happening.
Hello! I had to take a brief break from the tutorials / project (not that you could tell, this is all one big post) to finish up my senior year of college (yay!), but now I'm back! This gap was further compounded by the amount of stuff involved in this step, as it was centered around building out the environments and lighting, and creating a mood for the game. I stayed pretty close to the visual style of the tutorials, but still built out the environments and lighting on my own, and I'm very happy with it! Lighting is something that I really, really, REALLY want to learn more about, so it was fun to mess around with it here.
The next lesson was another pretty significant uptick in terms of newer, interesting concepts. This was, as you can see above, setting the foundations for moving platforms, and with a pretty modular approach as well which is always something I appreciate!

It was pretty simple as well, just a few variables and some very basic vector math!
The block now oscillates smoothly on its own! This was super interesting to learn about, as I've always felt like I need to learn more about the intersection of math and game dev (Yes, I know that sin is simple, I just mean in general. Everyone has to start somewhere!). I'm still undecided about the speed, but I think it works for now, and I don't know if I really want to spend too much time playtesting for a tutorial game.

Here's the code for that functionality! It doesn't look like much on "paper" but there's more to it conceptually, especially when learning about its applications in game development for the first time.

This is just a small change to the update function in the moving obstacle class that prevents against NaN errors.

The last "code-based" lecture was implementing a quit feature, which was pretty simple! This class is part of a new "QuitApplication" script that's attached to the player prefab. We can't actually test it until we play the build version of the game, but the debug is there as an initial test.
Ta Da! The game is now officially complete! As you can see, there's a few more levels now, some updated lighting and particles, and it's also running as a full build so it's really an actual game now! You can play it here if you'd like!
What I Learned
Well, for starters I'll just say quite a bit! The main points, however, are as follows:
Physics-based player controls
Particle Systems
Environment building and lighting
Implementing sound effects
Dynamic obstacles using Sin functions
Platformer puzzle design
Script management and class building
Scene management in the build settings
Exporting games in Unity
This was so much fun to learn, and hopefully I'll have another one of these to post soon!


Comments