added snacks with collision, switched to multiplayer arena
This commit is contained in:
@@ -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<Player, TurtleGameInstance> gameInstances = new WeakHashMap<>();
|
||||
private final Random random = new Random();
|
||||
private final int radius;
|
||||
private final Map<Player, EntityCreature> turtlePlayerMap = new WeakHashMap<>();
|
||||
private final ArrayList<Entity> 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<Void> 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<Entity> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ public class TurtleGameFactory implements GameFactory {
|
||||
|
||||
@Override
|
||||
public Game manufacture(Room parent, Map<String, Option<?>> configuration) throws Exception {
|
||||
return new TurtleGame(configuration.get("firstPerson").getAsBoolean());
|
||||
return new TurtleGame(configuration.get("firstPerson").getAsBoolean(), configuration.get("radius").getAsInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user