Skip to content
This repository has been archived by the owner on Jul 8, 2022. It is now read-only.

Integrate Fleks ECS into korge + example #472

Merged
merged 28 commits into from
Mar 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
627f45a
Add fleks ECS unchanged
jobe-m Jan 21, 2022
82938eb
Adapt registering of systems in World
jobe-m Jan 24, 2022
4b2437e
Add Injector to IntervalSystem
jobe-m Jan 24, 2022
da21e7c
Integate creation of ComponentMapper objects in systems
jobe-m Jan 24, 2022
a550710
Integrate Family creation
jobe-m Jan 29, 2022
e781ba7
Add singleton for injecting objects into systems
jobe-m Jan 29, 2022
1dba117
Implement adding of component listener in world configuration
jobe-m Jan 31, 2022
8a5a763
Update with latest changes from Fleks project
jobe-m Feb 2, 2022
8034b1d
Add comments and rename cmp to comp
jobe-m Feb 2, 2022
9cda2f6
Add sources for ECS example - wip
jobe-m Feb 4, 2022
af7d9f4
wip
jobe-m Feb 8, 2022
62fc79e
Update working example with enhanced spawner
jobe-m Feb 12, 2022
e81c16c
Implemented spawning of meteorid objects
jobe-m Feb 12, 2022
2ee5235
Implement dependency injection by type names
jobe-m Feb 16, 2022
96f91a0
Add rigidbody and destruct component and update systems
jobe-m Feb 18, 2022
62bd709
Add gravity and impulse to explosions
jobe-m Feb 25, 2022
e729b34
My pixels against Putin
jobe-m Feb 27, 2022
9f9339a
Move Fleks under korge-fleks and update fleks-ecs example code
jobe-m Mar 9, 2022
fd8e169
Convert unit tests of korge-fleks into junit4 style
jobe-m Mar 10, 2022
60fe985
Fix exceptions in unit tests
jobe-m Mar 11, 2022
f84c7ea
Add missing android manifest file
jobe-m Mar 11, 2022
e2d1474
Fix excepton with injection on Kotlin native
jobe-m Mar 13, 2022
19859d9
Fix BitArray equal function and add test cases
jobe-m Mar 14, 2022
353b901
Add support of fleks into korge-gradle-plugin
jobe-m Mar 14, 2022
32216b0
Merge branch 'main' into feature/Integrate_Fleks_ECS_into_Korge
jobe-m Mar 14, 2022
a099ca9
Fix bitArray equals to not throw exception
jobe-m Mar 14, 2022
f6c1349
Remove unused exception in Fleks
jobe-m Mar 14, 2022
1aaa952
Remove exception imports to fix build
jobe-m Mar 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions korge-fleks/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
21 changes: 21 additions & 0 deletions korge-fleks/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2021 Simon Klausner

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
5 changes: 5 additions & 0 deletions korge-fleks/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
description = "Multiplatform Game Engine written in Kotlin"

