My Contributions

Rendering

I ported Materials created in Unreal Engine 4 to hlsl code that could be rendered in my own renderer.

Engine

I added support for a variable amount of extra textures to be sent to shaders when rendering models, this could be specified in simple data files that go along with the model files. It was used for platforms among other things that had grass and moss projected onto them.

Post Processing

I implemented a sharpening filter in hlsl.
I also created a simple color grading that made the temperature a bit cooler.

Effects

I made all the particle effects in the game, such as the stars in the sky, the fog in the background, fireflies in the foreground and all the orbs.
The player was built using different particle effects and a streak.
When the player flies through a treetop, there is a particle effect of some leaves falling, a sound cue, subsurface scattering and some screen shake on the GUI.

Accessibility

I added localisation to the game so that the game is playable in 12 different languages.
I made a shader that covers 8 different types of color blindness.

Design

I designed all the levels and had people playtest and give me feedback, I then tweaked the levels with the feedback in mind.
I dressed all of the levels and made sure it looked good by double-checking with Elinore.

Audio

I gathered all of the sounds, built all of the different sound events in FMOD Studio and handled all of the sounds in-game.

Project Details

  • 5 weeks full time
  • My own engine and renderer
  • C++ and DirectX 11
  • Unity as editor
  • Team: Hussein Taher, Elinore Sander

About the team

Since the team only consisted of me and Elinore, it meant that I had to take care of pretty much everything except for the art.

Elinore had already created a lovely collection of assets for platforming, which you can see more of on her portfolio here, that she allowed me to use for my game.

It was nice knowing that I could always ask Elinore about my design decisions, to make sure that the assets were used in an acceptable way.

Materials

Elinore had created a material in Unreal Engine 4 that allowed her to place out platforms in any way she wanted, and have textures project onto them from above, while also allowing her to tweak how much would be visible at what angle, based on the normal. I got to take a look at this shader and implement it in hlsl to make it look the same in-game. This was pretty easy to implement as it was just a simple triplanar projection with worldspace mapping.

Sharpening Filter

When I saw the images that Elinore had on her portfolio, I noticed that all the textures looked a lot sharper and more crisp, so I asked her what she had done, and she showed me a little sharpening trick she uses in photoshop.

Basically, by creating a high-pass filter of the image, and applying it with an overlay blend mode onto the original image, she could make the image look sharper by removing low frequency data. So I did some research on high-pass filters and looked at how the overlay blend mode in photoshop is implemented.

Once I had all the resources needed, I wrote my own post processing shader and tweaked it until it looked good.

As you can see in the gif, I used a very cheap high-pass filter compared to the one in photoshop, but it was good enough for getting a little bit of detail back into the scene in real-time.

Here’s my sharpening algorithm:

  1. Remove any low frequency data around the current texel using a kernel(in this case, a 5x5 kernel).
  2. Blend the high-pass data with the original image to achieve the sharpening using the overlay blend mode as implemented in photoshop.

This is shown in the code below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const static float kernel[25] = {	-1,  0,  0,  0, -1,
									 0, -1,  0, -1,  0,
									 0,  0, +8,  0,  0,
									 0, -1,  0, -1,  0,
									-1,  0,  0,  0, -1 };
float blendOverlay(float base, float blend) {
	if(base < 0.5)
		return (2. * base * blend);

	return(1. - 2. * (1. - base)*(1. - blend));
}
float3 blendOverlay(float3 base, float3 blend) {
	return float3(	blendOverlay(base.r, blend.r),
					blendOverlay(base.g, blend.g),
					blendOverlay(base.b, blend.b) );
}
float3 blendOverlay(float3 base, float3 blend, float factor) {
	return blendOverlay(base, blend) * factor + base * (1.f - factor);
}
/* ... main function ... */
for(int x = -2; x <= 2; ++x)
{
	for(int y = -2; y <= 2; ++y)
	{
		float3 c = texture.Sample( instanceSampler, input.myUV + float2(x,y) * texelSize).rgb;
		sum += c * kernel[(x+2) + (y+2) * 5];
	}
}
sum = sum * 0.5 + 0.5;
output.myColor.rgb = blendOverlay(output.myColor.rgb, sum, 0.2);

