Wednesday, March 23, 2016

Look, Ma, No Framework! (my first Kotlin project)

I like the way that an entity component system (ecs) organizes my code. But I don't always want to use a big framework. Functional languages such as Kotlin can give me much of the benefits of ecs without the overhead.

Let's start with components:

data class Bounds(val radius: Float)
data class Expires(val value: Float)
data class Health(val current: Int, val maximum: Int)
data class Position(val x: Float, val y: Float)
data class Resource(val path: String)
data class Scale(val x: Float, val y:Float)
data class Size(val w: Float, val h:Float)
data class Sprite(val texture: TextureRegion)
data class Tween(val min:Float, val max:Float, val speed:Float, val repeat:Boolean, val active:Boolean)
data class Velocity(val x: Float, val y: Float)

That's it. TextureRegion is defined in LibGDX, and I defined a couple of enums - EntityType and SpriteLayer (https://github.com/darkoverlordofdata/shmupwarz-libgdx-kotlin) so that we can define our entity:




data class Entity(
    val id:         Int,           /* Unique id */
    val name:       String,        /* Display name */
    val active:     Boolean,       /* In use? */
    val entityType: EntityType,    /* EntityType Enum */
    val layer:      SpriteLayer,   /* Display Layer Enum 
         /* C O M P O N E N T S * */
    val bounds:     Bounds?,       /* Radius */
    val expires:    Expires?,      /* Entity expiration timer */
    val health:     Health?,       /* Health counter */
    val position:   Position?,     /* Screen x,y */
    val resource:   Resource?,     /* Sprite asset */
    val scale:      Scale?,        /* Size scale */
    val size:       Size?,         /* Display size */
    val sprite:     Sprite?,       /* Texture */
    val tween:      Tween?,        /* Tweener */
    val velocity:   Velocity?    /* Speed x,y */
)
var uniqueId: Int = 0

fun createEntity(entityType: EntityType, layer : SpriteLayer, name : String):Entity {
    uniqueId += 1
    return Entity(uniqueId, name, false, entityType, layer, null, null, null, null, null, null, null, null, null, null)
}



Components are initialized to null. I use a factory functions to create a full entities, such as Player:


fun createPlayer(entity:Entity, width: Int, height: Int):Entity {
    val name = entity.name
    val path = "images/$name.png"
    return entity.copy(
        active    = true,
        bounds    = Bounds(43.0f),
        health    = Health(100, 100),
        resource  = Resource(path),
        position  = Position(width.toFloat()/2.0f, 100.0f),
        sprite    = Sprite(TextureRegion(Texture(Gdx.files.internal(path)))),
        velocity  = Velocity(0.0f, 0.0f)
    )
}


Systems use pattern matching to determine which entities they act upon.


fun movementSystem(entity: Entity, delta: Float): Entity =
    when {
        (entity.position != null
        && entity.velocity != null) -> {

            val position = entity.position
            val velocity = entity.velocity
            val x = position.x + velocity.x * delta
            val y = position.y + velocity.y * delta
            entity.copy(position = Position(x, y))
        }
        else -> entity
    }


From a functional viewpoint, Kotlin's implementation of pattern matching seems a bit lame. Better destucturing would help. I should be able to say:

val (position, velocity) = entity

But I can't do that either, Kotlin doesn't support adhoc destructuring. Instead I would need to use

val (id, name, active, entityType, layer, bounds, expires, health, position, resource, scale, size, sprite, tween, velocity) = entity

Who thought that was a good idea? You can see why I'm not using it. Oh well. The thing to remember is that pattern matching does work. I think that compared to all of the good features of Kotlin, this is something I can live with, and hope that JetBrains will improve it - after all, this is only version 1.0.1!

Those are the pieces. How do they fit together? There is a joke-
Q How many Haskell programmers does it take to change a lightbulb
A None. They build a new house around the new lightbulb.

Well, that's what we're going to do, only in Kotlin. Notice that all of the fields of our components and entities are immutable (val). We cannot change them, only create new ones. Notice in the movement system, where the function returns the original entity or with entity.copy(position=Position(x,y)).

First, we create an array of all our entities, active or not:

fun createLevel(): List = arrayListOf(
    createEntity(EntityType.Enemy, SpriteLayer.ENEMY1, "enemy1"),
    ...
    createEntity(EntityType.Bullet, SpriteLayer.BULLET, "bullet"),
    createEntity(EntityType.Bullet, SpriteLayer.BULLET, "bullet"),
    createEntity(EntityType.Bullet, SpriteLayer.BULLET, "bullet"),
    ...
    createEntity(EntityType.Player, SpriteLayer.PLAYER, "fighter"),
    createEntity(EntityType.Explosion, SpriteLayer.EXPLOSION, "explosion"),
    ...
    )


Then our main update loop will create a pipeline out of our systems. This is where it all happens. Once each frame, we recalculate our game state, and then display it:


fun update(delta: Float, mainBatch: SpriteBatch) {
    level = collisionSystem(
        enemySpawningSystem(level, delta)
            .map {inputSystem(it, delta) }
            .map {entitySystem(it, delta) }
            .map {movementSystem(it, delta) }
            .map {tweenSystem(it, delta) }
            .map {expiringSystem(it, delta) }
            .map {removeOffscreenSystem(it, delta) }, delta)

    level.filter { it.active }
        .sortedBy { it.layer }
        .map {spriteRenderSystem(it, mainBatch)}

}


You might be tempted to just add your active entities as needed and remove them when you are done. I tried that. After about a minute, the game will grind to a halt due to memory fragmentation.

I've uploaded the full working project in AndroidStudio to github. It should run on both desktop and android. I generated the ios version also, but I am unable to test it. 

