CrumbleWorks / aTFC

BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

Enhance MoveAwayFromPlayerGoal #87

Open McDonnough opened 3 years ago

McDonnough commented 3 years ago

As an enhancement to the mob already implemented in #63, the behaviour defined in MoveAwayFromPlayerGoal.java should be changed to make a mob run away from a player instead of just running around (as inherited from the class PanicGoal). An attempt was made to do just that --- see code below --- but thus far resulted in non-satisfactory results. The most prominent problem with the solution below is that a mob's body will sometimes make a full 180° turn, while the mob's direction remains unchanged.

Todo:

package org.crumbleworks.forge.aTFC.content.entities.goals;

import java.util.EnumSet;

import net.minecraft.entity.MobEntity;
import net.minecraft.entity.ai.goal.Goal;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.vector.Vector3d;

/**
 * Goal which makes a mob move away from a player if they get too close.
 */
public class MoveAwayFromPlayerGoal extends Goal {

    private MobEntity mob;
    private double minDistance;
    private double speed;

    protected final float probability;

    /**
     * @param mob
     *            A mob entity
     * @param minDistance
     *            Minimum distance to player. If the actual distance is lower
     *            than this value, the mob will start to move away from the
     *            player.
     * @param speed
     *            Speed with which {@code mob} moves away from the player
     */
    public MoveAwayFromPlayerGoal(MobEntity mob, double minDistance,
            double speed) {
        this.mob = mob;
        this.minDistance = minDistance;
        this.speed = speed;

        probability = 0.8f;

        setMutexFlags(EnumSet.of(Goal.Flag.MOVE));
    }

    @Override
    public boolean shouldExecute() {
        return mob.world.getClosestPlayer(mob, minDistance) != null;
    }

    @Override
    public void tick() {
        PlayerEntity closestPlayer = mob.world.getClosestPlayer(mob,
                minDistance);

        Vector3d mobPosition = mob.getPositionVec();
        Vector3d playerPosition = closestPlayer.getPositionVec();

        Vector3d targetPosition = playerPosition.subtract(mobPosition)
                .normalize().inverse().mul(minDistance, 1.0, minDistance);
        if(mob.getRNG().nextFloat() >= probability) {
            float randomYawAngle = (float) (Math.random()
                    * (10.0 - (-10.0) + 1)
                    + -10.0);
            targetPosition = targetPosition
                    .rotateYaw((float)Math.PI / randomYawAngle);
        }
        targetPosition = targetPosition.add(mobPosition);

        mob.getNavigator().tryMoveToXYZ(targetPosition.getX(),
                mobPosition.getY(), targetPosition.getZ(), speed);
    }

}

Definitions of goals used:

@Override
protected void registerGoals() {
    goalSelector.addGoal(0, new MoveAwayFromPlayerGoal(this, 10d, 1.25d));
    goalSelector.addGoal(1, new SwimGoal(this));
    goalSelector.addGoal(3, new PanicGoal(this, 1.4D));
    goalSelector.addGoal(4, new BreedGoal(this, 1.0D));
    goalSelector.addGoal(5, new TemptGoal(this, 1.0D, false, TEMPTATION_ITEMS));
    goalSelector.addGoal(6, new FollowParentGoal(this, 1.1D));
    goalSelector.addGoal(7, new WaterSeekingRandomWalkingGoal(this, 1.0D));
    goalSelector.addGoal(8, new LookAtGoal(this, PlayerEntity.class, 6.0F));
    goalSelector.addGoal(9, new LookRandomlyGoal(this));
}