feat: Implemented sapling growing

This commit is contained in:
Jakub Žitník 2025-03-08 11:31:31 +01:00
parent bc7480459a
commit 13e2a74b37
Signed by: jzitnik
GPG Key ID: C577A802A6AF4EF3
4 changed files with 114 additions and 18 deletions

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;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Sapling {
}

View File

@ -2,13 +2,16 @@ package cz.jzitnik.game.entities.items.registry.blocks;
import cz.jzitnik.game.SpriteLoader;
import cz.jzitnik.game.annotations.BlockRegistry;
import cz.jzitnik.game.annotations.Sapling;
import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.logic.services.saplings.SaplingData;
@Sapling
@BlockRegistry("oak_sapling")
public class OakSaplingBlock extends Block {
public OakSaplingBlock() {
super("oak_sapling", SpriteLoader.SPRITES.OAK_SAPLING, 0);
setData(new SaplingData());
setGhost(true);
}
}

View File

@ -34,6 +34,8 @@ public class Generation {
// Spawn player at a valid starting point
world[terrainHeight[256] - 1][256].add(steveBlock2);
world[terrainHeight[256] - 2][256].add(steveBlock);
game.getInventory().addItem(ItemBlockSupplier.getItem("oak_sapling"));
}
private static void initializeWorld(List<Block>[][] world) {
@ -96,7 +98,11 @@ public class Generation {
if (treeBase - 3 < 0)
continue;
// Place trunk
tree(world, i, treeBase);
}
}
public static void tree(List<Block>[][] world, int i, int treeBase) {
for (int j = 0; j < 3; j++) {
if (treeBase - j >= 0) {
world[treeBase - j - 1][i].add(ItemBlockSupplier.getBlock("oak_log"));
@ -105,7 +111,6 @@ public class Generation {
int leafY = treeBase - 4;
// 2D Pyramid-shaped leaf placement
for (int layer = 0; layer < 3; layer++) {
int size = 5 - (layer * 2);
int offsetY = leafY - layer;
@ -120,7 +125,4 @@ public class Generation {
}
}
}
}
}

View File

@ -1,15 +1,95 @@
package cz.jzitnik.game.logic.services.saplings;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.annotations.BlockRegistry;
import cz.jzitnik.game.annotations.CustomLogic;
import cz.jzitnik.game.annotations.Sapling;
import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.generation.Generation;
import cz.jzitnik.game.logic.CustomLogicInterface;
import org.reflections.Reflections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@CustomLogic
public class SaplingLogic implements CustomLogicInterface {
private static final int RADIUS = 30;
private static final Set<String> saplings = new HashSet<>();
public SaplingLogic() {
Reflections reflections = new Reflections("cz.jzitnik.game.entities.items.registry.blocks");
Set<Class<?>> handlerClasses = reflections.getTypesAnnotatedWith(Sapling.class);
for (Class<?> clazz : handlerClasses) {
if (clazz.isAnnotationPresent(BlockRegistry.class)) {
String value = clazz.getAnnotation(BlockRegistry.class).value();
saplings.add(value);
}
}
}
@Override
public void nextIteration(Game game) {
int[] data = game.getPlayerCords();
var world = game.getWorld();
int playerX = data[0];
int playerY = data[1];
int startX = Math.max(0, playerX - RADIUS);
int startY = Math.max(0, playerY - RADIUS);
int endX = Math.min(world[0].length - 1, playerX + RADIUS);
int endY = Math.min(world.length - 1, playerY + RADIUS);
for (int x = startX; x <= endX; x++) {
for (int y = startY; y <= endY; y++) {
var blocks = world[y][x];
if (blocks.stream().anyMatch(block -> saplings.contains(block.getBlockId()))) {
sapling(game, x, y);
}
}
}
}
private boolean check(Block block) {
return block.isMob() || block.getBlockId().equals("air") || saplings.contains(block.getBlockId());
}
private boolean canGrowSapling(List<Block>[][] world, int x, int y) {
return
world[y][x].stream().allMatch(this::check) &&
world[y - 1][x].stream().allMatch(this::check) &&
world[y - 2][x].stream().allMatch(this::check) &&
world[y - 3][x].stream().allMatch(this::check) &&
world[y - 4][x].stream().allMatch(this::check) &&
world[y - 5][x].stream().allMatch(this::check) &&
world[y - 3][x - 2].stream().allMatch(this::check) &&
world[y - 3][x - 1].stream().allMatch(this::check) &&
world[y - 3][x + 1].stream().allMatch(this::check) &&
world[y - 3][x + 2].stream().allMatch(this::check) &&
world[y - 4][x - 1].stream().allMatch(this::check) &&
world[y - 4][x + 1].stream().allMatch(this::check);
}
private void sapling(Game game, int x, int y) {
var world = game.getWorld();
if (!canGrowSapling(world, x, y)) {
return;
}
var sapling = world[y][x].stream().filter(i -> saplings.contains(i.getBlockId())).findFirst().get();
var data = (SaplingData) sapling.getData();
if (data.getGrowWait() == 1) {
// Grow
world[y][x].remove(sapling);
Generation.tree(world, x, y + 1);
return;
}
data.setGrowWait(data.getGrowWait() - 1);
}
}