Table of contents
Introduction
Benjamin Franklin once said, “the best video games that I have ever made were the ones where I persisted and didn’t give up.”* Whether or not Benjamin Franklin actually said this, he is right. Welcome to Part 2, and congratulations on continuing this tutorial series on creating a 3D Smash Game in Unity! In this tutorial, we will be tying everything together into a complete game. We will be using the Scriptable Render Pipeline to add a shader to our glass and our ball. And we will set up a UI system for the start and end of the game. With that runthrough, let’s get started!
Check out Part 1 if you haven’t already
This tutorial is part of a series. You can check out Part 1 here. This is where you’ll also get the link to the Source Code files, as you won’t need to download additional ones from this part onwards.
Did you come across any errors in this tutorial? Please let us know by completing this form and we’ll look into it! FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.
Creating the shaders: Glass
Before we get started using the incredibly awesome SRP (Scriptable Render Pipeline), we need to first import the package. Go to Window -> Packages,
… and download (or update) the Lightweight Render Pipeline.
Once it is finished importing, go to your Materials folder and right-click. Go to Create -> Shader -> PBR Graph.
Call it “GlassShader” and then double-click on it to edit it.
You can dock this window where ever you like, I either keep it in the editor window or detached completely.
Let’s talk glass, how do we go about making a glass shader? This is probably oversimplified, but for our intents and purposes, glass has a transparent component and a reflective component. There are other things like scratches and smudges which give a different set of looks but for all we need to know, glass is reflective and transparent. With this in mind, we could go for a hyper-realistic type of glass, or we could make it sort of stylized. Since we don’t have access to vast amounts of textures to make it look hyper-realistic, we will be going the “stylized” glass look. But how do we create a reflective and transparent glass? It is really simple, go to your “GlassShader” window and change the shader type to be transparent:
This just means that we can apply values to the Alpha field. Right-click and select “Create Node”.
Search “Fresnel” (pronounced Frah-Nell),
create a “Fresnel Effect” node and drag the output into the “Alpha” socket on the material node.
What does a Fresnel node do? In our case, it makes the edges opaque and the centre transparent, which is perfect since we are making a glass material. The trick here is to find the right value for the power socket on the Fresnel node. What I did was to actually create a Vector1 property called “Fresnel Power” so that I can change this value in the editor without having to access the shader.
If you’d like, set a color for your glass
(I did a light blue) and then hit “Save Asset”.
Create a new material called “GlassMat” and set the Shader to be our “GlassShader”.
Now it’s just a matter of tweaking the “Fresnel Power” in order to get the look your after. You could make it harder for your players by making the glass more transparent, or you could be merciful and make it slightly more opaque, it all up to you (I would try and be merciful).
When you think you’ve found the right value, we need to assign it to our glass objects. This, I found, was slightly tricky. We want the glass shards to have the same material as the glass pane. The best way to do this is to drag each broken glass prefab into the hierarchy:
Group select a few shards and then drag the material onto the selected objects.
Keep doing this until all of the glass (whether broken or whole) has the Glass Material. It can be tedious so just get through it as fast as possible. Once you are done, apply your changes to the prefab.
Creating the shaders: Steel Ball
If you thought the glass shader was simple, wait ’till you see the shader for the Steel Ball! Go to the Materials folder and create a new PBR Graph called “BallShader”.
Double-click on it and let us start making this shader! Change the workflow type on the base node to “Metallic”. That’s it! Now it’s just a matter of changing the “Metallic” value to make it look like a shiny steel ball. If you’d like, you could also make this a float property called “Metalness” (or something else that doesn’t sound as ridiculous) and then you could change its value in the editor. You might fiddle around with the Smoothness and Occlusion values if your ball still isn’t the way you’d want it to look.
Once, you’ve finished tweaking those values, that’s it for our Steel Ball shader! Create a new material called “BallMat” and assign our “BallShader” to this new material. Then we drag this material onto our ball prefab to see how it looks!
If it looks good, apply this change to the prefab.
Creating a level: Ground
Now that we have our shaders setup, let’s create a level to place these things in. First, I am going to create a plane so that our shards fall and bounce around, making it look much more realistic. When creating a level, I actually got creative and made several different planes, each with different sizes. I encourage you not just create one flat plane for your entire level, create several. Spread them apart and angle them if you think it looks cool. Just get creative! Second, I assigned a material to the plane to make it look less like a 3D primitive and more like an actual part of the game. The material I used was in ExampleAssets -> Materials. Just pick one that you think would go well with your scene. Here is my final result:
Feel free to make your level longer or shorter.
Creating a level: Glass Panes
Now that we have a ground, let’s add something on top of it. We are now going to be adding the glass blocks to our scene. When you do this, I have one command that you MUST follow, BE CREATIVE! Seriously, just go crazy! I have found it is best to place the glass blocks slightly above the ground so that the glass shards have room to fall, but, if you place the glass so that it is slightly overlapping the grounds, the glass will explode if you hit it. With this in mind, start creating! Here is my finished level:
Adding a UI Canvas: Restart Button
If you notice on your CameraCharater script, there is a field called “Button”.
If you look at the code:
private void OnTriggerEnter(Collider other) { if (other.CompareTag("glass")) { collision = true; Debug.Log("Collided with glass!! Man down!!"); camMoving = false; button.SetActive(true); } }
You’ll see that this button is activated when the camera collides with the glass. If you were scratching your head when you put this in your code I am now going to explain why it is there. In the original game (do not go and download it! You are making your own now so you don’t need the original), there is really only one scene. This means that the UI controls whether or not the game is running or stopped. Because of this, we use a button to restart the scene so that the player isn’t jarred back to the beginning immediately. Go to the hierarchy and create a new button called “Restart”.
In the CameraCharacter script you’ll notice a public method called “Reset”:
public void Reset() { SceneManager.LoadScene("Scene1"); }
This is the method that will be called when we press our Restart button. Change the text on the button to say “Restart”,
Create a new “OnClick” action, drag the Camera into the field, and set the called method to “Reset”.
Disable the button, assign it to the proper field on the Camera:
…and hit play. Now we have a button that resets the game when we collide with a piece of glass!
There is just one thing I think we need to do before we are finished with the UI Canvas…..
Adding a UI Canvas: Start Button
…and that is to add a start button! It may seem like a trivial thing but it gives more control to the player which, in the case of our game, is a good thing. Create a new button called “Start” and place it directly over our Restart button.
If you have another look at the CameraCharacter script:
public void StartCam() { camMoving = !camMoving; }
You’ll see that there is a public method which sets a static boolean to a value different to what it was originally (by using the !boolean syntax). This boolean is false by default:
public static bool camMoving = false;
You’ll also see that the Update method has a series of logic statements which use this variable as well:
//This checks if we have collided if (!collision && camMoving) { cameraChar.Move(Vector3.forward * Time.deltaTime * speed); //This is so that the camera's movement will speed up speed = speed + incrementFactor; } else if (collision || !camMoving) { cameraChar.Move(Vector3.zero); } if (Input.GetMouseButtonDown(0) && camMoving) { GameObject ballRigid; ballRigid = Instantiate(ball, BallInstantiatePoint, transform.rotation) as GameObject; ballRigid.GetComponent<Rigidbody>().AddForce(Vector3.forward * ballForce); }
From a quick glance at where this variable appears, do you understand how it we are using it? We have a boolean that is static (in case we have other scripts that want to stop or start the camera) which dictates whether or not the camera is moving or not. So when we start creating this Start button, all we need to do is call the method which sets a different value to this boolean. And you know which method that is!
public void StartCam() { camMoving = !camMoving; }
Go to the Start button and create a new OnClick event. Assign the camera to the field and set the called method to be “StartCam”. Don’t forget to also change the text to read “Start”.
Now hit play and let’s see what it looks like!
It works, but the buttons are cluttering up our game view. They stay active even after we have pressed them. Let’s just have the Start and Reset buttons disable themselves whenever they are pressed. Create a new OnClick event in each button, drag the instance of each button into their respective OnClick event, then set the action field to “Gameobject -> SetActive”.
Leave the box unchecked on each one and we now should have a clean game view.
Well, I think that is all we need to do for the UI! Obviously, as it is, the buttons are very ugly so please make them more interesting. Here is another opportunity to get creative!
Fixing the Sky
Our game is almost complete! There is just one thing that I find not as aesthetically pleasing and that is the sky.
Now it may not bother you at all, in which case, just leave it as it is. But, I feel it would add another level of ambience if the game had a different color or style of background. In this case, I found it was only necessary to change the default skybox which can be found in the Materials folder.
This is a good thing to remember since you can get lots of varied looks without having to create your own skybox. I decided to have a go at tweaking these values.
I wanted a darker background because this would create a nice contrast between the dark sky and our light colored glass panes. In the end, I decided that these values were the result I was looking for.
In order for this to work though, we need to bring add a Skybox component to the camera and place the finished skybox in the “Custom Skybox” field.
Let’s hit play again and just appreciate our game for all its fine aesthetics and mechanics.
Conclusion
Congratulations on finishing this tutorial, you can check out part 3 next! At this point, you have learned 2 things, how to make a game similar to a popular mobile game, and what to do if you have no idea what kind of video games to make. It’s no small feat to have made this much progress. I hope you have enjoyed this tutorial series so far and found it useful. I’ve got nothing else to say except:
Keep making great games!
*Editor’s Note: Sadly as of this moment the historians haven’t discovered any evidence yet that game design was part of his famed routine.