/scala-game-library

Scala library for cross-platform 2D game development

Primary LanguageScalaMIT LicenseMIT

SGL: Scala Game Library

Scala CI

Scala Game Library (SGL) is a library for developing cross-platform 2D video games in Scala. It provides a high-level API for building games, and can export games to the Desktop, Android, and the web. More platforms, including iOS and consoles, are on the roadmap.

SGL is still in development, but is intended to provide an extensive toolkit to facilitate game development in Scala, with a layer of abstraction on top of the platform-specific functionalities, and an out-of-the-box implementation for many common features needed in games, such as physics, collision detection, tilemaps, and scenes management.

Objectives

SGL aims at providing a generic and cross-platform 2D game API. The API provides some layers of abstraction on top of the underlying systems, and a game written using the API should be able to get compiled and run on each platform with very litle platform-specific code. However, there are several non-goals of SGL:

  • The exported API hides the non-game specific features of each system, however it will export an API that ressembles the underlying systems, with a slight Scala stylisation when possible. What that means is that the API will be imperative as this is the prevalent system architecture, and it will look familiar to people used to write games directly on some of these systems. In case you are interested in writing games with a fully functional style, you will need to either build an abstraction on top of this API, or you can check out Indigo, another Scala game engine but with an explicit goal of providing a purely functional API for game developers.
  • SGL is not an opiniated way of building games. It's trying to provide the most simple yet general API that is cross-platform and enable programmers to create any 2D game. The design decisions are centered around what to export in the API, in the best possible style without losing low-level control. SGL can be thought of as a libGDX in pure Scala and optimized for 2D games. Another source of inspiration for the design of SGL is the Simple DirectMedia Layer, and the name SGL was chosen partly because it tries to be a sort of SDL for Scala.
  • Although SGL is currently providing a lot of extra toolkit library (scene management, game screen management, tiled maps, etc) to facilitate building games, internally there's a relatively clear distinction between what is the core cross-platform API and what are the components built on top of that. A lot of thoughts goes into desiging these core APIs, but components are kind of piled on top of each other quickly, mostly as the need arise in an actual game development project. In the long term, it's possible that SGL will be split between the core layers of abstraction, and the components that are built on top. The objective of SGL is to build the correct core abstraction, while the components are one possible take on a game engine API, it should be eventually possible to replace all the components and choose a totally different programming style (including functional reactive programming) and still share the same underlying platform abstractions.

Features

The main selling point of SGL is to provide a platform-independent Scala game framework to build games, and then deploy them to any platform. You can get started by writing a core generic game implementation, and then configure any backend with just a few lines of Scala. You can iterate on your game by running the AWT backend from sbt, which, depending on your configuration, is as straighforward as:

sbt mygame-awt/run

Thus, you can quickly iterate on your game locally, without the need to waste a lot of time deploying to your target platforms, such as mobile or console.

The current implementation provides the following backends:

  • Desktop with JVM and AWT. This is mostly convenient during development, but can also serve as a final release if you are able to distribute your game to people that have a JVM. It will be cross-platform across Windows, Mac, and Linux.
  • Android. The Android backend is implemented with the native Android SDK for Java, which means that SGL supports Android natively.
  • Web with Scalajs. The web backend is implemented with scalajs and uses the HTML5 canvas for graphics, the HTML5 audio tag for audio, and other standard web features.
  • Native (Experimental). The native backend implemented with scala-native is able to generate a native executable that can then be run on the target platform without a JVM. The support for native is not complete yet, but the current implementation is a proof of concept. Further extensions to this backend should enable SGL to eventually target iOS and various consoles.
  • iOS while we do not yet support iOS natively, it is possible to use the web backend combined with a tool like Cordova, to make an iOS app. This has been proven with this game.

Alternatives

