Master grapher

Pop ups

In our game we use space to pick up objects. To teach the player the controls we decided to have small prompts pop up when the player approaches something grabbable. After the player has picked up the object once, the prompt will no longer appear.

hitmark.png
The concept for the pop up window.

The red circle in the image is a trigger collider, which spawns the prompt window as a game object when triggered. But having the prompt just appear out of nowhere doesn’t look very good without a transition…

Introducing Interpolation

My idea was to slide the scale of the prompt up and down for the transitions. When the pop up appears, the scale will start at 0 and gradually increase to full size. If we look at the transition as a timeline going from 0 to 1, the size over time could look like this graph.

linear.png
Linear interpolation.

Having the prompt pop in like this would look much better than no transition at all! However, it looks kind of stale. The velocity of the scale is constant during the transition. There is no feeling, no drama!

Juicy graphs

To make the transition look good, we need to spice up this graph! Grapefrukt did a good talk on juice in video games, where they use a bunch of interpolation techniques to make the game feel juicer.

Naturally I made a static class with some interpolation methods so I can harness this great power.

I wanted the prompt to be a little bouncy, so I combined linear interpolation with a strangely squished Sine graph to create something beautiful:

transformers.png
Combine!

The resulting graph overshoots the target, making the interpolation bouncy! This is the resulting animation in-game:

true jif.gif
boing~♪

The length of the pop-in and pop-out is identical, but since the pop-out uses a cubic interpolation, the effect is completely different.

Graph heaven

As you can see, I combined two graphs to create a juicy graph. But this is hard-coded for this specific use; the method is called ”Overshoot()” or something. What we actually want is a general way to combine interpolation methods, which is something I would like to do. Also, there is no way of actually seeing or editing the graph visually in the editor.

Turns out there is already a way of doing exactly this and it’s built-in to Unity. RIP hard work. Just goes to show how valuable it is to do a quick search before reinventing the wheel like this (even though I wasted less than an hour).

EditorGUICurveField.png
How could they do this to me?

You can take a look at my code here.

More enemies

As we move into production the focus turns to producing a bunch of fish. This week I implemented the behavior for these baddies:

angus.png
Cute couple. (The head on the top is the male).
sad moray eel.png
A sleep deprived moray eel. Finalized art.

Anglerfish

We wanted the anglerfish to feel creepy. When she notices the player (or another fish) she will stalk them by keeping herself within a set distance.

stalker.png
The concept for the stalking behavior.

She doesn’t actively try to attack the player, just stays in close proximity. Spooky!

The fish is using the same state machine as in my first blogpost, which made the implementation quick. Most of the behavior is reused but modified; for example, the idle state is a slower version of the peaceful fish.

Moray eel

The eel was a bit trickier. Since it doesn’t swim around and share the same traits as the other fish, it didn’t make sense to use the same structure as the other fish (The fish are in acute need of refactoring, but I will put off this for after production).

murana.png
Eel behavior concept.

The biggest reason for redoing the structure was the flowchart of the state machines. The fish state machine switches states when reacting to different things. When the states are done they always revert to a default state.

fish-fsm
A simple fish flowchart

The moray is simpler, but uses another type of flowchart. The states don’t revert to a default state when they are done, but rather move to the next in the line.

moray fsm.png
The eel flowchart.

I’ve heard the Animator can be used as a state machine in Unity, which would be ideal, but I decided not to do this because of time pressure (it’s risky to research OK). Instead I made something similar, where each state has a tag and a way to switch to another state via tags.

tethered attack.png
Eel attack state

Just like the fish state machine, the states are added as components and switched on and off by a state machine component.

ifsm.png
Short and sweet!
fish fsm editor.png
The fish state machine.

The flowchart is not as visual as the Animator, but I don’t wanna make an editor OK? The fish state machine (to the right) had to get the states dragged into finite slots which were switched between according to a set logic. The new state machine only needs the starting (aka default) state and accesses the states automatically since it doesn’t need to know the states’ context. The states themselves holds the information on which state to move to next.

The finished eel uses a trigger collider to react to prey swimming by, which activates the attack state.

eel editor.png
The eel in the editor.

