Supporting files for VG1 quests are part of a single archive that you can download here.
You must complete all of part 1 before following these steps. Continue with the SpaceShooter scene.
Creating a Canvas also spawns an EventSystem which allows UI to respond to input.
When you create a Canvas, it adds a much more massive rectangular outline to the Scene view. Double-clicking the Canvas in the Hierarchy should zoom the Scene out to show it. Circled in the corner is how small the Camera view compares to the Canvas.
The Camera boundaries are much smaller than the Canvas view. This is because grid units for the Camera view are metric (meters), while units for the canvas are pixels. It is normal for a screen resolution to be in the thousands of pixels while a camera will only frame a few meters of width and height.
Normally, the Camera cannot see UI objects and the Canvas cannot render normal gameplay objects. Having these separate is helpful and allows us to separately address the unique challenges of camera framing and responsive UI design. There are advanced settings for merging the rendering of Cameras and UI, but we will not be using them at this time, so do not use the Camera to layout your UI in this assignment.
Use these settings so your Canvas is aligned for widescreen and simulates a reference 720 HD resolution. This gives us a consistent baseline target for building our UI regardless of what the players' hardware might be.
The first time you use TextMeshPro, you will be asked to set it up. Click "Import TMP Essentials". You DO NOT need to install any examples or extras. Just close this window when it's done.
Text objects should automatically be created within the Canvas.
A lot of UI design is about anticipating how dynamic content will change. As players score more, the text widens with more characters. Use the following settings. Pay special attention to all the details of sizing and alignment. We use these Wrapping and Overflow settings to prevent truncating the score text as it grows.
UI objects have a RectTransform instead of a Transform, which has extra settings for anchoring and alignment.
Position your Score Text in the Upper-Left by first setting the Anchor, then the Pivot, then the rest of the numbers.
Your Score Text should be anchored Upper-Left.
You can see how the Canvas render overlays the Camera render by previewing the Game tab.
We can Duplicate and Rename our “Text - Score” as “Text - Money” to save some time with Text settings.
Because we want our Money to be anchored and aligned Upper-Right, we will Align our Text to the Right.
Similarly, we will use an Upper-Right Anchor, adjusted Pivot settings, and Position values in our RectTransform.
Score is Anchored Upper-Left. Money is Anchored Upper-Right.
We can create Images the same way we create Text objects.
Rename our Image so we know what it is for.
Adjust the Image object settings for the look we want. Filled image types allow us to partially show portions of an image based on its fill amount. This is great for dynamic health.
We will Anchor our health bar Top-Center.
These settings will position it Top-Center.
Notice how the three UI elements (Score, Money, and Health Bar) stay anchored to the Top- Left, Top-Right, and Top-Center no matter what Aspect Ratio is chosen.
Creating Buttons works similar to other UI elements. Button GameObjects contain a Button Component and Image Component on the parent along with a Text Component in a child object. All of these play a part in customizing a Button.
We setup our button’s Text with placeholder text and formatting.
Switch to the Parent Button GameObject and position it as appropriate for our game.
We will be using a Left-Center anchoring for all of our UI buttons.
Duplicate this process for four more buttons.
Position them accordingly. All of them should be anchored Left-Center.
These are placeholder values. The prices must be updated to reflect the true cost of upgrades once those have been programmed.
This completes the UI layout of our quest. The remaining steps will add dynamic text and interactivity.
Notice that we are in the Ship Class. You must add the UI namespace to access UI classes.
We need an outlet to control our UI Image object. We also add properties for keeping track of health and maximum health.
We created a Public Outlet which requires us to fill in the property.
We modify our existing Update event with a conditional that requires the player to have health in order to move.
A death function will let us cleanup and transition to a dead state.
A TakeDamage function will handle damage. We need to check for less-than zero health because the player can take so much damage at once that health is never exactly zero and actually goes into the negative. Fill amounts for images are on a scale of 0 to 1, which makes it really easy to use ratio calculations.
On collision we will take damage which could lead to death.
Notice how the health bar is only partially rendered based on our health ratio.
Notice that we are in the GameController class. We will add the Namespace for UI, add a Public UI Text Outlet, and a property for keeping track of score.
Any time you make a Public Outlet, you must remember to fill in the property.
A dedicated Display Update function will let us update all the UI in one function. We will call our UpdateDisplay function every frame so it stays up to date.
A Points Earning Function will allow us to centralize point calculations.
Scores are reset to zero at the start.
In your Projectile C# script, we earn points when Asteroids are destroyed.
Money works almost identically to Score. It requires the same kind of Outlet and Integer Property.
Fill in the outlet for Money.
Money gets reset when score does.
You earn Money at the same time and amount you earn Score.
We must also update the UI for money the same way we do for score.
In your Ship class, we will create a function for Hull Repairs.
Buttons have a lot of settings for aesthetics along with a section for setting up click interactivity.
Click the + to add a Click Event. Drag the Object containing your Function into the blank. In our case, the Ship has the Function for Repairing Hull. From the Drop-Down, select the Component and finally the Function you would like the button to trigger.
The Hull Strength Upgrade Button is unique in that the Button Text changes every time we use the upgrade. To alter the Text, we need to create a Public Text Outlet to reference it in code.
Our UpgradeHull Function shares a lot of similarities with the RepairHull function. Both calculate a cost, check if enough money is available, subtract the money from our wallet, and grant the player some special stat.
UpgradeHull is unique in that we also update the Button Text to reflect the cost of the next upgrade purchase.
To update the Text we need to fill in the UI Outlet for the Text we are updating.
Be sure to drag the correct Button Text object into the blank.
We also need to hook up the Button Event the same way we did for the previous button.
Just as before, create your Public TMP Text Outlet.
Fill in the Outlet.
Create your Upgrade Function.
Setup the Button Event.
The next two upgrades work the same but are in a different class. We put these in the GameController class because the GameController is easily accessible by other Game Objects.
We create a Public TMP Text Outlet so our Button Text can be dynamic.
A Missile Speed property will increase as we upgrade it.
Fill in the TMP Text Outlet blank.
In our Projectile script, we will update the variables to make use of our new GameController property.
Back in GameController, we create an Upgrade Function similar to all of our other Upgrade Functions.
Setup the Button Event. We are referencing the GameController object this time instead of Ship.
Similar to before, we create a Public TMP Text Outlet and a number Property to keep track of our upgrade stat.
Fill in the blank for the Outlet.
We modify our EarnPoints function to make use of this Bonus Multiplier stat. Now we earn more points the more we upgrade.
An UpgradeBonus Function mirrors the other Upgrade Functions.
Finally, setup the Button Event.
When we first design UI, we often use placeholder text because we don’t always know the final values. Now that all the programming is complete, ensure that all the button texts match the actual costs of each upgrade. Do NOT leave them at their incorrect placeholder values.
Playtest to ensure all interactions work as expected and that the addition of any new features hasn’t broken any earlier interactions.
SAVE any open files or scenes.
Submit your assignment for grading following the instructions supplied for your particular classroom.