One of those pretentious portfolios with a video in the background

Who this?

My black and white portrait, posed like Steve Jobs
Eero Häihälä, the short version goes something like this:
  • Generalist programmer
  • Master of Science (Technology)
  • Lead developer at Vincit, doing mostly:
    • Full stack web dev
    • In direct customer communication
    • Infrastructure, CI pipes, most of the grunt work people tend to avoid
  • Hobbyist game developer
  • Part time programming teacher

Wowee describing oneself is hard. I'm just a dude working on whatever I find interesting. That mostly consists of 'engineering' (whatever that is) for a living and game development to live. Most of my what I do and deem worth writing about end up on my blog. The rest of this page is a list of cherry-picked game projects that hopefully showcase I can indeed make those.

I actively seek out new things to do, use and experience, to the point of having those listed in my project tracking app. Most of the projects here as well as the website itself have gotten started simply because I wanted to try something new. A natural consequence of doing a bit of this and that is having a lot to draw from when I stumble onto something new. After trying a few organizational structures, project management systems, game engines, programming languages, and frameworks picking up new ones is a quick process. I primarily want to learn by doing, but a close second is listening to someone who has a lot of experience works for me really well. I listen to a lot of conference talks and podcast-adjacent stuff for example. There is a TED interview where Linus Torvalds says something that resonates with me:

I'm perfectly happy with all the people who are walking around and just staring at the clouds and looking at the stars and saying, "I want to go there.", but I'm looking at the ground, and I want to fix the pothole that's right in front of me before I fall in.

I heavily relate with Torvalds. While talking about design with my friends, I'm often the one bringing the conversation back down to earth. I genuinely like thinking about the mundane problems and how to best tackle them. Despite my best efforts, this attention to details still every now and then comes across as dismissive or critical to my more idea-oriented friends. I don't want to belittle or put others down, but to help them create the best version of what they are making. If you have a game you think I could make better, do get in touch:

You can find a list of my skills, as well as my summarized employment history in my printable resume.

Whoops! All grapplers

What is it?

  • 2.5D fighting game
  • With moba-like upgrades
  • And online multiplayer
  • With rollback netcode
  • Built with Bevy and Rust
  • Scope: Solo project, semi-active since 2021

What did I do?

  • Game design
  • Programming
  • VFX
  • Modeling and animations
  • UI design
  • Icon art
  • SFX / Voice acting

What did I learn?

  • Fighting games are hard
  • Rollback netcode is hard
  • 3D can be hard
  • ECS is a double edged sword
  • Blender competence
  • Rust mindset shift is awesome
  • Lots of practial programming

How would I change it?

  • Better art in all forms
  • More characters
  • More items
  • Add a tutorial / single player mode
  • Add a proper lobby system
  • Countless slight tweaks

When I was younger I had a tendency to oscillate between projects that are way too big to finish before losing interest and projects that were way too small for me to ever get interested in the first place. I started work on this in 2021, and it has held my interest so far. I was getting into fighting games at the time with the release of Guilty Gear: Strive. One of the things that consistently motivates me is when a game evokes strong emotions in both ways. In some ways, GGST is fantastic (art, music, rollback netcode to pick a few cherries), but in others I can't stand it. My list of gripes changes over time, but some of the evergreen topics include the lobby system, loading times, unintuitive legacy mechanics, emphasis on block pressure and the corresponding de-emphasis on neutral and several specific character designs.

The elevator pitch is that WAG is a relatively simple fighting game at first, with most of the complexity gated behind an item shop, similarly to mobas. This was in part inspired by how several moba players refused to even try fighting games due to the perceived difficulty despite playing a game that is an order of magnitude more complex in some ways. The shop spreads out the cognitive load and allows the players to take it at their own pace. It makes theory crafting not only accessible, but encouraged for low to mid level players.

Unfortunately, the game doesn't screenshot well. The UI especially is very early on and is not representative of the final product. You can read more about it on my blog. Some of the posts include videos. I really tried to keep this concise, but if prompted can talk your ear off about it. The source code is available on Github.