Let’s hope I find a smooth way to implement the new state machine (or adapt it) for the old fishes, since it’s so much cleaner.

anglerfish.png
Did you know the male anglerfish slowly melts into the body of the female until he is reduced to a pair of testicles?

Tears are made of camera zoom

The size of the camera can be used to set the mood for the player. Look at this picture:

close-space-man
Guy in space

And then this picture:

far-space-man
Lonely guy in space. Don’t you feel bad for him?

Note the emotional impact! Now that you understand the great value of controlling camera zoom, let’s talk about how I implemented it in our game.

We want our level designers to have the tools to control camera zoom for different areas, like in the image below.

camera
A zoomed-out area and a more narrow section with a zoomed-in camera.

To accomplish this I created a node prefab that holds the target zoom and a trigger collider. This is what they look like in the editor:

editor.png

The player has a script which keeps track of the latest node that it collided with, and slowly moves the zoom of the camera towards the target zoom.

Generic is good

music zones.png
What if Pokémon had the same song for the entire game?

To set the mood for the game we have a spooky ambience looping in the background. But listening to the same song for the entire game will distract the player and force them to buy our OST. This means we want to switch ambience for different areas. But doesn’t the camera nodes sound similar to what we want to do here?

Turns out there are a bunch of stuff that could use the same system as the camera, including checkpoints and events (Like playing a sound or activating a fish).

Node controller UML diagram.png

I refactored the camera node and controller to two abstract classes, which can be derived into the specific functionalities. The node controllers only reacts to the nodes with the same tag as the searchTag member, so a camera controller doesn’t try to use a music node.

Most of the logic should happen in the Node, but if required, the controller can override Update() for example. This is kind of dangerous though, because overriding the function could destroy the implementation if it doesn’t call the base function. To make this safer we could provide abstract functions for the derived classes (like OnSwitch()) and make the important logic private. The searchTag member should also be refactored into something that enforces the user to provide the specific tag.

By using this interface I’ve mass produced node systems for different uses. Let’s end this post by looking at the beautiful result!

all nodes.png
All the checkpoints and music/camera/event nodes

Intelligent fish

In our game you play as an exploration robot that look at fish, and later avoid getting bit by meaner fish.

screenshot.png

Since you can’t kill any fish in the game, it’s important that they are interesting to interact with and swim around like actual fish. They are state machines, which makes it easy for us to reuse behaviors and organize logic. The fish use a bunch of trigger hitboxes to sense their surroundings.

fish sensors.png
An observant fish

When something enters the sight trigger, the fish can see it. If the fish spot something suspicious (e.g. the player or a hungry fish) it switches state. The intimate trigger does the same thing, but for more acute situations. For example, this fish would flee if the player enters the intimate zone.

To be able to tinker with values and edit the states, they are added as components to the fish. Then they are dragged to the state machine, which disables all states except for the active one.

fish fsm.png
The proximity field corresponds to the vision. This could be renamed for better communication.

As you can see from the image, the fish doesn’t need to react to every situation. This state machine is from the fish in the pictures above, and it doesn’t do anything when it sees the player. Other fish could slowly move towards the player, or subtly avoid them.

Homes and fish points

We want to have some control of the placements of the fish. These are two schools of fish placed on the map.

schools of fish.png

To force the fish to stay at the same location, they are bound to a ”fish point” (or fish node, but point sounds more military).

fish point alpha.png
Fish point alpha

The fish are children to the point, and they will know if they are outside of it. If the fish are in their idle state, they will make sure to stay close to their point. But what if the fish are chased around by the player and swim so far away that they can’t see their point anymore?

sad fish.png
The blue arrow is the correct way to the point, but the poor fish is too stupid too see.

The fish is breaking his head trying to go back to the fish point! We could add path finding, but it’s too much work. Instead, we move the fish point to the new location.

independent fish.png
A happy independent fish

Right now when a fish move from it’s original point, it creates a whole new fish point just for itself. This could be changed to first look for any fish points close by, but I chose this for now because it was fast to implement. The other solution could also potentially endanger the poor fish, if it mistakenly chose a shark nest for its home!

And that wraps up the fish AI for now. Next up is adding chomp hitboxes to the angry fish and make sure that they can kill things.