From f42029ab3edd3d0f04ebf1910cef834abb16ed0b Mon Sep 17 00:00:00 2001 From: fredboy Date: Sun, 12 May 2024 23:46:18 +0700 Subject: [PATCH] Add mobs damage and initial spawn --- .../cavedroid/game/GamePhysics.java | 4 +- .../actions/useitem/UsePigSpawnEggAction.kt | 4 +- .../cavedroid/game/mobs/FallingGravel.java | 7 ++- .../cavedroid/game/mobs/FallingSand.java | 7 ++- .../deadsoftware/cavedroid/game/mobs/Mob.java | 49 ++++++++++++++++++- .../deadsoftware/cavedroid/game/mobs/Pig.kt | 28 +++++++---- .../cavedroid/game/mobs/player/Player.java | 40 ++++++++++++++- .../cavedroid/game/world/GameWorld.java | 23 ++++++++- .../world/GameWorldMobDamageControllerTask.kt | 5 +- .../cavedroid/misc/utils/SpriteUtils.kt | 7 +++ 10 files changed, 155 insertions(+), 19 deletions(-) diff --git a/core/src/ru/deadsoftware/cavedroid/game/GamePhysics.java b/core/src/ru/deadsoftware/cavedroid/game/GamePhysics.java index d9bf21f..cb5b37e 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/GamePhysics.java +++ b/core/src/ru/deadsoftware/cavedroid/game/GamePhysics.java @@ -354,7 +354,7 @@ public class GamePhysics { for (Iterator it = mMobsController.getMobs().iterator(); it.hasNext(); ) { Mob mob = it.next(); - mob.ai(mGameWorld, mGameItemsHolder, delta); + mob.ai(mGameWorld, mGameItemsHolder, mMobsController, delta); mobPhy(mob, delta); if (mob.isDead()) { it.remove(); @@ -362,7 +362,7 @@ public class GamePhysics { } playerPhy(player, delta); - player.ai(mGameWorld, mGameItemsHolder, delta); + player.ai(mGameWorld, mGameItemsHolder, mMobsController, delta); if (player.isDead()) { player.respawn(mGameWorld, mGameItemsHolder); } diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UsePigSpawnEggAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UsePigSpawnEggAction.kt index 0c50d15..6c0c3ba 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UsePigSpawnEggAction.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UsePigSpawnEggAction.kt @@ -1,5 +1,6 @@ package ru.deadsoftware.cavedroid.game.actions.useitem +import ru.deadsoftware.cavedroid.game.GameItemsHolder import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.mobs.Pig @@ -10,6 +11,7 @@ import javax.inject.Inject @GameScope class UsePigSpawnEggAction @Inject constructor( private val mobsController: MobsController, + private val gameItemsHolder: GameItemsHolder, ) : IUseItemAction { override fun perform(item: Item.Usable, x: Int, y: Int) { @@ -18,7 +20,7 @@ class UsePigSpawnEggAction @Inject constructor( attachToController(mobsController) } - mobsController.player.inventory.decreaseCurrentItemAmount() + mobsController.player.decreaseCurrentItemCount(gameItemsHolder) } companion object { diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingGravel.java b/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingGravel.java index 641ffe5..2ad4287 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingGravel.java +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingGravel.java @@ -40,7 +40,7 @@ public class FallingGravel extends Mob { } @Override - public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, float delta) { + public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, MobsController mobsController, float delta) { if (mVelocity.isZero()) { gameWorld.setForeMap(getMapX(), getUpperMapY(), gameItemsHolder.getBlock("gravel")); kill(); @@ -51,6 +51,11 @@ public class FallingGravel extends Mob { public void changeDir() { } + @Override + public void damage(int damage) { + // no-op + } + @Override public void draw(SpriteBatch spriteBatch, float x, float y, float delta) { @CheckForNull final Texture texture = Assets.blockTextures.get("gravel"); diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingSand.java b/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingSand.java index f41da96..970ff53 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingSand.java +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingSand.java @@ -41,7 +41,7 @@ public class FallingSand extends Mob { } @Override - public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, float delta) { + public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, MobsController mobsController, float delta) { if (mVelocity.isZero()) { gameWorld.setForeMap(getMapX(), getUpperMapY(), gameItemsHolder.getBlock("sand")); kill(); @@ -52,6 +52,11 @@ public class FallingSand extends Mob { public void changeDir() { } + @Override + public void damage(int damage) { + // no-op + } + @Override public void draw(SpriteBatch spriteBatch, float x, float y, float delta) { @CheckForNull final Texture texture = Assets.blockTextures.get("sand"); diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/Mob.java b/core/src/ru/deadsoftware/cavedroid/game/mobs/Mob.java index fc9d61b..62ddc50 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/Mob.java +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/Mob.java @@ -1,13 +1,16 @@ package ru.deadsoftware.cavedroid.game.mobs; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Timer; import ru.deadsoftware.cavedroid.game.GameItemsHolder; import ru.deadsoftware.cavedroid.game.world.GameWorld; +import javax.annotation.CheckForNull; import java.io.Serializable; /** @@ -15,6 +18,11 @@ import java.io.Serializable; */ public abstract class Mob extends Rectangle implements Serializable { + private static final float DAMAGE_TINT_TIMEOUT_S = 0.5f; + private static final Color DAMAGE_TINT_COLOR = new Color(0xff8080ff); + + private static final float HIT_RANGE = 8f; + protected static int ANIMATION_SPEED = 360; public enum Type { @@ -51,6 +59,14 @@ public abstract class Mob extends Rectangle implements Serializable { } } + private class ResetTakeDamageTask extends Timer.Task { + + @Override + public void run() { + mTakingDamage = false; + } + } + protected Vector2 mVelocity; protected Type mType; protected int mAnimDelta = ANIMATION_SPEED; @@ -64,6 +80,9 @@ public abstract class Mob extends Rectangle implements Serializable { private final int mMaxHealth; private int mHealth; + private transient boolean mTakingDamage = false; + @CheckForNull private transient ResetTakeDamageTask mResetTakeDamageTask = null; + /** * @param x in pixels * @param y in pixels @@ -261,6 +280,8 @@ public abstract class Mob extends Rectangle implements Serializable { mHealth -= damage; checkHealth(); + + setTakingDamage(true); } public void heal(int heal) { @@ -277,9 +298,35 @@ public abstract class Mob extends Rectangle implements Serializable { checkHealth(); } + public Rectangle getHitBox() { + return new Rectangle(x - HIT_RANGE, y - HIT_RANGE, width + HIT_RANGE, height + HIT_RANGE); + } + + public boolean isTakingDamage() { + return mTakingDamage; + } + + public void setTakingDamage(boolean takingDamage) { + mTakingDamage = takingDamage; + + if (takingDamage) { + if (mResetTakeDamageTask != null && mResetTakeDamageTask.isScheduled()) { + mResetTakeDamageTask.cancel(); + } else if (mResetTakeDamageTask == null) { + mResetTakeDamageTask = new ResetTakeDamageTask(); + } + + Timer.schedule(mResetTakeDamageTask, DAMAGE_TINT_TIMEOUT_S); + } + } + + protected Color getTintColor() { + return isTakingDamage() ? DAMAGE_TINT_COLOR : Color.WHITE; + } + public abstract void draw(SpriteBatch spriteBatch, float x, float y, float delta); - public abstract void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, float delta); + public abstract void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, MobsController mobsController, float delta); public abstract void changeDir(); diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/Pig.kt b/core/src/ru/deadsoftware/cavedroid/game/mobs/Pig.kt index b55f429..68c457e 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/Pig.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/Pig.kt @@ -27,8 +27,18 @@ class Pig(x: Float, y: Float) : Mob(x, y, WIDTH, HEIGHT, randomDir(), Type.MOB, override fun jump() { velocity.y = JUMP_VELOCITY } - - override fun ai(world: GameWorld, gameItemsHolder: GameItemsHolder, delta: Float) { + + override fun damage(damage: Int) { + super.damage(damage) + + if (damage > 0) { + if (canJump()) { + jump() + } + } + } + + override fun ai(world: GameWorld, gameItemsHolder: GameItemsHolder, mobsController: MobsController, delta: Float) { if (MathUtils.randomBoolean(delta)) { if (velocity.x != 0f) { velocity.x = 0f @@ -45,19 +55,19 @@ class Pig(x: Float, y: Float) : Mob(x, y, WIDTH, HEIGHT, randomDir(), Type.MOB, val rightLegX = x + getRightLegRelativeX(direction) val legY = y + getLegsRelativeY() - spriteBatch.drawSprite(getBackgroundLeg(), leftLegX, legY, -anim) - spriteBatch.drawSprite(getBackgroundLeg(), rightLegX, legY, -anim) - spriteBatch.drawSprite(getBody(direction), x, y) - spriteBatch.drawSprite(getForegroundLeg(), leftLegX, legY, anim) - spriteBatch.drawSprite(getForegroundLeg(), rightLegX, legY, anim) + spriteBatch.drawSprite(getBackgroundLeg(), leftLegX, legY, -anim, tint = tintColor) + spriteBatch.drawSprite(getBackgroundLeg(), rightLegX, legY, -anim, tint = tintColor) + spriteBatch.drawSprite(getBody(direction), x, y, tint = tintColor) + spriteBatch.drawSprite(getForegroundLeg(), leftLegX, legY, anim, tint = tintColor) + spriteBatch.drawSprite(getForegroundLeg(), rightLegX, legY, anim, tint = tintColor) } private companion object { private const val WIDTH = 25f private const val HEIGHT = 18f - private const val SPEED = 69.072f + private const val SPEED = 48f private const val JUMP_VELOCITY = -133.332f - private const val MAX_HEALTH = 10; + private const val MAX_HEALTH = 10 } } \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/player/Player.java b/core/src/ru/deadsoftware/cavedroid/game/mobs/player/Player.java index 40b7c79..8ea87c1 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/player/Player.java +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/player/Player.java @@ -6,6 +6,7 @@ import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import ru.deadsoftware.cavedroid.game.GameItemsHolder; import ru.deadsoftware.cavedroid.game.mobs.Mob; +import ru.deadsoftware.cavedroid.game.mobs.MobsController; import ru.deadsoftware.cavedroid.game.model.block.Block; import ru.deadsoftware.cavedroid.game.model.item.InventoryItem; import ru.deadsoftware.cavedroid.game.model.item.Item; @@ -151,6 +152,29 @@ public class Player extends Mob { return !block.isNone() && block.getParams().getHitPoints() >= 0; } + /** + * @return true if any mob fas hit + */ + private boolean hitMobs(GameItemsHolder gameItemsHolder, MobsController mobsController) { + if (!hitting || !hittingWithDamage) { + return false; + } + + boolean result = false; + for (Mob mob : mobsController.getMobs()) { + if (overlaps(mob.getHitBox())) { + final Item activeItem = inventory.getActiveItem().getItem(); + final Item.Tool tool = activeItem.isTool() ? (Item.Tool) activeItem : null; + if (tool != null) { + decreaseCurrentItemCount(gameItemsHolder); + } + result = true; + mob.damage(MathUtils.floor(tool != null ? tool.getMobDamageMultiplier() : 1)); + } + } + return result; + } + private void hitBlock(GameWorld gameWorld, GameItemsHolder gameItemsHolder) { if (!hitting || !hittingWithDamage) { return; @@ -188,9 +212,14 @@ public class Player extends Mob { } @Override - public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, float delta) { + public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, MobsController mobsController, float delta) { updateAnimation(delta); - hitBlock(gameWorld, gameItemsHolder); + + if (!hitMobs(gameItemsHolder, mobsController)) { + hitBlock(gameWorld, gameItemsHolder); + } else { + stopHitting(); + } if (gameMode == 1) { return; @@ -385,6 +414,13 @@ public class Player extends Mob { frontHandAnim = -rightHandAnim; } + backHand.setColor(getTintColor()); + backLeg.setColor(getTintColor()); + frontLeg.setColor(getTintColor()); + head.setColor(getTintColor()); + body.setColor(getTintColor()); + frontHand.setColor(getTintColor()); + SpriteUtilsKt.drawSprite(spriteBatch, backHand, x + 2, y + 8, backHandAnim); if (looksLeft()) { diff --git a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorld.java b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorld.java index d52b50f..05a7d5f 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorld.java +++ b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorld.java @@ -1,9 +1,11 @@ package ru.deadsoftware.cavedroid.game.world; +import com.badlogic.gdx.math.MathUtils; import kotlin.Pair; import ru.deadsoftware.cavedroid.game.GameItemsHolder; import ru.deadsoftware.cavedroid.game.GameScope; import ru.deadsoftware.cavedroid.game.mobs.MobsController; +import ru.deadsoftware.cavedroid.game.mobs.Pig; import ru.deadsoftware.cavedroid.game.model.block.Block; import ru.deadsoftware.cavedroid.game.model.item.InventoryItem; import ru.deadsoftware.cavedroid.game.model.item.Item; @@ -55,6 +57,7 @@ public class GameWorld { Pair maps = new GameWorldGenerator(mWorldConfig, mGameItemsHolder).generate(); mForeMap = maps.getFirst(); mBackMap = maps.getSecond(); + spawnInitialMobs(); mMobsController.getPlayer().respawn(this, mGameItemsHolder); } else { mForeMap = foreMap; @@ -223,10 +226,25 @@ public class GameWorld { return toolLevel >= block.getParams().getToolLevel(); } + private void spawnInitialMobs() { + for (int x = 0; x < getWidth(); x++) { + int y = 0; + while (y < getWorldConfig().getSeaLevel()) { + if (getForeMap(x, y) == mGameItemsHolder.getBlock("grass")) { + if (MathUtils.randomBoolean(.125f)) { + mMobsController.addMob(new Pig(MeasureUnitsUtilsKt.getPx(x), MeasureUnitsUtilsKt.getPx(y))); + } + break; + } + y++; + } + } + } + public void destroyForeMap(int x, int y) { Block block = getForeMap(x, y); if (block.isContainer()) { - mContainerController.destroyContainer(x, y, FOREGROUND_Z); + mContainerController.destroyContainer(x, y, FOREGROUND_Z, true); } if (block.hasDrop() && shouldDrop(block)) { for (int i = 0; i < block.getParams().getDropInfo().getCount(); i++) { @@ -243,6 +261,9 @@ public class GameWorld { public void destroyBackMap(int x, int y) { Block block = getBackMap(x, y); + if (block.isContainer()) { + mContainerController.destroyContainer(x, y, BACKGROUND_Z, true); + } if (block.hasDrop() && shouldDrop(block)) { for (int i = 0; i < block.getParams().getDropInfo().getCount(); i++) { mDropController.addDrop(transformX(x) * 16 + 4, y * 16 + 4, mGameItemsHolder.getItem(block.getDrop())); diff --git a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldMobDamageControllerTask.kt b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldMobDamageControllerTask.kt index 8dc39b9..f016c67 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldMobDamageControllerTask.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldMobDamageControllerTask.kt @@ -24,7 +24,10 @@ class GameWorldMobDamageControllerTask @Inject constructor( val foregroundBlock = gameWorld.getForeMap(x, y) val backgroundBlock = gameWorld.getBackMap(x, y) - mob.damage(max(foregroundBlock.params.damage, backgroundBlock.params.damage)) + val damage = max(foregroundBlock.params.damage, backgroundBlock.params.damage) + if (damage > 0) { + mob.damage(damage) + } } } diff --git a/core/src/ru/deadsoftware/cavedroid/misc/utils/SpriteUtils.kt b/core/src/ru/deadsoftware/cavedroid/misc/utils/SpriteUtils.kt index 7b75e38..a26c5b9 100644 --- a/core/src/ru/deadsoftware/cavedroid/misc/utils/SpriteUtils.kt +++ b/core/src/ru/deadsoftware/cavedroid/misc/utils/SpriteUtils.kt @@ -1,5 +1,6 @@ package ru.deadsoftware.cavedroid.misc.utils +import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.g2d.Sprite import com.badlogic.gdx.graphics.g2d.SpriteBatch @@ -14,14 +15,20 @@ fun SpriteBatch.drawSprite( rotation: Float = 0f, width: Float = sprite.regionWidth.toFloat(), height: Float = sprite.regionHeight.toFloat(), + tint: Color? = null, ) { + val oldColor = sprite.color + sprite.setPosition(x, y) sprite.setSize(width, height) sprite.rotation = rotation + tint?.let(sprite::setColor) + sprite.draw(this) sprite.setSize(sprite.regionWidth.toFloat(), sprite.regionHeight.toFloat()) sprite.rotation = 0f + sprite.color = oldColor } fun Sprite.applyOrigin(origin: SpriteOrigin) { -- 2.29.2