[1.6.4] Гайд: Создание брони с нестандартной моделью

1,990
18
105
Эпизод 1.

Всем привет, с вами %ололошканейм%. Не судите строго, это мой первый тапок. Сегодня мы с вами будем создавать шапки.



Что нам потребуется:
1. MCP + Minecraft Forge.
2. Руки. Можно кривые, главное, чтобы основание было в правильной точке.
3. Приветствуется знание основ Java и ООП в целом.
4. Techne.
5. Растровый редактор изображений.
6. IDE или редактор кода.
 6.1. Eclipse/IntelliJ IDEa/NetBeans/чтонибудьещё
 6.2. NotePad++/VIM/чтонибудьещё
7. Уши глаза и умение слушать читать.
8. Знать что такое прокси и с чем его употребляют. Желательно.

Если из списка всё при себе - прошу под кат читаем, если нет - тоже читаем, (интересна жи):

Глава 1. Создание модели в Techne.
Создаем новый проект. Наследуем его от ModelBiped, если хотим, чтобы моделька корректно отображалась на ГГ.
P6Dg70P.png

Углубляться в процесс моделирования я не буду, дело ваше, но есть одна важная деталь:
Все детали определенной части модели должны иметь одинаковую систему координат с частью тела, которой они принадлежат. Начало системы координат в Techne обозначается синей сферой.
M0MXajT.png

Вот начало координат у головы.
Создаем бокс, смотрим где его начало координат.
JWjU5cp.png

Ага, в той же точке. Значит всё правильно.
- И что теперь, как мне задавать позицию, умник?
- Так для тебя же создали специальный параметр Offset. А позиция нашей "сферы" задается параметром Position.
ykLcwe8.png

Благодаря им мы и будем задавать позицию нужным частям нашей модели.
Кстати, есть ещё кое-что хорошее в Techne.
mC2ZuDK.png

Благодаря связке Copy + Paste With Coordinates можно сэкономить уйму времени, расставляя боксы модельки.

Остальную часть моделирования я опущу, покажу лишь итог моей фантазии:
Да, и ещё одно важное замечание, не забудьте удалить самого ГГ из итоговой модели.
Т.е. не должно быть никаких head/body/right/left(arm/leg).
Собственно, итог:
bLcY4UR.png

Иии совсем итог:
HcxCZFn.png


Дальше экспортируем модель в Java код.

Глава 2. Настройка модели
Итак, мы получили код, его придется немного подправить.
Во-первых правим наследованный класс:

Код:
public class ModelHelmet extends ModelBiped
Нам нужен ModelBiped, а не ModelBase.

Традиционно добавляем параметр Entity в нужные методы:
Вот такие методы должны быть:

Код:
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity) { //здесь добавился параметр entity
    super.setRotationAngles(f, f1, f2, f3, f4, f5, entity); //и здесь
}

