-
Notifications
You must be signed in to change notification settings - Fork 1
Poolable Components
KorGE-Fleks is using a slightly expanded version of Fleks Components. Components need to be poolable to avoid garbage collection and cloneable for the SnapshotSerializerSystem (rewind/forward snapshot and save-game (de-)serialization). Thus, KorGE-Fleks Components are derived from PoolableComponent<T>.
All provided components in KorGE-Fleks contain only basic property types like:
- String
- Number (Int, Float, Double)
- Enum class (like Easing from KorGE)
- Entity (static data class)
- Collections of above types in MutableLists and MutableMaps are also supported
For simplicity all properties are independent of any KorGE-specific complex classes. Components do not contain any KorGE-related complex objects like Views, Image, Camera, etc.
Also basic types from KorGE were taken over like the Easing enum class for the TweenAnimationSystem.
Poolable Components can override the following functions:
- initComponent
- cleanupComponent
- initPrefabs
- cleanupPrefabs
initComponent and cleanupComponent functions are called when the component was added or removed from an entity. This is transparent when the rewind/forward snapshot feature is used. Snapshots are full copies of a world configuration and contain already initialized components. Thus, both functions are not invoked when rewinding or forwarding the game state. I.e. when snapshots are loaded into a fleks world.
In most cases at least the cleanupComponent function has to be implemented in order to reset all property values to initial state for reusing the component after it was put back into the component pool.
initPrefabs and cleanupPrefabs are meant to initialize and cleanup external prefabs which a component/entity needs. Therefore these functions are called when components get added and removed to entities. But also they are called when rewinding or forwarding the game state after restoring a snapshot.
All four functions will be automatically called by KorGe-Fleks as part of component life cycle.
The functions are called in this order:
initComponentinitPrefabs
cleanupPrefabscleanupComponent
cleanupPrefabsinitPrefabs
initPrefabs
Two additional functions init(from) and cleanup needs to be used when a component class is not used as Fleks component. Thus, both functions are not called as part of component life cycle.
They are ment to manually initialize and cleanup a "component" object which is set as a property of another component. This is called Poolable Data below.
There are some rules that needs to be followed when writing or extending Components for KorGE-Fleks:
- Add only primitive types and mutable collections of primitive types
- Add primitive types as
var, so they can be reset by the cleanupComponent function before being reused through the pooling mechanism - Add only mutable types of collections and as
val, they should be cleared in cleanupComponent function - Own data classes (see Poolable Data below) which are used as properties needs to implement
Poolable<T>interface, too
By following these rules all components will be easily serializable and poolable in KorGE-Fleks.
Poolable (data) classes are not directly used as components but as properties of components.
For a consistent way of setting up Pools for poolable (data) classes they are also derived from Poolable<T> interface.
Make sure to call init(from) function from Poolable Data in the clone function of your components.
Call either cleanup or free functions in the cleanupComponent of the components. The cleanup function should be used when the data class is added as value property of a component. The free function has to be used to return a data object to the pool when the component is going to be recycled (put back into its pool, too). Those data objects which needs to be freed are mostly used in lists or maps of components.
For saving some time to write Component classes and also to make that process less error prone it is possible to use live templates in Intellij IDEA. Just open in Intellij Settings -> Live Templates. In the list choose Kotlin and press the + button at the top of the list box. Fill in below mentioned fields:
- Abbreviation:
flekscomponent - Description:
Creates a new Component class for an entity in Korge-fleks - Edit Variables...: Add Expression
decapitalize(FLEKS_COMPONENT)to variableLOWER_FLEKS_COMPONENT - Template text:
import com.github.quillraven.fleks.*
import korlibs.korge.fleks.utils.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* This component is used to ...
*
* Author's hint: When adding new properties to the component, make sure to reset them in the
* [cleanup] function and initialize them in the [init] function.
*/
@Serializable @SerialName("$FLEKS_COMPONENT$")
class $FLEKS_COMPONENT$ private constructor(
var answer: Int = 42
) : PoolableComponent<$FLEKS_COMPONENT$>() {
// Init an existing component data instance with data from another component
// This is used for component instances when they are a value property of another component
fun init(from: $FLEKS_COMPONENT$) {
answer = from.answer
}
// Cleanup the component data instance manually
// This is used for component instances when they are a value property of another component
fun cleanup() {
answer = 42
}
override fun type() = $FLEKS_COMPONENT$Component
companion object {
val $FLEKS_COMPONENT$Component = componentTypeOf<$FLEKS_COMPONENT$>()
// Use this function to create a new instance of component data as val inside another component
fun static$FLEKS_COMPONENT$Component(config: $FLEKS_COMPONENT$.() -> Unit): $FLEKS_COMPONENT$ =
$FLEKS_COMPONENT$().apply(config)
// Use this function to get a new instance of a component from the pool and add it to an entity
fun $LOWER_FLEKS_COMPONENT$Component(config: $FLEKS_COMPONENT$.() -> Unit): $FLEKS_COMPONENT$ =
pool.alloc().apply(config)
private val pool = Pool(AppConfig.POOL_PREALLOCATE, "$FLEKS_COMPONENT$") { $FLEKS_COMPONENT$() }
}
// Clone a new instance of the component from the pool
override fun clone(): $FLEKS_COMPONENT$ = $LOWER_FLEKS_COMPONENT$Component { init(from = this@$FLEKS_COMPONENT$) }
// Initialize the component automatically when it is added to an entity
override fun World.initComponent(entity: Entity) {
}
// Cleanup/Reset the component automatically when it is removed from an entity (component will be returned to the pool eventually)
override fun World.cleanupComponent(entity: Entity) {
cleanup()
}
// Initialize an external prefab when the component is added to an entity
override fun World.initPrefabs(entity: Entity) {
}
// Cleanup/Reset an external prefab when the component is removed from an entity
override fun World.cleanupPrefabs(entity: Entity) {
}
// Free the component and return it to the pool - this is called directly by the SnapshotSerializerSystem
override fun free() {
cleanup()
pool.free(this)
}
}Then click on Define and choose Kotlin from the drop-down menu. Finally press the Apply button to save the changes.
- Abbreviation:
fleksdata - Description:
Creates a new data class for usage in poolable components - Edit Variables...: Add Expression
decapitalize(DATA)to variableLOWER_DATA - Template text:
import korlibs.korge.fleks.utils.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* This class is used to ...
*/
@Serializable @SerialName("$DATA$")
class $DATA$ private constructor(
var value: Int = 42
) : Poolable<$DATA$> {
// Init an existing data instance with data from another one
override fun init(from: $DATA$) {
value = from.value
}
// Cleanup data instance manually
// This is used for data instances when they are a value property of a component
override fun cleanup() {
value = 0
}
// Clone a new data instance from the pool
override fun clone(): $DATA$ = $LOWER_DATA$ { init(from = this@$DATA$) }
// Cleanup the tween data instance manually
override fun free() {
cleanup()
pool.free(this)
}
companion object {
// Use this function to create a new instance of data as value property inside a component
fun static$DATA$(config: $DATA$.() -> Unit): $DATA$ =
$DATA$().apply(config)
// Use this function to get a new instance of the data object from the pool
fun $LOWER_DATA$(config: $DATA$.() -> Unit): $DATA$ =
pool.alloc().apply(config)
private val pool = Pool(AppConfig.POOL_PREALLOCATE, "$DATA$") { $DATA$() }
}
}Then click on Define and choose Kotlin from the drop-down menu. Finally press the Apply button to save the changes.
Korge-fleks framework by Marko Koschak is based on Korge Game Engine and Fleks Entity Component System