Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move view port size out of camera entity #49

Merged
merged 2 commits into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ data class PositionComponent(
*/
fun World.convertToWorldCoordinates(camera: Entity) {
val cameraPosition = camera[PositionComponent]
val cameraViewPortHalf = camera[SizeComponent]
x += cameraPosition.x - cameraPosition.offsetX - cameraViewPortHalf.width
y += cameraPosition.y - cameraPosition.offsetY - cameraViewPortHalf.height
x += cameraPosition.x - cameraPosition.offsetX - AppConfig.VIEW_PORT_WIDTH_HALF
y += cameraPosition.y - cameraPosition.offsetY - AppConfig.VIEW_PORT_HEIGHT_HALF
}

/**
Expand All @@ -38,19 +37,14 @@ data class PositionComponent(
*/
fun World.convertToScreenCoordinates(camera: Entity): PositionComponent {
val cameraPosition = camera[PositionComponent]
val cameraViewPortHalf = camera[SizeComponent]
return PositionComponent(
x = x - cameraPosition.x + cameraPosition.offsetX + cameraViewPortHalf.width,
y = y - cameraPosition.y + cameraPosition.offsetY + cameraViewPortHalf.height,
x = x - cameraPosition.x + cameraPosition.offsetX + AppConfig.VIEW_PORT_WIDTH_HALF,
y = y - cameraPosition.y + cameraPosition.offsetY + AppConfig.VIEW_PORT_HEIGHT_HALF,
offsetX = offsetX,
offsetY = offsetY
)
}

// TODO: Add convert to screen coordinates function

// TODO: Check if EntityByName is fed with Camera entity after deserialization of fleks world

// Author's hint: Check if deep copy is needed on any change in the component!
override fun clone(): PositionComponent = this.copy()
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ import kotlinx.serialization.*

@Serializable @SerialName("MainCameraConfig")
data class MainCameraConfig(
override val name: String,

private val viewPortWith: Int,
private val viewPortHeight: Int
override val name: String
) : EntityConfig {

override fun World.entityConfigure(entity: Entity) : Entity {
Expand All @@ -23,19 +20,6 @@ data class MainCameraConfig(
// Offset can be used to "shake" the camera on explosions etc.
it += PositionComponent()

// TODO: Move view port size to injectable object - it is dependent on the target device and game config might be
// moved to another device with different screen size
// Camera has a size which is the view port of the game
it += SizeIntComponent(
width = viewPortWith, // SizeIntComponent is used to store the view port size as integer values
height = viewPortHeight
)
// Save half size for middle point of view port in separate component
it += SizeComponent(
width = viewPortWith * 0.5f, // SizeComponent is used to store offset to middle point of view port
height = viewPortHeight * 0.5f
)

// Camera has a tag to make it easily accessible for other systems and entity configurations
it += MainCameraTag
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,8 @@ data class DialogBoxConfig(

override fun World.entityConfigure(entity: Entity) : Entity {

val camera: Entity = getMainCamera()
val cameraViewPort = camera[SizeIntComponent]

val viewPortWidth = cameraViewPort.width.toFloat()
val viewPortHeight = cameraViewPort.height.toFloat()
val viewPortWidth = AppConfig.VIEW_PORT_WIDTH.toFloat()
val viewPortHeight = AppConfig.VIEW_PORT_HEIGHT.toFloat()

val textBoxWidth = width + 14 // 190 <- 176
val textBoxHeight = height + 8 // 49 <- 41
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,10 @@ data class LogoEntityConfig(
override fun World.entityConfigure(entity: Entity) : Entity {
val assetStore: AssetStore = inject(name = "AssetStore")

val camera: Entity = getMainCamera()
val cameraViewPort = camera[SizeIntComponent]

entity.configure {
it += PositionComponent(
x = offsetX + (if (centerX) (cameraViewPort.width - assetStore.getImageData(assetName).width).toFloat() * 0.5f else 0f),
y = offsetY + (if (centerY) (cameraViewPort.height - assetStore.getImageData(assetName).height).toFloat() * 0.5f else 0f)
x = offsetX + (if (centerX) (AppConfig.VIEW_PORT_WIDTH - assetStore.getImageData(assetName).width).toFloat() * 0.5f else 0f),
y = offsetY + (if (centerY) (AppConfig.VIEW_PORT_HEIGHT - assetStore.getImageData(assetName).height).toFloat() * 0.5f else 0f)
)
it += LayeredSpriteComponent(
name = assetName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,7 @@ import korlibs.korge.fleks.tags.*
* Not needed because view port size is coming from entity config.
* Kept here for reference.
*/
val mainCameraFamily = World.family { all(SizeComponent, SizeIntComponent, MainCameraTag) }
val mainCameraFamily = World.family { all(MainCameraTag, PositionComponent) }

val onMainCameraAdded: FamilyHook = { entity ->
// Set view port half which is the middle point of the view port
val viewPortSize = entity[SizeIntComponent]
val viewPortHalf = entity[SizeComponent]
viewPortHalf.width = viewPortSize.width * 0.5f
viewPortHalf.height = viewPortSize.height * 0.5f

println("Set view port half: $viewPortHalf")
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,7 @@ class DebugRenderSystem(

// Set size of render view to display size
override fun getLocalBoundsInternal(): Rectangle = with (world) {
val camera: Entity = getMainCamera()
val cameraViewPort = camera[SizeIntComponent]
return Rectangle(0, 0, cameraViewPort.width, cameraViewPort.height)
return Rectangle(0, 0, AppConfig.VIEW_PORT_WIDTH, AppConfig.VIEW_PORT_HEIGHT)
}

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,7 @@ class FastSpriteRenderSystem(

// Set size of render view to display size
override fun getLocalBoundsInternal(): Rectangle = with (world) {
val camera: Entity = getMainCamera()
val cameraViewPort = camera[SizeIntComponent]
return Rectangle(0, 0, cameraViewPort.width, cameraViewPort.height)
return Rectangle(0, 0, AppConfig.VIEW_PORT_WIDTH, AppConfig.VIEW_PORT_HEIGHT)
}

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ class LevelMapRenderSystem(
override fun renderInternal(ctx: RenderContext) {
val camera: Entity = world.getMainCamera()
val cameraPosition = with(world) { camera[PositionComponent] }
val cameraViewPort = with(world) { camera[SizeIntComponent] }
val cameraViewPortHalf = with(world) { camera[SizeComponent] }

// Sort level maps by their layerIndex
family.sort(comparator)
Expand All @@ -54,18 +52,18 @@ class LevelMapRenderSystem(
val tileSize = worldData.gridSize

// Calculate viewport position in world coordinates from Camera position (x,y) + offset
val viewPortPosX: Float = cameraPosition.x + cameraPosition.offsetX - cameraViewPortHalf.width
val viewPortPosY: Float = cameraPosition.y + cameraPosition.offsetY - cameraViewPortHalf.height
val viewPortPosX: Float = cameraPosition.x + cameraPosition.offsetX - AppConfig.VIEW_PORT_WIDTH_HALF
val viewPortPosY: Float = cameraPosition.y + cameraPosition.offsetY - AppConfig.VIEW_PORT_HEIGHT_HALF

layerNames.forEach { layerName ->
val levelMap = worldData.getLevelMap(layerName)

// Start and end indexes of viewport area (in tile coordinates)
val xStart: Int = viewPortPosX.toInt() / tileSize - 1 // x in positive direction; -1 = start one tile before
val xTiles = (cameraViewPort.width / tileSize) + 3
val xTiles = (AppConfig.VIEW_PORT_WIDTH / tileSize) + 3

val yStart: Int = viewPortPosY.toInt() / tileSize - 1 // y in negative direction; -1 = start one tile before
val yTiles = cameraViewPort.height / tileSize + 3
val yTiles = (AppConfig.VIEW_PORT_HEIGHT / tileSize) + 3

ctx.useBatcher { batch ->
levelMap.forEachTile(xStart, yStart, xTiles, yTiles, worldData.levelWidth, worldData.levelHeight) { slice, px, py ->
Expand All @@ -85,9 +83,7 @@ class LevelMapRenderSystem(

// Set size of render view to display size
override fun getLocalBoundsInternal(): Rectangle = with (world) {
val camera: Entity = getMainCamera()
val cameraViewPort = camera[SizeIntComponent]
return Rectangle(0, 0, cameraViewPort.width, cameraViewPort.height)
return Rectangle(0, 0, AppConfig.VIEW_PORT_WIDTH, AppConfig.VIEW_PORT_HEIGHT)
}

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,7 @@ class ObjectRenderSystem(

// Set size of render view to display size
override fun getLocalBoundsInternal(): Rectangle = with (world) {
val camera: Entity = getMainCamera()
val cameraViewPort = camera[SizeIntComponent]
return Rectangle(0, 0, cameraViewPort.width, cameraViewPort.height)
return Rectangle(0, 0, AppConfig.VIEW_PORT_WIDTH, AppConfig.VIEW_PORT_HEIGHT)
}

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ class ParallaxRenderSystem(
private val assetStore: AssetStore = world.inject(name = "AssetStore")

override fun renderInternal(ctx: RenderContext) {
val camera: Entity = world.getMainCamera()
val cameraViewPort = with(world) { camera[SizeIntComponent] }

// Custom Render Code
ctx.useBatcher { batch ->

Expand All @@ -54,7 +51,6 @@ class ParallaxRenderSystem(
val localRgba = backgroundLayers[index].rgba.rgba

drawLayer(
cameraViewPort = cameraViewPort,
global = globalPositionComponent,
local = backgroundLayers[index].position,
config = parallaxDataContainer.config.backgroundLayers!![index],
Expand All @@ -73,7 +69,6 @@ class ParallaxRenderSystem(
val localRgba = parallaxPlane.rgba.rgba

drawParallaxPlaneLayer(
cameraViewPort = cameraViewPort,
global = globalPositionComponent,
local = parallaxPlane.position,
localScroll = parallaxPlane.attachedLayersRearPositions[index],
Expand All @@ -94,7 +89,6 @@ class ParallaxRenderSystem(
val localRgba = parallaxPlane.rgba.rgba

drawParallaxPlaneLayer(
cameraViewPort = cameraViewPort,
global = globalPositionComponent,
local = parallaxPlane.position,
localScroll = parallaxPlane.linePositions[index],
Expand All @@ -114,7 +108,6 @@ class ParallaxRenderSystem(
val localRgba = parallaxPlane.rgba.rgba

drawParallaxPlaneLayer(
cameraViewPort = cameraViewPort,
global = globalPositionComponent,
local = parallaxPlane.position,
localScroll = parallaxPlane.attachedLayersFrontPositions[index],
Expand All @@ -132,7 +125,6 @@ class ParallaxRenderSystem(
val localRgba = foregroundLayers[index].rgba.rgba

drawLayer(
cameraViewPort = cameraViewPort,
global = globalPositionComponent,
local = foregroundLayers[index].position,
config = parallaxDataContainer.config.foregroundLayers!![index],
Expand All @@ -145,13 +137,10 @@ class ParallaxRenderSystem(

// Set size of render view to display size
override fun getLocalBoundsInternal(): Rectangle = with (world) {
val camera: Entity = getMainCamera()
val cameraViewPort = camera[SizeIntComponent]
return Rectangle(0, 0, cameraViewPort.width, cameraViewPort.height)
return Rectangle(0, 0, AppConfig.VIEW_PORT_WIDTH, AppConfig.VIEW_PORT_HEIGHT)
}

private fun drawLayer(
cameraViewPort: SizeIntComponent,
global: PositionComponent,
local: PositionComponent,
config: ParallaxLayerConfig,
Expand All @@ -160,8 +149,8 @@ class ParallaxRenderSystem(
batch: BatchBuilder2D,
ctx: RenderContext
) {
val countH = if (config.repeatX) cameraViewPort.width / layer.width else 0
val countV = if (config.repeatY) cameraViewPort.height / layer.height else 0
val countH = if (config.repeatX) AppConfig.VIEW_PORT_WIDTH / layer.width else 0
val countV = if (config.repeatY) AppConfig.VIEW_PORT_HEIGHT / layer.height else 0

val x = if (countH != 0 && config.speedFactor != null) global.x else global.x + layer.targetX
val y = if (countV != 0 && config.speedFactor != null) global.y else global.y + layer.targetY
Expand All @@ -184,7 +173,6 @@ class ParallaxRenderSystem(
}

private fun drawParallaxPlaneLayer(
cameraViewPort: SizeIntComponent,
global: PositionComponent,
local: PositionComponent,
localScroll: Float,
Expand All @@ -197,13 +185,13 @@ class ParallaxRenderSystem(
) {
when (parallaxMode) {
ParallaxConfig.Mode.HORIZONTAL_PLANE -> {
val countH = if (repeat) cameraViewPort.width / layer.width else 0
val countH = if (repeat) AppConfig.VIEW_PORT_WIDTH / layer.width else 0
val x = if (countH != 0) global.x else global.x + layer.targetX

for(xIndex in -1 - countH until countH + 1) {
batch.drawQuad(
tex = ctx.getTex(layer.slice),
x = x + xIndex * layer.width + cameraViewPort.width * 0.5f + localScroll,
x = x + xIndex * layer.width + AppConfig.VIEW_PORT_WIDTH * 0.5f + localScroll,
y = global.y + layer.targetY + local.offsetY,
m = globalMatrix,
filtering = false,
Expand All @@ -212,14 +200,14 @@ class ParallaxRenderSystem(
}
}
ParallaxConfig.Mode.VERTICAL_PLANE -> {
val countV = if (repeat) cameraViewPort.height / layer.height else 0
val countV = if (repeat) AppConfig.VIEW_PORT_HEIGHT / layer.height else 0
val y = if (countV != 0) global.y else global.y + layer.targetY

for(yIndex in -1 - countV until countV + 1) {
batch.drawQuad(
tex = ctx.getTex(layer.slice),
x = global.x + layer.targetX + local.offsetX,
y = y + yIndex * layer.height + cameraViewPort.height * 0.5f + localScroll,
y = y + yIndex * layer.height + AppConfig.VIEW_PORT_HEIGHT * 0.5f + localScroll,
m = globalMatrix,
filtering = false,
colorMul = rgba
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ class CameraSystem(
val followPosition = entity[PositionComponent]

val camera: Entity = world.getMainCamera()

val cameraPosition = camera[PositionComponent]
val viewPortHalf = camera[SizeComponent]

val lastCameraPosX = cameraPosition.x
//val lastCameraPosY = cameraPosition.y
Expand All @@ -49,10 +47,10 @@ class CameraSystem(
val newCameraPositionY = cameraPosition.y + yDiff * factor

// Keep camera within world bounds (+1 tile in each direction as guard for shaking camera - via camera offset)
val leftBound = viewPortHalf.width + worldToPixelRatio
val rightBound = worldWidth - viewPortHalf.width - worldToPixelRatio
val topBound = viewPortHalf.height + worldToPixelRatio
val bottomBound = worldHeight - viewPortHalf.height - worldToPixelRatio
val leftBound = AppConfig.VIEW_PORT_WIDTH_HALF + worldToPixelRatio
val rightBound = worldWidth - AppConfig.VIEW_PORT_WIDTH_HALF - worldToPixelRatio
val topBound = AppConfig.VIEW_PORT_HEIGHT_HALF + worldToPixelRatio
val bottomBound = worldHeight - AppConfig.VIEW_PORT_HEIGHT_HALF - worldToPixelRatio
cameraPosition.x =
if (newCameraPositionX < leftBound) leftBound
else if (newCameraPositionX > rightBound) rightBound
Expand All @@ -70,18 +68,17 @@ class CameraSystem(
parallaxFamily.forEach { parallaxEntity ->
val motion = parallaxEntity[MotionComponent]
val position = parallaxEntity[PositionComponent]
val viewPortHeight = camera[SizeIntComponent].height

// Convert pixel distance of camera movement in the level to horizontal velocity for parallax layers
val distanceInWorldUnits = cameraDistX * worldToPixelRatioInv // (distance in pixel) / (world to pixel ratio)
motion.velocityX = -distanceInWorldUnits / deltaTime // world units per delta-time

// Calculate the ratio of the camera position in the world to the world height
// Camera position is in world coordinates
val ratio = (cameraPosition.y - viewPortHalf.height) / (worldHeight - viewPortHeight) // range: [0...1]
val ratio = (cameraPosition.y - AppConfig.VIEW_PORT_HEIGHT_HALF) / (worldHeight - AppConfig.VIEW_PORT_HEIGHT) // range: [0...1]

// Get the global position of the parallax layer in screen coordinates
val parallaxVerticalLength = viewPortHeight - parallaxHeight
val parallaxVerticalLength = AppConfig.VIEW_PORT_HEIGHT - parallaxHeight
val parallaxVerticalPosition = ratio * parallaxVerticalLength

position.y = parallaxVerticalPosition - parallaxOffset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,6 @@ class SnapshotSerializerSystem(module: SerializersModule) : IntervalSystem(
private var snapshotSecondCounter: Int = 0
private var snapshotDeletePointer: Int = 0

companion object {
/**
* Setup function for creating the SnapshotSerializerSystem. Here it is possible to
* add [SerializersModule] as parameter. This enables to add components, tags and config data
* classes outside Korge-fleks.
*/
fun SystemConfiguration.setup(module: SerializersModule) = add(SnapshotSerializerSystem(module))
}

override fun onTick() {
val snapshotCopy = mutableMapOf<Entity, Snapshot>()

Expand Down
Loading