Код:
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) {
    super.render(entity, f, f1, f2, f3, f4, f5);
    setRotationAngles(f, f1, f2, f3, f4, f5, entity); //и здесь
    ...
    ...
Дальше мы заранее кое-что сделаем, позже обьясню.
Нам нужен список всех моделей, обьявляем его
Код:
private ArrayList<ModelRenderer> modelList = new ArrayList<ModelRenderer>();
И добавляем в лист из тела конструктора:
   
Код:
     modelList.add(Shape1);
     modelList.add(Shape2);
     modelList.add(Shape3);
     modelList.add(Shape4);
     modelList.add(Shape5);
     modelList.add(Shape6);
     modelList.add(Shape7);
     modelList.add(Shape8);
     modelList.add(Shape9);
     modelList.add(Shape10);
     modelList.add(Shape11);
     modelList.add(Shape12);
     modelList.add(Shape13);
     modelList.add(Shape14);
     modelList.add(Shape15);
     modelList.add(Shape16);
     modelList.add(Shape17);
     modelList.add(Shape18);
     modelList.add(Shape19);
     modelList.add(Shape20);
     modelList.add(Shape21);
     modelList.add(Shape22);
Да, индусокод теперь в моде.

Нуу, вроде всё, да? Пока хватит. Идем к следующей главе.

Глава 3. Создание предмета брони
Я не буду описывать здесь создание всех элементов брони, пока. Если вы попросите, то постараюсь сделать и для всего остального, только уж без наглядных моделек (в плане, мне лень делать модельки в течне), слишком много на них времени уходит.
Хватит отходить от темы, приступаем.
Сначала создадим класс брони:

Код:
public class ItemHelmet extends ItemArmor  {

    public ItemHelmet (int par1) {
        super(par1, EnumArmorMaterial.CHAIN, 0, 0);
        //аргументы: ID, материал, индекс рендера (нам не нужен, 0), тип брони
        //типы брони:
        //0 - шлем
        //1 - кираса
        //2 - поножи
        //3 - ботинки
    }
}

Методы регистрации иконки и текстуры:
Код:
    @SideOnly(Side.CLIENT)
    @Override
    public void registerIcons(IconRegister par1IconRegister) {
        this.itemIcon = par1IconRegister.registerIcon(ModInfo.MODID+":"+"icon_name");
       //очевидно регистрируем иконку для брони
    }

    @Override
    public String getArmorTexture(ItemStack stack, Entity entity, int slot, String type) {
       if (slot == 0) //шлем?
            return ModInfo.MODID + ":textures/armor/" + "texture_name.png";
       return ModInfo.MODID + ":textures/armor/" + "texture_name.png"; //ну мне лень было делать пустую текстуру
       //привязываем текстуру, путь именно в таком в формате
       //после MODID двоеточие, потом папки разделяются привычными слешами
       //в конце обязательно .png!
    }

И теперь переходим к главному, да-да, наша модель!
Код:
    @SideOnly(Side.CLIENT)
    @Override 
    public ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, int armorSlot) {
        if (armorSlot != 0) //если не шлем - бай-бай
            return null;
       
        if (itemStack != null && itemStack.getItem() instanceof ItemHelmet) {
            ModelBiped model = ClientProxy.getArmorModel(); //Я сохранил инстанс модельки в клиентском прокси
            return model;
        }
        else
            return null;
    }

Сразу покажу нетерпеливым регистрацию модели в прокси:
Код:
    public static ModelBiped modelHelmet;

    @Override
    public void init() {
        super.init();
        modelHelmet = new ModelHelmet();
    //хотел поиздеваться, да не буду, сразу скажу, что надо отключить рендер стандартных боксов брони
        modelHelmet.bipedHead.showModel = false;
        modelHelmet.bipedHeadwear.showModel = false;
        modelHelmet.bipedBody.showModel = false;
        modelHelmet.bipedLeftArm.showModel = false;
        modelHelmet.bipedRightArm.showModel = false;
        modelHelmet.bipedLeftLeg.showModel = false;
        modelHelmet.bipedRightLeg.showModel = false;
        modelHelmet.bipedCloak.showModel = false;
    }

Больше про прокси пояснять не буду, сами изучайте, тем полно.
Ну вот вроде и всё, так?
Запускаем.
tpgcis2.png

Ура ура!

Глава 4. Облом

Стоп, подожди-ка...
PbPwsKd.png

Что? Чтооооо? Пачимуявсёделалтаккактисказал! Тутор говно!
А вот что, если заглянуть в код нормальной ванильной брони, или просто ModelBiped (как сделал я), можно внимательно посмотреть на метод setRotationAngles и кое-что попытаться понять.
Происходит такое: рендерится игрок, при этом на матрицу (камеру, кому как легче) заранее применяются некоторые трансформации, а именно - смещение, скейл, и поворот (немного не в таком порядке, ну неважно, хотя матрицы вот от порядка бесятся).
Но игра же не знает когда и как ей повернуть определенную часть брони, мы об этом ей должны сообщить сами.
Итак, берем из кода ModelBiped в методе setRotationAngles две строки
Код:
this.bipedHead.rotateAngleY = par4 / (180F / (float)Math.PI);
this.bipedHead.rotateAngleX = par5 / (180F / (float)Math.PI);
Они задают боксу головы нужный поворот. По оси Z не нужен, потому что в майнкрафте игроков не хкренит.
Иии применяем их к своим моделькам.
Но подождите, у нас 22 шейпа :0
А тут вспоминаем, что мы всё кидали в лист.
Тогда все укладывается в пару строчек, создадим метод для поворота по нужным осям.

