Wer, Wie, Was?

Spieleprogrammierung in Kotlin

Tobse Fritz

ITscope GmbH

Java Entwickler

Kotlin Fanboy

Hobby Fotograf

Gaming Nerd

3D Printer

Daddy

Mit ITscope vereinfachen Systemhäuser
Ihre Verkaufsprozesse & IT Beschaffung

WO

WO

WO

WO

2003

Gründung

62

Mitarbeiter

7.800

Aktive Nutzer

420+

Distributoren

3 Mio

Produkte

Fakten

Tech Stack

Spieleprogrammierung in Kotlin

My Games

Hospital

Kathis Kleiner Sattelit

My Games

Swing Plus Remake

My Games

Hit Klack Remake

My Games

My Games

Candy Crush Clone

Magic Maze Online Multiplayer

My Games

K

or

G

E

K

or

otlin

G

E

K

or

otlin

C

outines

G

E

K

or

otlin

C

outines

G

E

ame

ngine

K

or

G

E

Kotlin Multiplatform

JVM

image/svg+xml
image/svg+xml

Win

Mac

image/svg+xml
image/svg+xml

Linux

JS

Browser

Native

image/svg+xml

Android

IOS

image/svg+xml

K

or

G

E

JVM

image/svg+xml
image/svg+xml

Win

Mac

image/svg+xml
image/svg+xml

Linux

JS

Browser

image/svg+xml

Win

Mac

image/svg+xml

Linux

image/svg+xml

Native

image/svg+xml

Android

IOS

image/svg+xml

Common
Code

Kotlin
Compiler

LLVM IR

Kotlin Multiplatform

K

or

G

E

Kotlin Multiplatform

JVM

image/svg+xml
image/svg+xml

Win

Mac

image/svg+xml
image/svg+xml

Linux

JS

Browser

image/svg+xml

Win

Mac

image/svg+xml

Linux

image/svg+xml

Native

image/svg+xml

Android

IOS

image/svg+xml

KorGE
Libs

Common
Code

Kotlin
Compiler

LLVM IR

K

or

G

E

Kotlin Multiplatform

JVM

image/svg+xml
image/svg+xml

Win

Mac

image/svg+xml
image/svg+xml

Linux

JS

Browser

image/svg+xml

Win

Mac

image/svg+xml

Linux

image/svg+xml

Native

image/svg+xml

Android

IOS

image/svg+xml

KorGE
Libs

Common
Code

expect
expect fun play(file: Sound)
actual
actual
actual
actual
actual

K

or

G

E

.org

K

or

G

E

  • 2D Game Engine
  • Open Source
  • Native Multiplatform
  • Live Debugging
  • IDE Integration
  • Visual editor
  • 100 % Kotlin

⭐Features

Kotlin

Spiele... warum in

Kotlin

  • Prägnant
  • Sicher
  • Interoperabel
  • Optimales Tooling
  • Frei & OpenSource

Features

Kotlin

public class Person {

    private final String firstName;
    private final String lastName;
    private final LocalDate birthDay;

    public Person(String firstName, String lastName, 
                  LocalDate birthDay) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.birthDay = birthDay;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public LocalDate getBirthDay() {
        return birthDay;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return Objects.equals(firstName, person.firstName) &&
                Objects.equals(lastName, person.lastName) &&
                Objects.equals(birthDay, person.birthDay);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstName, lastName, birthDay);
    }

    @Override
    public String toString() {
        return "Person{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", birthDay=" + birthDay +
                '}';
    }
}
data class PersonK(
    val firstName: String,
    val lastName: String,
    val birthDay: LocalDate
)

Java

Kotlin

Prägnanz

Kotlin

public class RectangleJava {

    private int x = 0;
    private int y = 0;
    private int width = 0;
    private int height = 0;

    public boolean contains(int x, int y) {
        var inWidth = (x >= this.x) && (x <= this.x + width);
        var inHeight = (y >= this.y) && (y <= this.y + height);
        return inWidth && inHeight;
    }

}

Java

Kotlin

public class RectangleKotlin {

    private val x = 0;
    private val y = 0;
    private val width = 0;
    private val height = 0;

