mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-08 09:27:58 +01:00
RangedAttackGoal implementation initial commit
This commit is contained in:
parent
1fda2aba6d
commit
3c8824c7b0
@ -862,6 +862,16 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
|
|||||||
return getPosition().getDistance(entity.getPosition());
|
return getPosition().getDistance(entity.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the distance squared between two entities.
|
||||||
|
*
|
||||||
|
* @param entity the entity to get the distance from
|
||||||
|
* @return the distance squared between this and {@code entity}
|
||||||
|
*/
|
||||||
|
public double getDistanceSquared(@NotNull Entity entity) {
|
||||||
|
return getPosition().getDistanceSquared(entity.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the entity vehicle or null.
|
* Gets the entity vehicle or null.
|
||||||
*
|
*
|
||||||
|
@ -22,6 +22,7 @@ import net.minestom.server.sound.Sound;
|
|||||||
import net.minestom.server.sound.SoundCategory;
|
import net.minestom.server.sound.SoundCategory;
|
||||||
import net.minestom.server.utils.BlockPosition;
|
import net.minestom.server.utils.BlockPosition;
|
||||||
import net.minestom.server.utils.Position;
|
import net.minestom.server.utils.Position;
|
||||||
|
import net.minestom.server.utils.Vector;
|
||||||
import net.minestom.server.utils.block.BlockIterator;
|
import net.minestom.server.utils.block.BlockIterator;
|
||||||
import net.minestom.server.utils.time.CooldownUtils;
|
import net.minestom.server.utils.time.CooldownUtils;
|
||||||
import net.minestom.server.utils.time.TimeUnit;
|
import net.minestom.server.utils.time.TimeUnit;
|
||||||
@ -590,6 +591,30 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
|
|||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the current entity has line of sight to the given one.
|
||||||
|
* If so, it doesn't mean that the given entity is IN line of sight of the current,
|
||||||
|
* but the current one can rotate so that it will be true.
|
||||||
|
*
|
||||||
|
* @param entity the entity to be checked.
|
||||||
|
* @return if the current entity has line of sight to the given one.
|
||||||
|
*/
|
||||||
|
public boolean hasLineOfSight(Entity entity) {
|
||||||
|
Vector start = getPosition().toVector().add(0D, getEyeHeight(), 0D);
|
||||||
|
Vector end = entity.getPosition().toVector().add(0D, getEyeHeight(), 0D);
|
||||||
|
Vector direction = end.subtract(start);
|
||||||
|
int maxDistance = (int) Math.ceil(direction.length());
|
||||||
|
|
||||||
|
Iterator<BlockPosition> it = new BlockIterator(start, direction.normalize(), 0D, maxDistance);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Block block = Block.fromStateId(getInstance().getBlockStateId(it.next()));
|
||||||
|
if (!block.isAir() && !block.isLiquid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the target (not-air) {@link BlockPosition} of the entity.
|
* Gets the target (not-air) {@link BlockPosition} of the entity.
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
package net.minestom.server.entity.ai.goal;
|
||||||
|
|
||||||
|
import net.minestom.server.entity.Entity;
|
||||||
|
import net.minestom.server.entity.EntityCreature;
|
||||||
|
import net.minestom.server.entity.ai.GoalSelector;
|
||||||
|
import net.minestom.server.entity.pathfinding.Navigator;
|
||||||
|
import net.minestom.server.utils.Position;
|
||||||
|
import net.minestom.server.utils.time.CooldownUtils;
|
||||||
|
import net.minestom.server.utils.time.TimeUnit;
|
||||||
|
import net.minestom.server.utils.validate.Check;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by k.shandurenko on 22.02.2021
|
||||||
|
*/
|
||||||
|
public class RangedAttackGoal extends GoalSelector {
|
||||||
|
|
||||||
|
private long lastShot;
|
||||||
|
private final int delay;
|
||||||
|
private final TimeUnit timeUnit;
|
||||||
|
private final int attackRangeSquared;
|
||||||
|
private final int desirableRangeSquared;
|
||||||
|
private final boolean comeClose;
|
||||||
|
|
||||||
|
private boolean stop;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param entityCreature the entity to add the goal to.
|
||||||
|
* @param delay the delay between each shots.
|
||||||
|
* @param attackRange the allowed range the entity can shoot others.
|
||||||
|
* @param desirableRange the desirable range: the entity will try to stay no further than this distance.
|
||||||
|
* @param comeClose whether entity should go as close as possible to the target whether target is not in line of sight.
|
||||||
|
* @param timeUnit the unit of the delay.
|
||||||
|
*/
|
||||||
|
public RangedAttackGoal(@NotNull EntityCreature entityCreature, int delay, int attackRange, int desirableRange, boolean comeClose, @NotNull TimeUnit timeUnit) {
|
||||||
|
super(entityCreature);
|
||||||
|
this.delay = delay;
|
||||||
|
this.timeUnit = timeUnit;
|
||||||
|
this.attackRangeSquared = attackRange * attackRange;
|
||||||
|
this.desirableRangeSquared = desirableRange * desirableRange;
|
||||||
|
this.comeClose = comeClose;
|
||||||
|
Check.argCondition(desirableRange <= attackRange, "Desirable range can not exceed attack range!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldStart() {
|
||||||
|
return findAndUpdateTarget() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
Entity target = findAndUpdateTarget();
|
||||||
|
Check.notNull(target, "The target is not expected to be null!");
|
||||||
|
this.entityCreature.getNavigator().setPathTo(target.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick(long time) {
|
||||||
|
Entity target = findAndUpdateTarget();
|
||||||
|
if (target == null) {
|
||||||
|
this.stop = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double distanceSquared = this.entityCreature.getDistanceSquared(target);
|
||||||
|
boolean comeClose = false;
|
||||||
|
if (distanceSquared <= this.attackRangeSquared) {
|
||||||
|
if (!CooldownUtils.hasCooldown(time, this.lastShot, this.timeUnit, this.delay)) {
|
||||||
|
if (this.entityCreature.hasLineOfSight(target)) {
|
||||||
|
|
||||||
|
this.lastShot = time;
|
||||||
|
} else {
|
||||||
|
comeClose = this.comeClose;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Navigator navigator = this.entityCreature.getNavigator();
|
||||||
|
Position pathPosition = navigator.getPathPosition();
|
||||||
|
if (!comeClose && distanceSquared <= this.desirableRangeSquared) {
|
||||||
|
if (pathPosition != null) {
|
||||||
|
navigator.setPathTo(null);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Position targetPosition = target.getPosition();
|
||||||
|
if (pathPosition == null || !pathPosition.isSimilar(targetPosition)) {
|
||||||
|
navigator.setPathTo(targetPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldEnd() {
|
||||||
|
return this.stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void end() {
|
||||||
|
// Stop following the target
|
||||||
|
this.entityCreature.getNavigator().setPathTo(null);
|
||||||
|
}
|
||||||
|
}
|
@ -345,23 +345,19 @@ public class BlockIterator implements Iterator<BlockPosition> {
|
|||||||
thirdError -= gridSize;
|
thirdError -= gridSize;
|
||||||
secondError -= gridSize;
|
secondError -= gridSize;
|
||||||
currentBlock = 2;
|
currentBlock = 2;
|
||||||
return;
|
|
||||||
} else if (secondError > 0) {
|
} else if (secondError > 0) {
|
||||||
blockQueue[1] = blockQueue[0].getRelative(mainFace);
|
blockQueue[1] = blockQueue[0].getRelative(mainFace);
|
||||||
blockQueue[0] = blockQueue[1].getRelative(secondFace);
|
blockQueue[0] = blockQueue[1].getRelative(secondFace);
|
||||||
secondError -= gridSize;
|
secondError -= gridSize;
|
||||||
currentBlock = 1;
|
currentBlock = 1;
|
||||||
return;
|
|
||||||
} else if (thirdError > 0) {
|
} else if (thirdError > 0) {
|
||||||
blockQueue[1] = blockQueue[0].getRelative(mainFace);
|
blockQueue[1] = blockQueue[0].getRelative(mainFace);
|
||||||
blockQueue[0] = blockQueue[1].getRelative(thirdFace);
|
blockQueue[0] = blockQueue[1].getRelative(thirdFace);
|
||||||
thirdError -= gridSize;
|
thirdError -= gridSize;
|
||||||
currentBlock = 1;
|
currentBlock = 1;
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
blockQueue[0] = blockQueue[0].getRelative(mainFace);
|
blockQueue[0] = blockQueue[0].getRelative(mainFace);
|
||||||
currentBlock = 0;
|
currentBlock = 0;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user