DEADSOFTWARE

Store block references intead of ids
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / model / block / Block.kt
1 package ru.deadsoftware.cavedroid.game.model.block
3 import com.badlogic.gdx.graphics.g2d.Sprite
4 import com.badlogic.gdx.graphics.g2d.SpriteBatch
5 import com.badlogic.gdx.math.Rectangle
6 import com.badlogic.gdx.utils.TimeUtils
7 import kotlin.contracts.ExperimentalContracts
8 import kotlin.contracts.contract
10 @OptIn(ExperimentalContracts::class)
11 sealed class Block {
13 abstract val params: CommonBlockParams
15 val width: Float get() = 16f - params.collisionMargins.left - params.collisionMargins.right
16 val height: Float get() = 16f - params.collisionMargins.top - params.collisionMargins.bottom
18 private val spriteWidth: Float get() = 16f - params.spriteMargins.left - params.spriteMargins.right
19 private val spriteHeight: Float get() = 16f - params.spriteMargins.top - params.spriteMargins.bottom
21 private var animation: Array<Sprite>? = null
23 private var _sprite: Sprite? = null
24 get() {
25 return animation?.get(currentAnimationFrame) ?: field
26 }
28 val sprite: Sprite
29 get() = requireNotNull(_sprite) { "null sprite for block '${params.key}'" }
31 private val currentAnimationFrame: Int
32 get() {
33 return params.animationInfo?.let { animInfo ->
34 ((TimeUtils.millis() / ANIMATION_FRAME_DURATION_MS) % animInfo.framesCount).toInt()
35 } ?: 0
36 }
38 fun initialize() {
39 initAnimation()
40 initSprite()
41 }
43 private fun initAnimation() {
44 animation = params.animationInfo?.let { animInfo ->
45 requireNotNull(params.texture) { "Cannot derive animation frames from null sprite" }
46 Array(animInfo.framesCount) { y ->
47 val width = 16 - params.spriteMargins.left - params.spriteMargins.right
48 val height = 16 - params.spriteMargins.top - params.spriteMargins.bottom
49 Sprite(params.texture, params.spriteMargins.left, 16 * y + params.spriteMargins.top, width, height)
50 .apply { flip(false, true) }
51 }
52 }
53 }
55 private fun initSprite() {
56 _sprite = animation?.get(0) ?: params.texture?.let { tex ->
57 val width = 16 - params.spriteMargins.left - params.spriteMargins.right
58 val height = 16 - params.spriteMargins.top - params.spriteMargins.bottom
59 Sprite(tex, params.spriteMargins.left, params.spriteMargins.top, width, height)
60 .apply { flip(false, true) }
61 }
62 }
64 fun requireSprite() = requireNotNull(sprite)
66 fun draw(spriter: SpriteBatch, x: Float, y: Float) {
67 sprite.apply {
68 setBounds(
69 /* x = */ x + params.spriteMargins.left,
70 /* y = */ y + params.spriteMargins.top,
71 /* width = */ spriteWidth,
72 /* height = */ spriteHeight
73 )
74 draw(spriter)
75 }
76 }
78 fun isFluid(): Boolean {
79 contract { returns(true) implies (this@Block is Fluid) }
80 return this is Fluid
81 }
83 fun isWater(): Boolean {
84 contract { returns(true) implies (this@Block is Water) }
85 return this is Water
86 }
88 fun isLava(): Boolean {
89 contract { returns(true) implies (this@Block is Lava) }
90 return this is Lava
91 }
93 fun isSlab(): Boolean {
94 contract { returns(true) implies (this@Block is Slab) }
95 return this is Slab
96 }
98 fun getRectangle(x: Int, y: Int): Rectangle {
99 return Rectangle(
100 /* x = */ x * 16f + params.collisionMargins.left,
101 /* y = */ y * 16f + params.collisionMargins.top,
102 /* width = */ width,
103 /* height = */ height
109 data class Normal(
110 override val params: CommonBlockParams,
111 ) : Block()
113 data class Slab(
114 override val params: CommonBlockParams,
115 val fullBlockKey: String,
116 ): Block()
118 sealed class Fluid: Block() {
119 abstract val state: Int
122 data class Water(
123 override val params: CommonBlockParams,
124 override val state: Int,
125 ) : Fluid()
127 data class Lava(
128 override val params: CommonBlockParams,
129 override val state: Int,
130 ) : Fluid()
132 /* Legacy accessors below */
134 // collision margins
135 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val left: Int get() = params.collisionMargins.left
136 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val right: Int get() = params.collisionMargins.left
137 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val top: Int get() = params.collisionMargins.left
138 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val bottom: Int get() = params.collisionMargins.left
140 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val hp: Int get() = params.hitPoints
141 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val collision: Boolean get() = params.hasCollision
142 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val animated: Boolean get() = params.animationInfo != null
143 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val frames: Int get() = params.animationInfo?.framesCount ?: 0
144 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val drop: String get() = params.dropInfo?.itemKey ?: "none"
145 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun hasDrop() = params.dropInfo != null
146 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun toJump() = params.hasCollision && params.collisionMargins.top < 8
147 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun hasCollision() = params.hasCollision
148 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun isBackground() = params.isBackground
149 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun isTransparent() = params.isTransparent
150 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun getTexture() = sprite
153 companion object {
154 private const val LEGACY_ACCESSOR_DEPRECATION = "legacy accessors will be removed"
155 private const val ANIMATION_FRAME_DURATION_MS = 100L