The Capsule Three team have been making great progress the last few weeks and we're extremely close to our Alpha milestone. For our third Indie DB post of 2016, our coder/designer - Clive Lawrence - has put together a post which explores some of the sea-life you'll find encounter in Observatorium including an insight into the code/design processes behind them.
For those unfamiliar with our game, Observatorium is a puzzle adventure game where the core gameplay involves creating constellations that connect stars and sea-life. Over the last few months, we've been in the process of finalising the types of fish that will be featured in the game alongside their behaviours.
The Core Sea-Life Classes
Observatorium is split into 12 chapters and 8 core paths which stem from the central 'moon' hub. Each path is tied to a single class of fish which represents a unique kind of puzzle. Below you can see the friend fish orbiting the ship and the 8 core sea-life classes placed on compass points around the central zone:
When creating the core classes, we aimed to choose silhouettes that were very distinct so they could be easily read when placed side-by-side. This let us ignore inner details and focus on overall readability. We also wanted to make sure that the look of the fish complimented the gameplay you'd expect from them. As a result, the fish and designs went through several iterations before we were happy with their scope and behaviour.
Observatorium is being constructed using the Unity 2D toolset and each visible asset in our game has a Sprite Renderer component attached. Each fish is hand-animated and has multiple states including inactive (dark) and active (bright). An example of our rigging process from our last post is shown below:
Each fish has an Animator attached and uses variables to move between animation states using Unity's built-in state machine. For instance, the most basic fish - like the starfish - use a bool called Activated which allows them to move between a dark (inactive) and bright (active) state:
Although the fish in our Alpha demo appear as solid colours, we're planning to add additional details as we move into Beta. Here's an example from our concept artwork:
This will be achieved using an art swap and re-exporting of 2D assets whilst maintaining the animations.
Puzzle Fish - Examples
In Act 1 of the game, the player is introduced to the basic mechanics through the starfish and jellyfish classes: these fish don't move but provide the foundation for much of our gameplay. The starfish introduce point, line and shape puzzles and represent our simplest puzzles in the game:
The jellyfish chapter introduces propagation and dependency mechanics and, as such, these puzzles are a little trickier:
Act 2 introduces dynamic fish in the form of the 'fleetfins'. The fleetfins can move and activate other fish from a distance. We also introduce a few additional classes of fish that enhance their functionality somehow. For now, here's an example showing their basic movement:
Act 3 introduces some of our strangest fish in the game including the Octopus - that can create wormholes - and the Squid: whose ink can transform the nature of the current puzzle:
Overall we have 8 core classes of fish and 3 sub-types per class leading to 24 varieties in total. It's alot of work to keep track of - especially for our first release - and we realised this during development. To reduce our workload, I decided to take a structured approach to dealing with so much variety:
The Fish System
I've implemented a 'fish hierarchy' in code (C#) which aims to take advantage of the 3 pillars of Object Oriented programming: Inheritance, Encapsulation and Polymorphism. Here's an example of how the orange starfish is structured within the hierarchy:
- IFish - the fish interface - defines public methods (and their signatures) and properties (including whether they have get and/or set accessors) but no implementation.
- Fish - the fish class - implements IFish - provides an implementation for all of the public methods and properties from IFish and, also, introduces some private and protected methods/variables. Some methods are marked as 'virtual' as they are not implemented here but via subclasses.
- Fish_Star - extends fish - provides an implementation of virtual methods using the 'override' keyword.
- Fish_Star_Orange - adds behaviour that is specific to the orange starfish. Classes at this level are usually quite small and therefore quick to implement.
To tie this back to the aforementioned core pillars, some examples:
- Inheritance Example - Fish_Star inherits functionality - such as the ability to move between an active and inactive state - from the Fish class so there's no need to duplicate that code.
- Encapsulation Example - some methods and variables are public (where relevant) whereas others are private or protected. For instance, the 'CurrentState' enum (whose value can be Active or Inactive), is publicly accessible through a Property (via a get accessor) as this is commonly used by the Puzzle code to check whether or not a certain fish is active.
- Polymorphism Example - the puzzle code can check for instances of Fish (or better yet - objects of type IFish) rather than worrying about specific types of fish. Every Fish_Star_Orange 'is a' Fish_Star and every Fish_Star 'is a' Fish. When a line activates a fish it simply wants to set the fish state as bright - it doesn't actually care about the type of fish so doesn't need to know that information.
Throughout development, the specific fish classes (such as Fish_Star_Orange) have become smaller and the 'Fish' class has taken on most reusable functionality: this makes adding a new type of fish very quickly as I can add just a few new lines of code to invoke some special behaviour.
The Friendly Fish
One of our favourite 'accidental-features-turned-core-mechanic' was the addition of the friend fish.
Prior to our Dare 2015 showcase, we added a small orange fish to lead players through the tutorial puzzles. The fish was merely added to echo what the compass was already telling the player and to give a visual 'follow' type cue for the early stages of the game.
The mechanic was a little rough in that I was spawning and culling multiple instances of the same fish all over the place and jumping between positions in a very noticeable way. Alot of players at Dare 2015 were really warming to having this companion fish and we were getting feedback like:
- "Can you slow it down a bit?"
- "Why does he keep swimming so far away from me"
- "You wouldn't possibly kill that little fish would you?"
- "Does that fish represent Kit's father?"
- "You better not kill the fish!"
Following Dare 2015, we decided to use this fish more often and also clean up its behaviour. The changes we decided to make were:
- Only spawn a single friend fish per level
- Make the friend fish wait for the player when it gets out of range
- Use our existing curve system to create a 'friend' network in each level
- Use star zones as mini-roundabouts as the player solves a puzzle
We've also been writing this fish into more parts of our story.
As per our often-used work-smarter-not-harder philosophy, we opted to create a dynamic system that would ultimately reduce our workload and let us roll this fish out more easily. Here's an example of our revised friend fish gameplay:
All of this plays out dynamically in game and is incredibly quick to setup in-editor as shown below:
We also added some randomisation to make when the fish starts/stops seem less predictable. Moving forward, we will continue to improve the friend fish and add more character to it as we move towards our Beta phase of development.
The Not-So-Friendly Fish
In addition to our positive fish mechanics, we also have a secondary range of fish which don't always help the player. For instance, the 'spikey' fish wreck any lines or stars that touch it.
We have a few special fish too that we haven't mentioned but we'll save their examples for another day:
We also plan on rebalancing the artwork so these fish stand out better against the dark background.
Observatorium was always intended to be a rich game with respect to amount of content but as a small indie team of just 3 people (of whom I am the only coder/designer) you need to keep your limitations in mind and reduce or simplify where you can.
From a code/design point of view, putting alot of work into the fish system has allowed us to implement a flexible approach whilst keeping things manageable. We were always keen to expand the fish gameplay ahead of the star gameplay as we feel the sea-life is a great chance for us to add alot more character to the game.
We're comfortable we have plenty of variety as we push towards release whilst having a system that's quick to modify and - more importantly - fix up should any issues arise.
That’s it for our look into the sea-life of Observatorium. We've held some stuff back so you don't get completely spoiled when you finally come to play the game. Stay tuned for our next post where we'll be revealing our art style update.
You can stay up to date with Observatorium and Capsule Three developments via:
Thanks for reading