Commit 2379b5f8 by Jonathan Thomas

Limit waypoint locations to 45 degree angle from current direction. Remove…

Limit waypoint locations to 45 degree angle from current direction. Remove FuzzyTargeting (since it finds things too close to the entity to be useful). Fixed non path aware to use custom LookControls.
parent 7fc533f6
Pipeline #12709 passed with stages
in 1 minute 49 seconds
......@@ -10,8 +10,10 @@ All notable changes to **CreatureChat** are documented in this file. The format
- New LEAD behavior, to guide a player to a random location (and show message when destination is reached)
### Changed
- Updated README.md to include HTML inside spoiler instructions, and whitelist/blacklist commands
- Updated LookControls to support PhantomEntity and made it more generalized (look in any direction)
- Updated FLEE behavior Y movement speed
- Updated unit tests to add new LEAD tests
- Updated README.md to include HTML inside spoiler instructions, and whitelist/blacklist commands
## [1.0.8] - 2024-07-16
......
package com.owlmaddie.controls;
import net.minecraft.entity.boss.dragon.EnderDragonEntity;
import net.minecraft.entity.mob.*;
import net.minecraft.entity.passive.SquidEntity;
import net.minecraft.server.network.ServerPlayerEntity;
......@@ -13,27 +12,31 @@ import net.minecraft.util.math.Vec3d;
*/
public class LookControls {
public static void lookAtPlayer(ServerPlayerEntity player, MobEntity entity) {
lookAtPosition(player.getPos(), entity);
}
public static void lookAtPosition(Vec3d targetPos, MobEntity entity) {
if (entity instanceof SlimeEntity) {
handleSlimeLook((SlimeEntity) entity, player);
handleSlimeLook((SlimeEntity) entity, targetPos);
} else if (entity instanceof SquidEntity) {
handleSquidLook((SquidEntity) entity, player);
handleSquidLook((SquidEntity) entity, targetPos);
} else if (entity instanceof GhastEntity) {
handleFlyingEntity(entity, player, 10F);
handleFlyingEntity(entity, targetPos, 10F);
} else if (entity instanceof FlyingEntity || entity instanceof VexEntity) {
handleFlyingEntity(entity, player, 4F);
handleFlyingEntity(entity, targetPos, 4F);
} else {
// Make the entity look at the player
entity.getLookControl().lookAt(player, 10.0F, (float)entity.getMaxLookPitchChange());
entity.getLookControl().lookAt(targetPos.x, targetPos.y, targetPos.z, 10.0F, (float)entity.getMaxLookPitchChange());
}
}
private static void handleSlimeLook(SlimeEntity slime, ServerPlayerEntity player) {
float yawChange = calculateYawChangeToPlayer(slime, player);
private static void handleSlimeLook(SlimeEntity slime, Vec3d targetPos) {
float yawChange = calculateYawChange(slime, targetPos);
((SlimeEntity.SlimeMoveControl) slime.getMoveControl()).look(slime.getYaw() + yawChange, false);
}
private static void handleSquidLook(SquidEntity squid, ServerPlayerEntity player) {
Vec3d toPlayer = calculateNormalizedDirection(squid, player);
private static void handleSquidLook(SquidEntity squid, Vec3d targetPos) {
Vec3d toPlayer = calculateNormalizedDirection(squid, targetPos);
float initialSwimStrength = 0.15f;
squid.setSwimmingVector(
(float) toPlayer.x * initialSwimStrength,
......@@ -41,7 +44,7 @@ public class LookControls {
(float) toPlayer.z * initialSwimStrength
);
double distanceToPlayer = squid.getPos().distanceTo(player.getPos());
double distanceToPlayer = squid.getPos().distanceTo(targetPos);
if (distanceToPlayer < 3.5F) {
// Stop motion when close
squid.setVelocity(0,0,0);
......@@ -49,17 +52,16 @@ public class LookControls {
}
// Ghast, Phantom, etc...
private static void handleFlyingEntity(MobEntity flyingEntity, ServerPlayerEntity player, float stopDistance) {
Vec3d playerPosition = player.getPos();
private static void handleFlyingEntity(MobEntity flyingEntity, Vec3d targetPos, float stopDistance) {
Vec3d flyingPosition = flyingEntity.getPos();
Vec3d toPlayer = playerPosition.subtract(flyingPosition).normalize();
Vec3d toPlayer = targetPos.subtract(flyingPosition).normalize();
// Calculate the yaw to align the flyingEntity's facing direction with the movement direction
float targetYaw = (float)(MathHelper.atan2(toPlayer.z, toPlayer.x) * (180 / Math.PI) - 90);
flyingEntity.setYaw(targetYaw);
// Look at player while adjusting yaw
flyingEntity.getLookControl().lookAt(player, 10.0F, (float)flyingEntity.getMaxLookPitchChange());
flyingEntity.getLookControl().lookAt(targetPos.x, targetPos.y, targetPos.z, 10.0F, (float)flyingEntity.getMaxLookPitchChange());
float initialSpeed = 0.15F;
flyingEntity.setVelocity(
......@@ -68,23 +70,22 @@ public class LookControls {
(float) toPlayer.z * initialSpeed
);
double distanceToPlayer = flyingEntity.getPos().distanceTo(player.getPos());
double distanceToPlayer = flyingEntity.getPos().distanceTo(targetPos);
if (distanceToPlayer < stopDistance) {
// Stop motion when close
flyingEntity.setVelocity(0, 0, 0);
}
}
public static float calculateYawChangeToPlayer(MobEntity entity, ServerPlayerEntity player) {
Vec3d toPlayer = calculateNormalizedDirection(entity, player);
public static float calculateYawChange(MobEntity entity, Vec3d targetPos) {
Vec3d toPlayer = calculateNormalizedDirection(entity, targetPos);
float targetYaw = (float) Math.toDegrees(Math.atan2(toPlayer.z, toPlayer.x)) - 90.0F;
float yawDifference = MathHelper.wrapDegrees(targetYaw - entity.getYaw());
return MathHelper.clamp(yawDifference, -10.0F, 10.0F);
}
public static Vec3d calculateNormalizedDirection(MobEntity entity, ServerPlayerEntity player) {
Vec3d playerPos = player.getPos();
public static Vec3d calculateNormalizedDirection(MobEntity entity, Vec3d targetPos) {
Vec3d entityPos = entity.getPos();
return playerPos.subtract(entityPos).normalize();
return targetPos.subtract(entityPos).normalize();
}
}
\ No newline at end of file
......@@ -34,6 +34,8 @@ public class SpeedControls {
speed = 2F;
} else if (entity instanceof RabbitEntity) {
speed = 1.5F;
} else if (entity instanceof PhantomEntity) {
speed = 0.2F;
}
return speed;
......
......@@ -64,7 +64,7 @@ public class FleePlayerGoal extends PlayerBaseGoal {
Vec3d fleeDirection = entityPos.subtract(playerPos).normalize();
// Apply movement with the entity's speed in the opposite direction
this.entity.setVelocity(fleeDirection.x * this.speed, this.entity.getVelocity().y, fleeDirection.z * this.speed);
this.entity.setVelocity(fleeDirection.x * this.speed, fleeDirection.y * this.speed, fleeDirection.z * this.speed);
this.entity.velocityModified = true;
}
}
......
package com.owlmaddie.goals;
import com.owlmaddie.chat.ChatDataManager;
import com.owlmaddie.controls.LookControls;
import com.owlmaddie.network.ServerPackets;
import net.minecraft.entity.ai.FuzzyTargeting;
import net.minecraft.entity.ai.pathing.Path;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.mob.PathAwareEntity;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -59,7 +63,7 @@ public class LeadPlayerGoal extends PlayerBaseGoal {
// Are we there yet?
if (currentWaypoint >= totalWaypoints && !foundWaypoint) {
foundWaypoint = true;
LOGGER.info("destination reached");
LOGGER.info("Tick: You have ARRIVED at your destination");
ServerPackets.scheduler.scheduleTask(() -> {
// Prepare a message about the interaction
......@@ -80,65 +84,86 @@ public class LeadPlayerGoal extends PlayerBaseGoal {
setNewTarget();
moveToTarget();
ticksSinceLastWaypoint = 0;
}
}
private void setNewTarget() {
boolean targetFound = false;
if (this.entity instanceof PathAwareEntity) {
int attempts = 0;
while (attempts < 3 && !targetFound) {
Vec3d target = FuzzyTargeting.findFrom((PathAwareEntity) this.entity, 16, 6, this.entity.getPos());
if (target != null) {
currentWaypoint++;
this.currentTarget = target;
LOGGER.info("Waypoint " + currentWaypoint + " / " + this.totalWaypoints);
targetFound = true;
}
attempts++;
}
}
if (!targetFound) {
// Fallback if no target found after 3 attempts
currentWaypoint++;
LOGGER.info("Waypoint " + currentWaypoint + " / " + this.totalWaypoints);
double distance = 20 + random.nextDouble() * 80;
double angle = random.nextDouble() * 2 * Math.PI;
double x = this.targetEntity.getX() + distance * Math.cos(angle);
double y = this.targetEntity.getY() + (random.nextDouble() * 10 - 5); // Similar y-coordinate depth
double z = this.targetEntity.getZ() + distance * Math.sin(angle);
this.currentTarget = new Vec3d(x, y, z);
} else if (!(this.entity instanceof PathAwareEntity)) {
moveToTarget();
}
}
private void moveToTarget() {
if (this.currentTarget != null) {
if (this.entity instanceof PathAwareEntity) {
int attempts = 0;
while (attempts < 3) {
Path path = this.entity.getNavigation().findPathTo(this.currentTarget.x, this.currentTarget.y, this.currentTarget.z, 1);
if (path != null) {
this.entity.getNavigation().startMovingAlong(path, this.speed);
return;
}
attempts++;
}
// Make the entity look at the player without moving towards them
LookControls.lookAtPosition(this.currentTarget, this.entity);
Path path = this.entity.getNavigation().findPathTo(this.currentTarget.x, this.currentTarget.y, this.currentTarget.z, 2);
if (path != null) {
LOGGER.info("Start moving towards waypoint PATH");
this.entity.getNavigation().startMovingAlong(path, this.speed);
} else {
// Move directly towards the target for non-path aware entities
// Move towards the target for non-path aware entities
Vec3d entityPos = this.entity.getPos();
Vec3d moveDirection = this.currentTarget.subtract(entityPos).normalize();
this.entity.setVelocity(moveDirection.x * this.speed, this.entity.getVelocity().y, moveDirection.z * this.speed);
// Calculate current speed from the entity's current velocity
double currentSpeed = this.entity.getVelocity().horizontalLength();
// Gradually adjust speed towards the target speed
currentSpeed = MathHelper.stepTowards((float)currentSpeed, (float)this.speed, (float) (0.005 * (this.speed / Math.max(currentSpeed, 0.1))));
// Apply movement with the adjusted speed towards the target
Vec3d newVelocity = new Vec3d(moveDirection.x * currentSpeed, this.entity.getVelocity().y, moveDirection.z * currentSpeed);
this.entity.setVelocity(newVelocity);
this.entity.velocityModified = true;
}
}
}
@Override
public void start() {
moveToTarget();
private void setNewTarget() {
// Increment waypoint
currentWaypoint++;
LOGGER.info("Waypoint " + currentWaypoint + " / " + this.totalWaypoints);
this.currentTarget = findNextWaypoint();
emitParticleAt(this.currentTarget, ParticleTypes.FLAME);
}
private Vec3d findNextWaypoint() {
LOGGER.info("Create waypoint position");
Vec3d entityPos = this.entity.getPos();
Vec3d currentDirection;
// Check if currentTarget is null
if (this.currentTarget == null) {
// If currentTarget is null, use the entity's facing direction
double yaw = this.entity.getYaw() * (Math.PI / 180); // Convert to radians
currentDirection = new Vec3d(Math.cos(yaw), 0, Math.sin(yaw));
} else {
// Calculate the current direction vector
currentDirection = this.currentTarget.subtract(entityPos).normalize();
}
// Calculate the angle of the current direction
double currentAngle = Math.atan2(currentDirection.z, currentDirection.x);
// Generate a random angle within ±45 degrees of the current direction
double randomAngleOffset = (random.nextDouble() * (Math.PI / 4)) - (Math.PI / 8); // ±45 degrees
double angle = currentAngle + randomAngleOffset;
// Calculate the random distance
double distance = 16 + random.nextDouble() * 2;
// Calculate new coordinates based on the limited angle
double x = entityPos.x + distance * Math.cos(angle);
double y = entityPos.y + (random.nextDouble() * 10 - 5); // Similar y-coordinate depth
double z = entityPos.z + distance * Math.sin(angle);
return new Vec3d(x, y, z);
}
private void emitParticleAt(Vec3d position, ParticleEffect particleType) {
ServerWorld serverWorld = (ServerWorld) this.entity.getWorld();
serverWorld.spawnParticles(particleType, position.x, position.y, position.z, 3, 0, 0, 0, 0);
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment