Since our games was almost finished after the update of 23 may, all there was left to do was tweaking values and fixing bugs.
– Shielded enemies are now visually updated to have particles spawned when backstabbed (Particles made by Michaël).
– Color of the Question Mark when losing sight of the Player is now a darker shade of yellow.
– Menu navigation with Controller is no longer receiving double input, pressing a button now works as intended.
– Menu now has a back key in combination with a back button (B on Keyboard, B on Controller), so that navigating to the back button is not required
– Navigating in Menus on Controller now uses the same Input as in Inventory (Joystick instead of D-PAD)
When introducing the colliding camera, we had no smoothing whatsoever. This meant that, when colliding with the irregular terrain, you’d get a shaking camera, which is not what we wanted. Later on we’ve added some smoothing, but we forgot to test whether or not this worked well on the Terrain.
When Michael accidentally forgot the terrain tag in Level 3, we noticed this issue from earlier was actually fixed, so this helped us fix the terrain clipping we had earlier.
Also, because our FPS is less terrible right now, we can set the occlusion a bit less harsh, which meant we could tweak the near plane from our camera without having clipping issues.
This way, there seems to be no more clipping terrain planes anywhere in our game, which will increase the immersion effect.
The enemies have been a struggle since the beginning, with a script that kept growing in size, the bugs kept appearing whenever something was changed.
Therefor, Brecht, Nick and I have been sitting together to rework the entire script. It has now been divided into smaller scripts that define the behaviour of the enemy, depending on its type (i.e. Ranged or Melee, Shield or no Shield, Patrol or Guard). This increases maintainability and readability by a lot, and writing the script from scratch gave us more insight in where each bug might be coming from.
Since there are 3 enemy models, each with 3 possible weapons, and the option to have a shield, creating a prefab for each type would clutter our prefab list. Therefor, I’ve created a script which allows us to easily generate a different enemy model in edit mode.
Last week, I’ve been working on auditory feedback for the Player, adding sound effects to as many actions as possible. However, it is not guaranteed that the Player will be playing with sound on. Therefor, having auditory effects alone will not suffice. Visual feedback is always required, and sounds are just there to complement this.
One of the key things at the very start, is that the gate opens when you pick up the lantern. This was not always as obvious as we thought it was. People struggled getting past the first part. Therefor I have now added a system in the Camera where you can start a Cutscene. This will move along a path, set by waypoints, over a specified duration.
Although the path isn’t automatically curved like bezier curves would do, it is still capable of creating a decent cutscene when the waypoints are placed correctly.
Up till this point, the menus existed of standard Unity UI visuals, which didn’t fit our style.
This week I’ve updated these visuals, using the images our artist Mathias made for us. Using slicing, I can easily adjust the size of each window, without stretching the corners, if this is later needed.
I also updated the Colors of selected items, to make them pop out a bit more and make them fit the updated colors more.
A toggle for the FPS Counter was also added.
Last week I added the basics for the Sound Manager, and added a few simple sounds to demonstrate this.
This week I’ve improved the script a lot, adding functionalities such as fading in and out, and 3D sounds. We now have added almost every sound that the game requires. These can easily be changed if we find a better fitting sound later on.
The boss fight now has its own background music, which creates a more tense atmosphere and really elevates the boss-fight-like experience.
Other than that, sounds now have their own volume (split in two groups: Music and SFX) which can be adjusted to your preferences in the Settings menu.
Since these have to be altered with Sliders, and moving the sliders around with buttons felt really slow, I’ve added an overriding script for the slider handler, that now moves the slider faster the longer you hold down the button.
Footsteps have been introduced in Solani a while back, but they were using magic numbers and inefficient code.
Adding Sounds was simply impossible since the footsteps didn’t match with the actual foot positions of the Player. This was not so visible, thus not so important when only the footprints were there, but when adding the sounds, it become too obvious that something was wrong.
To fix this, I had to figure out a way to find out if the foot of the Player, that was attached to one of the Bones, was touching the ground. Since his feet are animated, they don’t always touch the ground perfectly. Calculating the difference between the hips bone and the foot bone actually gave us a result that looks right in almost every case.
Also the rotation had to be taken care of. The print has to be aligned with his foot, but also be parallel with the ground. Using some raycasts and cross product maths did the trick.
Since instantiating and destroying the footstep objects every time is a very heavy operation, I added pooling to optimize this simple script. Hiding and unhiding these GameObjects is way better performance-wise.
[Note: Video has sound!]
During the holidays I’ve been looking into how to make a system that can play multiple sounds, can be accessed from all scripts and is easily maintainable.
To achieve this, I’ve made a manager that has a list of Audio Sources. These can be easily added and tagged, so they can be accessed through some simple functions in the script.
Since the manager is a singleton, this will also ensure that there’s always one and only one manager present in the scene.
I also added a functionality to pick a random sound if multiple sounds with the same tag have been added. This is often done in games to create variation for very repetitive sounds, such as footsteps, hurt sounds, and so on.
All there’s left to do to have all the sounds in our game, is to find or make them, add them to the manager, and call them in the corresponding scripts.
When completing level 1, you enter a new scene that represents level 2. Since unity unloads level 1, and level 1 and 2 are not synced, we needed a way to save everything that we needed to know from scene 1 and apply that to scene 2.
This can be done by saving all the variables to our GameManager, since this manager does stay loaded, and load the variables back into the corresponding scripts. This way we can keep our Inventory the same, which means your stats from level 1 will be saved when going to level 2, just like you keep your learned abilities and Spawn Position.
It was necessary to save the variables, so that we could later write a Save file that’s stored locally, which would allow the player to continue from where he last left the game. Saves won’t occur regularly though, only predefined checkpoints and the transition to a new level will be seen as a point where the player information is saved.
After having some people play with the new main menu and settings, I noticed it was sometimes not clear which element or button was selected. To resolve this, I added color options for UI Elements. It can easily change the color of all UI elements in the menus with a single defined Color. This way we can find a color that fits our theme and contrasts enough with the background to make it obvious which element is selected.
It also makes sure text remains readable when changing colors. Whenever a color is too bright, the text will change to a darker color instead of keeping the light one, and vice versa.
Since check boxes and slider handles are tiny buttons, changing color doesn’t make it pop out a lot. Therefor, I added a border around the setting that is selected. This border will be hidden when selecting buttons, since buttons are big enough by themselves.
Since our Game needs to have Keyboard/Mouse and Controller support, creating menus with interactable UI elements isn’t as easy as usual. Clicking on a Button with your mouse is easy, but Controllers don’t have a mouse, nor are they able to control the Cursor. To fix this issue, I’ve decided to get rid of the Cursor entirely (Now always locked and invisible in the game), and instead select the UI elements using a Script.
Going through the different elements wasn’t as difficult as anticipated. Unity’s UI Elements inherit from a Selectable class, where I can get any adjacent UI element. It is then very easy to get the Input from your controls and look for the next element using that method. Controls are currently set as WSAD or Arrow Keys for Keyboard, and D-PAD for Controller. The submit key is X or Enter for Keyboard, and X for Controller. To change the values of a Slider, just simply have it selected (highlighted) and move left or right.
One issue that emerged from using these controls, is that Unity internally already does this selecting based on input. Since their axis is the same as ours, holding down any of these keys will make the highlight blink on the wrong button, or highlight a wrong button until you let go of the key. To prevent this, I had to manually overwrite the Colors depending on the selected element, instead of relying on the normal and highlighted colors that are defined the Button.
This also means I have to keep track of the last used button, so I can reset its colors when another button is selected. This gave me the opportunity to add a system that remembers which button you last pressed, which is convenient when switching from Main Menu to Settings Menu and back, for example.
In the previous Camera, you’d often lose sight of your player because something was obstructing your line of sight, such as a wall or a pillar. To prevent this from happening, we needed some kind of Collision Check on our Camera, to see whether or not the view was obstructed.
To achieve this, we simple have to cast a ray from our Camera’s Look at position to our Camera Position, and the first hit point of the Ray determines the new Camera position. This method is very simple and works for most cases, but it needs some tweaking and optimizing in a few occasions.
One of the main issues is that the Camera will “jump” to it’s new position. This sometimes gives ugly Camera movement and should be avoided.
Another issue is when you’re looking along the side of a wall. This will allow “wallhacks”, since the Camera will partly exactly on the face of the wall, meaning the first part of the wall will not be rendered due to it being outside the near plane. The backside of the wall is backfacing, making it is also ignored during rendertime.
We also weren’t sure whether to add the Terrain itself as a collider for the Camera. The pro of using it as a Collider is that you don’t see random gray-ish planes in your Viewport because of the raw terrain shape (some faces will not be entirely backfacing, so these will still be rendered). The con is however, is that your Camera will “jump” a lot while sliding across the faces of the terrain collider. This will give the Camera a “twitching” effect, which is not really what we want.
We’ve voted to ignore the Terrain Collider when casting the ray, as the con was more obtrusive than the pro.
Jumping right into the game once the game has loaded is never appealing in a Game. It surprises the Player, and that’s not something we want. We’ve added a Main Menu Screen to prevent this from happening.
The looks of the Main Menu are just a temporary placeholder until we created a decent background to fill the screen with.
In the Start Screen you’ll find a few buttons:
– New Game: Start playing in a new game (Currently the only supported way to start a game, since your progress is not yet saved)
– Load Game: Load an existing save file (Game will have checkpoints, this progress can be saved onto your PC and loaded in when you wish to continue playing)
– Settings: Open the Settings Menu. In here you can configure a few settings such as Sensitivity and inverted movement. This menu can also be accessed in game by pausing the game with ‘P’ (Keyboard) or ‘Start’ (Controller)
– Controls: Open the Controls Menu. This (currently) shows an image of the keybindings that you’ll need to know to play the game
– Quit: Quit the Game.
The Quit Button in the Pause Menu has now been replaced with a “Main Menu” button, which brings you back to this main menu screen.
This menu is currently only controllable with the mouse, just like the Pause Menu does. Controller support should be added by next week.
The Controls can now be seen in game, in case you’ve forgotten the key binding.
You can display the controls image by going to the Pause Menu (P), and clicking on the Controls button.
Currently, the Pause Menu does not yet have support for Controllers, but this will be added very soon.
This feature can later also be improved to have customizable key binds (this is just an idea at this moment in time).
Previously, the only setting added was the Mouse Sensitivity. The value was just changed and saved in the Camera script, as it was only needed in there. Since the Camera was destroyed when switching or reloading Scene, the Settings would thus be reset to its default value.
To fix this, I introduced a GameManager singleton into the game, where settings and other values can be saved to, which can later be written to and loaded from a file, if necessary.
Other than that, the Slider also didn’t really give a good indication of what the Sensitivity value was, but we could not get rid of it due its handy slider feature. Therefor, I added an Input Field to the side, where the value of the slider is displayed, as well as where you can enter a value and the slider will update to that exact value.
As mentioned by many, our Camera didn’t feel right for a Shooter Game. The smoothing made players nauseous, giving them a “Drunk Camera” feeling. Besides that, the sensitivity on our WebGL build was always too high since it didn’t match the sensitivity on our Standalone build.
Therefor, following changes were made:
We got rid of the Smoothing calculations, making the response to your mouse instant. This should give the player a better experience when trying to kill the enemies or just looking around in the world.
To fix the Sensitivity mismatch we could either release our builds with different Sensitivity settings, or be smart in the long run and make a Slider for the player do adjust to their preferences. Since everyone likes a different Sensitivity and plays differently, adding Settings to our Game would always come in handy.
To achieve this, I had to create a Pause menu that the Player can open using the ‘P’ key. This will also pause the game so that you’re safe from anything bad happening in game.
However, just adding the setting to the pause menu wouldn’t be very pretty, so instead I made a Pause Menu that has a Settings button, taking you to the Settings of our game. To make sure that nothing starts overlapping or blending, I had to make sure that the Pause menu was hidden when the Settings menu was open and vice versa.
Also we had to unlock the mouse whenever you open an interface that needs a mouse, such as the Inventory and the Pause Menu. Whenever you leave this interface, the mouse would have to get locked again. This is also a temporary fix because there currently is no way for the Controller to move the mouse or click buttons.
Learning an Ability sometimes looked awkward or not obvious, where the Player would be confused what was going on since he couldn’t move anymore. To make it more obvious what is happening, the Camera now moves to fixed point where you can see your Character looking at the stone. This should give the feeling of a small “Cutscene”, making the Player know that he won’t be able to move until he has learned the Ability. We can later make this even more obvious by passing the magic words on the screen, as if you’d be reading the spell on the stone.
The Position is a fixed point defined for each stone, which we can access in our script. Currently, the camera will always be facing the stone, but if needed, we can change it so that our Camera will follow the forward of the fixed point.
We’ve decided to switch things around. Previously, our Player would rotate using Left and Right, and the Camera would follow that rotation smoothly. Since this didn’t fit the 3rd person shooter setting we were going for, we’ve now decided to do it the other way around. Moving your Mouse / Right Analog Stick will now rotate the Camera (this defines your Aim), and the Camera will rotate along so it faces where it wants to Aim to.
One of the many advantages is that we can now use Left and Right to move sideways, as well as that aiming is now easier and feels more natural.
Since our Game has Light Bullets that can be shot from our Lantern, we needed a way to visualise the Aiming direction.
We’ve chosen to do this using a Crosshair on the middle of the screen as overlay. The current crosshair is just a temporary placeholder and can be easily changed into something more obvious or subtle, so that it fits our theme.
Calculating at which object you are looking was, however, a bit more difficult. We need to cast a ray starting from our player towards the direction of the camera, however, this would result in either having the crosshair on the back of our Player, or aiming below our crosshair if we move our Camera upwards.
To fix this, we cast a ray at the the position of our player but with this height offset kept in mind. This will give us the correct direction to cast the ray, which will then return the Collider you were looking at. This hit point can be used to then calculate the direction from the lantern, so our bullet can be fired towards the targeted object.
These directions can be visualised to debug. In the video below, the Red line represents the direction from the ray, while the Green line represents the direction for the bullet. The point where these lines intersect, should be the position of where your crosshair was looking at.
A final issue that came up, was when the Ray didn’t collide with anything (i.e. Looking at the Sky). We needed a default point somewhere in the distance to set as Target. Using the Far Plane of our Camera (The point where anything further won’t be seen, thus creating “sky” from this distance on) seemed like a good idea at first, but since the Far Plane didn’t match with the Distance that our bullets reached, I stepped away from using this.
Instead, I’m calculating the distance that a bullet can reach (lifeTime * speed) and set this as “far plane” (Note that this isn’t actually the Far Plane of the camera, but instead an imaginary plane with which the Ray will collide in case it hasn’t collided before).
This results in our bullet always reaching the crosshair position right before it vanishes due to its lifetime. This can also be seen in the video at the top, and in the debug view (second video) the lines will indeed intersect at the point where the bullet vanishes.
We chose to add a Smooth Follow Camera to our Player, which can be rotated freely around the player, but will always follow the Player from a close to medium range distance.
The Camera can be controlled by holding RMB and moving the mouse around, or, preferably, by using the Right Analog Stick on your controller.