Build Snake with Zircon and Kotlin Part 1


This tutorial will show you the basic usage of the OpenSource library Zircon.

Setting up

For this tutorial we will use gradle to build the application. But instead of groovy we will use the kotlin gradle dsl.

mkdir kotlin_zircon
cd kotlin_zircon
gradle init --dsl kotlin 

All Scripts used in this tutorial are tested with PowerShell under Windows 10 but they should work fine in any posix compliant shell too.

At first we open the generated build.gradle.ts. It should be empty and we add the minimal configuration

plugins {
    application
    kotlin("jvm") version "1.2.61"
}

application {
    mainClassName = "main.Main"
}

dependencies {
    compile(kotlin("stdlib"))
}

repositories {
    jcenter()
}

We add the dependency for Zircon using the compile() function:

plugins {
    application
    kotlin("jvm") version "1.2.61"
}

application {
    mainClassName = "main.MainKt"
}

dependencies {
    compile(kotlin("stdlib"))
    compile("org.hexworks.zircon:zircon.jvm.swing:2018.5.0-RELEASE")
}

repositories {
    jcenter()
}

Then we should be able to build our project:

gradle build

To start developing we need the src dirs to place the sourcecode in so we create them:

  mkdir -p src/main/kotlin

Starting up

At first we create the entrypoint in the file main/Main.kt under src/main/kotlin.

package main

import org.hexworks.zircon.api.SwingApplications

fun main(args: Array<String>) {
    SwingApplications.startApplication()
}

And start it with:

gradle run

This starts up the zircon application and shows an empty window.

Draw on the board

Next thing we want to do is do actually display something. Zircon has a tile based rendering engine so we will have a grid to display our game on.

Before we can start painting we have to first extend our SwingApplication method start. We need to create a TileGrid with a specified size.

package main

import org.hexworks.zircon.api.AppConfigs
import org.hexworks.zircon.api.Sizes
import org.hexworks.zircon.api.SwingApplications
import org.hexworks.zircon.api.builder.application.AppConfigBuilder


fun main(args: Array<String>) {

    // 1. Create a new tileGrid with the SwingApplications helper
    val grid = SwingApplications.startTileGrid(

            // 2. Create a tileConfig with the wanted size
            tileConfig {
                withSize(Sizes.create(30, 20))
            }
    )
}

// 3. Create a simple builder function to avoid calling build an get a cleaner syntax
fun tileConfig(lambda: AppConfigBuilder.() -> Unit) =
        AppConfigs.newConfig().apply(lambda).build()

For those who aren’t familiar with the construct in point 3 may have a look at this tutorial Writing DSLs in Kotlin. It helped me a lot to understand these structures.

In short this is a function that takes a lambda as Parameter where in this lambda you have access to a AppConfigBuilder via this (which is omitted here). You can now chain as many calls of AppConfigBuilder as you want and after finishing this lambda, the builder function will take over again call the build() method and returns a valid AppConfig

Next thing we do is to add a new file main/DisplayController.kt to handle all the displaying stuff.

package main

import org.hexworks.zircon.api.Screens
import org.hexworks.zircon.api.Tiles
import org.hexworks.zircon.api.builder.data.TileBuilder
import org.hexworks.zircon.api.color.ANSITileColor
import org.hexworks.zircon.api.data.Position
import org.hexworks.zircon.api.data.Tile
import org.hexworks.zircon.api.grid.TileGrid

class DisplayController(tileGrid: TileGrid) {
    // 1. Start with adding a gameScreen to display all stuff we need to play
    private val gameScreen = Screens.createScreenFor(tileGrid)

    // 2. We cant paint directly on the screen so we have to take the first layer and paint on that
    private val gameLayer = gameScreen.layers.first()

    // 3. Create the tile to display
    private val snakeTile = snakeTile()

    // 4. Start painting 
    fun draw() {
        // 5 Create a tile with the snakeTile() function and display it at position x=2, y=3
        gameLayer.setTileAt(Position.create(2, 3), snakeTile)

        // 6. Flush all contents on the gameScreen onto the real screen (Double Buffering)
        gameScreen.display()
    }

    // 7. Create a snake tile with backgroundColor Green and foreground in White containing the character 'o'
    private fun snakeTile() = tileBuilder {
        withBackgroundColor(ANSITileColor.GREEN)
        withForegroundColor(ANSITileColor.WHITE)
        withCharacter('o')
    }
}

// 8. Create a simple builder function to avoid calling build() each time
fun tileBuilder(lambda: TileBuilder.() -> Unit): Tile {
    return Tiles.newBuilder().apply(lambda).build()
}

At last we have to add this class to our main method:

fun main(args: Array<String>) {

    val grid = SwingApplications.startTileGrid(
            tileConfig {
                withSize(Sizes.create(30, 20))
            }
    )
    
    DisplayController(grid).apply{
      while(true){
        draw()
      }
    }
}

This starts the paint loop, to be able to see it till you quit the application.

Now we just have to call gradle and can see a result:

gradle run

First Draw on Screen

The sources are available on github: zircon_part1

Next tutorial: Part 2