Skip to content

Commit

Permalink
Make KorgeViewCache a singleton
Browse files Browse the repository at this point in the history
  • Loading branch information
jobe-m committed Feb 19, 2024
1 parent 1fbaf2f commit c95106b
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 129 deletions.
2 changes: 1 addition & 1 deletion korge-fleks/kproject.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ dependencies:
#- https://github.com/korlibs/korge-ldtk/tree/3cc31bddd707037084f8e0d764a9706cc99f0bfb/korge-ldtk
- ../../korge-ldtk/korge-ldtk
- https://github.com/korlibs/korge-tiled/tree/a54e3b2cacf24e0a0eb87e2580f69f8c81d083ce/korge-tiled
targets: [jvm, android]
targets: [jvm, js, android]
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,9 @@ object ParallaxBackground {
private val configureParallaxLayersFct = fun(world: World, entity: Entity, assetConfig: Identifier): Entity = with(world) {
println("Re-configure attached parallax Layers")

val korgeViewCache = inject<KorgeViewCache>("KorgeViewCache")

val config = AssetStore.getBackground(assetConfig.name).config
val isHorizontal = config.mode == ParallaxConfig.Mode.HORIZONTAL_PLANE
val view = korgeViewCache[entity] as ParallaxDataView
val view = KorgeViewCache[entity] as ParallaxDataView
val layerMap = entity[SubEntities]

config.parallaxPlane?.let { planeConf ->
Expand All @@ -47,7 +45,7 @@ object ParallaxBackground {

// Update only attached layers because they might change their speed depending on their position on the ground plane
planeConf.attachedLayersFront?.fastForEach { conf ->
val layer = korgeViewCache.getLayer(entity, conf.name)
val layer = KorgeViewCache.getLayer(entity, conf.name)
configureSubEntityForLayer(
world = world,
entity = layerMap[conf.name],
Expand All @@ -58,7 +56,7 @@ object ParallaxBackground {
)
}
planeConf.attachedLayersRear?.fastForEach { conf ->
val layer = korgeViewCache.getLayer(entity, conf.name)
val layer = KorgeViewCache.getLayer(entity, conf.name)
configureSubEntityForLayer(
world = world,
entity = layerMap[conf.name],
Expand All @@ -73,7 +71,6 @@ object ParallaxBackground {
}

private val configureParallaxBackgroundFct = fun(world: World, entity: Entity, config: Identifier): Entity = with(world) {
val korgeViewCache = inject<KorgeViewCache>("KorgeViewCache")
val parallaxConfig = AssetStore.getEntityConfig<Config>(config.name)

entity.configure {
Expand All @@ -86,7 +83,7 @@ object ParallaxBackground {
}

// Once the base ParallaxDataView is created with above base entity we can access it from the cache
val view = korgeViewCache[entity] as ParallaxDataView
val view = KorgeViewCache[entity] as ParallaxDataView
val layerMap = entity[SubEntities]

val config = AssetStore.getBackground(parallaxConfig.assetName.name).config
Expand All @@ -107,14 +104,14 @@ object ParallaxBackground {
val selfSpeedX = if (isHorizontal) planeConf.selfSpeed else 0.0f
val selfSpeedY = if (!isHorizontal) planeConf.selfSpeed else 0.0f
planeConf.attachedLayersFront?.fastForEach { conf ->
val layer = korgeViewCache.getLayer(entity, conf.name)
val layer = KorgeViewCache.getLayer(entity, conf.name)
layerMap.entities[conf.name] = createSubEntityForLayer(world, entity, conf.name,
speedFactor = view.parallaxPlaneSpeedFactor[layer.y.toInt() - offset + (layer.height.toInt().takeIf { conf.attachBottomRight } ?: 0)],
selfSpeedX = selfSpeedX, selfSpeedY = selfSpeedY,
isHorizontal = isHorizontal)
}
planeConf.attachedLayersRear?.fastForEach { conf ->
val layer = korgeViewCache.getLayer(entity, conf.name)
val layer = KorgeViewCache.getLayer(entity, conf.name)
layerMap.entities[conf.name] = createSubEntityForLayer(world, entity, conf.name,
speedFactor = view.parallaxPlaneSpeedFactor[layer.y.toInt() - offset + (layer.height.toInt().takeIf { conf.attachBottomRight } ?: 0)],
selfSpeedX = selfSpeedX, selfSpeedY = selfSpeedY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ fun drawableFamily(): Family = World.family { all(Drawable, PositionShapeCompone
val onDrawableFamilyAdded: FamilyHook = { entity ->
val world = this
val layers = inject<HashMap<String, Container>>("Layers")
val korgeViewCache = inject<KorgeViewCache>("KorgeViewCache")

val drawable = entity[Drawable]
val positionShapeComponent = entity[PositionShapeComponent]
Expand Down Expand Up @@ -142,7 +141,7 @@ val onDrawableFamilyAdded: FamilyHook = { entity ->
null -> error("onDrawableFamilyAdded: Cannot add view for entity '${entity.id}' to layer '${drawable.drawOnLayer}'!")
else -> {
layer.addChild(view)
korgeViewCache.addOrUpdate(entity, view)
KorgeViewCache.addOrUpdate(entity, view)
}
}

Expand Down Expand Up @@ -186,7 +185,6 @@ val onDrawableFamilyAdded: FamilyHook = { entity ->
}

val onDrawableFamilyRemoved: FamilyHook = { entity ->
val korgeViewCache = inject<KorgeViewCache>("KorgeViewCache")
(korgeViewCache.getOrNull(entity) ?: error("onDrawableFamilyRemoved: Cannot remove view of entity '${entity.id}' from layer '${entity[Drawable].drawOnLayer}'!")).removeFromParent()
korgeViewCache.remove(entity)
(KorgeViewCache.getOrNull(entity) ?: error("onDrawableFamilyRemoved: Cannot remove view of entity '${entity.id}' from layer '${entity[Drawable].drawOnLayer}'!")).removeFromParent()
KorgeViewCache.remove(entity)
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,16 @@ fun specificLayerFamily(): Family = World.family { all(SpecificLayer).any(Specif

val onSpecificLayerFamilyAdded: FamilyHook = { entity ->
val world = this
val korgeViewCache = inject<KorgeViewCache>("KorgeViewCache")

// Need to get parent entity to search for view object which contains the sprite layer
val specificLayer = entity[SpecificLayer]

val view: View = if (specificLayer.parallaxPlaneLine != null) {
val pView = korgeViewCache[specificLayer.parentEntity]
val pView = KorgeViewCache[specificLayer.parentEntity]
pView as ParallaxDataView
pView.parallaxLines[specificLayer.parallaxPlaneLine!!] ?: error("onSpecificLayerFamilyAdded: Parallax Line '${specificLayer.parallaxPlaneLine}' is null!")
} else if (specificLayer.spriteLayer != null) {
korgeViewCache.getLayer(specificLayer.parentEntity, specificLayer.spriteLayer!!)
KorgeViewCache.getLayer(specificLayer.parentEntity, specificLayer.spriteLayer!!)
} else {
error("onSpecificLayerFamilyAdded: No sprite layer name or parallax plane line number set for entity '${entity.id}'!")
}
Expand Down Expand Up @@ -88,9 +87,9 @@ val onSpecificLayerFamilyAdded: FamilyHook = { entity ->
}
}

korgeViewCache.addOrUpdate(entity, view)
KorgeViewCache.addOrUpdate(entity, view)
}

val onSpecificLayerFamilyRemoved: FamilyHook = { entity ->
inject<KorgeViewCache>("KorgeViewCache").remove(entity)
KorgeViewCache.remove(entity)
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,13 @@ class AnimatePositionShapeSystem : IteratingSystem(
}
}

class AnimateSpriteSystem(
private val korgeViewCache: KorgeViewCache = inject("KorgeViewCache")
) : IteratingSystem(
class AnimateSpriteSystem : IteratingSystem(
family { all(Sprite).any(TweenSpriteAnimName, TweenSpriteIsPlaying, TweenSpriteForwardDirection, TweenSpriteLoop, TweenSpriteDestroyOnPlayingFinished) },
interval = EachFrame
) {
override fun onTickEntity(entity: Entity) {
val sprite = entity[Sprite]
val imageView = korgeViewCache[entity] as ImageDataViewEx
val imageView = KorgeViewCache[entity] as ImageDataViewEx
updateProperty(entity, TweenSpriteAnimName, sprite::animationName) { imageView.animation = sprite.animationName }
updateProperty(entity, TweenSpriteIsPlaying, sprite::isPlaying)
updateProperty(entity, TweenSpriteForwardDirection, sprite::forwardDirection)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ import korlibs.time.TimeSpan
* In case the [Drawable] entity is of type [Sprite] it takes the image configuration from
* [Sprite] component to setup and control the sprite animations.
*/
class KorgeViewSystem(
private val korgeViewCache: KorgeViewCache = inject("KorgeViewCache"),
private val korgeViewCacheDebug: KorgeViewCache = inject("KorgeViewCacheDebug")
) : IteratingSystem(
class KorgeViewSystem : IteratingSystem(
family { all(Appearance).any(Appearance, SwitchLayerVisibility, SpecificLayer, PositionShapeComponent, Offset) },
interval = EachFrame
) {
Expand All @@ -46,7 +43,7 @@ class KorgeViewSystem(
// try to switch on again
(0.0..1.0).random() <= visibility.onVariance // variance in switching value on again - 1: changed value switches back immediately - 0: changed value stays forever
}
(korgeViewCache[entity] as ImageDataViewEx).getLayer(layer.name)?.visible = layer.visible
(KorgeViewCache[entity] as ImageDataViewEx).getLayer(layer.name)?.visible = layer.visible
}
}
}
Expand All @@ -55,15 +52,15 @@ class KorgeViewSystem(
else Point(entity[Offset].x, entity[Offset].y)
entity.getOrNull(OffsetByFrameIndex)?.let {
// Get offset depending on current animation and frame index
val currentFrameIndex = (korgeViewCache[it.entity] as ImageDataViewEx).currentFrameIndex
val currentFrameIndex = (KorgeViewCache[it.entity] as ImageDataViewEx).currentFrameIndex
val animationName = it.entity.getOrNull(Sprite)?.animationName ?: ""
val frameOffset = it.list[animationName]?.get(currentFrameIndex)
?: error("KorgeViewSystem: Cannot get offset by frame index (entity: ${entity.id}, animationName: '$animationName', currentFrameIndex: $currentFrameIndex)")
offset.x += frameOffset.x
offset.y += frameOffset.y
}

korgeViewCache[entity].let { view ->
KorgeViewCache[entity].let { view ->
if (appearance.visible) {
view.visible = true
view.alpha = appearance.alpha.toDouble()
Expand All @@ -88,62 +85,5 @@ class KorgeViewSystem(
}

}

// Do debug drawing if component is configured for this entity
entity.getOrNull(Info)?.let { debugInfo ->
// TODO check for Keys to enable certain debug options
// if (!debugInfo.showName) return

val positionShapeComponent = entity[PositionShapeComponent]

korgeViewCacheDebug[entity].let { debugView ->
debugView.xy(positionShapeComponent.x, positionShapeComponent.y)

@OptIn(KorgeExperimental::class)
(debugView as Container).renderableView {
val fontSize = 8.0
// if (debugInfo.showName) {
// ctx.drawText(
// ctx.views?.debugBmpFont ?: error("KorgeViewSystem: Could not load debugBmpFont!"),
// fontSize, debugInfo.name,
// positionShape.x.toInt(),
// positionShape.y.toInt() + 1,
// colMul = Colors.RED,
// filtering = false
// )
// }

ctx.useLineBatcher { lines ->
lines.drawVector(Colors.RED) {
// // Draw pivot point
// if (debugInfo.showPivotPoint) {
// TODO val centerX = globalX
// val centerY = globalY
// line(centerX, centerY - 5, centerX, centerY + 5)
// line(centerX - 5, centerY, centerX + 5, centerY)
// }
// // Draw overall entity object size
// if (debugInfo.showSizeBox) {
// TODO rect(Rectangle(globalX - offset.x, globalY - offset.y, positionShape.width, positionShape.height))
// }
}

/* here as reference for future use ;-)
lines.drawVector(Colors.YELLOW) {
moveTo(localToGlobal(Point(0.0 - offset.x, 0.0 - offset.y)))
lineTo(localToGlobal(Point(0.0 - offset.x, positionShape.height - offset.y)))
lineTo(localToGlobal(Point(positionShape.width - offset.x, positionShape.height - offset.y)))
lineTo(localToGlobal(Point(positionShape.width - offset.x, 0.0 - offset.y)))
lineTo(localToGlobal(Point(0.0 - offset.x, 0.0 - offset.y)))
close()
val radius = 6.0 * ctx.views!!.windowToGlobalScaleAvg
circle(Point(20, 30), radius)
}
*/
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ import korlibs.korge.parallax.ImageDataViewEx
* It can be configured to periodically spawn entities until a total number of spawned objects is reached, or
* it can also spawn an unlimited number of entities (run forever until it dies).
*/
class SpawnerSystem(
private val korgeViewCache: KorgeViewCache = inject("KorgeViewCache")
) : IteratingSystem(
class SpawnerSystem : IteratingSystem(
family { all(SpawnerComponent) },
interval = EachFrame
) {
Expand All @@ -40,7 +38,7 @@ class SpawnerSystem(
}
entity.getOrNull(OffsetByFrameIndex)?.let {
// Get offset depending on current animation and frame index
val currentFrameIndex = (korgeViewCache[it.entity] as ImageDataViewEx).currentFrameIndex
val currentFrameIndex = (KorgeViewCache[it.entity] as ImageDataViewEx).currentFrameIndex
val animationName = it.entity.getOrNull(Sprite)?.animationName ?: ""
val offset = it.list[animationName]?.get(currentFrameIndex)
?: error("SpawnerSystem: Cannot get offset by frame index (entity: ${entity.id}, animationName: '$animationName', currentFrameIndex: $currentFrameIndex)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,53 @@ import com.github.quillraven.fleks.Entity
import korlibs.korge.parallax.ImageDataViewEx
import korlibs.korge.view.View
import korlibs.korge.parallax.ParallaxDataView
import kotlin.concurrent.*
import kotlin.math.max

interface KorgeViewBase {
fun getLayer(name: String) : View?
}

class KorgeViewCache(arraySize: Int = 64) {
// Korge specific internal objects which we do not want to store in the components - they are accessed by entity id the same way as components
private var views: Array<View?> = Array(arraySize) { null }
class KorgeViewCache {
companion object {
// Korge specific internal objects which we do not want to store in the components - they are accessed by entity id the same way as components
@Volatile
private var views: Array<View?>? = null
private val VIEWS: Array<View?> get() = views ?: error("KorgeViewCache instance has not been created!")

fun addOrUpdate(entity: Entity, view: View) {
if (entity.id >= views.size) {
views = views.copyOf(max(views.size * 2, entity.id + 1))
fun createInstance(arraySize: Int = 64) {
if (views == null) views = Array(arraySize) { null }
}
views[entity.id] = view
}

fun remove(entity: Entity) {
if (views.size > entity.id) {
views[entity.id] = null
} else error("KorgeViewCache: Entity '${entity.id}' is out of range on remove!")
}
fun addOrUpdate(entity: Entity, view: View) {
if (entity.id >= VIEWS.size) {
views = VIEWS.copyOf(max(VIEWS.size * 2, entity.id + 1))
}
VIEWS[entity.id] = view
}

operator fun get(entity: Entity) : View {
return if (views.size > entity.id) {
views[entity.id] ?: error("KorgeViewCache: View of entity '${entity.id}' is null!")
} else error("KorgeViewCache: Entity '${entity.id}' is out of range on get!")
}
fun remove(entity: Entity) {
if (VIEWS.size > entity.id) {
VIEWS[entity.id] = null
} else error("KorgeViewCache: Entity '${entity.id}' is out of range on remove!")
}

fun getOrNull(entity: Entity) : View? {
return if (views.size > entity.id) views[entity.id] // Cache potentially has this view. However, return value can still be null!
else null
}
operator fun get(entity: Entity) : View {
return if (VIEWS.size > entity.id) {
VIEWS[entity.id] ?: error("KorgeViewCache: View of entity '${entity.id}' is null!")
} else error("KorgeViewCache: Entity '${entity.id}' is out of range on get!")
}

fun getLayer(entity: Entity, name: String) : View {
return when (val view = get(entity)) {
is ImageDataViewEx -> view.getLayer(name)
?: error("KorgeViewCache: Could not find layer '$name' from ImageAnimView entity '${entity.id}'!")
is ParallaxDataView -> view.getLayer(name)
?: error("KorgeViewCache: Could not find layer '$name' from ParallaxDataView entity '${entity.id}'!")
else -> error("KorgeViewCache: View does not have getLayer function!")
fun getOrNull(entity: Entity) : View? {
return if (VIEWS.size > entity.id) VIEWS[entity.id] // Cache potentially has this view. However, return value can still be null!
else null
}
}
}

class AssetReloadCache {
val backgroundEntities = mutableSetOf<Entity>()
val spriteEntities = mutableSetOf<Entity>()
fun getLayer(entity: Entity, name: String) : View {
return when (val view = get(entity)) {
is ImageDataViewEx -> view.getLayer(name)
?: error("KorgeViewCache: Could not find layer '$name' from ImageAnimView entity '${entity.id}'!")
is ParallaxDataView -> view.getLayer(name)
?: error("KorgeViewCache: Could not find layer '$name' from ParallaxDataView entity '${entity.id}'!")
else -> error("KorgeViewCache: View does not have getLayer function!")
}
}
}
}

0 comments on commit c95106b

Please sign in to comment.