EntityTrowable или предмет, который можно кинуть

EntityTrowable или предмет, который можно кинуть

Нет прав для скачивания
Версия(и) Minecraft
1.12+
Доброго времени суток, господа.
Этот туториал ориентирован, прежде всего, на новичков и ничего сложного не представляет. Здесь я даже не упомяну про рендер, пользуясь исключительно ванильными средствами.
Однако, на эту версию подобных статей практически нет, и я думаю лишней она не будет.
Ну а те, кто не новички, возможно, найдут что-нибудь интересное в главе 5.
Ладно, хватит лирики, поехали!

Содержание:
  1. Глава 0. Предисловие
  2. Глава 1. Подготовка
  3. Глава 2. Класс entity
  4. Глава 3. Рендер
  5. Глава 4. Привязка entity к предмету
  6. Глава 5. Для продвинутых

Глава 0. Предисловие:
Мы создадим летающее яблоко. Да, как бы странно это не звучало. Более того, это яблоко будет наносить довольно большой урон по слизням.

Глава 1. Подготовка:
1.Будет неплохо, если у нас уже есть готовый предмет, или на худой конец основа мода и настроенный прокси. Если вы этого не сделали, советую заглянуть сюда: Прокси, Предмет.
2.Также нам потребуется сделать инстанцию.
Для этого в главном классе нашего мода (в моём случае он называется FlyApple) добавим вот такой код:
Java:
    //Инстанция нашего мода. Потребуется для создания нашего entity
    @Instance(Info.ID) // В данном случае Info.ID - это id мода
    public static FlyApple instance;
Если вы проделали всё вышеописанное, можете переходить к следующей главе.

Глава 2. Класс entity:
В основном пакете мода (в моём случае это ru.mousecray.flyapple) создадим пакет entity.
Далее создадим класс EntityFlyApple:
Java:
//Вообще-то мы могли бы наследовать от EntitySnowball, однако
//в нашем случае, это ничего не даст + придётся
//переопределить лишний метод, и оставить его пустым.
public class EntityFlyApple extends EntityThrowable {

    //Три блока ниже - это конструкторы. На разные случаи жизни.
    public EntityFlyApple(World world) {
        super(world);
    }

    public EntityFlyApple(World world, EntityLivingBase thrower) {
        super(world, thrower);
    }

    public EntityFlyApple(World world, double x, double y, double z) {
        super(world, x, y, z);
    }

    //Вызов различных событий (частицы, звуки), при попадени снаряда в цель (живое существо, блок)
    @Override
    @SideOnly(Side.CLIENT)
    public void handleStatusUpdate(byte id) {
        if (id == 3) {
            for (int i = 0; i < 8; ++i) {
                //Появляются частицы лавы. В обычном майнкрафте они образуются на потолке, если сверху лава.
                this.world.spawnParticle(EnumParticleTypes.DRIP_LAVA, this.posX, this.posY, this.posZ, 0.0D, 0.0D, 0.0D);
            }
        }
    }

    //Вызывается, когда предмет попадает в цель (живое существо, блок)
    @Override
    protected void onImpact(RayTraceResult result) {
        //Проверяем, что цель - это другой entity
        if (result.entityHit != null) {
            //Урон от яблока по умолчанию
            int i = 0;

            //Урон от яблока, если цель - это слизень
            if (result.entityHit instanceof EntitySlime) {
                i = 3;
            }

            //Атакуем цель, в качестве 1-ого аргумента, передаём хозяина снаряда,
            //а в качестве 2-ого - урон.
            //Хозяин снаряда нужен, чтобы при смерти цели, можно было вывести сообщение о виновнике смерти.
            //Не писать же, что убийца - стрела или яблоко)
            //DamageSource.causeThrownDamage относится к так называемому косвенному урону, то-есть урону,
            //с помощью подручных средств, в нашем случае с помощью яблока.
            result.entityHit.attackEntityFrom(DamageSource.causeThrownDamage(this, this.getThrower()), (float)i);
        }

        //Проверяем, что мир - "ВсёКромеКлиента", то-есть мир НЕ подключён к какому-либо серверу,
        //а значит сам является сервером. Имеется в виду ЛОГИЧЕСКИЙ сервер
        if (!this.world.isRemote) {
            //Название метода не очень корректное. Отправляет пакет с "действием" нашего снаряда,
            //где идентификтором выступает байт
            this.world.setEntityState(this, (byte)3);
            //entity умирает
            this.setDead();
        }
    }
}
Теперь зарегистрируем entity. Для этого в классе CommonProxy в методе preInit
добавим вот эту строчку:
Java:
EntityRegistry.registerModEntity(new ResourceLocation("flyapple", "flying_apple"), EntityFlyApple.class, "flyapple:flying_apple", 0, FlyApple.instance, 64, 20, true);
new ResourceLocation("flyapple", "flying_apple") - Ссылка на ресурсы нашего entity (modid:name).
EntityFlyApple.class - Имя класса нашего entity.
"flyapple:flying_apple" - Имя entity. Рекомендуется писать в стиле modid:name чтобы не было конфликтов с майнкрафтом.
0 - Идентификатор нашего entity. В одном моде, у каждого entity должен быть свой уникальный id.
FlyApple.instance - То, о чём мы говорили в первой главе - инстанция.
64, 20 - 1. Радиус, в котором entity будет замечать других существ; 2.Частота этого наблюдения.
true - Нужно ли слать пакеты об изменении скорости. Не имеет смысла, для неподвижных существ.

