feat: Water breaks grass

This commit is contained in:
Jakub Žitník 2025-03-13 13:24:43 +01:00
parent f9b78f4236
commit 4ef8e217ad
Signed by: jzitnik
GPG Key ID: C577A802A6AF4EF3
8 changed files with 70 additions and 14 deletions

View File

@ -48,7 +48,7 @@ public class Main {
e.printStackTrace(); e.printStackTrace();
} }
if ( game.getWindow() == Window.WORLD) { if (game.getWindow() == Window.WORLD) {
screenRenderer.render(game); screenRenderer.render(game);
} }

View File

@ -0,0 +1,11 @@
package cz.jzitnik.game.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface BreakableByWater {
}

View File

@ -32,7 +32,19 @@ public class Player implements Serializable {
public void fell() { public void fell() {
int damage = Math.max(fallDistance - 3, 0); int damage = Math.max(fallDistance - 3, 0);
health = Math.max(0, health - damage); dealDamage(damage);
fallDistance = 0; fallDistance = 0;
} }
public synchronized void dealDamage(int amount) {
health = Math.max(0, health - amount);
if (health == 0) {
// TODO: Implement dead
}
}
public synchronized void dealDamage() {
dealDamage(1);
}
} }

View File

@ -3,11 +3,13 @@ package cz.jzitnik.game.entities.items.registry.blocks;
import cz.jzitnik.game.SpriteLoader; import cz.jzitnik.game.SpriteLoader;
import cz.jzitnik.game.annotations.BlockDropPercentage; import cz.jzitnik.game.annotations.BlockDropPercentage;
import cz.jzitnik.game.annotations.BlockRegistry; import cz.jzitnik.game.annotations.BlockRegistry;
import cz.jzitnik.game.annotations.BreakableByWater;
import cz.jzitnik.game.annotations.CustomDrop; import cz.jzitnik.game.annotations.CustomDrop;
import cz.jzitnik.game.annotations.PlaceOnSolid; import cz.jzitnik.game.annotations.PlaceOnSolid;
import cz.jzitnik.game.entities.Block; import cz.jzitnik.game.entities.Block;
@PlaceOnSolid @PlaceOnSolid
@BreakableByWater
@CustomDrop(tool = "shears", drops = "grass_bush") @CustomDrop(tool = "shears", drops = "grass_bush")
@BlockDropPercentage(13) @BlockDropPercentage(13)
@BlockRegistry(value = "grass_bush", drops = "wheat_seeds") @BlockRegistry(value = "grass_bush", drops = "wheat_seeds")

View File

@ -34,7 +34,8 @@ public class Generation {
world[terrainHeight[256] - 1][256].add(steveBlock2); world[terrainHeight[256] - 1][256].add(steveBlock2);
world[terrainHeight[256] - 2][256].add(steveBlock); world[terrainHeight[256] - 2][256].add(steveBlock);
game.getInventory().addItem(ItemBlockSupplier.getItem("shears")); game.getInventory().addItem(ItemBlockSupplier.getItem("water_bucket"));
game.getInventory().addItem(ItemBlockSupplier.getItem("lava_bucket"));
} }
private static void initializeWorld(List<Block>[][] world) { private static void initializeWorld(List<Block>[][] world) {

View File

@ -1,6 +1,7 @@
package cz.jzitnik.game.logic.services.flowing; package cz.jzitnik.game.logic.services.flowing;
import cz.jzitnik.game.Game; import cz.jzitnik.game.Game;
import cz.jzitnik.game.annotations.BreakableByWater;
import cz.jzitnik.game.annotations.CustomLogic; import cz.jzitnik.game.annotations.CustomLogic;
import cz.jzitnik.game.entities.Block; import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.entities.items.ItemBlockSupplier; import cz.jzitnik.game.entities.items.ItemBlockSupplier;
@ -67,6 +68,14 @@ public class FlowingLogic implements CustomLogicInterface {
private void flow(List<Block>[][] world, int x, int y, int strength, Set<Point> visited, String liquidId) { private void flow(List<Block>[][] world, int x, int y, int strength, Set<Point> visited, String liquidId) {
if (y + 1 < world.length && canFlowInto(world[y + 1][x])) { if (y + 1 < world.length && canFlowInto(world[y + 1][x])) {
var blocks = world[y + 1][x];
List<Block> remove = new ArrayList<>();
for (Block block : blocks) {
if (block.getClass().isAnnotationPresent(BreakableByWater.class)) {
remove.add(block);
}
}
blocks.removeAll(remove);
Block newLiquid = ItemBlockSupplier.getBlock(liquidId); Block newLiquid = ItemBlockSupplier.getBlock(liquidId);
newLiquid.setSpriteState(Water.WaterState.get(5)); newLiquid.setSpriteState(Water.WaterState.get(5));
((FlowingData) newLiquid.getData()).setSource(false); ((FlowingData) newLiquid.getData()).setSource(false);
@ -94,16 +103,14 @@ public class FlowingLogic implements CustomLogicInterface {
} }
private void transformOrFlow(List<Block>[][] world, int newX, int newY, int strength, Set<Point> visited, String liquidId) { private void transformOrFlow(List<Block>[][] world, int newX, int newY, int strength, Set<Point> visited, String liquidId) {
var targetBlocks = world[newY][newX]; var blocks = world[newY][newX];
boolean hasWater = targetBlocks.stream().anyMatch(b -> b.getBlockId().equals("water")); List<Block> remove = new ArrayList<>();
boolean hasLava = targetBlocks.stream().anyMatch(b -> b.getBlockId().equals("lava")); for (Block block : blocks) {
if (block.getClass().isAnnotationPresent(BreakableByWater.class)) {
if (liquidId.equals("water") && hasLava) { remove.add(block);
return;
} }
if (liquidId.equals("lava") && hasWater) {
return;
} }
blocks.removeAll(remove);
Block newLiquid = ItemBlockSupplier.getBlock(liquidId); Block newLiquid = ItemBlockSupplier.getBlock(liquidId);
newLiquid.setSpriteState(Water.WaterState.get(strength - 1)); newLiquid.setSpriteState(Water.WaterState.get(strength - 1));
@ -114,6 +121,6 @@ public class FlowingLogic implements CustomLogicInterface {
private boolean canFlowInto(List<Block> blocks) { private boolean canFlowInto(List<Block> blocks) {
return blocks.stream().allMatch( return blocks.stream().allMatch(
block -> block.getBlockId().equals("steve") || block.getBlockId().equals("air") || block.isMob() || block.isFlowing()); block -> block.getBlockId().equals("steve") || block.getBlockId().equals("air") || block.isMob() || block.isFlowing() || block.getClass().isAnnotationPresent(BreakableByWater.class));
} }
} }

View File

@ -0,0 +1,23 @@
package cz.jzitnik.game.logic.services.suffocating;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.annotations.CustomLogic;
import cz.jzitnik.game.logic.CustomLogicInterface;
@CustomLogic
public class Suffocating implements CustomLogicInterface {
@Override
public void nextIteration(Game game) {
var world = game.getWorld();
int[] data = game.getPlayerCords();
int x = data[0];
int y = data[1];
var blocks = world[y - 1][x];
if (blocks.stream().anyMatch(i -> !i.isGhost())) {
// Deal damage when solid block
game.getPlayer().dealDamage();
}
}
}

View File

@ -15,7 +15,7 @@ public class NoHungerThread extends Thread {
try { try {
Thread.sleep(3000); Thread.sleep(3000);
if (player.getHunger() == 0) { if (player.getHunger() == 0) {
player.setHealth(player.getHealth() - 1); player.dealDamage();
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
break; break;