Кастомные мобы

В игре Майнкрафт уже присутствует огромное количество различных мобов. У каждого и них свои особенности - строение тела, текстура, поведение... Все аспекты создания новых мобов я попытаюсь пояснить в этой статье.

Регистрация моба[править]

Для того, чтобы создать собственного моба, необходимо сначала зарегистрировать его тип. Делается это с помощью функции MobRegistry.registerEntity("name"), где name - уникальный идентификатор типа сущности. Чтобы в дальнейшем было проще работать с новым типом мобов, сохраним его в переменной:

var customEntity = MobRegistry.registerEntity("customEntity");

Для того, чтобы заспавнить нашего моба в мире Майнкрафт, в InnerCore используется метод Entity.spawnCustom("name", x, y, z), принимающая в качестве аргументов идентификатор моба и координаты спавна. В сочетании с функцией использования кастомных предметов можем создать яйцо призыва:

IDRegistry.genItemID("customEntitySpawn"); // регистрируем id предмета-спавнера
Item.createItem("customEntitySpawn", "Spawn custom entity", {name: "stick"}); // создаем предмет- спавнер
// задаем предмету- спавнеру функцию использования
Item.registerUseFunction("customEntitySpawn", function(coords, item, block){ 
    // при использовании создать моба нашего типа на координатах использования 
    Entity.spawnCustom("customEntity", coords.relative.x + .5, coords.relative.y + .5, coords.relative.z + .5); 
});

Получаем следующий результат:

Custom entity basic.png

Переменные и методы объекта моба[править]

Поскольку для мобов в мире и для базового типа мобов используется один и тот же объект, многие методы и переменные этого объекта можно использовать как на объекте описания, так и на объекте созданного в мире моба. Исключениями являются customizeEvents, customizeDescription, customizeVisual, customizeAI и setBaseType.

customizeEvents[править]

customizeEvents(custom) - позволяет задать контроллер событий (объект) следующего формата:

{
    tick: function() {}, // вызывается каждый игровой тик для моба этого типа
    created: function(extra) {}, // вызывается при создании моба данного типа, extra - дополнительные данные, которые могут быть переданы в   функцию спавна 5 параметром
    loaded: function() {}, // вызывается, когда моб загружается в мир - после создания, входа в мир или загрузки чанка, если игрок был далеко, но подошел достаточно близко
    unloaded: function() {}, // вызывается, когда чанк с мобом был выгружен, игрок ушел слишком далеко
    removed: function() {}, // вызывается, если моб уничтожен или деспавнился
    death: function(attacker) {}, // вызывается, если моб убит, attacker - в случае убийства мобом и игроком в него передается моб-убийца
    attackedBy:     function(attacker) {}, // вызывается при атаке моба, attacker - атакующий
    hurtBy: function(attacker, amount) {}, // вызывается при получении урона, attacker определен если урон получен от моба или игрока
    projectileHit: function(projectile) {} // вызывается, когда в моба попадает снаряд, projectile - этот снаряд
}

Выше приведены все возможные функции событий, в реальных примерах можно писать только те, которые непосредственно нужны в моде.

customizeDescription[править]

customizeDescription(custom) - позволяет задать контроллер описания следующего формата:

{
    getHitbox: function() {
        // возвращает ширину и высоту хитбокса моба, если не задана, его размеры будут 1, 1
        // На данный момент не работает (уточнение?)
        return {
            w: hitboxWidth,
            h: hitboxHeight
        };
    },

    getHealth: function() {
        // возвращает максимальное здоровье моба, которое задается ему при спавне, если не задана, то здоровье будет 20 единиц
        return maxHealth;
    },

    getNameTag: function() {
        // возвращает имя моба, если не задана, имени не будет
        return "name tag";
    },

    getDrop: function(attacker) {
        // возвращает массив возможного дропа при смерти, если определен attacker - одержит ссылку на моба-убийцу
        // Формат дропа: массив, состоящий из возможных предметов, каждый предмет задается так:
        return [{
            id: id, //id предмета: число,
            count: count, //кол-во предмета: число / массив чисел (будет выбрано случайно из массива) / объект {min: min, max: max} (кол-во будет выбрано между min и max включительно)
            data: data, // метадата предмета, формат аналогичен count
            chance: chance, // шанс: число с плавающей точкой от 0 до 1 - вероятность дропа этого предмета
            separate: false // если true, то при количестве больше 1, предмет будет дропнут в виде нескольких предметов, каждый с кол-вом 1
         },
         // {...}
         ]
     }
}

customizeVisual[править]

customizeVisual(custom) - позволяет задать контроллер внешнего вида моба следующего формата:

{
    getModels: function() {
        // Возвращает модели для различных состояний моба.
        return {
            "main": model
        };
    }
}  

Названия моделям даются для дальнейшего вызова visual.setModel(name, ticks), что позволяет создавать анимации.

Необходимы дополнения.

customizeAI[править]

customizeAI(custom) - позволяет устанавливать контроллер поведения (исскуственного интеллекта, ИИ мобов). Необходимы дополнения.

Прочие переменные и методы объекта моба[править]

  • setBaseType(Number) - устанавливает тип, на основе которого создается моб. По умолчанию 28 (Native.EntityType.POLAR_BEAR). 
  • recreateEntity() - создает сущность, при этом событие removed не вызывается, но вызывается событие loaded (что логично).
  • getPlayerDistance() - получает расстояние от сущности до игрока в мире.
  • denyDespawn() - запрещает деспавн сущности.
  • allowNaturalDespawn() - разрешает природный деспавн сущности.
  • destroy() - уничтожает сущность и убирает из мира. Вызываются события removed и unloaded.

Принципы создания мобов на ванильных рендерах [править]

При создании моба, основанного на ванильном рендере, могут возникать проблемы с установкой текстуры и типа рендера. В событии loaded сущности установка скина и типа рендеров не работают. Единственным простым вариантом решения проблемы является установка скина и типа рендера в тике:

customEntity.customizeEvents({
   tick: function() {
        Entity.setRender(this.entity, 3);
        Entity.setSkin(this.entity, "mob/steve.png");
    }
});

С точки зрения быстродействия данный подход не является оптимальным, поскольку установка рендера и скина требуют процессорного времени. Исправить это можно, устанавливая скин и рендер в тике, но единожды, после загрузки сущности в мире:

customEntity.customizeEvents({
    tick:function(){
        if(this.setSkin === 0){
            Entity.setRender(this.entity, 3);
            Entity.setSkin(this.entity, "mob/zombie.png");
        }
        if(this.setSkin != undefined && this.setSkin > -1){
           this.setSkin--;
        }
    },

    loaded:function(){
        this.setSkin = 5;
    },
});

Такой подход позволяет значительно оптимизировать время, затрачиваемое процессором на обработку каждого отдельного моба.