Код:
private void setRotationAngleX(float angle) {
    for (ModelRenderer modelRenderer : modelList) {
        modelRenderer.rotateAngleX = angle;
    }
}

private void setRotationAngleY(float angle) {
    for (ModelRenderer modelRenderer : modelList) {
        modelRenderer.rotateAngleY = angle;
    }
}

Переделываем чуть метод setRotationAngles:
Код:
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity) {
    super.setRotationAngles(f, f1, f2, f3, f4, f5, entity); 
    //те 2 строки из ModelBiped
    setRotationAngleY(f3 / (180F / (float)Math.PI));
    setRotationAngleX(f4 / (180F / (float)Math.PI));
}
Проверим ещё раз?
WJV0tn2.png

Всё поворачивается с головой как надо, но модель шлема не опускается при приседании?
Снова ползем в ModelBiped и дополняем наш код.
В модели setRotationAngles будет выглядеть как-то так:

Код:
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity)
  {
    super.setRotationAngles(f, f1, f2, f3, f4, f5, entity); 
    
    setRotationAngleY(f3 / (180F / (float)Math.PI));
    setRotationAngleX(f4 / (180F / (float)Math.PI));
    
    if (isSneak) 
        setRotationPointY(1.0F);
    else 
        setRotationPointY(0.0F);
  }

Вот новый метод:

Код:
  private void setRotationPointY (float par) {
    for (ModelRenderer modelRenderer : modelList) {
        modelRenderer.rotationPointY = par;
    }
  }

И заодно снова идем в класс брони и не забываем менять состояние переменной isSneak, ведь модель сама не узнает, крадется игрок или нет.
Код:
    @SideOnly(Side.CLIENT)
    @Override  
    public ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, int armorSlot) { 
        if (armorSlot != 0)
            return null;
        
        if (itemStack != null && itemStack.getItem() instanceof ItemHelmet) {
            ModelBiped model = ClientProxy.getArmorModel();
            model.isSneak = entityLiving.isSneaking();
            return model;
        }
        else 
            return null;
    }

Дальше проверяйте сами.
Пока всё, если надо будет ещё что добавить - пишите, скорее всего допишу всё в этой же теме.
[merge_posts_bbcode]Добавлено: 17.08.2014 01:27:00[/merge_posts_bbcode]

Кое-что забыл.
Лучше создать в начале в классе модели 4 отдельных списка, если хотите добавить и другие части брони, в каждый список добавляем нужные части модели и всё. Просто никто же не хочет, чтобы у него кираса или ШТАНЫ поворачивались вместе с головой?
 

timaxa007

Модератор
5,831
409
672
Спасибо, Oldestkon. Гайд мне частично помог (исправил свой баг). Лучше, чем на иностранном сайте. Я типа, некоторые шаги сделал по-свойму. Но всё-же спасибо.
=)
Банка с жидкостью, *.obj файл, типа как броня.
4912968dcc276f4531775b7c8015fd48.jpg

И так у меня и дойдёт до backpack, т.е. рюкзаков и ранцев в 3D виде, а не боксы от Techne.
 
771
5
Классный тутор у тебя, продолжай делать что-то интересненькое. :)
 
2,955
12
Да. Мне тоже очень понравилось. Теперь мне не нужно пилить такой туториал. Молодец.
Но ты как и все написал не в том разделе и перенести что-то из флудилки я не могу. Жди анти.
P.S Дал бы тебе доступ писать в раздел учебник, но анти не дал мне таких прав.
 
68
0
Спасибо за гайд. Все четко, ясно и понятно, а самое главное- разжован каждый шаг/кусок кода.Жду с нетерпением чего-нибудь еще.
 
