- Версия(и) Minecraft
- 1.12.2
Требования: достойное знание Java, знание как создавать своего Entity
В классе EntityLiving есть список возможных заданий (или действий) и у каждого задания есть свой приоритет. Сильнее приоритет, тот который меньше другого. Допустим чтобы моб не тонул, когда пытается ударить кого-то, то приоритет на плавание нужно поставить 0, а приоритет на преследование 1. Некоторые виды задач срабатывают без задержки (к примеру плавание), а некоторые с задержкой, пока задача не выполниться (пока моб не убьёт кого-то).
В обычном Minecraft есть следующие ИИ-задачи:
При атаке издали выполняется метод
Также можно установить разные приоритетные цели для атаки. К примеру, для того чтобы чтобы моб отбивался от того кто его ударяет, а не случайных окружающих.
Есть список целей для атак. Их есть несколько:
Для добавления задачи нужно написать
Пример:
Для добавление целей нужно написать
Пример:
Теперь этот моб плавает, атакует животных и ведёт себя как обычная сущность!
Для примера создадим ИИ-задачу, которая будет пытаться взять все предметы вокруг.
Часть 1
Что за ИИ-задачи?
Для начала выясним как работает ИИ в Minecraft.Что за ИИ-задачи?
В классе EntityLiving есть список возможных заданий (или действий) и у каждого задания есть свой приоритет. Сильнее приоритет, тот который меньше другого. Допустим чтобы моб не тонул, когда пытается ударить кого-то, то приоритет на плавание нужно поставить 0, а приоритет на преследование 1. Некоторые виды задач срабатывают без задержки (к примеру плавание), а некоторые с задержкой, пока задача не выполниться (пока моб не убьёт кого-то).
В обычном Minecraft есть следующие ИИ-задачи:
- EntityAISwimming - плавать
- EntityAIAttackMelee - атака врукопашную
- EntityAIWanderAvoidWater - блуждать избегая воды
- EntityAIWatchClosest - смотреть на кого-то/что-то
- EntityAILookIdle - смотреть в другую сторону
- EntitySquid.AIMoveRandom - двигаться хаотично (как спрут)
- EntityAIAvoidEntity - избегать сущность
- EntityAIFleeSun - убегать от солнца (как зомби)
- EntityAITempt - преследовать игрока, у которого какой-либо предмет в руках
- EntityAIMate - спаривание
- EntityAIPanic - паника от урона
- EntityAIFollowParent - преследовать родителей (только для EntityAnimal)
- EntityAIFollowOwner - преследовать владельца (только для EntityTameable)
- EntityAIFollowOwnerFlying - лететь за владельцем
- EntityAIWanderAvoidWaterFlying - блуждать летя
- EntityAIAttackRanged - атака издали
При атаке издали выполняется метод
public void attackEntityWithRangedAttack(EntityLivingBase target, float distanceFactor)
и с помощью его можно сделать выстреливание стрелы, снежка и прочего.Также можно установить разные приоритетные цели для атаки. К примеру, для того чтобы чтобы моб отбивался от того кто его ударяет, а не случайных окружающих.
Есть список целей для атак. Их есть несколько:
- EntityAIHurtByTarget - тот кто ударил
- EntityAINearestAttackableTarget - ближайшая сущность
- EntityAITargetNonTamed - сущности без бирок
- EntityAIOwnerHurtTarget - тот кто ударил владельца
- EntityAIOwnerHurtByTarget - тот кого ударил владелец
Часть 2
Добавление ИИ-задач в сущность
Чтобы добавлять ИИ-задачи в классе Entity нужно добавить следующий метод:Добавление ИИ-задач в сущность
Java:
protected void initEntityAI() {
}
tasks.addTask(priorety, task);
Пример:
Java:
protected void initEntityAI() {
tasks.addTask(0, new EntityAISwimming(this));
tasks.addTask(1, new EntityAIAttackMelee(this, 0.6D, false)); // 0.6D - скорость
tasks.addTask(2, new EntityAIWanderAvoidWater(this, 0.6D)); // 0.6D - скорость
tasks.addTask(3, new EntityAIWatchClosest(this, EntityPlayer.class, 6F)); // 6F - дистанция
tasks.addTask(4, new EntityAILookIdle(this));
}
targetTasks.addTask(priorety, task);
Пример:
Java:
protected void initEntityAI() {
tasks.addTask(0, new EntityAISwimming(this));
tasks.addTask(1, new EntityAIAttackMelee(this, 0.6D, false));
tasks.addTask(2, new EntityAIWanderAvoidWater(this, 0.6D));
tasks.addTask(3, new EntityAIWatchClosest(this, EntityPlayer.class, 6F));
tasks.addTask(4, new EntityAILookIdle(this));
targetTasks.addTask(0, new EntityAINearestAttackableTarget(this, EntityAnimal.class, true));
}
Теперь этот моб плавает, атакует животных и ведёт себя как обычная сущность!
Часть 3
Создание своих ИИ-задач
Чтобы сделать свою задачу нужно создать класс наследованный Создание своих ИИ-задач
EntityAIBase
. В данном классе есть методы, которые и выполняют саму логику работы задачи.public boolean shouldExecute()
- будет ли выполняться данная задача? Если нет, то пытаемся выполнить другую задачу.public boolean shouldContinueExecuting()
- будет ли ещё выполняться эта задача? Если нет, то задача прервалась.public void startExecuting()
- метод срабатывающий, когда задача начинает выполняться.public void resetTask()
- метод срабатывающий, когда задача прерывается.public void updateTask()
- метод выполнения задачи.Для примера создадим ИИ-задачу, которая будет пытаться взять все предметы вокруг.
Java:
public class EntityAIItemPickup extends EntityAIBase {
public EntityLiving living;
public Path path;
public EntityAIItemPickup.Sorter sorter;
public EntityAIItemPickup(EntityLiving living) {
this.living = living;
sorter = new EntityAIItemPickup.Sorter(living);
setMutexBits(1);
}
@Override
public boolean shouldExecute() {
List<EntityItem> list = living.world.getEntitiesWithinAABB(EntityItem.class, getTargetableArea(10D)); // все предметы в радиусе действия
if (list.isEmpty()) { // нету предметов?
return false;
} else { // есть предметы?
Collections.sort(list, sorter);
targetItem = list.get(0); // самый близкий предмет
}
if (targetItem == null) {
return false;
} else {
path = living.getNavigator().getPathToEntityLiving(targetItem); // поиск пути до предмета
return path != null;
}
}
/*
* Создание зоны, в которой сущность будет брать предметы
*/
protected AxisAlignedBB getTargetableArea(double targetDistance) {
return living.getEntityBoundingBox().grow(targetDistance, 4.0D, targetDistance);
}
public void resetTask() {
living.getNavigator().clearPath(); // обнуляем путь
}
public void updateTask() {
living.getLookHelper().setLookPositionWithEntity(targetItem, 30F, 30F); // чтобы сущность смотрела на предмет
double d = living.getDistanceSq(targetItem.posX, targetItem.posY, targetItem.posZ); // дистанция от сущности до предмета
living.getNavigator().tryMoveToEntityLiving(targetItem, 0.5D); // пробуем добраться до предмета
if (d <= 1D) { // если предмет очень близко
living.onItemPickup(targetItem, targetItem.getItem().getCount()); // делаем эффект взятия в инвентарь
// берём в инвентарь
targetItem.setDead(); // убираем предмет
}
}
public void startExecuting() {
living.getNavigator().setPath(path, 0.5D); // задаём путь к предмету
}
/*
* Сортировка предметов по дальности от сущности, чтобы взять самый близкий предмет
*/
public static class Sorter implements Comparator<EntityItem> {
private final EntityLiving entity;
public Sorter(EntityLiving entity) {
this.entity = entity;
}
public int compare(EntityItem e1, EntityItem e2) {
double d0 = entity.getDistanceSq(e1);
double d1 = entity.getDistanceSq(e2);
if (d0 < d1) {
return -1;
} else {
return d0 > d1 ? 1 : 0;
}
}
}
}