Dev Blog June 14, 2020

I Can't C#, That's Why I Need Glasses

Welcome back to the Little Squid Dev Blog!

First, we'd like to apologize for the joke, it was a little on the nose.

Get it?

This week was a pretty productive one. We made some solid progress on a few things and have hopefully laid some groundwork that will make production of the game a bit smoother moving forward.

So what was it that we made progress on this week? ...B-Side(s) our comedic timing? (I could keep going here).

  • First, we did some experimenting with background concepts and think we're on the right path there. There's of course more work to be done though.
So colorful 😮
  • Second, we watched the Playstation 5 reveal event (was supposed to actually attend E3 this year, but that's 2020 😔) and saw some cool games, which we think is always a productive use of time. (our hype for Horizon II: Forbidden West is unreal)
  • Third, we reworked a portion of our codebase to get seamless level loading

That third bullet point is what we'll be talking about in a little more detail today. We think this is a super important task and it's one that we've actually spent almost 2 weeks on at this point, which is a bit unheard of for our little team of two trying to make a game by the end of the year.

We know not everyone that would be reading this is all that interested in coding or game engines or the more technical things like that so we won't go into excruciating detail about any of it. (Drop us a comment if we're wrong in that assumption!) But we do want to give an idea of what it is we did/are doing and why. It might be a little bit dry or dense but stick with us.
What exactly is being reworked?
For a tl;dr of everything: we made levels load in the background so that when you reach the end of one level, you're automatically put into the next one. This is in contrast to how it worked before - when you reached the end of a level, it would fade out to black, load the next level, and fade back in.
How this was accomplished is quite a bit more complicated than it might sound, mainly because this new behavior was not planned from the beginning of development. This meant that the code base just wasn't set up to load levels in the background and "rework" turned more into "rewrite".
"How was it set up from the beginning?" you might ask.
Good question. Since I (Mike) started prototyping the idea for what is now B-Side in October 2016, I didn't yet have much experience on how games are made, so I coded the core functions to work within each level independently. This meant that code for things like the "flipping" mechanic, player character, UI, etc would exist only within one level. It would then get unloaded with the rest of the level when you finished it, the next level would load, and that next level's instances of all of that code would also load.

...what?

It might help to very briefly explain how Unity works and show a picture or two.

The main functionality of Unity revolves around the use of what it calls "GameObjects". These make up almost everything that is in a game built with Unity. By themselves they are nothing, literally, but when you attach things like 3D models, animations, sounds, etc to them, they can be characters, items, scenery, or props. Each character or prop or whatever can be made up of a bunch of different, smaller GameObjects each with its own models, animations, effects.

All of these are GameObjects

You can also attach "scripts", or chunks of code, to these GameObjects and those scripts let you or the player do what is intended with that Object. You want the player character to jump when the player presses a button? Attach a script to the character GameObject that has the code for "when player presses button, character jumps".

There's a common practice, regardless of game engine, where developers make important scripts that help manage game states like what level the player is on, what the player's score is, what the player can/can't do at this moment. These are usually called "manager" objects/scripts.

All of these GameObjects end up going into "Scenes", which can most closely be related to what's traditionally called a level. How a developer handles Scenes is up to the type of game they are making - Scenes can hold a specific puzzle, they can be a particular section of a larger level, they could be an entire world if desired (but that would usually be unreasonable).

This scene contains all of the GameObjects from above (cube, player, etc)

So for B-Side, up to this point we had all of the game's core functions operating from Manager GameObjects that were placed into individual Scenes, with each Scene being one level or puzzle. When a level ended, the next Scene would load and so would that Scene's instances of the Manager GameObjects.

This worked totally fine! It was actually kind of nice and efficient to not need to worry about any kind of game state transferring over from level to level. Every state just got "refreshed" at the beginning of each new level and anything that seemed to transfer over was really just set to that specific state within that particular Scene. It also allowed for really quick testing and iteration since I could load any level and know that it would be handling itself and not relying on anything outside of that level.

The problem arose when the game's design evolved. To tell a better story, the levels couldn't be so separated.

So began an arduous process of disconnecting the Game Managers from their specific levels, making them stop relying so much on each other and the other Objects in a Scene, and making it so they can exist on their own regardless of a level. The Scenes now have one specific object in them that passes some important info relating to that Scene into these Managers when the Scene is loaded, and gone are the days of fading in and out to black. So far it's working as intended!

What's it look like?

I know that was pretty dense stuff. Sorry, I got carried away. But if you stuck with it, here's some more visuals!

Anyone who has tested B-Side will have an idea of what the behavior used to be between levels, but here's a look at it. Pay attention to where the player character is when a level switches.

Now this is a little taste of what it looks like with the reworked code. If it's done right, you shouldn't actually be able to tell that anything is happening.

Why go through the trouble?

This comes down to a design decision more than anything else. It definitely wasn't an engineering or performance issue (at least at this point), and in fact may be creating performance issues that will need to be addressed.

But it came to a point in the game's design that we wanted each level, and the paths within it, to connect directly to the next level and its paths. That way it's always a continuous path that the player is moving through (you can see it in action in the gif above).

For us, the implications of one continuous path through every level is worth the trouble of rewriting a bunch of code and breaking other things along the way. In the end we think it'll make a much better player experience and it really supports the story we're telling within the game.

- 🦑

B-Side Arrives 2021
Follow our Indie Journey with us! @LittleSquidStudios
wishlist b-side
© Little Squid Studios 2020