DEADSOFTWARE

Support different block texture sizes and animation
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / objects / Block.kt
index e8ed1e752cd33e1990bd6c08a0dc12345bab5248..d44f017e0647016afb767fba663815f63a699063 100644 (file)
@@ -2,9 +2,12 @@
 
 package ru.deadsoftware.cavedroid.game.objects
 
+import com.badlogic.gdx.graphics.Texture
 import com.badlogic.gdx.graphics.g2d.Sprite
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
 import com.badlogic.gdx.math.Rectangle
 
+private const val ANIMATION_FRAME_DURATION = 100L
 private const val DEPRECATION_MESSAGE =
         "Deprecated since moved to Kotlin. Use generated getter or kotlin property access."
 
@@ -21,7 +24,13 @@ private const val DEPRECATION_MESSAGE =
  * @param requiresBlock true if block should break when there is no block with collision under it
  * @param fluid         true if fluid
  * @param meta          extra info for storing
- * @param sprite        block's texture
+ * @param texture       block's texture
+ * @param animated      indicates if block has animation
+ * @param frames        number of animation frames. ignored if animated is false
+ * @param spriteLeft    block's sprite x on texture
+ * @param spriteTop     block's sprite y on texture
+ * @param spriteRight   block's sprite right edge on texture
+ * @param spriteBottom  block's sprite bottom on texture
  */
 data class Block(
         val left: Int,
@@ -36,21 +45,80 @@ data class Block(
         val requiresBlock: Boolean,
         val fluid: Boolean,
         val meta: String,
-        val sprite: Sprite?
+        private val texture: Texture?,
+        val animated: Boolean,
+        val frames: Int,
+        private val spriteLeft: Int,
+        private val spriteTop: Int,
+        private val spriteRight: Int,
+        private val spriteBottom: Int
 ) {
 
+    val width = 16 - right - left
+    val height = 16 - top - bottom
+
+    private val spriteWidth = 16 - spriteLeft - spriteRight
+    private val spriteHeight = 16 - spriteTop - spriteBottom
+
+    private val sprite: Sprite?
+        get() {
+            return if (animated) {
+                animation[currentFrame()]
+            } else {
+                field
+            }
+        }
+
+
+    private val animation: Array<Sprite>
+
     init {
-        sprite?.flip(false, true)
+        if (frames !in 0..Int.MAX_VALUE) {
+            throw IllegalArgumentException("Animation frames must be in range [0, ${Int.MAX_VALUE}]")
+        }
+
+        animation = if (animated) {
+            if (texture == null) {
+                throw IllegalArgumentException("Cannot derive animation frames from null sprite")
+            }
+            Array(frames) { y ->
+                Sprite(texture, spriteLeft, 16 * y + spriteTop, spriteWidth, spriteHeight).apply {
+                    flip(false, true)
+                }
+            }
+        } else {
+            emptyArray()
+        }
+
+        sprite = if (animated) { animation[0] } else {
+            if (texture != null) {
+                Sprite(texture, spriteLeft, spriteTop, spriteWidth, spriteHeight).apply {
+                    flip(false, true)
+                }
+            } else {
+                null
+            }
+        }
     }
 
-    val width = 16 - right - left
-    val height = 16 - top - bottom
+    private fun currentFrame() = if (animated) {
+        ((System.currentTimeMillis() / ANIMATION_FRAME_DURATION) % frames).toInt()
+    } else {
+        0
+    }
+
+    fun requireSprite() = sprite ?: throw IllegalStateException("Sprite is null")
+
+    fun draw(spriter: SpriteBatch, x: Float, y: Float) {
+        requireSprite().apply {
+            setBounds(x + spriteLeft, y + spriteTop, spriteWidth.toFloat(), spriteHeight.toFloat())
+            draw(spriter)
+        }
+    }
 
     fun getRectangle(x: Int, y: Int) =
             Rectangle(x * 16f + left, y * 16f + this.top, width.toFloat(), height.toFloat())
 
-    fun requireSprite() = sprite ?: throw IllegalStateException("Sprite is null")
-
     fun hasDrop() = drop != "none"
 
     fun toJump() = top < 8 && collision
@@ -70,7 +138,7 @@ data class Block(
     @Deprecated(DEPRECATION_MESSAGE)
     fun requiresBlock() = requiresBlock
 
-    @Deprecated("Was renamed to Sprite to comply with variable type.", ReplaceWith("getSprite()"))
+    @Deprecated("Was renamed to Sprite to comply with variable type.", ReplaceWith("requireSprite()"))
     fun getTexture() = sprite
 
 }
\ No newline at end of file