dependencies {
add("commonMainApi", project(":korio"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package com.github.quillraven.fleks.benchmark

import com.artemis.Component
import com.artemis.ComponentMapper
import com.artemis.World
import com.artemis.WorldConfigurationBuilder
import com.artemis.annotations.All
import com.artemis.annotations.Exclude
import com.artemis.annotations.One
import com.artemis.systems.IteratingSystem
import org.openjdk.jmh.annotations.*
import java.util.concurrent.TimeUnit

data class ArtemisPosition(var x: Float = 0f, var y: Float = 0f) : Component()

data class ArtemisLife(var life: Float = 0f) : Component()

data class ArtemisSprite(var path: String = "", var animationTime: Float = 0f) : Component()

@All(ArtemisPosition::class)
class ArtemisSystemSimple : IteratingSystem() {
private lateinit var mapper: ComponentMapper<ArtemisPosition>

override fun process(entityId: Int) {
mapper[entityId].x++
}
}

@All(ArtemisPosition::class)
@Exclude(ArtemisLife::class)
@One(ArtemisSprite::class)
class ArtemisSystemComplex1 : IteratingSystem() {
private var processCalls = 0
private lateinit var positions: ComponentMapper<ArtemisPosition>
private lateinit var lifes: ComponentMapper<ArtemisLife>
private lateinit var sprites: ComponentMapper<ArtemisSprite>

override fun process(entityId: Int) {
if (processCalls % 2 == 0) {
positions[entityId].x++
lifes.create(entityId)
} else {
positions.remove(entityId)
}
sprites[entityId].animationTime++
++processCalls
}
}

@One(ArtemisPosition::class, ArtemisLife::class, ArtemisSprite::class)
class ArtemisSystemComplex2 : IteratingSystem() {
private lateinit var positions: ComponentMapper<ArtemisPosition>
private lateinit var lifes: ComponentMapper<ArtemisLife>

override fun process(entityId: Int) {
lifes.remove(entityId)
positions.create(entityId)
}
}

@State(Scope.Benchmark)
open class ArtemisStateAddRemove {
lateinit var world: World

@Setup(value = Level.Iteration)
fun setup() {
world = World(WorldConfigurationBuilder().run {
build()
})
}
}

@State(Scope.Benchmark)
open class ArtemisStateSimple {
lateinit var world: World

@Setup(value = Level.Iteration)
fun setup() {
world = World(WorldConfigurationBuilder().run {
with(ArtemisSystemSimple())
build()
})

repeat(NUM_ENTITIES) {
world.createEntity().edit().create(ArtemisPosition::class.java)
}
}
}

@State(Scope.Benchmark)
open class ArtemisStateComplex {
lateinit var world: World

@Setup(value = Level.Iteration)
fun setup() {
world = World(WorldConfigurationBuilder().run {
with(ArtemisSystemComplex1())
with(ArtemisSystemComplex2())
build()
})

repeat(NUM_ENTITIES) {
val entityEdit = world.createEntity().edit()
entityEdit.create(ArtemisPosition::class.java)
entityEdit.create(ArtemisSprite::class.java)
}
}
}

@Fork(1)
@Warmup(iterations = WARMUPS)
@Measurement(iterations = ITERATIONS, time = TIME, timeUnit = TimeUnit.SECONDS)
open class ArtemisBenchmark {
@Benchmark
fun addRemove(state: ArtemisStateAddRemove) {
repeat(NUM_ENTITIES) {
state.world.createEntity().edit().create(ArtemisPosition::class.java)
}
repeat(NUM_ENTITIES) {
state.world.delete(it)
}
}

@Benchmark
fun simple(state: ArtemisStateSimple) {
repeat(WORLD_UPDATES) {
state.world.delta = 1f
state.world.process()
}
}

@Benchmark
fun complex(state: ArtemisStateComplex) {
repeat(WORLD_UPDATES) {
state.world.delta = 1f
state.world.process()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package com.github.quillraven.fleks.benchmark

import com.badlogic.ashley.core.*
import com.badlogic.ashley.systems.IteratingSystem
import org.openjdk.jmh.annotations.*
import java.util.concurrent.TimeUnit

data class AshleyPosition(
var x: Float = 0f,
var y: Float = 0f
) : Component {
companion object {
val MAPPER: ComponentMapper<AshleyPosition> = ComponentMapper.getFor(AshleyPosition::class.java)
}
}

data class AshleyLife(
var life: Float = 0f
) : Component

data class AshleySprite(
var path: String = "",
var animationTime: Float = 0f
) : Component {
companion object {
val MAPPER: ComponentMapper<AshleySprite> = ComponentMapper.getFor(AshleySprite::class.java)
}
}

class AshleySystemSimple : IteratingSystem(Family.all(AshleyPosition::class.java).get()) {
override fun processEntity(entity: Entity?, deltaTime: Float) {
AshleyPosition.MAPPER.get(entity).x++
}
}

class AshleySystemComplex1 : IteratingSystem(
Family
.all(AshleyPosition::class.java)
.exclude(AshleyLife::class.java)
.one(AshleySprite::class.java)
.get()
) {
private var processCalls = 0

override fun processEntity(entity: Entity?, deltaTime: Float) {
if (processCalls % 2 == 0) {
AshleyPosition.MAPPER.get(entity).x++
entity?.add(engine.createComponent(AshleyLife::class.java))
} else {
entity?.remove(AshleyPosition::class.java)
}
AshleySprite.MAPPER.get(entity).animationTime++
++processCalls
}
}

class AshleySystemComplex2 : IteratingSystem(
Family
.one(AshleyPosition::class.java, AshleyLife::class.java, AshleySprite::class.java)
.get()
) {
override fun processEntity(entity: Entity?, deltaTime: Float) {
entity?.remove(AshleyLife::class.java)
entity?.add(engine.createComponent(AshleyPosition::class.java))
}
}

@State(Scope.Benchmark)
open class AshleyStateAddRemove {
lateinit var engine: Engine

@Setup(value = Level.Iteration)
fun setup() {
engine = Engine()
engine.addSystem(AshleySystemSimple())
}
}

@State(Scope.Benchmark)
open class AshleyStateSimple {
lateinit var engine: Engine

@Setup(value = Level.Iteration)
fun setup() {
engine = Engine()
engine.addSystem(AshleySystemSimple())
repeat(NUM_ENTITIES) {
val cmp = engine.createComponent(AshleyPosition::class.java)
val entity = engine.createEntity()
entity.add(cmp)
engine.addEntity(entity)
}
}
}

@State(Scope.Benchmark)
open class AshleyStateComplex {
lateinit var engine: Engine

@Setup(value = Level.Iteration)
fun setup() {
engine = Engine()
engine.addSystem(AshleySystemComplex1())
engine.addSystem(AshleySystemComplex2())
repeat(NUM_ENTITIES) {
val entity = engine.createEntity()
entity.add(engine.createComponent(AshleyPosition::class.java))
entity.add(engine.createComponent(AshleySprite::class.java))
engine.addEntity(entity)
}
}
}

@Fork(1)
@Warmup(iterations = WARMUPS)
@Measurement(iterations = ITERATIONS, time = TIME, timeUnit = TimeUnit.SECONDS)
open class AshleyBenchmark {
@Benchmark
fun addRemove(state: AshleyStateAddRemove) {
repeat(NUM_ENTITIES) {
val cmp = state.engine.createComponent(AshleyPosition::class.java)
val entity = state.engine.createEntity()
entity.add(cmp)
state.engine.addEntity(entity)
}
state.engine.removeAllEntities()
}

@Benchmark
fun simple(state: AshleyStateSimple) {
repeat(WORLD_UPDATES) { state.engine.update(1f) }
}

@Benchmark
fun complex(state: AshleyStateComplex) {
repeat(WORLD_UPDATES) { state.engine.update(1f) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.quillraven.fleks.benchmark

const val NUM_ENTITIES = 10_000
const val WORLD_UPDATES = 1_000
const val WARMUPS = 3
const val ITERATIONS = 3
const val TIME = 3 // in seconds
Loading