Теперь мы можем запустить игру и посмотреть, что получилось.
Screenshot_1.png
Мы можем призвать наш entity, однако не увидим его. Ведь мы не сделали ему рендер.

Глава 3. Рендер:
В отличии от других примеров по созданию entity мы Не будем делать свой рендер, мы просто используем ванильный класс RenderSnowball.
Итак, приступим!

После 1.12 случилось? обновление, и стандартный метод регистрации стал @Deprecated. В связи с этим нам нужно создавать класс-наследник IRenderFactory. Суть в том, что для каждого "снаряда", придётся создавать новый класс IRenderFactory, пусть даже анонимный. Это не очень удобно, поэтому мы создадим один общий класс для всех EntityTrowable. Начнём.
В главном пакете мода создадим пакет render, а в нём класс SnowballRenderFactory:
Java:
public class SnowballRenderFactory implements IRenderFactory {

    public final Item item;

    //Конструктор. В него мы передаём предмет, от которого нужно взять текстуру
    public SnowballRenderFactory(Item item) {
        this.item = item;
    }

    @Override
    public Render createRenderFor(RenderManager manager) {
        //Возвращаем рендер снежка, и передаём предмет, который мы инициализировали в конструкторе
        return new RenderSnowball(manager, item, Minecraft.getMinecraft().getRenderItem());
    }

}
Затем мы зарегистрируем рендер для яблока, используя наш RenderFactory. В ClientProxy, нашего мода добавим такую строчку:
Java:
        //Регистрируем рендер, и в качестве 1-ого аргумента передаём класс нашего entity,
        //а в качестве второго - наш RenderFactory. Items.APPLE - предмет, с которого entity
        //возьмёт текстуру.
        RenderingRegistry.registerEntityRenderingHandler(EntityFlyApple.class, new SnowballRenderFactory(Items.APPLE));
ВАЖНО: Эту строчку нужно поместить в метод preInit, и только в него. НЕ в init, НЕ в postInit. Иначе рендер entity работать не будет.
После того, как мы всё сделали, запустим игру и посмотрим, что получилось:
Screenshot_2.png


Чтобы призвать entity, введите вот такую команду:
/summon flyapple:flying_apple ~2 ~2 ~ {Motion:[1.0,0.0,0.0]}

Глава 4. Привязка entity к предмету:
Мы ведь хотим, чтобы у нас не просто был свой снаряд, но и чтобы его можно было кинуть с помощью предмета. Всё, что нам нужно, это добавить в класс предмета вот этот метод:
Java:
    //Метод вызывается, когда игрок кликет ПКМ с предметом
    public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
        //Получаем стак в руке игрока
        ItemStack itemstack = player.getHeldItem(hand);

        //Проверяем, что игрок НЕ в творческом режиме
        if (!player.capabilities.isCreativeMode) {
            //Уменьшаем стак на 1
            itemstack.shrink(1);
        }

        //Проигрываем звук
        world.playSound((EntityPlayer)null, player.posX, player.posY, player.posZ, SoundEvents.ENTITY_SNOWBALL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F));
        //Делаем задержку между бросаниями
        player.getCooldownTracker().setCooldown(this, 20);

        if (!world.isRemote) {
            //Создаём объект нашего летающего яблока
            EntityFlyApple apple = new EntityFlyApple(world, player);
            //Поворачиваем его "лицом" к игроку и устанавливаем параметры движения
            apple.setHeadingFromThrower(player, player.rotationPitch, player.rotationYaw, 0.0F, 1.5F, 1.0F);
            //Призываем наш entity
            world.spawnEntity(apple);
        }

        //Для статистики
        player.addStat(StatList.getObjectUseStats(this));
        //Возвращаем успешное действие, то-есть при ПКМ рука дёрнется как будто игрок кинул предмет
        return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, itemstack);
    }