Friday, March 18, 2016

Kotlin and FSharp and Scala! Ocaml!

After re-writing ShmupWars using idiomatic FSharp, I had my ML epiphany. Immutable is good. But FSharp syntax seems a bit rough, and it's hard to be original in Unity, so I'd like to find an alternative. Another strong cross platform game environment is LibGDX, and the jvm has functional languages. But I have limited experience using the jvm, and find the whole java ecosystem intimidating and confusing.

So, first up Scala 2.9. Scala is easy to install, and there is a template for LibGDX, it's all here: http://raintomorrow.cc/post/70000607238/develop-games-in-scala-with-libgdx-getting

Both Scala and FSharp were influenced by OCAML. I can do just about the same things in Scala as in FSharp, but with a cleaner syntax. Moving from FSharp to Scala is straightforward, and in about 3 days I had a working example of ShmupWars. I found that sbt, the Scala Build Tool, does a good job of hiding the jvm from me, and I appreciate that. There are Atom plugins for both Scala and SBT, so I can avoid using a big bloated java ide. SBT also allows quick iterative compiles. I like to test continually while I code, and SBT keeps up with me.

Second, Kotlin 1.0.0. Speaking of big bloated java ide's, Kotlin installs with IntelliJ Community Edition 15. I used Obviam's template http://obviam.net/index.php/libgdx-and-kotlin/ to get started. I couldn't get it to compile from the ide. LibGDX includes command line build scripts, so I installed the kotlinc command line compiler.  IntelliJ keeps trying to reconfigure kotlin, and when it succeeds, the compile script is then broken. So, I'm using Atom with the kotlin-language plugin. Compile iteration is slow. I probably don't fit Kotlin's demographic. They are targeting existing java progamers who would know the secret to fix this snafu. Did I mention that I hate java?

Some Kotlin features I ran into:
* Destructured assignment won't compile unless I list all properties. That's not very convenient if I want just 2 out of 11 properties.
* Pattern matching is 2nd class. No tuples, no destructuring. It's like the Visual Basic Select statement.
* Rather than use an Option wrapper, fields are marked as nullable, and then must checked for null before each use.
* No native immutable linked list.

In the end, Scala is a more mature ML language. Coverting ML idiom from FSharp to Scala was like falling off a log. I was almost disappointed; I thought this would be more of a challenge. I'm sure I just haven't gotten to that part yet.

Kotlin, however does not have first class support for ML idiom. Nor does it promise to - Kotlin has it's own idiom. My original FSharp version uses OOP idiom, would that be a better candidate for Kotlin? I'll give it a try.



Friday, March 11, 2016

Just Say No To Microsoft

I never thought I'd hear myself say that. After all, as some of you know, I worked there for almost 20 years. But they've crossed the line.

Today, I woke up, and my Windows7 machine had upgraded to Windows10. No warnings. No permission. It just did it. And yes, my files are still there, but none of my dev tools work. While I love Linux, I've always tried to make sure my projects work on Microsoft products as well. No more - Microsoft has seen to that. No CygWin, no Babun, no MinGW. Even stuff made for Microsoft - Unity3d, Cocos2D - none of it is working after the upgrade to Windows 10.

It would be different, if I has initiated the upgrade. If I had been prepared. If I had reserved the time to deal with it. This isn't about Open Source vs Closed Source. This is about customer service, and Microsoft obviously doesn't give 2 scraps about their customers needs and wants.

I have a solution. Already had it. I'm selecting a new distro now - I've been meaning to try Fedora. Now is the time. No dual boot needed. There is nothing I need Microsoft for.

I think the next computer I purchase will probably be an OS/X machine.  Thank you Microsoft, for kicking me out of your nest - I can learn to fly without you!

Tuesday, March 8, 2016

A Functional ECS

I recently changed my distro from Mint Cinnamon to ElementaryOS. My research had reached the conclusion that the issues I was having with Unity3D were due to old kernal. I'm happy to report that it's a success - I can now access the Unity Store. And with the latest 5.3.3 version, some breaking changes have been resolved. All of this allows me to get back to FSharp.

And so, I've finished up my very basic port of Entitas to FSharp. While converting the demo game, ShmupWarz, I started wondering if my systems could just be functions. And why not use FSharp's built in pattern matching instead of calling a Match api? Could I juse express my ECS directly in FSharp?

So, for example, I could write the movement system like this:

let MovementSystem (delta:float32) entity =

    match entity.Velocity, entity.Position with

    | Some(velocity), Some(position) ->
        let x = position.X + velocity.X * delta
        let y = position.Y + velocity.Y * delta
        { entity with Position = Vector2(float32 x, float32 y)}

    | _ -> entity

Where the oop version looks like this:

type MovementSystem(world:World) =

    let group = world.GetGroup(Matcher.AllOf(Matcher.Position, Matcher.Velocity))

    interface IExecuteSystem with
        member this.Execute() =

            let delta = Time.deltaTime/100.0f

            for e in (group.GetEntities()) do
                e.position.x <- e.position.x + (e.velocity.x * delta)
                e.position.y <- e.position.y + (e.velocity.y * delta)
                e.position.z <- e.position.z + (e.velocity.z * delta)



While reading this post https://bruinbrown.wordpress.com/2013/10/06/making-a-platformer-in-f-with-monogame/ I noticed that the author was using a pattern very similar to en ECS. So I played with it a bit, tweaked the naming convention, and got it working.

I went ahead and created a full game for a poc. You can see it at https://github.com/darkoverlordofdata/mono-fsharp-shmupwarz

Performance seems just as good, although I'm comparing MonoGame to Unity3D. So my next step is to try to integrate this technique with Unity.