feat: Hurt animation and killing of zombie

This commit is contained in:
2025-09-22 15:29:58 +02:00
parent 32cb96dd49
commit 5d57d8e069
9 changed files with 99 additions and 63 deletions

View File

@ -57,7 +57,9 @@ public class Game {
private transient GameStates gameStates = new GameStates(this); private transient GameStates gameStates = new GameStates(this);
private Stats stats = new Stats(); private Stats stats = new Stats();
/** Current time of day in the game (0600 range). */ /**
* Current time of day in the game (0600 range).
*/
@Setter @Setter
private int daytime = 0; private int daytime = 0;
// //
@ -208,12 +210,16 @@ public class Game {
int dealDamage = inventory.getItemInHand().map(Item::getDealDamage).orElse(1); int dealDamage = inventory.getItemInHand().map(Item::getDealDamage).orElse(1);
if (mob.getHp() - dealDamage <= 0) { if (mob.getHp() - dealDamage <= 0) {
// Mob is killed // Mob is killed
gameStates.dependencies.entityKill.get(mob.getBlockId()).killed(this, mob); gameStates.dependencies.entityKill.get(mob.getBlockId()).killed(this, mob, x, y);
world[y][x].remove(mob); world[y][x].remove(mob);
} else { } else {
mob.decreaseHp(dealDamage); mob.decreaseHp(dealDamage);
mob.setSpriteState(gameStates.dependencies.entityHurtAnimation.get(mob.getBlockId()) mob.setSpriteState(gameStates.dependencies.entityHurtAnimation.get(mob.getBlockId())
.setHurtAnimation(true, mob.getSpriteState().get())); .setHurtAnimation(true, mob.getSpriteState().get()));
if (mob.getLinkedMobTexture() != null) {
mob.getLinkedMobTexture().setSpriteState(gameStates.dependencies.entityHurtAnimation.get(mob.getBlockId())
.setHurtAnimation(true, mob.getLinkedMobTexture().getSpriteState().get()));
}
} }
} }
screenRenderer.render(this); screenRenderer.render(this);
@ -228,6 +234,11 @@ public class Game {
for (Block mob : mobs) { for (Block mob : mobs) {
mob.setSpriteState(gameStates.dependencies.entityHurtAnimation.get(mob.getBlockId()) mob.setSpriteState(gameStates.dependencies.entityHurtAnimation.get(mob.getBlockId())
.setHurtAnimation(false, mob.getSpriteState().get())); .setHurtAnimation(false, mob.getSpriteState().get()));
if (mob.getLinkedMobTexture() != null) {
mob.getLinkedMobTexture().setSpriteState(gameStates.dependencies.entityHurtAnimation.get(mob.getBlockId())
.setHurtAnimation(false, mob.getLinkedMobTexture().getSpriteState().get()));
}
} }
screenRenderer.render(this); screenRenderer.render(this);
}).start(); }).start();

View File

