Создаем кубок для InnerCore

Всем привет, сегодня, мы будем делать кубок со своими собственными рендерами (аж тремя!), создадим и настроим ему тайл энтити и добавим возможность наливать в него воду и лаву.


Ещё давным-давно во времена блоклаунчера, единственным способом сделать блоку хоть какой-то рендер, был блокшейп. Это давало возможность заменить стандартный куб на параллелепипед любой формы, но на весь блок он был только один. Была возможность создать ковёр, столбик, но блок вроде лестницы или маяка создать нельзя было. Можно было пробовать создавать различные костыли, как делал я, во время первой разработки Blood Magic – создал 5 блоков и размещал их рядом, это создавало видимость цельного рендера, но появлялись различные артефакты. Все изменилось с выходом аддона IC Render, как дополнения для Core Engine. Тогда появилась возможность создавать полноценные рендеры, но даже тогда, это было не очень удобно. В Inner Core встроены возможности того аддона в модуль ICRender. Он позволяет достаточно быстро и просто создавать рендеры блокам. На вики, можно почитать, что делает каждая из функций данного модуля. Для того, чтобы сделать свой рендер вам нужно создать свою модель, добавить ей боксы (параллелепипеды), присвоить рендеру эту модель. Затем этот рендер нужно установить блоку, есть несколько способов: setStaticRender и enableCoordMapping. Первый позволяет иметь блоку только один рендер, указанный в аргументах функции, а второй, позволяет изменять рендер по мере надобности при помощи метода mapAtCoords, а рендер указанный в аргументах будет стандартным для этого блока.

Для начала мы как обычно создадим блок, дадим ему имя и перевод для него:

1
2
3
4
5
6
7
8
9
10
11
IDRegistry.genBlockID("cup");
Block.createBlock("cup", [{
    name: "Gold Cup",
    texture: [
        ["gold_block", 0]
    ],
    inCreative: true
}]);
Translation.addTranslation("Gold Cup", {
    ru: "Золотой кубок"
})

Теперь установим тип материала для блока:

1
ToolAPI.registerBlockMaterial(BlockID.cup, "stone");

Сейчас добавим кубку рецепт, он будет создаваться из золотых слитков:

1
2
3
4
5
6
7
8
Recipes.addShaped({
    id: BlockID.barrel,
    count: 1,
    data: 0
}, ["gvg",
    "ggg",
    "vgv"
], ["g", 266, -1]);

Теперь займёмся рендером, здесь мы создадим 3 вида рендера: для пустого кубка, наполненного лавой и наполненного водой.

1
2
3
var standartCup = new ICRender.Model();
var waterCup = new ICRender.Model();
var lavaCup = new ICRender.Model();

Затем мы создадим модель и начнём добавлять боксы (параллелепипеды), добавлять мы все их будем с текстурой золотого блока, поэтому просто в конце напишем 41,0 – айди золотого блока. Делать всё это нужно внутри функции, чтобы не дублировать код для заполненного кубка. Сейчас мы создадим ножку, подставку и нижнюю часть чаши.

1
2
3
4
5
function getCupModel() {
    var model = BlockRenderer.createModel();
    model.addBox(6 / 16, 0, 6 / 16, 10 / 16, 1 / 16, 10 / 16, 41, 0);
    model.addBox(7 / 16, 1 / 16, 7 / 16, 9 / 16, 5 / 16, 9 / 16, 41, 0);
    model.addBox(5 / 16, 5 / 16, 5 / 16, 11 / 16, 6 / 16, 11 / 16, 41, 0);

После этого создадим стенки для кубка.

1
2
3
4
model.addBox(5 / 16, 6 / 16, 5 / 16, 11 / 16, 12 / 16, 6 / 16, 41, 0);
    model.addBox(5 / 16, 6 / 16, 10 / 16, 11 / 16, 12 / 16, 11 / 16, 41, 0);
    model.addBox(5 / 16, 6 / 16, 6 / 16, 6 / 16, 12 / 16, 10 / 16, 41, 0);
    model.addBox(10 / 16, 6 / 16, 6 / 16, 11 / 16, 12 / 16, 10 / 16, 41, 0);

А теперь правую и левую ручку от кубка и завершим функцию возвращением модели

1
2
3
4
5
6
7
8
9
10
//левая ручка
    model.addBox(4 / 16, 7 / 16, 7.5 / 16, 5 / 16, 8 / 16, 8.5 / 16, 41, 0);
    model.addBox(3 / 16, 8 / 16, 7.5 / 16, 4 / 16, 10 / 16, 8.5 / 16, 41, 0);
    model.addBox(3 / 16, 10 / 16, 7.5 / 16, 5 / 16, 11 / 16, 8.5 / 16, 41, 0);
    //правая ручка
    model.addBox(11 / 16, 7 / 16, 7.5 / 16, 12 / 16, 8 / 16, 8.5 / 16, 41, 0);
    model.addBox(12 / 16, 8 / 16, 7.5 / 16, 13 / 16, 10 / 16, 8.5 / 16, 41, 0);
    model.addBox(11 / 16, 10 / 16, 7.5 / 16, 13 / 16, 11 / 16, 8.5 / 16, 41, 0);
    return model;
}