One of the motivations I had for starting this project was that I wanted to learn Rust and the ECS pattern. Nowadays I would consider Rust to be my most comfortable language, even over simpler languages like JavaScript and Python. I don't know if I would call it a good language for game development, but beyond a shadow of a doubt it has applications in the vicinity, such as tooling and engine development. ECS was a bipolar experience. In some ways, it is incredibly good. Splitting code comes naturally and extending existing systems can be very easy. In other ways it is cumbersome. The game has rollback netcode, which means it must be completely deterministic regardless of machine architecture or frame rate. Ensuring determinism was a low point for Bevy's otherwise very ergonomic APIs. The project started on bevy 0.5, which was before Bevy was a year old. This has lead to a lot of growing pains. I've redone some systems several times due to Bevy changing. That's not to say they are perfect or even that the primary reason for me to rewrite something is a Bevy update, just that there has been a lot of effort put into ventures one would probably not need to worry about on a more established engine.

Implementation highlight: Builder pattern for actions

The game is a fighting game, so there are lots of actions a character can take. In a traditional fighting game like Street Fighter, a character usually has about 20 different moves on the low end. Multiple Tekken characters have 100+ moves in their arsenal, with several of those being multi-part strings you can think of as distinct moves. WAG will be closer to Street Fighter than Tekken, but the problem is still notable. On top of having lots of moves,I wanted things like jumping and dashing to also use the action system. This way I can implement something once and use it for all sorts of actions.

Problem: Lots of actions with all sorts of corner cases. Some have attacks attached, some do not. Some change the animation, some do not. Some trigger with an input, some get triggered automatically by something else. It's hard to describe actions in a concise and readable way.

Solution: Use of the builder pattern. For the most part I'm not a big fan of the Gang of Four patterns, with a few notable exceptions. The builder pattern is one of those exceptions. I implemented a base action builder and then built specialized builders on top of that, so now I can describe various types of actions clearly while maintaining the flexibility of the underlying system. I've attached screenshots of a few builders used for different types of actions.

Code of an attack builder

The example pictures are from the Samurai's file (may not be up to date). The first one is a jumping knee thrust, the second one is her grounded dash, which puts her airborne on frame 5, and the third one is a cancel option for her sword stance. I've become too used to the code to tell for real, but to me the code seems like it should be understandable for someone who is familiar with fighting games without much prior knowledge of how WAG has been programmed. Systems like the shop system can transform moves mid match, so I needed a tool that could match that level of dynamism. The builders can even take in functions that will get evaluated per frame to do whatever I want it to do. The builders have a bunch of assertions in them that make sure I don't make any easy mistakes. If I forget to add an end time to an action or a hitbox to an attack, an assert will catch that.

Maintainability highlight: Automated input parser tests

Fighting games have special moves, which only activate after a specific set of motion inputs. Street Fighter has it's hadoukens and shoryukens, both of which require moving the movement stick through a set of points before pressing a punch button in order to come out. The input parser is hard to get right. It has to be reliable, but not give false positives. It has to allow for all sorts of input descriptions but be reasonable to use. It has to run quickly and consider things like which way the player is facing. I've rewritten the input parser three times now from scratch. You can read more about it on the dev log post I did the third rewrite.

Tangent about how motion input parsing is complex

The border between a bug and a feature is razor thin. Quirks from old games have solidified as features of the genre. There are tricks the players have gotten accustomed to and expect to work. You more or less have to program the quirks in, or design around them.

It's expected that the input parser can reuse inputs for one action for a following one, and that the inputs for complex motions don't need to be 100% "correct". Leon Massey explains it better than I could in his video about combo variety, but I will give it a shot anyways. What you need to know is that in most games you can cancel normal moves into specials (the motion moves). In some games including Street Fighter 3, you can also cancel specials into supers (even more motion-y moves). Because of this, Ken can do a combo where he first lands a crouching medium kick (normal), cancels into shoryuken (special), and then cancels into super. The input for crouching medium kick is any of the down directions + medium kick, shoryuken is + any punch button, and the super is a double quarter circle forward () + any kick button. You can do the whole combo by inputting the crouching medium kick into punch kick. The shoryuken should be pretty clear, you are doing the input fair and square. It's harder to know why the super comes out without two quarter circles. Most games allow you to miss an input or two in complex motions like supers. The full series of inputs should looks something like mk p k. The game could find the quarter circles where I've put the angle brackets: [ mk, (missing here, permitted by leniency) ][ p ] k(this kick triggers super, since it comes after two "quarter circles"). Alternatively the game could just trigger the super when it sees enough of the desired directions in a short period of time regardless of order. This is what Leon thinks is going on. No matter why it works, the game is recycling the shoryuken motion in the super, and allowing for some leniency with the super input.

Some of these tricks are game specific, like the Street Fighter crouching shoryuken, inputted with + punch, instead of the proper listed input of + punch. The shoryuken is often used as an anti-air, a counter to the opponent jumping at you. Being able to do it crouching means your character's hurtbox is lower, which means the opponent jumping at you will hit you later, giving you more time to react to the jump. This is not really game breaking, but a technique that stems from the input parser being lenient.

Some tricks are so common players just consider them the normal input. Grapplers have these big grabs called command grabs which often have a "360" input. On paper the 360 is a full rotation of the stick. Zangief's spinning piledriver input is shown in the input list as + punch. This has a few problems. One of them is that any of the upwards inputs will cause you to jump if able, which forces you to churn the input when Zangief is in a state where he can't jump. The second problem is that even on an arcade stick, it's very easy to miss a corner. Developers have since made the 360 input more lenient to the point where the name and notation are misleading to new players. For most games, you only really need to hit half of the designated directions. Sometimes you need to hit the cardinal directions, sometimes not. The way Zangief players really do SPDs is more like + punch, which is a nice rolling motion with only one jump input and it's the last required direction, so if you hit the punch within a few frames of the last direction you get an SPD instead of a jump. It's not the easiest thing in the world, but a silver Zangief player can land it nine times out of ten. If they had to do the input as written, I doubt they would hit it once out of ten attempts. The confusion of the 360 motion is largely why I probably won't ever put one in WAG despite loving them as a concept.

Point here being there are lots of input shenanigans that players expect. Sometimes you can get multiple birds with one stone, but some require their own changes. Adding a shortcut the wrong way can cause you to accidentally invalidate other shortcuts, cause false positives, or add a new degenerate shortcut that ruins a character or even the game.

Problem: Changes to the parser can very easily break a corner case elsewhere.

Solution: Automated tests. I've gone back and forth on the amount of tests in the project and it currently has about 30. The test coverage is not that great, but I don't think it should be. Coverage is a misleading metric, and there have been lots of sweeping changes in the architecture as I learn more about Rust, Bevy, or programming in general, which invalidate parts of the codebase. I've removed maybe 20 or so tests because the system being tested no longer exists. The input parsing tests are without a doubt the most valuable tests I have. They were originally written for the previous parser, but I made them generic enough to work with the current and any future parsers. They simply test if a series of inputs gets registered as a specific input, or that it doesn't produce a common false positive. They could be more detailed, but they already catch most of the problems I've had. Having a test suite this good allows me to do TDD when I work on the input parser, which I think is a great application of TDD.

Green eggs and ham

What is it?

  • Level based
  • 2D adventure
  • Platformer
  • Built with Godot
  • Scope: Solo project, two weeks

What did I do?

  • Game design
  • Programming
  • Everything besides assets

What did I learn?

  • Hitstop adds a lot
  • Charm is surprisingly cheap
  • Godot is nice
  • Prioritization

How would I change it?

  • I'm pretty satisfied with this one
  • Extend with more worlds
  • Fix the font rendering
  • Add more music
  • Maybe add burst movement or a parry

This is my most visually appealing game so far. It took about a week or two of effort spread out over about a month or so. This was my assignment for a university course. The course started with the students following along a Godot tutorial and then adding their own stuff on top. Having already made a couple of games, the tutorial was a bit basic, but informative as this was my first game in Godot. I self-imposed additional time constraints to focus on efficiency over effort. I set an upper limit on how much time I would spend on the game, and tried to maximize what I got done in that time. I recycled a lot for the levels and spend most of my time on juice and polish. There is very notable hitstop and screen shake. The hearts in the top left corner for example pulse faster when there are fewer of them and pulse with a slight offset to each other.

The only thing I regret about it is the self-indulgent writing that seems to creep into my projects when nobody is looking. If you are curious, you can find the game on itch.io. Feel free to try it. For most players it takes 30 minutes to an hour to beat. Code is available on Github.

Implementation highlight: State machine

Problem: Character can be in many different states. Some with animations, some without. How to manage that in a maintainable way?

Solution: Node based state machine. As long as I've worked in Godot, I've really liked the nodes. I made a system where the player node has a state machine node as a child. The state machine then contains all of the states as children and references one in it's script as the active state. Each state node has a script that inherits from the base State script and implements any number of the provided functions. It has functions that get called when the state is activated or deactivated and one called each frame when the state is active. Any script can request a state transition, which will then call the state functions. Overall the system worked remarkably well and adding new states was very easy. I would probably not do this for 20+ states like in WAG, but for the eight discrete states that were in this game the system was solid.

A lot of the behavior was also done outside the states. For example, the movement of walking was done in the player root node script, since that has to move the root object anyways. I probably could've moved more of the behavior to the states, but took a pragmatic approach and went with the path of least resistance over the theoretically 'purest' solution. This is also something I would heavily reconsider if there were more states.

Full disclosure: The approach is not originally mine, but I can't remember where I took the initial version from. I do remember heavily modifying the code, as I remember the original version wanted to do more in the states than I did and the noise was unnecessary here. It was hard to think of something special for this one, as it was a very smooth project.

Screenshot of Godot node hierarchy of the state machine

Mission IMPossible

House elf in front of a shelf in a basement

What is it?

  • 3D stealth game
  • With a goal to clean a house
  • Before the resident catches you
  • Built with Unity
  • Scope: Team of five, two months

What did I do?

  • Programming
  • Coaching
  • VFX
  • Game design

What did I learn?

  • Unity is surprisingly extendable
  • Decals and animation blending
  • The power of friendship!

How would I change it?

  • Most of the game, for example:
  • Improve the HUD
  • Add a model to the NPC
  • Add more levels / progression
  • Fix the lighting
  • Add more interesting minigames

In the game, you play as a house self that sneaks around a house doing chores. The bar on the left indicates how many chores you have left. Some chores required tools that start the game scattered around the play space. For example, you need a sponge to wash off the brown dirt smears (right side of picture 2). Once you've filled the bar, you have to get back to the place you started the level in. Originally we planned to have multiple levels, but ended up boiling it down to just the one. There are items besides tools, for example a coin similar to the one from the Hitman series and the hat worn in the third picture, which I think gave you a movement speed buff.

This was made for the same university course as Green eggs and ham. The course had us work in teams of five, but unfortunately this was the second game most of us had ever made. The first one being following a godot tutorial with a few custom tweaks like changing the sprites. The course mandated that everyone had a role. I primarily wanted to be the programmer and secondarily to not be the project manager. I tend to take charge in these sorts of projects, and see this is a problem for my ability to work in teams. I deliberately wanted to practice delegation and giving other team members the freedom to work. In the end I did end up helping most of the team, including the project manager quite a bit, but still consider this a successful delegation exercise. The help was mostly technical stuff like helping team members with git, as most of them had never heard of it before. I also did a quick overview of how Scrum works, as the course enforced some of the rituals. Overall, I'm satisfied with the project, even if it doesn't really meet my personal threshold of quality. The kindest thing I can say is that I think we tried our best and it has some decent ideas. If you want to check it out, you can find the game over on itch.io and the code over at GitHub.

Tooling highlight: Automatic item icons

Problem: We have lots of items in the game. The items require HUD icons. Drawing icons by hand would take a lot of time.

Solution: Use Unity to automate the process. The objects needed to show up in the game world, so we had 3D models. I built a scene that was only used in development. The scene had a camera, a light, and all the 3D models of the objects. I then did some editor scripting. The script looped over all the objects, activating them one by one, taking a screenshot with the camera, and saving that screenshot on disk. These screenshots were then used as the icons. This way if we wanted to edit the item positions in the icons, we could simply change the item positions in that scene and redo the screenshots. I think we had maybe 15 items and it took a few seconds to generate all the icons.

It could've been a lot more sophisticated in terms of visuals. The items could maybe have a background to them to make them pop more and we did run into issues with model fidelity. We got the models from some asset pack that had game ready models, meaning the poly counts were on the lower end. Not a problem in the actual game, but when you want to shoot close-ups of them it becomes an issue. Some items like the sponge are literally squished capsules with a texture and this was really obvious in the icons. I did add some bumps to the sponge with a vertex shader, but it still wasn't quite what I wanted. If I had to make a sponge now, I wouldn't hesitate to just hop into blender and bang out a sponge.

Smaller projects

Some of my newer microprojects have a post on my blog. I started the blog in 2024, so it won't include projects before that for the most part. I'll try to make a post for every new Jam game or notable hyperfixation. The blog posts should have visuals, I don't want to bloat this page.

  • Squeli - Top down 2d 2-4 player pvp arena shooter weekend Jam game
  • Mankind knew - A political statement / weekend game jam project.

My Dystopian Laserhell Hovercar

Poster art for 'My dystopian Laserhell hovercar'

I used to partake in the yearly GMTK itch.io game jam. I've liked the themes and since it only takes a weekend it's pretty easy to fit into a calendar. My teaching gig schedule sadly overlaps with the jam, so I've been unable to attend for the past few years. In total I think I submitted four times, with most of them being not that great. This one I did with Lauri Virtanen, a fellow programmer I've known since high school. I did mostly design and programming with maybe a 30/70 split. Lauri did both of those, but also art and music with something like a 10/40/30/20 design/programming/art/music split. It has been years and I'm handwaving the numbers, but the gist is that I did most of of the programming and design, while Lauri focused more on the aesthetics.

You can find the game on itch.io and the source code on Github, although I must warn you that this is an older submission and the quality doesn't necessarily reflect my current skill level.

Teaching computer science

Couldn't figure out if this should go here or not, but for three years I was the head teacher for the summer computer science course over at Matematiikkalinja. The program is meant to teach people entering high school the basics of computer science. Some students are already competent programmers by the time the course starts, while a growing number have never touched a keyboard before. My role was twofold. I was lecturing and hosting exercise sessions, but also responsible for recruiting and managing other lecturers and TAs. I loved doing it and cherish all the memories I made along the way, but after the summer of 2024 chose to give it up. I felt like I had accomplished everything I wanted and there was nothing left to do. Managing the chaos did cause me stress and eat into my summer vacations, but the primary problem was the lack of a goal. I reformed the traditionally rigid curriculum, taking out what was no longer useful, reforming existing materials to be more approachable for the students, and introducing lessons to cover traditional blind spots such as web development. The last year went off without a hitch, which in a weird way was a disappointment, as it proved I had mastered the craft to be a tad egotistical.

Tabletop role playing

In addition to digital, I'm quite fond of analog games. Board games, card games and most of all, tabletop role playing games are my jam. I've designed a few adventures, systems, and player options for them, but haven't had sufficient faith in any of them to show them to a crowd larger than my friends. I do like how tinkering with designs like that makes you think and still occasionally spend a few hours drafting something up, just to understand why the thing I'm trying to fix works the way it does.

As of writing, I mostly play Pathfinder 2e, with occasional D&D and Fate, I've also read through many others like Gurps and Swade, but haven't had a chance to play those yet. In general I prefer DMing, but that depends on the system and the group. I'm passively interested in rules light or more "LARP-like" games, but don't seek them out.

The end

Thanks for reading, you can get back to the blog. If any of this seems helpful or interesting, get in contact: