From 81524cfecf55108781981073e7c13b028392944e Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 4 Oct 2025 00:09:19 +0200 Subject: [PATCH] added snacks with collision, switched to multiplayer arena --- .../types/turtleGame/TurtleGame.java | 123 ++++++++++++++---- .../types/turtleGame/TurtleGameFactory.java | 2 +- .../turtleGame/game/TurtleGameInstance.java | 62 --------- 3 files changed, 99 insertions(+), 88 deletions(-) delete mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 4e49edf..bc4fbe7 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -2,62 +2,95 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame; import eu.mhsl.minenet.minigames.instance.Dimension; import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; -import eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame.game.TurtleGameInstance; import eu.mhsl.minenet.minigames.score.PointsWinScore; import net.kyori.adventure.text.Component; import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Vec; +import net.minestom.server.entity.Entity; import net.minestom.server.entity.EntityCreature; +import net.minestom.server.entity.EntityType; import net.minestom.server.entity.Player; import net.minestom.server.entity.attribute.Attribute; +import net.minestom.server.entity.metadata.other.FallingBlockMeta; import net.minestom.server.event.player.PlayerTickEvent; +import net.minestom.server.instance.block.Block; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import org.jetbrains.annotations.NotNull; -import java.util.Map; -import java.util.Random; -import java.util.WeakHashMap; +import java.util.*; +import java.util.concurrent.CompletableFuture; class TurtleGame extends StatelessGame { private final boolean firstPerson; - private final Map gameInstances = new WeakHashMap<>(); - private final Random random = new Random(); + private final int radius; + private final Map turtlePlayerMap = new WeakHashMap<>(); + private final ArrayList snacks = new ArrayList<>(); + private final double speed = 2; - public TurtleGame(boolean firstPerson) { + public TurtleGame(boolean firstPerson, int radius) { super(Dimension.OVERWORLD.key, "Turtle Game", new PointsWinScore()); this.firstPerson = firstPerson; + this.radius = radius; this.eventNode() .addListener(PlayerTickEvent.class, this::onPlayerTick); } + @Override + protected void onLoad(@NotNull CompletableFuture callback) { + this.generatePlatform(); + } + + private void generatePlatform() { + for(int x = -this.radius - 1; x <= this.radius + 1; x++) { + for(int z = -this.radius - 1; z <= this.radius + 1; z++) { + double distance = new Pos(x, 0, z).distance(new Pos(0, 0, 0)); + if(distance <= this.radius) { + boolean isEdge = this.radius - 1 < distance; + this.setBlock(x, 0, z, Block.SAND); + this.setBlock(x, 1, z, isEdge ? Block.STONE : Block.AIR); + this.setBlock(x, 2, z, isEdge ? Block.STONE_SLAB : Block.AIR); + } else { + this.setBlock(x, 0, z, Block.AIR); + } + } + } + } + protected void onPlayerTick(@NotNull PlayerTickEvent event) { - TurtleGameInstance gameInstance = this.gameInstances.get(event.getPlayer()); - gameInstance.getTurtle().teleport(gameInstance.getTurtle().getPosition().withView(event.getPlayer().getPosition())); - if(this.isRunning()) gameInstance.moveTurtle(event.getPlayer().getPosition().direction()); + EntityCreature turtle = this.turtlePlayerMap.get(event.getPlayer()); + turtle.teleport(turtle.getPosition().withView(event.getPlayer().getPosition())); + Vec direction = event.getPlayer().getPosition().direction(); + if(this.isRunning()) { + Vec targetDirection = direction.withY(0).normalize().mul(this.speed); + turtle.setVelocity(targetDirection); + + List hit = this.snacks.stream() + .filter(snack -> snack.getBoundingBox().intersectBox(turtle.getPosition().sub(snack.getPosition()), turtle.getBoundingBox())) + .toList(); + hit.forEach(snack -> { + this.snacks.remove(snack); + snack.remove(); + this.generateNewSnack(); + }); + } } @Override protected boolean onPlayerJoin(Player p) { p.getInventory().setItemStack(0, ItemStack.builder(Material.BARRIER).customName(Component.text("Reset Snack")).build()); - // TODO: instance auflösen, ein großer Kreis - if(this.gameInstances.get(p) == null) { - this.gameInstances.put(p, new TurtleGameInstance( - this, - this.getSpawn().sub(6, 8, 15).add(this.gameInstances.size()*50, 0, 0) - )); - this.gameInstances.get(p).generate(); + if(this.turtlePlayerMap.get(p) == null) { + EntityCreature turtle = new EntityCreature(EntityType.TURTLE); + this.turtlePlayerMap.put(p, turtle); } - TurtleGameInstance gameInstance = this.gameInstances.get(p); - - p.teleport(gameInstance.getPlayerSpawnPosition()); - - EntityCreature turtle = gameInstance.getTurtle(); + EntityCreature turtle = this.turtlePlayerMap.get(p); MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { turtle.setInstance(this); - turtle.teleport(gameInstance.getPlayerSpawnPosition()); + turtle.teleport(p.getPosition()); turtle.addPassenger(p); turtle.getAttribute(Attribute.MOVEMENT_SPEED).setBaseValue(0.15); }); @@ -65,9 +98,49 @@ class TurtleGame extends StatelessGame { return super.onPlayerJoin(p); } + @Override + protected void onPlayerLeave(Player p) { + EntityCreature turtle = this.turtlePlayerMap.get(p); + turtle.remove(); + } + + @Override + public Pos getSpawn() { + double theta = this.rnd.nextDouble() * 2 * Math.PI; + + double spawnRadius = this.radius - 4; + double x = spawnRadius * Math.cos(theta); + double z = spawnRadius * Math.sin(theta); + + return new Pos(x, 1, z).withLookAt(new Pos(0, 0, 0)); + } + + private void generateNewSnack() { + Pos spawnPosition; + boolean isInRadius, isEmpty; + int counter = 0; + do { + if(counter > 200) return; + int x = this.rnd.nextInt(-this.radius+2, this.radius-2); + int z = this.rnd.nextInt(-this.radius+2, this.radius-2); + spawnPosition = new Pos(x, 1, z); + isInRadius = new Pos(x, 1, z).distance(0, 1, 0) < this.radius-2; + isEmpty = this.snacks.stream().noneMatch(entity -> entity.getPosition().sameBlock(x, 1, z)); + counter++; + } while (!(isEmpty && isInRadius)); + + Entity snack = new Entity(EntityType.FALLING_BLOCK); + FallingBlockMeta meta = (FallingBlockMeta) snack.getEntityMeta(); + meta.setBlock(Block.CHORUS_FLOWER); + snack.setInstance(this); + snack.teleport(spawnPosition.add(0.5, 0, 0.5)); + this.snacks.add(snack); + } + @Override protected void onStart() { - this.gameInstances.forEach(((player, gameInstance) -> gameInstance.moveTurtle(player.getPosition().direction()))); -// this.gameInstances.forEach(((player, turtleGameInstance) -> turtleGameInstance.start())); + for (int i = 0; i < 3; i++) { + this.generateNewSnack(); + } } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java index f3f673a..b47f82a 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java @@ -33,7 +33,7 @@ public class TurtleGameFactory implements GameFactory { @Override public Game manufacture(Room parent, Map> configuration) throws Exception { - return new TurtleGame(configuration.get("firstPerson").getAsBoolean()); + return new TurtleGame(configuration.get("firstPerson").getAsBoolean(), configuration.get("radius").getAsInt()); } @Override diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java deleted file mode 100644 index 438f8af..0000000 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java +++ /dev/null @@ -1,62 +0,0 @@ -package eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame.game; - -import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; -import eu.mhsl.minenet.minigames.util.BatchUtil; -import net.minestom.server.coordinate.Pos; -import net.minestom.server.coordinate.Vec; -import net.minestom.server.entity.EntityCreature; -import net.minestom.server.entity.EntityType; -import net.minestom.server.instance.batch.AbsoluteBlockBatch; -import net.minestom.server.instance.block.Block; - -import java.awt.*; - -public class TurtleGameInstance { - private final StatelessGame instance; - private final Pos startPosition; - private final EntityCreature turtle = new EntityCreature(EntityType.TURTLE); - private double speed = 2; - - public TurtleGameInstance(StatelessGame instance, Pos startPosition) { - this.instance = instance; - this.startPosition = startPosition; - } - - public void moveTurtle(Vec direction) { - Vec targetDirection = direction.withY(0).normalize().mul(speed); - this.turtle.setVelocity(targetDirection); - } - - // TODO: kleine display entities, die rotieren und so -// public void generateNewSnack() { -// int z, x; -// do { -// z = random.nextInt(0, 66); -// x = random.nextInt(0, 44); -// } while (!this.instance.getBlock(this.startPosition.add(x, 1, z)).isAir()); -// } - - public void generate() { - AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); - - for (int z = -1; z < 66; z++) { - for (int x = -1; x < 44; x++) { - if(z < 0 || z >= 65 || x < 0 || x >= 43) { - batch.setBlock(this.startPosition.add(x, 1, z), Block.STONE); - batch.setBlock(this.startPosition.add(x, 2, z), Block.STONE_SLAB); - } - batch.setBlock(this.startPosition.add(x, 0, z), Block.SAND); - } - } - - BatchUtil.loadAndApplyBatch(batch, this.instance, () -> {}); - } - - public Pos getPlayerSpawnPosition() { - return this.startPosition.add(20, 1, 30); - } - - public EntityCreature getTurtle() { - return this.turtle; - } -}