BGP Week 8 – UI Switching

The final real ‘feature’ added by me before we changed focus entirely to solving bugs and polishing details before Gotland Game Conference was a change in the UI. As the game features three characters that the player switches between, using the right and left trigger buttons on the controller.

For this reason, above the button images that were added last time, which were of the triggers, we wanted pictures to tell which slime you would shift to by pressing that button. This was to make it easier for the player to tell what they were doing, without forcing a lot of meaningless trial and error.

We had code for telling which character was currently selected previously made to work with the camera. Taking this, I reconstructed it to instead tell which one was selected and determine what sprite should then be displayed, and then used that in two different scripts. One for the left side and one for the right.

Whenever the player changed character, the script would note the character chosen not matching with the current value of an integer (with the options 1, 2, and 3, to match the characters) and then adapt to match it up and change the images to display images of the characters the player could select with the correlating button.

While it took me some time to understand how to change the look of images in a canvas, the end result was effective and worked for the intended task, thou I hope to have a chance to upgrade it at some point after the conference.

BGP Week 7 – UI basics

As Gotland Game Conference got closer, we realized we needed at least a simple UI, and as such I took on the work to put that in. While the work was not that overwhelming, I was new to working with the Canvas layer of Unity, and as such had to learn as I worked.

The first step was quite easy, add some images into the screen. This was simply implanted using the Raw Image template, which for someone inexperienced seemed the easiest way. With this I placed in icons for the collectibles and two button icons placed in the bottom corners, for future use.

Next was to implement score into the mix. This was done by adding two text objects on the canvas and then modifying score counter, the receiving script made earlier to hold the values for score. By adding new parts two public Text objects to take in the ones added to the canvas, the score was rebuilt to print out the current number of collected pieces. This was also when the chance for it to calculate the total was made, so that it also could display the total amount the player had to collect next to the collected amount.

With this, the most essential information was being displayed. However, there was one more UI feature we wanted, which will be the focus of the next post.

BGP Week 6 – Puff and Cutting it

For most of this week, I worked on another new platforming challenge, the puff shroom. The concept was quite simple: If the player stood close to it, after a set time limit it would explode and fire the player away from it. The design idea was for it to be used both to get the player away from locations or down from ledges if they were too slow, but also as a short-cut for those skilled enough to utilize the gained force.

At first, it did not seem that tricky. We already had bounce shrooms, so for the force the basics needed were just to use that same kind of mechanic to fire away the player, just instead of it going straight up, have it angled based on the angle between the puff shroom and the player. To that I just needed to use code similar to the timer I used for the Venus Slimetrap to calculate the delay.

Sadly, all good things must come to an end, and once I had all of this working, I ran into an unexpected issue. As part of our movement code, the player, while on the ground, ran a clamping script to make sure it remained on a surface rather than falling through it. This was an essential part of our movement system.

The issue was that, if the player was on the ground when the puff exploded, the claming cancelled out any upward momentum, causing the player to just slide along on the ground. This was a pretty major issue, and one, given the limited time left, finally led to the decision to cut the puff shrooms from the product for now rather than spend more of the programmers time on something we were unsure how to solve easily.

BGP Week 5 – Calibrating Rotations

While the rotating shroom was something I started on some weeks before, this was the week when the final issues were fixed up as the final version would work, and as such this seems like a good time to explain how it works.

While not massively complex, the curse of this platform that took time is that for rotation, Unity relies on quaternions, which is not exactly the easiest to understand. However, eventually I realized all that was needed was a relatively simple line of code need: transform.rotation = Quaternion.AngleAxis(spin, Vector3.up) * transform.rotation;

With this, all modifications to how the rotations occur, such as speed and direction, were modified in the spin variable, keeping the rest untouched. To this, I added a Clamp function that sets a maximum and minimum rotation limit as public floats, as well as a public bool to turn the limitation on or off, as needed. And as a final touch, a bool which, if turned on, would make the rotation start in reverse.

If the rotation reaches the set clamp limits with the function on, spin is set to its opposite, causing it to reverse and go back until hitting the opposite limit, repeating the process to send the rotation back and forth. As one of the later touches, I changed how the limits worked so that they adjusted to any rotation done to the object in the editor, to make it more designer friendly.

BGP Week 4 – Collectibles

While it did not take up much time, the most noticeable thing I worked with during the fourth week was our collectibles. Specifically, the scripts needed for them to be picked up and for the result to be recorded.

The first part was to create a script that would receive the information. This was made out of two integers representing small and large collectibles, and two functions that when called would increase the designated integer. So it the pickup for a small collectible was called, the integer for small ones would increase with a set amount.