@ -32,6 +32,7 @@ public class Block {
private boolean onFire = false; private boolean onFire = false;
private int burningTime = 0; private int burningTime = 0;
private int burningTime2 = 0; private int burningTime2 = 0;
private Block linkedMobTexture;
public Block(String blockId, SpriteLoader.SPRITES sprite) { public Block(String blockId, SpriteLoader.SPRITES sprite) {
this.blockId = blockId; this.blockId = blockId;

View File

@ -4,5 +4,5 @@ import cz.jzitnik.game.Game;
import cz.jzitnik.game.entities.Block; import cz.jzitnik.game.entities.Block;
public interface EntityKillInterface { public interface EntityKillInterface {
void killed(Game game, Block mob); void killed(Game game, Block mob, int x, int y);
} }

View File

@ -199,7 +199,7 @@ public class CowLogic
} }
@Override @Override
public void killed(Game game, Block mob) { public void killed(Game game, Block mob, int x, int y) {
int leatherAmount = random.nextInt(3); int leatherAmount = random.nextInt(3);
InventoryItem inventoryItem = new InventoryItem(leatherAmount, ItemBlockSupplier.getItem("leather")); InventoryItem inventoryItem = new InventoryItem(leatherAmount, ItemBlockSupplier.getItem("leather"));
int beefAmount = random.nextInt(3) + 1; int beefAmount = random.nextInt(3) + 1;

View File

@ -199,7 +199,7 @@ public class PigLogic
} }
@Override @Override
public void killed(Game game, Block mob) { public void killed(Game game, Block mob, int x, int y) {
int amount = random.nextInt(2) + 1; int amount = random.nextInt(2) + 1;
InventoryItem inventoryItem = new InventoryItem(amount, ItemBlockSupplier.getItem("porkchop")); InventoryItem inventoryItem = new InventoryItem(amount, ItemBlockSupplier.getItem("porkchop"));
game.getInventory().addItem(inventoryItem); game.getInventory().addItem(inventoryItem);

View File

@ -242,7 +242,7 @@ public class SheepLogic
} }
@Override @Override
public void killed(Game game, Block mob) { public void killed(Game game, Block mob, int x, int y) {
int amount = random.nextInt(3) + 1; int amount = random.nextInt(3) + 1;
var sheepData = (SheepData) mob.getData(); var sheepData = (SheepData) mob.getData();

View File

@ -0,0 +1,49 @@
package cz.jzitnik.game.mobs.services.zombie;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.annotations.EntityHurtAnimationHandler;
import cz.jzitnik.game.annotations.EntityKillHandler;
import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.mobs.*;
import cz.jzitnik.game.sprites.Zombie;
import java.util.*;
import static cz.jzitnik.game.sprites.Zombie.ZombieState.*;
@EntityHurtAnimationHandler("zombie")
@EntityKillHandler("zombie")
public class ZombieHurtKillLogic implements EntityHurtAnimationChanger, EntityKillInterface {
private final Random random = new Random();
public Zombie.ZombieState setHurtAnimation(boolean hurt, Enum current) {
if (hurt) {
return switch (current) {
case TOP, TOP_HURT -> TOP_HURT;
case BOTTOM, BOTTOM_HURT -> BOTTOM_HURT;
default -> throw new IllegalStateException("Unexpected state: " + current);
};
}
return switch (current) {
case TOP, TOP_HURT -> TOP;
case BOTTOM, BOTTOM_HURT -> BOTTOM;
default -> throw new IllegalStateException("Unexpected state: " + current);
};
}
@Override
public void killed(Game game, Block mob, int x, int y) {
int rottenFlesh = random.nextInt(3) + 1;
boolean isTop = mob.getSpriteState().isPresent() && (mob.getSpriteState().get().equals(TOP_HURT) || mob.getSpriteState().get().equals(TOP));
int newY = isTop ? y + 1 : y - 1;
game.getWorld()[newY][x].remove(mob.getLinkedMobTexture());
// Rotten flesh is currently not an item. So this is commented out
// TODO: Add rotten flesh to the game
//InventoryItem drop = new InventoryItem(rottenFlesh, ItemBlockSupplier.getItem("rotten_flesh"));
//game.getInventory().addItem(drop);
}
}

View File

@ -0,0 +1,13 @@
package cz.jzitnik.game.mobs.services.zombie;
import cz.jzitnik.game.annotations.EntityLogic;
import cz.jzitnik.game.mobs.EntityLogicInterface;
import cz.jzitnik.game.mobs.EntityLogicProvider;
@EntityLogic("zombie")
public class ZombieMoveLogic implements EntityLogicInterface {
@Override
public void nextIteration(EntityLogicProvider.EntityLogicMobDTO entityLogicMobDTO) {
}
}

View File

@ -1,49 +1,30 @@
package cz.jzitnik.game.mobs.services.zombie; package cz.jzitnik.game.mobs.services.zombie;
import cz.jzitnik.game.Game; import cz.jzitnik.game.Game;
import cz.jzitnik.game.annotations.EntityHurtAnimationHandler;
import cz.jzitnik.game.annotations.EntityKillHandler;
import cz.jzitnik.game.annotations.EntityLogic;
import cz.jzitnik.game.annotations.EntitySpawn; import cz.jzitnik.game.annotations.EntitySpawn;
import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.entities.items.InventoryItem;
import cz.jzitnik.game.entities.items.ItemBlockSupplier; import cz.jzitnik.game.entities.items.ItemBlockSupplier;
import cz.jzitnik.game.mobs.*; import cz.jzitnik.game.mobs.EntitySpawnInterface;
import cz.jzitnik.game.sprites.Zombie; import cz.jzitnik.game.sprites.Zombie;
import cz.jzitnik.game.sprites.Zombie.ZombieState;
import cz.jzitnik.tui.ScreenMovingCalculationProvider; import cz.jzitnik.tui.ScreenMovingCalculationProvider;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jline.terminal.Terminal; import org.jline.terminal.Terminal;
import java.util.*; import java.util.*;
import static cz.jzitnik.game.sprites.Zombie.ZombieState.*;
@Slf4j
@EntitySpawn @EntitySpawn
@EntityLogic("zombie") public class ZombieSpawnLogic implements EntitySpawnInterface {
@EntityHurtAnimationHandler("zombie")
@EntityKillHandler("zombie")
public class ZombieLogic
implements EntityLogicInterface, EntitySpawnInterface, EntityHurtAnimationChanger, EntityKillInterface {
private final Random random = new Random(); private final Random random = new Random();
@Override
public void nextIteration(EntityLogicProvider.EntityLogicMobDTO entityLogicMobDTO) {
log.debug("Running zombie logic");
}
@Override @Override
public void spawn(int playerX, int playerY, Game game, Terminal terminal) { public void spawn(int playerX, int playerY, Game game, Terminal terminal) {
int[] view = ScreenMovingCalculationProvider.calculate(playerX, playerY, terminal.getHeight(), terminal.getWidth(), game.getWorld()[0].length, game.getWorld().length); int[] view = ScreenMovingCalculationProvider.calculate(playerX, playerY, terminal.getHeight(), terminal.getWidth(), game.getWorld()[0].length, game.getWorld().length);
int startX = view[0]; int startX = view[0];
int endX = view[1]; int endX = view[1];
//attemptZombieSpawn(startX - 20, startX - 5, playerY, game); attemptZombieSpawn(startX - 20, startX - 5, playerY, game);
//attemptZombieSpawn(endX + 5, endX + 20, playerY, game); attemptZombieSpawn(endX + 5, endX + 20, playerY, game);
} }
private void attemptZombieSpawn(int startX, int endX, int centerY, Game game) { private void attemptZombieSpawn(int startX, int endX, int centerY, Game game) {
if (countZombies(startX, endX, centerY - 15, centerY + 15, game) < 3 && random.nextInt(100) < 2) { if (countZombies(startX, endX, centerY - 15, centerY + 15, game) < 3 && random.nextInt(100) < 2) {
var spawnLocations = zombieCanSpawn(startX, endX, centerY, game); var spawnLocations = zombieCanSpawn(startX, endX, centerY, game);
@ -54,10 +35,13 @@ public class ZombieLogic
int y = loc.getValue(); int y = loc.getValue();
var top = ItemBlockSupplier.getEntity("zombie"); var top = ItemBlockSupplier.getEntity("zombie");
top.setSpriteState(ZombieState.TOP); top.setSpriteState(Zombie.ZombieState.TOP);
var bottom = ItemBlockSupplier.getEntity("zombie"); var bottom = ItemBlockSupplier.getEntity("zombie");
bottom.setSpriteState(ZombieState.BOTTOM); bottom.setSpriteState(Zombie.ZombieState.BOTTOM);
top.setLinkedMobTexture(bottom);
bottom.setLinkedMobTexture(top);
game.getWorld()[y - 1][x].add(top); game.getWorld()[y - 1][x].add(top);
game.getWorld()[y][x].add(bottom); game.getWorld()[y][x].add(bottom);
@ -66,6 +50,7 @@ public class ZombieLogic
} }
} }
private HashMap<Integer, Integer> zombieCanSpawn(int startX, int endX, int playerY, Game game) { private HashMap<Integer, Integer> zombieCanSpawn(int startX, int endX, int playerY, Game game) {
var map = new HashMap<Integer, Integer>(); var map = new HashMap<Integer, Integer>();
var world = game.getWorld(); var world = game.getWorld();
@ -89,29 +74,6 @@ public class ZombieLogic
return count / 2; // Each zombie has two parts return count / 2; // Each zombie has two parts
} }
public Zombie.ZombieState setHurtAnimation(boolean hurt, Enum current) {
if (hurt) {
return switch (current) {
case TOP, TOP_HURT -> TOP_HURT;
case BOTTOM, BOTTOM_HURT -> BOTTOM_HURT;
default -> throw new IllegalStateException("Unexpected state: " + current);
};
}
return switch (current) {
case TOP, TOP_HURT -> TOP;
case BOTTOM, BOTTOM_HURT -> BOTTOM;
default -> throw new IllegalStateException("Unexpected state: " + current);
};
}
@Override
public void killed(Game game, Block mob) {
int rottenFlesh = random.nextInt(3) + 1;
//InventoryItem drop = new InventoryItem(rottenFlesh, ItemBlockSupplier.getItem("rotten_flesh"));
//game.getInventory().addItem(drop);
}
public static <K, V> Map.Entry<K, V> getRandomEntry(HashMap<K, V> map) { public static <K, V> Map.Entry<K, V> getRandomEntry(HashMap<K, V> map) {
List<Map.Entry<K, V>> list = new ArrayList<>(map.entrySet()); List<Map.Entry<K, V>> list = new ArrayList<>(map.entrySet());
return list.get(new Random().nextInt(list.size())); return list.get(new Random().nextInt(list.size()));