Accessibility

Color Blindness

At the time of writing this, I realised that another accessibility feature that could be supported was color blindness.

Since I couldn’t resist it, I just had to implement it and see what it looked like, I think it turned out pretty cool, as you can see in the gif.

Localisation

Adding localisation can change the way you design things.

When I added localisation, me and Elinore decided that it would be best to have the How To Play and Tutorial be images instead of text, it also forced us to change some of the GUI.

It was a design challenge to add localisation to the game, but it was a fun one, and it worked out well. And in the end, I was happy to see my game being playable in 12 different languages.

Sequential Win Screen

My win screen went through a lot of changes both in code and in design.

You can see the different stages of my win screen in the gif.

Here’s a breakdown of the different stages(note that I didn’t have a win screen in week 1):

  • Week 2: The stars moved down from the top of the screen and scaled up, and the timer appeared in the center, then the background faded black.

  • Week 3: The stars got updated textures but everything worked essentially the same. The background was now left a bit transparent as well.

  • Week 4: I added a high score badge and a special star that you would get if you beat the developer time on that level. It was starting to look good at this stage, but the problem now was that everything appeared at the same time. As a player, you don’t really know what to look at when you reach the win screen, everything just gets thrown in your face.

  • Week 5: I had been playing a lot of Blossom Blast Saga around this time and liked how sequential their win screen was, and was wondering how I could do the same in my game. When I woke up 2 days before hand-in, I thought of a way of implementing sequencing in an easy and flexible way. As I got to school, I starting implementing it right away. The result is visible in week 5 of the gif, I had control of everything from delay/duration to effects/feedback. You can also see the result in the trailer above at 00:46 if you want to see it with sound and in better quality.

Sequencer

Here’s a short snippet showing how easy it was to setup and control the entire win screen sequence:

1
2
3
4
5
6
7
8
// AddSequence(aDelay, aDuration, aCallback)
myWinSequence.AddSequence( 0.0, 0.5, &CGameState::AnimateCanvasOverlay );
myWinSequence.AddSequence( 0.0, 1.0, &CGameState::AnimateTimeText );
myWinSequence.AddSequence( 0.5, 1.0, &CGameState::AnimateStar1 );
myWinSequence.AddSequence( 1.0, 1.0, &CGameState::AnimateStar2 );
myWinSequence.AddSequence( 1.5, 1.0, &CGameState::AnimateStar3 );
myWinSequence.AddSequence( 2.0, 1.0, &CGameState::AnimateHighscore );
myWinSequence.AddSequence( 2.5, 1.0, &CGameState::AnimateDevStar );

Once I had this, I could just implement the callback functions and tweak them individually until I was happy with the result. The callback functions received 2 parameters, one was a float between [0 - 1] telling us how far into the animation we are, and the other one was a bool telling us if it was the last frame of the animation, so we can play a sound and apply screen shake.

Here’s an example of a star animation:

1
2
3
4
5
6
7
8
9
10
void CGameState::AnimateStar3(float aAlpha, bool aLastUpdate)
{
	AnimateStar(aAlpha, 2); // Animate the star at index 2

	if (aLastUpdate) // Apply some extra effects on the last frame
	{
		AM.PlayNewInstance("star3"); // Play a sound
		IWorld::Shake(0.001f); // Apply some screen shake
	}
}

Treetops

At the last day of my project, I had some time over to add more juicing, so I decided to put that juice into my trees cause it was fun!

The things I implemented were:

  • Leaves coming out when you enter and exit the treetop.
  • I made an event in FMOD Studio that played a random sound every time you would enter and exit.
  • I added a little screen shake to the GUI when you enter and exit. If you look carefully at the video, you can see that the bar at the top shakes a little bit.
  • I had subsurface scattering on the tree which gave a really cool effect while the player was moving inside of the treetop.