Next was creating the scrips for the collectibles themselves, a rather simple case where I made two very similar scripts for the small and large collectibles. When the collectible detects collision with the player, they call upon their respective functions over in the receiver script, increasing the relevant score, and then destroys itself.

Finally, some time later on, the receiving script was upgraded so that when 10 small collectibles were gathered, the count resets to 0 and one large collectible is gained. Along with this, I also wrote a function that counts the number of large and small collectibles in the map, and from that declare the total amount of large ones the player can collect.

BGP Week 3 – Shrivel Shrooms

During the third week, I worked on the shrivel shroom, a relatively simple concept. The idea was for it to be a platform that would shrink whenever a player stepped on it, shriveling in to the center point.

This was relatively easy to make the basics for, simply setting up a a function that turned a bool true if a player collided with the platform, and false if they jumped off, and then have the shroom shrink by a variable amount while the bool was true, down to a predetermined minimum size.

To this, I added a function using deltaTime to see how long had passed since the player left, and then, if the shroom was smaller than the original size, have it grow back until it hit the original value. Thus letting the platforms reset after a moment should the player need to try again.

As a final touch, deltaTime was added to the shrink and grow functions, meaning the speed at which it happens is the same no matter framerate or possible lag.

BGP Week 2 – Venus Slimetrap

During the second week, I started on the game’s main challenges, the special platforms that the player has to work with or around to move ahead in the game. The first one I ended up finishing up was the Venus Slimetrap, a platform inspired by the infamous Venus flytrap plant.

The Venus shroom is a simple construction, working by detecting if the player collides with it, and if so triggering a bool that starts a count taking in deltaTime. Once it reaches a set value, the player is teleported to the location of another invisible gameObject, the Exit Spot. Once the player is no longer touching the fly trap, be it through jumping off the object, or being teleported by it, the time count resets, allowing the player to repeat it.

The main challenge of this was figuring out how to formulate the code, with using the unity function OnTriggerStay/OnColliderStay tanking the framerate. To get around this enter just triggered a bool that made the counting happen in the update of the script instead.

The end result turned out better than expected, doing what was intended while easy for the designer to work with. All in all a positive end result.

BGP Week 1 – Camera Angles

It seems proper to start with an introduction. This blog post, and the ones that will follow it are on the subject of the Big Game Project course at Uppsala University Campus Gotland where I, as part of a group of six people, will be working on developing a game. The game I will be working on has started out with the project name Spacegoo Adventures, and is a 3D puzzle platformer.

The first week I started out working on getting the camera to work. Using the Super Character Controller module we already had basic movement with the camera following the player, so all that was needed was the ability to steer the direction of the camera. To do this all that was needed was an input for Quaternions, Unity’s main way to calculate rotation, using the controller input, the camera’s current angle, and a preset speed value. By using Quaternion.AngleAxis with the input of the set value and a Vector holding the controller input, times the the current angle.

Next was locking the vertical rotation so that the camera could not end up up-side down. This ended up taking longer than expected due to me originally placing an extra variable in the Quaternion.AngleAxis. By moving this variable outside the AngleAxis, I could use the Unity function Mathf.Clamp to define the limits of the camera and lock it to them.

The final result was a simple but working camera that will need improvements later, but was good enough to work for initial testing, allowing our designer to proceed ahead with testing the game and starting to design levels.

The Menu

This is the final week with a blog post from this course, and as the projects wraps up I believe it is only fair to talk about one of the features we waited the longest with completing, so today we will talk about the menu and the process behind creating it.

The reason this was something we waited so long with is that we wrote it off as relatively simple and not requiring any special expertise, and thus our time seemed better spent to make sure the core mechanics worked the way we wanted them to. This meant that it was not until the beta that we seriously took the time to make the menu work entirely as intended. It was first by this week I saw to add the final details.

The menu, as we had expected, was relatively easy, even if I had to deal with some minor mistakes. The basic elements of the menu was a background image, and four sprites, one for each button. Each button then also needed their own click reactions implemented to make sure they send the player to the right screen. As of now, the menu looks something like this:

Blog Menu-base

When the mouse intersects the area of a button’s sprite, the sprite changes texture so that it looks like the text lights up to help the player see what they are selecting. Beneath we have a case to the mouse hovering over the Play button, even if it seems the computer’s screen capture function was unwilling to include the mouse for some reason.

Blog Menu-button down

The play button activates the GameState and sends the player directly to the first level. The Credits and Controls buttons exists to show ”pop-ups” that reveal their relevant information. The quit button’s role is relatively obvious.

