Skip to content

Commit e9f1933

Browse files
committed
#178 one-shot components
1 parent 80d7a24 commit e9f1933

4 files changed

Lines changed: 137 additions & 4 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.github.quillraven.fleks
2+
3+
import com.github.quillraven.fleks.World.Companion.family
4+
5+
/**
6+
* An [IteratingSystem] that automatically removes any [components][Component]
7+
* or [tags][EntityTag] of an [entity][Entity] that are passed as the [types] argument.
8+
*
9+
* This system is only used internally and is called at the end of a [World.update].
10+
*/
11+
class OneShotComponentSystem(
12+
private val types: Array<out UniqueId<*>>,
13+
world: World,
14+
) : IteratingSystem(
15+
family = family { any(*types) },
16+
world = world,
17+
) {
18+
19+
override fun onTickEntity(entity: Entity) {
20+
entity.configure {
21+
types.forEach { componentType ->
22+
entity -= componentType
23+
}
24+
}
25+
}
26+
27+
}

src/commonMain/kotlin/com/github/quillraven/fleks/world.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ class World internal constructor(
9797
@PublishedApi
9898
internal val tagCache = mutableMapOf<Int, UniqueId<*>>()
9999

100+
// optional system that automatically removes components/tags registered in the WorldConfiguration
101+
internal var oneShotComponentSystem: OneShotComponentSystem? = null
102+
100103
init {
101104
/**
102105
* Maybe because of design flaws, the world reference of the ComponentService must be
@@ -408,7 +411,7 @@ class World internal constructor(
408411
this.recycle(entity)
409412
val entitySnapshot = snapshot[versionLookup[it]]
410413
if (entitySnapshot != null) {
411-
// snapshot for entity is provided -> create it
414+
// a snapshot for the entity is provided -> create it
412415
// note that the id for the entity will be the recycled id from above
413416
this.configure(this.create { }, entitySnapshot)
414417
}
@@ -449,6 +452,7 @@ class World internal constructor(
449452
system.onUpdate()
450453
}
451454
}
455+
oneShotComponentSystem?.onUpdate()
452456
}
453457

454458
/**

src/commonMain/kotlin/com/github/quillraven/fleks/worldCfg.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,20 @@ class WorldConfiguration(@PublishedApi internal val world: World) {
154154
world.entityService.entityProvider = world.run(factory)
155155
}
156156

157+
/**
158+
* Registers the given [components][Component]/[tags][EntityTag] as
159+
* one-shot, meaning that they are automatically removed from an [entity][Entity]
160+
* at the end of [World.update].
161+
*/
162+
fun oneShotComponents(vararg types: UniqueId<*>) {
163+
world.oneShotComponentSystem = OneShotComponentSystem(types, world)
164+
}
165+
157166
/**
158167
* Configures the world in the following sequence:
159-
* - injectables
160-
* - family
161-
* - system
168+
* - Injectable
169+
* - Family
170+
* - System
162171
*
163172
* The order is important to correctly trigger [FamilyHook]s and [EntityHook]s.
164173
*/
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package com.github.quillraven.fleks
2+
3+
import kotlin.test.Test
4+
import kotlin.test.assertFalse
5+
import kotlin.test.assertTrue
6+
7+
private class OneShotComp : Component<OneShotComp> {
8+
override fun type() = OneShotComp
9+
10+
companion object : ComponentType<OneShotComp>()
11+
}
12+
13+
private data object OneShotTag : EntityTag()
14+
15+
private class NormalComp : Component<NormalComp> {
16+
override fun type() = NormalComp
17+
18+
companion object : ComponentType<NormalComp>()
19+
}
20+
21+
internal class OneShotComponentSystemTest {
22+
@Test
23+
fun oneShotComponentShouldGetRemovedAfterOnUpdate() {
24+
val world = configureWorld {
25+
oneShotComponents(OneShotComp)
26+
}
27+
val entity = world.entity { it += OneShotComp() }
28+
29+
with(world) {
30+
assertTrue { entity has OneShotComp }
31+
32+
world.update(0f)
33+
34+
assertFalse { entity has OneShotComp }
35+
}
36+
}
37+
38+
@Test
39+
fun oneShotTagShouldGetRemovedAfterOnUpdate() {
40+
val world = configureWorld {
41+
oneShotComponents(OneShotTag)
42+
}
43+
val entity = world.entity { it += OneShotTag }
44+
45+
with(world) {
46+
assertTrue { entity has OneShotTag }
47+
48+
world.update(0f)
49+
50+
assertFalse { entity has OneShotTag }
51+
}
52+
}
53+
54+
@Test
55+
fun normalComponentShouldNotGetRemovedAfterOnUpdate() {
56+
val world = configureWorld {
57+
oneShotComponents(OneShotComp)
58+
}
59+
val entity = world.entity { it += NormalComp() }
60+
61+
with(world) {
62+
assertTrue { entity has NormalComp }
63+
64+
world.update(0f)
65+
66+
assertTrue { entity has NormalComp }
67+
}
68+
}
69+
70+
@Test
71+
fun listOfOneShotsShouldGetRemovedAfterOnUpdate() {
72+
val world = configureWorld {
73+
oneShotComponents(OneShotComp, OneShotTag)
74+
}
75+
val entity = world.entity {
76+
it += NormalComp()
77+
it += OneShotComp()
78+
it += OneShotTag
79+
}
80+
81+
with(world) {
82+
assertTrue { entity has NormalComp }
83+
assertTrue { entity has OneShotComp }
84+
assertTrue { entity has OneShotTag }
85+
86+
world.update(0f)
87+
88+
assertTrue { entity has NormalComp }
89+
assertFalse { entity has OneShotComp }
90+
assertFalse { entity has OneShotTag }
91+
}
92+
}
93+
}

0 commit comments

Comments
 (0)