If you want to write games in Scala, you have a few alternatives. Here's a biased opinion on how SGL compares with these alternatives. But first a disclaimer: SGL is not production-ready and is under heavy development, so if you want to limit your interaction with the game engine, you probably should look somewhere else for now.

  • libGDX is an extremely mature game library written in Java and thus fully useable in Scala. It provides solid support for many platforms, and it supports 3D and you can make full use of OpenGL with it. You can't really compare SGL to libGDX, as they are just not playing in the same league. Today, if you decide to use SGL, you are betting on the future. You are betting on a future where SGL will get to feature-parity with libGDX, and where the Scala-first approach will pay off for your game.

    I do think there are fundamental technical advantages with having the engine written in Scala, which might eventually justify using SGL over libGDX:

    • Scala is a better language than Java (biased opinion, but I think it's true).
    • Scala opens up extremely powerful design pattern for the core engine and the plugins built arount it.
    • SGL leverages Scala Native and Scala.js to provide a high-level of control on each target platform, which I think is superior to what can be done with traditional cross-platform development offered by libGDX.
  • Indigo is a pure Scala game engine with a design focused on developer productivity. It offers a purely functional way of writing games, which is likely to appeal more to Scala developers. By contrast, SGL does not emphasize the funcitonal programming style, it limits itself at abstracting away multiple platforms into a consistent API. Indigo is currently in development so the set of features is constantly moving (just like SGL), so it's hard to truly compare them. Given the current state of the engines, I think it's fair to say that Indigo invested a lot of work into building the right API for the developer, while SGL invested a lot of work into supporting multiple platforms in a very native way (Android, AWT, Native, HTML5 are supported, while today Indigo runs only with Scala.js).

Work in Progress

This is a work in progress, so please don't hesitate to get in touch if you are interested in writing a game in Scala. This is not production ready yet and things will need to be tweak in order to make them work, but I'm putting this project out there as I think it has a good potential, and I'm looking for feedback from people interested in such a library.

I'm developing new features on a need basis. I'm working on some Android games, and I started to use this library as it was much nicer to build and test the game on my Linux desktop, and only deploy to the phone for the final tests. I'm constantly adding new features to the library based on my needs for my games, but if you miss some other features, please let me know and I will add them! You're also very welcome to contribute :)

If you check out the latest master branch, and find out that some stuff is not working as expected, please understand that the project is evolving rapidly and I'm likely just breaking existing stuff to try to improve the overall design. The library does truly help in building actual games, and I successfully developed one published Android game with it. The library helped tremendously, by being entirely Scala-based and by allowing for transparent porting from the Desktop to the Android platform.

How to Write a Game with SGL

SGL is split across several sub-projects so that games built by the framework only pack the necessary dependencies. The organization is to provide a core project, which defines all the APIs, and roughly one backend per platform. A game should then depend on both the core abstraction and the platform on which it will deploys. Cross-platform games can be further split into smaller units, with a cross-platform core logic that will only depends on the core SGL abstractions and various platform-specific implementations. The small snake project demonstrates how you can organize a game to be cross platform. A more advanced example can be found by looking at the sources of Scalavator.

SGL is currently splited into the following sub-projects:

  • coreJVM, coreJS, coreNative (the core abstractions compiled for JVM, scalajs, and scala-native). The core project contains the abstract API for the platform as well as all the features that are platform-agnostic.
  • desktopAWT, depends on coreJVM and provide window and graphics with AWT.
  • desktopNative, depends on coreNative and use scala-native and OpenGL to build a native executable.
  • html5, depends on coreJS and use scala.js to generate a javascript game.
  • coreAndroid and android, for the android platform.
  • jvmShared, some non-core utilities shared by all JVM-based platform.

These projects are defined in the built.sbt file and have their sources in each corresponding subdirectory. Android definitions are in a sub-directory because the Android plugins does not work with the most recent sbt version.

Understanding the Versioning

For a long time, the only way to use SGL was to declare direct source dependencies. That proved relatively unsuccessful and most of the Scala community seems to believe that binary dependencies is the way to go. Since SGL is still an early prototype, I wasn't very keen on publishing a stable version as a binary that people could just depend on through Maven.

Nevertheless, to make SGL easier to use, I will soon start officially releasing on Maven. The first release will be 0.0.1, with the intent to be clear that this is a highly experimental version. Future versions will simply increase the last digit, i.e. 0.0.2 and then 0.0.3. As long as SGL stays in the 0.0 version line, there will be no guarantee on backward compatibility, and each new version could break absolutely everything the previous version introduced. This is all in the name of velocity and innovation, of course. If you do give a chance to SGL 0.0.X, just be aware that there will be bugs, and updates will likely break your code. You must be willing to actively engage with the developers of SGL.

The eventual goal is to reach the 0.1 version line, which at that point will be a more stable release and future updates would hopefully better respect backward compatibility.

At the current time, version 0.0.1 is not yet released on Sonatype. Most of the build config and code is there, but I want to make a few adjustments before publishing. Until then, you can use publishLocal to publish the version locally and use it on your own games.

Roadmap to 0.0.1

I would like to ensure that the artifact for 0.0.1 is good enough to write interesting games without constantly requiring tweaking SGL. Currently, as I'm working on my games, I constantly need to go back and tweak SGL a little bit in order to get something working as I would expect. That tells me that the library is not quite stable enough to reach the highly unstable and experimental version 0.0.1. Of course, 0.0.1 should not be perfect, but we should have a reasonable chance to be able to complete a game without requiring an update to the library. There are a few things that I would like to get done before getting there:

  1. Get a commercial game published. Fish Escape fits the bill here and is already published on iOS and Android. There are still extra features that I want to implement to tweak the games (ads on iOS, analytics on iOS, iAP on both platforms), so these should be implemented and deployed (although maybe iAP can wait for 0.0.2).