    public fun contains(x: Int, y: Int): Boolean {
        val inWidth = (x >= this.x) && (x <= this.x + width);
        val inHeight = (y >= this.y) && (y <= this.y + height);
        return inWidth && inHeight;
    }

}

Kotlin

public fun
public
private fun
new
;

Kotlin

class RectangleKotlinNice {

    private val x = 0
    private val y = 0
    private val width = 0
    private val height = 0

    fun contains(x: Int, y: Int): Boolean {
        val inWidth = x in (x .. this.x + width)
        val inHeight = y in (y .. this.y + height)
        return inWidth && inHeight
    }

}

Kotlin

Kotlin

  • Prägnant
  • Sicher
  • Interoperabel
  • Optimales Tooling
  • Frei & OpenSource

Features

Kotlin

Prägnant

Sicher

Interoperabel

Optimales Tooling

Frei & OpenSource

Inline Classes

Extensions

Contracts

Operator Overloading

Gradle DSL

Data Classes

Coroutines

KorGE

The Tree Game

KorGE

The Tree Game
The Tree Game

Lesson learned

image(backgroundBitmap){
    size(gameWidth, gameHeight)
}
image(treeBitmap).centerOnStage()
Image(appleBitmap).addTo(this)
container {
  name = "Happy Sun"
  circle(radius = 50.0, fill = YELLOW)
  circle(radius = 8.0, fill = BLACK).position(60, 20)
  circle(radius = 8.0, fill = BLACK).position(24, 20)
  circle(radius = 10.0, fill = RED).position(50, 60)
  position(50, 50)
}
The Tree Game
private suspend fun hit() {
  tween(this::y[gameHeight], 
        time = 1.seconds, easing = EASE_IN)
  tween(this::rotation[Random[-40, 40].degrees], 
        time = 100.milliseconds, easing = EASE_IN)
}
EASE_IN_ELASTIC
EASE_OUT_ELASTIC
EASE_OUT_BOUNCE
LINEAR
EASE_IN
EASE_OUT
EASE_IN_OUT
EASE_OUT_IN
EASE_IN_BACK
EASE_OUT_BACK
EASE_IN_OUT_BACK
EASE_OUT_IN_BACK
EASE_IN_OUT_ELASTIC
EASE_OUT_IN_ELASTIC
EASE_IN_BOUNCE
EASE_IN_OUT_BOUNCE
EASE_OUT_IN_BOUNCE
EASE_IN_QUAD
EASE_OUT_QUAD
EASE_IN_OUT_QUAD

Lesson learned

The Tree Game
val bus = GlobalBus()

class GameOverEvent()

private fun eatApple() {
  if (apples == 0) {
    bus.send(GameOverEvent())
  }
}

bus.register<GameOverEvent> {
  text("Game Over", textSize = 64.0).centerOnStage()
}
private suspend fun hit() {
  tween(this::y[gameHeight], 
        time = 1.seconds, easing = EASE_IN)
  tween(this::rotation[Random[-40, 40].degrees], 
        time = 100.milliseconds, easing = EASE_IN)
}

Game Over

Lesson learned

The Tree Game
class Bird(...){
	
  init {
    onClick {
      hit()
    }
}
class Bird(...){
	