The menu, while simplistic, can be seen as a core part of the game and give the player a first impression of what they are dwelling into. It also gives a chance to look up controls if the player feels unsure as to how the game should be played. By not throwing the player directly into the game we spare them a lot of confusion, and let them enter when they feel ready to take on the challenge.

Over all it took some time to make sure everything worked as intended, but it was not too challenging, and it was a relatively fun thing to take on. The relative quickness and clear graphical feedback helped in making it all feel a bit more rewarding, as I could easily see the changes every time I started the program to check if things were working as intended.

/Stefan

Oxygen Bar and Flare Count

The past week I decided to focus on the player’s HUD (Heads-Up Display) which is key to displaying information to the player, something which has proven itself an issue as we tested the game. Being unaware of their ammunition’s limit has repeatedly caused players waste away shots, something I believe will be resolved when there is and easy and clear visual display of their ammunition.

The HUD also contains several bubbles with represents the player’s current oxygen. The oxygen slowly decreases over time and if it ever reaches zero, the player loses. Oxygen can easily be refilled by finding and picking up a sample, which helps motivate the player to seek the samples on a mechanical level. Oxygen’s main role is similar to the timer in a 2D Mario game: it means you cannot just stand around forever, but at the same time does not force you to stress. IT is just a motivator to keep the player swimming.

But let us take a look at a screenshot from the game;

Blog HUD-Full

Here we have just entered the level. On our upper left we can see ten bubbles, all identical. This is the oxygen bar. One bubble fades for each ten seconds that pass. Over to the left we can see fire flare shells representing the player’s ammunition, currently at max capacity. Each time the player fires a flare one cartridge disappears and when there are none left the player is out of ammunition and thus unable to use the flares. Let us now step forward a bit:

Blog HUD-Later

As we can see, the player has gone about for something above thirty second since they found their last sample, which has caused three of the oxygen bubbles to fade out. There are still seven more bubbles left, so they still have ample time to look around and figure out where to go next. They have however spent two flares, leaving only three shells in the upper-right. The only way to replenish flares is to find crate of ammunition, meaning being sparing in the use of them could be wise.

Both bars were really just created from arrays of sprites that create several sprites just next to each other. Each sprite remains separate for the purpose of having their texture changed:

sf::Texture* texture;
for (int i = 0; i < 10; i++)
{
filename = ”../external/graphics/o2bar.png”;
texture = m_texture_manager->CreateTextureFromFile(filename);
O2[i] = new sf::Sprite(*texture);
O2[i]->setPosition(64*i, 10);
}

for (int i = 0; i < 5; i++)
{
filename = ”../external/graphics/bullet.png”;
texture = m_texture_manager->CreateTextureFromFile(filename);
m_flareLimit[i] = new sf::Sprite(*texture);
m_flareLimit[i]->setPosition(1856 – (64 * i), 10);
}

This is then checked during each update cycle:

Player* player = (Player*)m_player;

for (int i = 0; i < 10; i++)
{
if (10 * i < m_oxygen)
{
//sf::Texture* texture;
filename = ”../external/graphics/o2bar.png”;
m_texture = m_texture_manager->CreateTextureFromFile(filename);
O2[i] = new sf::Sprite(*m_texture);
O2[i]->setPosition(64 * i, 10);
}

if (10 * i > m_oxygen)
{
//sf::Texture* texture;
filename = ”../external/graphics/o2bar2.png”;
m_texture = m_texture_manager->CreateTextureFromFile(filename);
O2[i] = new sf::Sprite(*m_texture);
O2[i]->setPosition(64 * i, 10);
}

if (i < 5)
{
if (i < m_flares && m_limit[i] == false)
{
m_limit[i] = true;
}

if (i + 1 > m_flares && m_limit[i] == true)
{
m_limit[i] = false;
}
}
}

So so for oxygen, if m_oxygen is lower than the sprite’s array number times ten, the sprite turns to the darkened version to show that it is currently expended. However, the game keeps checking, and if m_oxygen goes over said value again then the bubble is refilled. Flares follows a similar method, checking the array value plus one against m_flares. If the array number (plus one) is higher, then a correlating bool is set to false, causing the sprite not to be drawn during the following update cycles unless m_flares once again raises in value to that the array value is no longer higher.

All in all this was a rather simple method. I met some issues due to bugs leading into bugs that lead to memory leaks which led to bugs, but in the end we got it working. I see this as an essential tool to give the player feedback and help them know what is going on, and I am currently considering to try and make it easier to understand. Hope you liked reading all of this.

/Stefan