Development

Making an entire game in 5 weeks is tough, but here’s my process and how I made sure to have fun while making the game.

Schedule

Since I only had 5 weeks, it was very important to plan my time and focus on having a polished product in the end.

So here’s roughly what my schedule looked like:

Week 1 Week 2 Week 3 Week 4 Week 5
Pre-production - Alpha Alpha - Beta Beta - Gold Gold Gold


As you can see, I decided to put a lot of time into the Gold Stage, which is all about polishing and pushing the game over the edge.

Pre-production and Prototyping

When I was doing the pre-production and prototyping, I scoped super low and tried to keep things simple. I already knew that I wanted to make a platformer, but I hadn’t nailed the mechanics yet, so here are a few clips from my first week. You can click on the days to view short clips.

  • Day 1: I was testing out my collision, basic camera movement and controls. You can also see a world space grid being projected onto the cube(the player), this was useful to get a sense of what scale the game was going to be in.

  • Day 2: I tried a crazy thing, I changed the gravity direction to the collision normal of the surface that the player was standing on. That resulted in a really cool mechanic where the player could run around the edges of a platform. You can also see that I replaced the cube with a bunch of particles and a streak, to make it a bit more alive.

  • Day 3: I tried playing with the scenery to find the right feel for the game. This is when I got the setting figured out, I wanted the player to be a wisp and the game would take place in a dark forest at night. At this time, I was starting to have second thoughts about the gravity being able to change to any direction. As a player this didn’t feel good since you didn’t have much control over the movement. I decided to limit the directions to up/down, and had the player control when to switch direction. This felt a lot better and gave the player more control.

  • Day 4-5: After the first 3 days, I had nailed the setting, scale, look and feel. So I spent the last couple of days completing my game loop. The player could press play in the menu, play a level with an actual objective and get back to the menu.

Alpha

After only one week, I had a fully functional game, and could already start sending it to people for playtesting. This was really useful to have early in development, because it helped with a lot of things:

  • Approximating how many levels I should have
  • Seeing what level designs worked
  • Testing Metrics
  • Finding bugs

So for the second week, I had full focus on making a complete game, which has everything from menus to multiple levels and audio in-game. This went really well and I was finished with the Alpha Stage. From this point, I decided to send out a copy each weekend for playtesting. This helped me with planning and knowing what to focus on the upcoming week.

Beta

During the Beta Stage, I focused on finishing everything needed for my game to be complete:

  • All the menus should be fully functional
  • All the levels should be playable
  • Progress should be saved between sessions
  • There should be audio for everything needing it

Gold

Once my entire game was finished, I had 2.5 weeks left for juicing!

This is when I started making all of the things that made the game look and feel much better:

  • I iterated on the win screen
  • I iterated on the GUI
  • I added localisation to support different languages
  • I dressed all the levels
  • I iterated on the sounds
  • I improved most of the particle systems and added more feedback to player actions to make the player more engaged
  • And much more…

Final Thoughts

So, the main reasons why I think this whole process went so smoothly for me are:

  • I had planned well
  • I scoped low
  • I prototyped a lot in the first week
  • I cut features early on
  • I playtested on people after only one week of development
  • I had a clear goal of where I wanted my game to go after the pre-production

And finally, here’s a gif of how my game evolved throughout the weeks:

Special Thanks

I’d like to thank the people who helped me with the localisation:

Person Language
Hussein Taher Swedish, English, Korean
Joel Klevje Japanese, Korean
Magnus Cristiansson Spanish, French
Alina Gromova Russian
Oliver Nyholm Finnish
Dustin Spannhake German
Aleksandar Pijunovic Polish
Anton Pilmark Danish
Job van der Zwan Dutch

What now?

If you got this far, thank you for reading and I hope you liked what I had to show.

If you want to play the game, you can download it below.

Requirements:

  • Windows 10
  • A high-end pc if you want to run the game in HD.

Download Game!

Screenshot