  init {
    onCollision(filter = { it is Image}) {
      if (it.name == "apple") {
        it.removeFromParent()
        eatApple()
      }
    }
  }
}

Lesson learned

resourcesVfs["bird.mp3"].readSound().play()
The Tree Game

JS

Browser

Gradle icon

runAndroidRelease 

runJs 

runJvm 

runNativeRelease 

Native

image/svg+xml

Android

Native

IOS

image/svg+xml
image/svg+xml

Win

Mac

image/svg+xml

Linux

image/svg+xml

Native

JVM

image/svg+xml
image/svg+xml

Win

Mac

image/svg+xml
image/svg+xml

Linux

Tasks > run

iosRunSimulatorDebug

Lesson learned

The Tree Game

Coming soon

🆕
Jetzt mit  Hörnchen! 

The Tree Game
gamepad.down(0, GameButton.LEFT) {
  x -= 40
}
gamepad.down(0, GameButton.RIGHT) {
  x += 40
}
gamepad.down(0, GameButton.BUTTON0) {
  shoot()
}
keys {
  down {
    if (it.key == Key.LEFT) {
      x -= 20
    }
    if (it.key == Key.RIGHT) {
      x += 20
    }
    if (it.key == Key.SPACE) {
      shoot()
    }
  }
}

Coming soon

Box2D

solidRect(50, 50, Colors.RED)
solidRect(50, 50, Colors.RED)
solidRect(50, 50, Colors.RED)
solidRect(600, 100, Colors.WHITE)

Box2D

solidRect(50, 50, Colors.RED)
    .registerBodyWithFixture(type = BodyType.DYNAMIC, density = 2, friction = 0.01)
solidRect(50, 50, Colors.RED)
    .registerBodyWithFixture(type = BodyType.DYNAMIC)
solidRect(50, 50, Colors.RED)
    .registerBodyWithFixture(type = BodyType.DYNAMIC)
solidRect(600, 100, Colors.WHITE)
    .registerBodyWithFixture(
	    type = BodyType.STATIC,
	    friction = 0.2
)

Box2D

solidRect(50, 50, Colors.RED)
    .registerBodyWithFixture(type = BodyType.DYNAMIC, density = 2, friction = 0.01)
solidRect(50, 50, Colors.RED)
    .registerBodyWithFixture(type = BodyType.DYNAMIC)
solidRect(50, 50, Colors.RED)
    .registerBodyWithFixture(type = BodyType.DYNAMIC)
solidRect(600, 100, Colors.WHITE)
    .registerBodyWithFixture(
	    type = BodyType.STATIC,
	    friction = 0.2
)

onClick {
	val pos = it.currentPosLocal
	solidRect(50, 50, Colors.RED).position(pos.x, pos.y).rotation(randomAngle())
		.registerBodyWithFixture(type = BodyType.DYNAMIC)
}

fun randomAngle(): Angle = Random.nextInt(0, 90).degrees

Box2D

Kor

UI

val container = fixedSizeContainer(width, height)
container.korui {
  vertical {
    layoutChildrenPadding = 2
    horizontal {
      preferredWidth = 100.percent
      button("HELLO", {
        preferredWidth = 70.percent
      })
      button("WORLD", {
        preferredWidth = 30.percent
        preferredHeight = 32.pt
      })
    }
    button("TEST")
    checkBox("CheckBox", checked = true)
    comboBox("test", listOf("test", "demo"))
  }

}

DSL

Kor

UI

Absolute Positionierung 

uiButton(256.0, 32.0) {
  text = "Disabled Button"
  position(128, 128)
}
val emitter = resourcesVfs["particle2.pex"].readParticleEmitter()
particleEmitter(emitter)

Particles

Particles

Hiero

Axiom Verge

Brigador

2016

2015

Edit Worlds

Performance

10K

Performance

10K

1Mio

100K

need
more?

Performance

https://store.steampowered.com/app/379720/DOOM/

  • 😁Weil es Spaß macht
  • 💡 Programmier-Skills verbessern
  • 🔭Neues ausprobieren
  • 👨‍👦Für Entwicklung begeistern
  • 😊Wertschätzung für eigene Arbeit
  • 🤝Zusammenarbeit im Team
  • 👾Kleine abgeschlossene Projekte

Warum ein Spiel programmieren?

https://produktivkeller.com/game-jams
29 - 31 Oktober 2021

https://globalgamejam.org
28 - 30 Januar 2022

28 000 creators
104 Countries
6 000 Games 

Warum ein Spiel programmieren?

Warum ein Spiel programmieren?

Jetzt bist Du dran!

https://globalgamejam.org/news/poster-showcase-2018-0

git clone https://github.com/korlibs/korge-hello-world

Tools

Werde Teil der ITscope Familie

Werde Teil der ITscope Familie

Java Backend Developer (m/w/d)
Festanstellung, Vollzeit

Informatikstudenten (m/w/d)
Werkstudent, Teilzeit

Werkstudent (m/w/d) im Marketing
Werkstudent, Teilzeit

Werde Teil der ITscope Familie