Kotlin ja JavaFX – ihanaa!

Aloin kesäloman ratoksi perehtymään hiukan Kotlin ohjelmointikieleen – kirjailin siitä jo ensivaikutelmia aiempaan blogiini. Koska en näillä näkymin pääse hetikohta käyttelemään Kotlinia työprojekteissa, päätin harrastella sillä jotain muuta ominpäin.

JavaFX on entuudestaan suuri rakkaus – harmillisen vähän käytettyä tekniikkaa sekin, mutta toimivaa. Ajattelin yhdistellä näitä ja katsoa mitä siitä syntyy, voi olla että peli vielä jossain vaiheessa. Peliohjelmointi ei ole oma vahva lajini – mutta huonommankin pelin koodailusta tulee opittua paljon. 😉

No niin, joka tapauksessa, kaikki alkaa hello worldistä. Eli miltä näyttää Kotlinilla tehty pääohjelma joka käynnistää JavaFX ikkunan?

import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.layout.Pane
import javafx.stage.Stage

class Test : Application() {

  override fun start(stage: Stage) {
    var pane = Pane()
    var scene = Scene(pane, 200.0, 200.0)
    stage.scene = scene
    stage.show()
  }

  companion object {
    @JvmStatic
    fun main(args: Array<String>) {
      launch(Test::class.java)
    }
  }

}

Mitä juuri tapahtui? 😉 Kotlinissa on tosiaan vähän yksinkertaistettu syntaksi Javaan verrattuna. Kuten kuvasta näkyy, muutama modifieri puuttuu, tyyppejä ei tarvitse toistaa, vaan ne päätellään fiksusti tarvittaessa. Funktiot määritetään fun avainsanalla. Ehkä kiintoisin osa tässä on Scalasta tuttu Companion Object. Static avainsanaa kun ei Kotlinissa ole, Companion Object on luokan ’automaattinen instanssi’. Tämän lisäksi tietysti ilmeistä, että Kotlinista käsin voi käyttää kaikkia Java kirjastoja, mukaanlukien Java 8 sisältämä JavaFX.

Miten tuon sitten voi kääntää, paketoida, ajaa? Mavenin voi opettaa prosessoimaan Kotlinia. Oma pom.xml sisältää seuraavia osia:

<dependencies>
  <dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-stdlib</artifactId>
    <version>${kotlin.version}</version>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>${junit.version}</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-test-junit</artifactId>
    <version>${kotlin.version}</version>
    <scope>test</scope>
  </dependency>
</dependencies>

Ylempänä on tietysti määritetty property-muuttujat kotlin.version ja junit.version (1.0.3 ja 4.12 tällä hetkellä). Kotlin käännöksiä varten tarvitaan tietysti kotlin-stdlib riippuvuus. Ilman etukäteen kirjoitettuja yksikkötestejä ei voi ihminen elää, joten siksi junit riippuvuus. Ja lopuksi vielä kotlin-test-junit riippuvuus tuomaan vähän lisämukavuutta liitokseen. Seuraavaksi veivataan build prosessi käsittelemään kotlin-koodit src/main/kotlin, ja src/test/kotlin kansioiden alta:

<build>
  <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
  <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>

  <plugins>
    <plugin>
    <artifactId>kotlin-maven-plugin</artifactId>
    <groupId>org.jetbrains.kotlin</groupId>
    <version>${kotlin.version}</version>
    <configuration/>
      <executions>
        <execution>
          <id>compile</id>
          <phase>compile</phase>
          <goals>
            <goal>compile</goal>
          </goals>
       </execution>
       <execution>
         <id>test-compile</id>
         <phase>test-compile</phase>
         <goals>
           <goal>test-compile</goal>
         </goals>
       </execution>
     </executions>
    </plugin>
  </plugins>
</build>

Jep, ja näin Maven kääntää Kotlin-koodit pluginin avulla bytecodeksi, tavanomaiseen paikkaan, normaaleissa Maven vaiheissa. Lopuksi säädetään vähän paketointia.

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>game.Pong</mainClass>
      </manifest>
    </archive>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Eli, tämä Maven Assembly plugin tekee lopputuotoksesta mega-jar paketin, jossa on kaikki tarvittava. Oman maun mukaan voi tehdä fiksumman käyttäen manifest riippuvuuksia, tai Java 9 moduuleita, mutta tässä kohtaa tämä on ihan bueno, ja helpottaa levitystä ja testausta.

Vein koodia vähän pidemmällekin, otin käyttöön game loopin, animaatiota, piirtoa, mutta puidaa niitä toisella kertaa. Pistin koodit Git repositoryyn, josta löytyy välivaiheita. Nykyinen koodi ei tee vielä paljoa, mutta on hauska tutkimuspöytä sille mitä JavaFX on nykymuodossaan, ja miten Kotlin helpottaa koodin kirjoittelua.

Linkki Gittiin: https://github.com/crystoll/kotlinfx