После этого мы создадим модель пустую, с водой и с лавой, и присвоим их соотвествующим рендерам.

1
2
3
4
5
6
7
8
9
var model = getCupModel()
standartCup.addEntry(model);
BlockRenderer.enableCoordMapping(BlockID.cup, -1, standartCup);
var model = getCupModel()
model.addBox(6 / 16, 8 / 16, 6 / 16, 10 / 16, 10 / 16, 10 / 16, 8, 0);
waterCup.addEntry(model);
var model = getCupModel()
model.addBox(6 / 16, 8 / 16, 6 / 16, 10 / 16, 10 / 16, 10 / 16, 10, 0);
lavaCup.addEntry(model);

Если до этого, вы никогда не сталкивались с ICRender, создание рендера для блока может показаться очень сложным процессом, где вам придётся после каждого добавленного бокса придётся запускать иннер и смотреть, что получается. На самом деле так только по началу, и то не точно, затем вы сможете создавать сложные рендера без проблем, если будете тренироваться в этом.
Очень важно, при добавлении боксов следить за тем, чтобы стенки (поверхность бокса) не находилась в том же месте, что и стенка другого бокса, так как это вызовет артефакты, как на скрине ниже.

Теперь перейдём к Tile Entity, здесь нам понадобится в defaultValues записать переменную id, которая у нас будет использоваться для определения заполнения кубка.

1
2
3
4
5
TileEntity.registerPrototype(BlockID.cup, {
    defaultValues: {
        id: 0
    }
});

Сейчас создадим функцию setRender, которую будем вызывать при инициализации и при изменении жидкости в кубке. Здесь мы используем конструкцию switch…case для установки рендера для блока. Он будет устанавливаться только при id =8||10, иначе будет оставаться стандартный рендер. Также мы добавим функцию init(), вызываемую при инициализации тайл энтити и вызовем там функцию setRender()

1
2
3
4
5
6
7
8
9
10
11
12
13
    init: function () {
        this.setRender();
    },
    setRender: function () {
        switch (this.data.id) {
            case 8:
                BlockRenderer.mapAtCoords(this.x, this.y, this.z, waterCup);
                break;
            case 10:
                BlockRenderer.mapAtCoords(this.x, this.y, this.z, lavaCup);
                break;
        }
    },

Теперь поработаем с функцией click: здесь мы создадим переменную item, где будем хранить информацию о предмете, которым нажал игрок. Проверим, ведро ли это, а также что ведро заполнено чем-то (не дата 0), или заполнен чем-то кубок (не ид 0), если так, то отнимаем предмет, дропаем предмет с айди ведра и датой того, что хранилось в кубке (дата 0 – пустое ведро, 8-вода, 10-лава). И присваиваем переданной this.data.id значение того, что хранилось в ведре и вызываем функцию установки рендера setRender.

1
2
3
4
5
6
7
8
9
10
11
12
    click: function () {
        var item = Player.getCarriedItem();
        if (item.id == 325) {
            Game.prevent();
            if (item.data != 0 || this.data.id != 0) {
                Player.decreaseCarriedItem(1);
                World.drop(this.x, this.y, this.z, 325, 1, this.data.id);
                this.data.id = item.data;
                this.setRender();
            }
        }
    }

