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
Win
Mac
Linux
JS
Browser
Native
Android
IOS
K
or
G
E
JVM
Win
Mac
Linux
JS
Browser
Win
Mac
Linux
Native
Android
IOS
Common
Code
Kotlin
Compiler
LLVM IR
Kotlin Multiplatform
K
or
G
E
Kotlin Multiplatform
JVM
Win
Mac
Linux
JS
Browser
Win
Mac
Linux
Native
Android
IOS
KorGE
Libs
Common
Code
Kotlin
Compiler
LLVM IR
K
or
G
E
Kotlin Multiplatform
JVM
Win
Mac
Linux
JS
Browser
Win
Mac
Linux
Native
Android
IOS
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
runAndroidRelease
runJs
runJvm
runNativeRelease
Native
Android
Native
IOS
Win
Mac
Linux
Native
JVM
Win
Mac
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
- Tiled (Level Editor)
- Spine (Paid, Character Animation)
- Free Sprite Sheet Packer (Web App)
- Texture Packer (Paid)
- Hiero (Bitmap Font Editor)
-
KorGE IDE Plugin
- Visual Editor
- Particle Editor
- Level Editor
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
ITscope - Carrer Contacts
By Tobse Fritz
ITscope - Carrer Contacts
Spieleprogrammierung mit KorGE - Der Kotlin Multiplatform Game Engine
- 707