This would prove that SGL can get the job done and make a feature-complete game.

  1. Make sure that Desktop, Web, Android, and iOS (through Cordova) have complete support for the core providers. It's ok to be missing some addon providers (ads, analytics, etc) on some of the platforms, but we should at least be able to get a game with the fundamental providers on each of these platforms. We can ship with the experimental native backend, but we need to be clear that this is not supported and is still a PoC.

  2. Provide a basic tutorial.

  3. Provide a demo game. Scalavator is good for that, but it needs updating. This also doubles as another proof that the library can build games.

  4. We probably don't need a website, but we should publish the scaladoc somehow.

  5. Expand the scaladoc. In particular, we should have a starting point in the sgl root package, where we explain the high level design of the library and how to put a game together with the cake. Ideally this would serve as the documentation until we have a proper documentation (like an actual system manual, much more verbose).

  6. Review the core API and make sure most of the obvious mistakes have been fixed. Examples that have already been fixed are using int coordinates in the canvas. Another one that is in the process of being addressed is the weird behavior when loading multi-dpi bitmaps. There are probably many more such stupid mistakes, and I should do a pass to make sure we aren't releasing something that's obviously bad. There will be plenty more design mistakes, and that's fine we can fix them later, but let's at least fix the ones we know today.

Getting Started

You can start with a step-by-step tutorial on writing a game with SGL. The tutorial explains some of the concept of the library.

If you feel ready to start a project from scratch, you can fork the starter project as a mostly blank slate. You can check out the examples projects for how to use some of the features of SGL.

If you want to see how a small, but complete, game looks like, I developed an open-source game with SGL. The game is intended to demonstrate some of the features of the library.

Some Design Principles

  • Games and only games. This is not a general media toolkit. The only things that should be build with this library are games. Yes, there's a feeling like we can do more with this cross-platform style, and that's probably true, but this is better left to other frameworks.

  • Pure and true Scala library. We want to expose a Scala-like library a much as possible. No compromise for compatibility with other languages, everything is done in Scala.

  • Entirely cross-platform, no cheating. The core library should abstract everything and only exposes features that are truly cross-platform. Any platform-specific extensions should be provided in a type-safe way.

  • Generic but pragmatic. We try to remain as generic as possible, in the sense that only features that would be useful for at least two different games would be integrated. However, we want to provide a very effective toolkit, so almost anything that is remotely useful for building games should be made available. Whenever a problem has many alternative implementations, we should try to provide an abstract interface, with each alternative implementation available and let the user select the one they prefer.

  • 2D only. The library does not target 3D games. I believe there are an infinite number of wonderful games that can be build entirely in 2D, and I would rather focus on getting a great library to build 2D games than an average library to do everything.

  • No building magic. Everything is explicitly implemented in Scala. No additional code generator to handle the different platforms. Setting up a deployment platform should be simple enough to be done manually. That said, eventually a good sbt plugin would come in handy, as long as it is a light, and optional, layer on top.

  • Try to be as native as possible. We want to always use the platform native and standard APIs. We should try to map the SGL API as directly as possible to each system API. For example on Android, we want to try to map to the drawable-Xdpi built-in system to handle multiple pixel densities, instead of building a custom asset loading code. By mapping directly into the platform behavior, we get more optimized apps, and can take advantage of future evolution of the system (like app bundles on Android, which requires to use the standard drawable-xdpi layout).

Gallery

SGL has been used so far to produce mobile-friendly games, usually cross-published to Android, iOS, and the web. That said it could be used to make more classic indie titles for Steam, it just hasn't been done yet.

The most ambitious game created with SGL is the cross-platform commercial game Fish Escape, available on:

Additionally, a small number of experimental games have been published with SGL:

If you are using SGL for your commercial game, please contact me and I'll be happy to mention you in this section.

Code Organization

I heavily use the cake pattern as a means to abstract the different backends and to correctly modularize the system. A good article to introduce using the cake pattern for dependencies injection is this one. There is also a great talk that describes how to use the cake pattern, which closely ressembles our usage here.

More recent articles seem to criticise the Cake pattern and many people seem to have drop it. The choice of using the cake pattern was made more than 4 years ago and I still haven't reached the point where I think the drawbacks outweight the benefits.

Developing

In order to run the tests for scala-native, you will need to follow the installation instructions on the Scala Native website if you have not done so already. Additionally, you will need to have development libraries to link against OpenGL, SDL2, and SDL2 Image.