Вот и всё! Мы сделали всё, что нужно!

Глава 5. Для продвинутых:
Итак, мы дошли до цели. Но, предположим, что ты, читатель, не совсем новичок! Тогда тебе может показаться мало того, что я написал. И именно на этот случай я подготовил эту главу. Она будет короткой, но в ней ты найдёшь информацию, для ещё большей кастомизации нашего с тобой предмета.
Нет, не нашего с тобой предмета, ТВОЕГО!
  • Допустим, ты хочешь, чтобы твой entity появлялся, при использовании ванильного предмета. Без проблем. Однако, тебе потребуется сделать свой EventHandler. Самый обычный - EVENT_BUS. Дальше тебе нужно добавить эвент, который будет ниже. Код практически идентичен коду, который я использовал в 4-ой главе, поэтому без комментариев:
    Java:
        @SubscribeEvent    public static void onItemRightClick(PlayerInteractEvent.RightClickItem event) {
            ItemStack stack = event.getItemStack();
            if(stack.getItem() == Items.APPLE) {
                EntityPlayer player = event.getEntityPlayer();
                World world = event.getWorld();
          
                if (!player.capabilities.isCreativeMode) {
                    stack.shrink(1);
                }
    
                world.playSound((EntityPlayer)null, player.posX, player.posY, player.posZ, SoundEvents.ENTITY_SNOWBALL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (new Random().nextFloat() * 0.4F + 0.8F));
                player.getCooldownTracker().setCooldown(stack.getItem(), 20);
    
                if (!world.isRemote) {
                    EntityFlyApple apple = new EntityFlyApple(world, player);
                    apple.setHeadingFromThrower(player, player.rotationPitch, player.rotationYaw, 0.0F, 1.5F, 1.0F);
                    world.spawnEntity(apple);
                }
            }
        }
    Здесь я добавил спавн entity, при ПКМ ванильным яблоком. Жаль теперь его нельзя съесть.

  • Помнишь метод setHeadingFromThrower? Да, да в 4-ой главе. К слову сказать, в конструкторе entity можно использовать метод похожий на вышеупомянутый, за исключением, пожалуй, параметров скорости, и зависимости от игрока: setThrowableHeading.
Параметры метода:​
x, y, z - Буквально, движение. Задаёт направление перемещения;​
Velocity - скорость полёта пули;​
Accuracy - разброс при стрельбе.​

  • Ты всё ещё можешь регистрировать рендер entity без использования IRenderFactory, но этот метод регистрации помечен аннотацией @Deprecated. Используй его, на свой страх и риск:)
  • В пакете net.minecraft.entity.projectile ты сможешь найти ванильные классы всех "летучих" entity, но такие entity как фейерверк, жемчужина эндера и глаз эндера, находятся в пакете net.minecraft.entity.item.
  • Все рендеры ванильных entity можно найти в пакете net.minecraft.client.renderer.entity.
Ах да, ещё ты можешь воспользоваться этими ссылками для получения дополнительной информации, но я Не являюсь автором этих статей.
Вот и всё. Всё, что я мог сказать по этой теме, я сказал. И не забывайте, что вы можете скачать архив с рабочим кодом, если у вас что-либо не получилось. А теперь... желаю удачи!;)
Автор
mousecray
Скачивания
7
Просмотры
2,543
Первый выпуск
Обновление
Оценка
4.50 звёзд 2 оценок

Другие ресурсы пользователя mousecray

Последние рецензии

Отлично! Сам пользовался, никаких нареканий нет! (Только обнови его чуть-чуть ;) )
Регистрацию в прокси бы попроще сделать, а так молодец!)
Сверху