From 44b306a3ac4fa0e6192ef2d87042c158c2cf8688 Mon Sep 17 00:00:00 2001 From: fred-boy Date: Tue, 16 Jun 2020 00:49:23 +0700 Subject: [PATCH] Support different block texture sizes and animation --- android/assets/json/game_items.json | 87 ++++++++++++++++--- .../cavedroid/game/GameItems.java | 41 +++++++-- .../cavedroid/game/GameRenderer.java | 4 +- .../cavedroid/game/objects/Block.kt | 84 ++++++++++++++++-- 4 files changed, 189 insertions(+), 27 deletions(-) diff --git a/android/assets/json/game_items.json b/android/assets/json/game_items.json index b3394e6..aa7bb3e 100644 --- a/android/assets/json/game_items.json +++ b/android/assets/json/game_items.json @@ -37,17 +37,20 @@ "background": false, "transparent": true, "fluid": true, - "meta": "water" + "texture": "water_still", + "meta": "water", + "animated": true, + "frames": 16 }, "lava": { "hp": -1, "collision": false, "background": false, "fluid": true, - "animated": true, - "frames": 16, "texture": "lava_still", - "meta": "lava" + "meta": "lava", + "animated": true, + "frames": 16 }, "sand": { "hp": 45 @@ -215,7 +218,8 @@ "stone_slab": { "top": 8, "hp": 600, - "transparent": true + "transparent": true, + "sprite_top": 8 }, "double_stone_slab": { "hp": 600, @@ -267,33 +271,96 @@ "collision": false, "background": false, "transparent": true, - "texture": "water", "fluid": true, - "meta": "water" + "texture": "water_still", + "meta": "water", + "animated": true, + "frames": 16 }, "water_12": { + "top": 4, "hp": -1, "collision": false, "background": false, "transparent": true, "fluid": true, - "meta": "water" + "texture": "water_still", + "meta": "water", + "animated": true, + "frames": 16, + "sprite_top": 4 }, "water_8": { + "top": 8, "hp": -1, "collision": false, "background": false, "transparent": true, "fluid": true, - "meta": "water" + "texture": "water_still", + "meta": "water", + "animated": true, + "frames": 16, + "sprite_top": 8 }, "water_4": { + "top": 12, "hp": -1, "collision": false, "background": false, "transparent": true, "fluid": true, - "meta": "water" + "texture": "water_still", + "meta": "water", + "animated": true, + "frames": 16, + "sprite_top": 12 + }, + "lava_16": { + "hp": -1, + "collision": false, + "background": false, + "fluid": true, + "texture": "lava_still", + "meta": "lava", + "animated": true, + "frames": 16 + }, + "lava_12": { + "top": 4, + "hp": -1, + "collision": false, + "background": false, + "fluid": true, + "texture": "lava_still", + "meta": "lava", + "animated": true, + "frames": 16, + "sprite_top": 4 + }, + "lava_8": { + "top": 8, + "hp": -1, + "collision": false, + "background": false, + "fluid": true, + "texture": "lava_still", + "meta": "lava", + "animated": true, + "frames": 16, + "sprite_top": 8 + }, + "lava_4": { + "top": 12, + "hp": -1, + "collision": false, + "background": false, + "fluid": true, + "texture": "lava_still", + "meta": "lava", + "animated": true, + "frames": 16, + "sprite_top": 12 }, "obsidian": { "hp": 1500 diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameItems.java b/core/src/ru/deadsoftware/cavedroid/game/GameItems.java index 64fba5a..85f4b9c 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/GameItems.java +++ b/core/src/ru/deadsoftware/cavedroid/game/GameItems.java @@ -105,19 +105,46 @@ public class GameItems { int right = Assets.getIntFromJson(block, "right", 0); int top = Assets.getIntFromJson(block, "top", 0); int bottom = Assets.getIntFromJson(block, "bottom", 0); + int clipX = Assets.getIntFromJson(block, "sprite_left", 0); + int clipY = Assets.getIntFromJson(block, "sprite_top", 0); + int clipWidth = Assets.getIntFromJson(block, "sprite_right", 0); + int clipHeight = Assets.getIntFromJson(block, "sprite_bottom", 0); int hp = Assets.getIntFromJson(block, "hp", -1); - boolean coll = Assets.getBooleanFromJson(block, "collision", true); - boolean bg = Assets.getBooleanFromJson(block, "background", false); - boolean tp = Assets.getBooleanFromJson(block, "transparent", false); - boolean br = Assets.getBooleanFromJson(block, "block_required", false); + boolean collision = Assets.getBooleanFromJson(block, "collision", true); + boolean background = Assets.getBooleanFromJson(block, "background", false); + boolean transparent = Assets.getBooleanFromJson(block, "transparent", false); + boolean requiresBlock = Assets.getBooleanFromJson(block, "block_required", false); boolean fluid = Assets.getBooleanFromJson(block, "fluid", false); String drop = Assets.getStringFromJson(block, "drop", key); String meta = Assets.getStringFromJson(block, "meta", ""); String tex = Assets.getStringFromJson(block, "texture", key); - Sprite sprite = tex.equals("none") ? null : - new Sprite(new Texture(Gdx.files.internal("textures/blocks/" + tex + ".png"))); + Texture texture = tex.equals("none") ? null : + new Texture(Gdx.files.internal("textures/blocks/" + tex + ".png")); + boolean animated = Assets.getBooleanFromJson(block, "animated", false); + int frames = Assets.getIntFromJson(block, "frames", 0); + + Block newBlock = new Block( + left, + top, + right, + bottom, + hp, + drop, + collision, + background, + transparent, + requiresBlock, + fluid, + meta, + texture, + animated, + frames, + clipX, + clipY, + clipWidth, + clipHeight + ); - Block newBlock = new Block(left, top, right, bottom, hp, drop, coll, bg, tp, br, fluid, meta, sprite); blocksIds.put(key, blocks.size); blocks.put(key, newBlock); } catch (GdxRuntimeException e) { diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java b/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java index 864938d..19f2681 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java +++ b/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java @@ -67,14 +67,14 @@ public class GameRenderer extends Renderer { if (drawBG) { if ((!mGameWorld.hasForeAt(x, y) || mGameWorld.getForeMapBlock(x, y).isTransparent()) && mGameWorld.hasBackAt(x, y)) { - spriter.draw(mGameWorld.getBackMapBlock(x, y).getTexture(), drawX(x), drawY(y)); + mGameWorld.getBackMapBlock(x, y).draw(spriter, drawX(x), drawY(y)); if (!mGameWorld.hasForeAt(x, y) && x == mGameInput.getCurX() && y == mGameInput.getCurY()) { drawWreck(mGameWorld.getBackMap(mGameInput.getCurX(), mGameInput.getCurY())); } } } if (mGameWorld.hasForeAt(x, y) && mGameWorld.getForeMapBlock(x, y).isBackground() == drawBG) { - spriter.draw(mGameWorld.getForeMapBlock(x, y).getTexture(), drawX(x), drawY(y)); + mGameWorld.getForeMapBlock(x, y).draw(spriter, drawX(x), drawY(y)); if (x == mGameInput.getCurX() && y == mGameInput.getCurY()) { drawWreck(mGameWorld.getForeMap(mGameInput.getCurX(), mGameInput.getCurY())); } diff --git a/core/src/ru/deadsoftware/cavedroid/game/objects/Block.kt b/core/src/ru/deadsoftware/cavedroid/game/objects/Block.kt index e8ed1e7..d44f017 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/objects/Block.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/objects/Block.kt @@ -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 + 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 -- 2.29.2