176
0
А не проще задавать привязку частям нашей модельки при помощи child-ов?

Код:
              this.bipedHead.addChild(EarL);
              this.bipedHead.addChild(EarR);
              this.bipedHead.addChild(Rim);
 

timaxa007

Модератор
5,831
409
672
Volkula я пробовал давно (ещё на 1.5.2), части модели брони оказывали не на своём месте.
504c6daf505b1b910be2fad5fff54532.png

Тем более "bipedHead.addChild(bla_bla);" работает для "ModelRenderer" (типа модели сделанные в Techne). А вот когда придётся использовать *.obj файлы и/или Tessellator, то там нужно будет создавать свои углы поворота брони (так как стандартные углы поворота не подойдут).
 
176
0
timaxa007 написал(а):
Volkula я пробовал давно (ещё на 1.5.2), части модели брони оказывали не на своём месте.
504c6daf505b1b910be2fad5fff54532.png

Тем более "bipedHead.addChild(bla_bla);" работает для "ModelRenderer" (типа модели сделанные в Techne). А вот когда придётся использовать *.obj файлы и/или Tessellator, то там нужно будет создавать свои углы поворота брони (так как стандартные углы поворота не подойдут).
Чтобы такого не было надо ставить RotationPoint на 0F, 0F, 0F. Да и, как я вижу, сама броня сильно больше игровой "модели". Ты еще через увеличение делал, или такой и моделлил?

И это ГОРАЗДО удобнее для шапки (а тут же только шапка в туторе, да?) чем куча дополнительного кода (ну ок, строк 10).

Но в целом, для брони это не очень удобно (child-ы). Я еще и не смог найти плавающий баг с тем, что при блоке (пкм с оружием) руки неверно наклоняются. Но это надо уже в ModelBiped искать, а мне пока не до этого.
 

timaxa007

Модератор
5,831
409
672
Volkula написал(а):
Ты еще через увеличение делал, или такой и моделлил?
Нет, такая модель. То что не двигается с частями тела это вроде как-бы стандартная модель брони. Я точно не знаю, не проверял и перепроверять уже не охота.
 
122
0
Можно пожалуйста поподробнее куда вписать это
private ArrayList<ModelRenderer> modelList = new ArrayList<ModelRenderer>();
НУ и затем куда уже шейпы вписывать
 
1,990
18
105
Layser написал(а):
Можно пожалуйста поподробнее куда вписать это
private ArrayList<ModelRenderer> modelList = new ArrayList<ModelRenderer>();
НУ и затем куда уже шейпы вписывать
Конструктор модели.
Обьявление переменной, конечно, вне конструктора.
 
771
5
Кстати, у модели есть лист cubeList, можно не создавать свой.
 
34
0
Я сделал модель штанов, но они не меняют положение когда крадусь...
 

timaxa007

Модератор
5,831
409
672
Царь, ты давал условия для модели в итем броне? Ты делал угол и/или положении этой модели в фале модели?
 
Все привет  кто нибудть может написать не только про шлем но и про штаны нагрудник ?
 
72
0
[1.6.4] Гайд: Создание брони с нестандартной моделью - читай внимательно код, там этот случай разобран, а именно эти места объясняют другие виды брони
Код:
//аргументы: ID, материал, индекс рендера (нам не нужен, 0), тип брони
        //типы брони:
        //0 - шлем
        //1 - кираса
        //2 - поножи
        //3 - ботинки


Код:
 if (armorSlot != 0) //если не шлем - бай-бай
            return null;
 
LazyRavenMan написал(а):
Через NB можно писать?
[font=Verdana, Helvetica, Arial, sans-serif]6. IDE или редактор кода.[/font]
[font=Verdana, Helvetica, Arial, sans-serif] 6.1. Eclipse/IntelliJ IDEa/NetBeans/чтонибудьещё[/font]
[font=Verdana, Helvetica, Arial, sans-serif] 6.2. NotePad++/VIM/чтонибудьещё[/font]
 
Сверху