Вот и всё, кубок готов, все работает. Теперь, надеюсь вы знаете, как создавать рендеры и менять их. Для ленивых, код ниже:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
IDRegistry.genBlockID("cup");
Block.createBlock("cup", [{
    name: "Gold Cup",
    texture: [
        ["gold_block", 0]
    ],
    inCreative: true
}]);
Translation.addTranslation("Gold Cup", {
    ru: "Золотой кубок"
})
ToolAPI.registerBlockMaterial(BlockID.cup, "stone");
Recipes.addShaped({
    id: BlockID.barrel,
    count: 1,
    data: 0
}, ["gvg",
    "ggg",
    "vgv"
], ["g", 266, -1]);
 
function getCupModel() {
    var model = BlockRenderer.createModel();
    model.addBox(6 / 16, 0, 6 / 16, 10 / 16, 1 / 16, 10 / 16, 41, 0);
    model.addBox(7 / 16, 1 / 16, 7 / 16, 9 / 16, 5 / 16, 9 / 16, 41, 0);
    model.addBox(5 / 16, 5 / 16, 5 / 16, 11 / 16, 6 / 16, 11 / 16, 41, 0);
 
    model.addBox(5 / 16, 6 / 16, 5 / 16, 11 / 16, 12 / 16, 6 / 16, 41, 0);
    model.addBox(5 / 16, 6 / 16, 10 / 16, 11 / 16, 12 / 16, 11 / 16, 41, 0);
    model.addBox(5 / 16, 6 / 16, 6 / 16, 6 / 16, 12 / 16, 10 / 16, 41, 0);
    model.addBox(10 / 16, 6 / 16, 6 / 16, 11 / 16, 12 / 16, 10 / 16, 41, 0);
    //левая ручка
    model.addBox(4 / 16, 7 / 16, 7.5 / 16, 5 / 16, 8 / 16, 8.5 / 16, 41, 0);
    model.addBox(3 / 16, 8 / 16, 7.5 / 16, 4 / 16, 10 / 16, 8.5 / 16, 41, 0);
    model.addBox(3 / 16, 10 / 16, 7.5 / 16, 5 / 16, 11 / 16, 8.5 / 16, 41, 0);
    //правая ручка
    model.addBox(11 / 16, 7 / 16, 7.5 / 16, 12 / 16, 8 / 16, 8.5 / 16, 41, 0);
    model.addBox(12 / 16, 8 / 16, 7.5 / 16, 13 / 16, 10 / 16, 8.5 / 16, 41, 0);
    model.addBox(11 / 16, 10 / 16, 7.5 / 16, 13 / 16, 11 / 16, 8.5 / 16, 41, 0);
    return model;
}
var standartCup = new ICRender.Model();
var waterCup = new ICRender.Model();
var lavaCup = new ICRender.Model();
var model = getCupModel()
standartCup.addEntry(model);
BlockRenderer.enableCoordMapping(BlockID.cup, -1, standartCup);
var model = getCupModel()
model.addBox(6 / 16, 8 / 16, 6 / 16, 10 / 16, 10 / 16, 10 / 16, 8, 0);
waterCup.addEntry(model);
var model = getCupModel()
model.addBox(6 / 16, 8 / 16, 6 / 16, 10 / 16, 10 / 16, 10 / 16, 10, 0);
lavaCup.addEntry(model);
 
TileEntity.registerPrototype(BlockID.cup, {
    init: function () {
        this.setRender();
    },
    setRender: function () {
        switch (this.data.id) {
            case 8:
                BlockRenderer.mapAtCoords(this.x, this.y, this.z, waterCup);
                break;
            case 10:
                BlockRenderer.mapAtCoords(this.x, this.y, this.z, lavaCup);
                break;
        }
    },
    defaultValues: {
        id: 0
    },
    click: function () {
        var item = Player.getCarriedItem();
        if (item.id == 325) {
            Game.prevent();
            if (item.data != 0 || this.data.id != 0) {
                Player.decreaseCarriedItem(1);
                World.drop(this.x, this.y, this.z, 325, 1, this.data.id);
                this.data.id = item.data;
                this.setRender();
            }
        }
    }
});
Запись опубликована в рубрике InnerCore. Добавьте в закладки постоянную ссылку.

2 комментария на «Создаем кубок для InnerCore»

  1. NikoDit_ говорит:

    Топ ща мод пилить буду!

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *