Indigo is now built against Scala 3.6.4 and Scala.js 0.19.0, your projects will need to use at least those versions to be compatible.
This release is called: "There's more to do, but sometimes you need to call it and cut a release." π
Below is a brief summary of changes and features included in version 0.21.0.
Actors & Performers
The major addition that comes with this release, is the notion of Actors and Performers, two flavours of the same solution to a core problem.
Finding the Fun
Indigo (via the Elm Architecture) was designed for 'correctness'. Well, not absolute correctness. Actually, not even the level of correctness many Scala developers strive for commercially, but a level of correctness I'd never experienced as a Flash developer at least.
Correctness, and related topics like type safety and borrow checkers and so on, lend themselves very well to highly specified and generally understood software builds such as data pipelines, backend services, systems tools, and even games engines.
What frameworks, libraries and languages aimed at correctness are not good at, it turns out, is having fun. Finding fun. Making something that feels fun, and making it .
quickly
This is very important in game development. Anyone who is trying to learn gamedev or take part in a game jam, needs to see results quickly to know if they're making progress or not.
Take for example someone trying out a game idea. That person needs to be able to test and reject lots of ideas and prototypes quickly to figure out which ones are worth pursuing. If they can't do that with a 'correct' engine, they'll find a more relaxed one, and probably just stick with it, willingly sacrificing correctness for a sense of productivity. Later in the build they may pay the price for that decision, but that's a high quality problem for later when they have something worth finishing.
Refactoring game wiring to appease a type checker is a waste of time and energy when your goal is to test an idea.
So the problem is: How do we introduce a way to build quickly, sacrificing a little correctness and ability to reason about the game's behaviour, in exchange for a productivity boost, and dare I say it, for having some fun? How do we make Indigo gamejam friendly?
The good news is that Indigo uses the Elm architecture, and the Elm architecture composes quite well. So all we need to do, is provide convenient ways for people to describe mini-elm architecture based things that can communicate with each other and the rest of the game via messages. Sounds a bit like an actor to me..
Actors are a building block. They're an intentionally incredibly simple construct. You wire an ActorPool into your game model and update and present loop, and the ActorPool does the rest. Actors can be spawned, killed, and discovered directly on the pool in a type safe way.
An Actor can be any type at all, as long as you can provide an instance of the Actor typeclass for it. As such, you can think of actors as the more FP solution, but that doesn't make them the better option, at least initially. Actors work nicely, but they do require more manual management than performers. For example, being a building block, if you want to use actors with physics, then you'll need to join them onto the physics world 'building block' yourself, manually.
Performers are very similar to actors, but are a much more opinionated solution and intentionally lean slightly more towards OO (but don't let that put you off!). Performers run in a subsystem, so the set up is much easier and there's no wiring to do. If you want to add / remove performers you do so with PerformerEvents. Some of them also work with physics out of the box!
Performers lean on a 'Stage & Screen' metaphor, and offer a range of types you can extend (inherit from) that provide different levels of functionality at the cost of increasing interface complexity. They are:
Performer.Extra - Extra performers are the background characters of the performance. They are responsible for rendering themselves and updating their state, but they cannot interact with the game directly since they have no way to listen to or emit events.
Performer.Stunt - Stunt performers are like Extras, but they can do their own stunts! In practical terms, they are background performers like extras, but have their motion automatically controlled by a managed physics simulation.
Performer.Support - Support performers are the main character actors. They are responsible for rendering themselves, updating their state, and can also listen to and emit events, but they leave physical work to Stunt and Lead performers.
Performer.Lead - Lead performers are the stars of the show. They are responsible for rendering themselves, updating their state, listen to and emitting events, and even doing their own stunts! They are the most complex type of performer, but also the most powerful.
Using performers is the fastest way to start building a game that requires the least mental gymnastics! ...the drawback is that the pattern is limiting and opinionated, and as your game grows, you'll probably want to try other organisation methods.
Where Actors and Performers live in relation to the main game loop
We'll see how it pans out, but the intention is that people will start with performers as the quickest solution, as their game develops they could selectively introduce actors for more control at the cost of more overhead / wiring, and ultimately manage the core game state and logic in the main game loop.
...but who knows what people do with them, it'll be fun finding out! π
You can give them a fixed position as you always could before.
You can now tell a window to anchor somewhere on the page, using exactly the same Anchor and Padding data types that components use.
The use case for anchoring is that, for example, you want a pause menu to appear in the center of the screen, or a menu to be fixed in the top right corner - with some padding to keep it away from the edges, naturally.
Windows can decide whether they are active or not
Sometimes you need a window to disable itself. Using the pause menu as an example again, when the game is paused you want the rest of the UI to decide that it is disabled temporarily. Or perhaps you're dragging something around on the screen and don't want to interactive with menu's until you drop it, again, the window can determine if it should be enabled or disabled based on the game state.
You can now achieve this using the 'activeCheck' in a window definition.
Physics improvements
Below is a brief summary of Physics improvements. These were either in service of Actors and Performers, or are paving the way to a more substantial reworking of the physics code that keeps-threatening-but-never-quite-makes-it to the top of my list of things to do.
World bounds are now optional - You no longer need to say how big the simulation is although it is more efficient if you can.
Added a Worldcollect method - so that you can return / look up a partial set of colliders
Added a WorldmodifyAll method - so that you can update all or a sub-set of colliders based on the game model. E.g., telling a hoard of zombies to move towards the player.
Added a WorldremoveAllByTag to remove a batch of colliders by tag
Added a WorldwithSimulatationSettings helper method
Colliders can now report velocityDirectionAngle - Handy if you want to know which way they're travelling, say, to make a spaceship point in the right direction.
Physics code reorganised ahead of future work - big plans, big plans...
Layer rendering performance
Layers are useful things that have a dreadful impact on game / rendering performance. Without a serious rethink of the rendering pipeline, this remains the case.
Layer rendering performance has come to be a real problem since the release of the UI framework, which uses prodigious numbers of layers to lay everything out.
However, a change has been done so that the engine will now attempt to render (far) fewer layers without changing the expected output, via a process of 'layer compacting'. Simple put, if two layers are sufficiently similar, they get squashed. Top level layers, where you might find a layer key, are unaffected.
In the case of UI layouts at least, this produces a vast performance improvement.
Plugins
The IndigoOptions type has had a few new helpers added to it, which I hope are self explanatory:
openDeveloperTools
modifyGameMetadata
modifyElectronOptions
Other notable changes
Viewport information in the frame context
I love this change, I just wish I'd thought of it before. If you want to know how big the screen is, it's now right there in the frame context. No need to listed to ViewportResize events if you don't want to! There is also a reference to the globally configured magnification setting too.
Radians, better wrap + centeredWrap functions
wrap now works better and more efficiently in the range (0, 2 * PI], and the new centeredWrap produces a range (-PI, PI].
Batch
Added a dropWhile function. πͺ
FPSCounter
FPSCounter can now be placed dynamically based on the Context, this is thanks to the viewpoint info being in the frame context.
Generated notes:
What's Changed
Reduce DiceTest iteration by @exoego in https://github.com/PurpleKingdomGames/indigo/pull/889
Actors & Performers by @davesmith00000 in https://github.com/PurpleKingdomGames/indigo/pull/871
Reorganised the physics engine code by @davesmith00000 in https://github.com/PurpleKingdomGames/indigo/pull/897
Fixed #900: Viewport info in Context by @davesmith00000 in https://github.com/PurpleKingdomGames/indigo/pull/902
Issue #859: Window Anchoring by @davesmith00000 in https://github.com/PurpleKingdomGames/indigo/pull/901
Layer rendering performance tuning by @davesmith00000 in https://github.com/PurpleKingdomGames/indigo/pull/904
Full Changelog: https://github.com/PurpleKingdomGames/indigo/compare/v0.20.0...v0.21.0