Smart GUI

1,111
47
420
Итак, я понял, что если не сделать нормального описания, никто ничего использовать не будет, а потому погнали!

Вот например, как вы делаете кнопки?
Кодер: Ну как, как, вот так:
Код:
package ru.justagod.justacore.example.tutorial;

import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;

/**
 * Created by JustAGod on 12.11.17.
 */
public class TutorialGui extends GuiScreen {

   

    @Override
    public void initGui() {
        super.initGui();
        buttonList.add(new GuiButton(0, width / 2, height / 2, "Кнопка"));
    }
}
Ага, прикольно, а как обрабатывать нажатие буишь?
Кодер: 
Код:
public class TutorialGui extends GuiScreen {



    @Override
    public void initGui() {
        super.initGui();
        buttonList.add(new GuiButton(0, width / 2, height / 2, "Кнопка"));
    }

    @Override
    protected void actionPerformed(GuiButton button) {
        super.actionPerformed(button);
        
        if (button.id == 0) {
            System.out.println("Кнопка нажата");
        }
    }
}
Да, выглядит довольно просто. А как сделать кнопку которая будет выглядеть как твоя текстурка?
Кодер: Я не понимаю к чему ты ведешь, но вот так:
Код:
package ru.justagod.justacore.example.tutorial;

import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.ResourceLocation;

/**
 * Created by JustAGod on 12.11.17.
 */
public class TutorialGui extends GuiScreen {



    @Override
    public void initGui() {
        super.initGui();
        buttonList.add(new GuiButton(0, width / 2, height / 2, "Кнопка"));
    }

    @Override
    protected void actionPerformed(GuiButton button) {
        super.actionPerformed(button);

        if (button.id == 0) {
            System.out.println("Кнопка нажата");
        }
    }
    
    private class TextureButton extends GuiButton {

        public TextureButton(int id, int x, int y, String text) {
            super(id, x, y, text);
        }

        public TextureButton(int id, int x, int y, int width, int height, String text) {
            super(id, x, y, width, height, text);
        }

        @Override
        public void drawButton(Minecraft minecraft, int mouseX, int mouseY) {
            minecraft.renderEngine.bindTexture(new ResourceLocation("modid", "texture"));

            Tessellator t  = Tessellator.instance;
            t.startDrawingQuads();
            t.addVertexWithUV(xPosition, yPosition, zLevel, 0, 0);
            t.addVertexWithUV(xPosition + width, yPosition, zLevel, 1, 0);
            t.addVertexWithUV(xPosition + width, yPosition + height, zLevel, 1, 1);
            t.addVertexWithUV(xPosition, yPosition + height, zLevel, 0, 1);
            t.draw();
        }
    }
}
Ух, согласись кода уже довольно много, не так ли?
Кодер: Ну, да, много, тем более я до сих пор не понял зачем я это писал.
А все очень просто! Смотри как это сделаю я:
Код:
package ru.justagod.justacore.example.tutorial;

import net.minecraft.util.ResourceLocation;
import ru.justagod.justacore.gui.overlay.ImageOverlay;
import ru.justagod.justacore.gui.overlay.ScaledOverlay;
import ru.justagod.justacore.gui.screen.PichGui;

/**
 * Created by JustAGod on 12.11.17.
 */
public class TutorialGui extends PichGui {

    public TutorialGui() {
        ScaledOverlay o = new ImageOverlay(50, 50, 25, 25, new ResourceLocation("modid", "texture"));
        addOverlay(o);
        
        o.mouseClickListeners.add((x, y, overlay) -> {
            System.out.println("Нажатие!");
        });
    }
}
Кодер: удобно конечно, но если это все на что способна твоя библиотек, не интересно.

Если это было бы все, я б такое не выкладывал. Допустим ты хочешь сделать так чтобы твою кнопку можно было бы таскать по экрану. Как бы ты это сделал?

Кодер: вопросики у тебя конечно те еще. Я бы переопределил mouseClickMove и каждый раз бы просчитывал находится ли мышка в кнопке и в зависимости от этого двигал бы ее или не двигал. Код я писать не буду, потому что слишком много.

Вооот! А я вот сделал бы это так:
Код:
package ru.justagod.justacore.example.tutorial;

import net.minecraft.util.ResourceLocation;
import ru.justagod.justacore.gui.model.Vector;
import ru.justagod.justacore.gui.overlay.ImageOverlay;
import ru.justagod.justacore.gui.overlay.ScaledOverlay;
import ru.justagod.justacore.gui.screen.PichGui;

/**
 * Created by JustAGod on 12.11.17.
 */
public class TutorialGui extends PichGui {

    public TutorialGui() {
        ScaledOverlay o = new ImageOverlay(50, 50, 25, 25, new ResourceLocation("modid", "texture"));
        addOverlay(o);

        o.mouseClickListeners.add((x, y, overlay) -> {
            System.out.println("Нажатие!");
        });
        o.dragListeners.add((scaledOverlay, from, to) -> {
            Vector way = to.subtract(from);
            o.setScaledPos(way.add(o.getScaledPos()));
        });
    }

    @Override
    protected void mouseClickMove(int mouseX, int mouseY, int lastButton, long time) {
        super.mouseClickMove(mouseX, mouseY, lastButton, time);
    }
}
Кодер: Да у тебя там какой то не знакомый мне Vector появляется. Нее, твоя библиотека слишком сложна.

Вектор в данном случае просто точка. Где from - откуда переместилась мышь, а to - куда она переместилась. Я просто нахожу разницу и перемещаю на эту разницу мою псевдо-кнопку.

Кодер: Звучит просто. А этот ивент вызывается при любом перемещении мыши?

Конечно нет. Он вызывает только если from внутри элемента. Когда ты будешь писать свои необычные элементы обязательно переопредели метод "public Rect getMouseRect()" именно эта область учитывается при любом взаимодействиях с мышью. 

Кодер: И все же твоя библиотека пока не впечатляет. Что там есть еще?

Помимо все возможных ивентов, которые отлавливают клавиатуру, нажатие, колесико, перемещение итд. Есть очень простая в использовании система анимации каких то отдельных элементов. Допустим ты хочешь чтоб твоя кнопка довольно плавно передвинулась из центра в край экрана.
Код:
o.addAnimator(new MovingToAnimation(60, 80, 15));
Где o это ScaledOverlay.
60 - время в тиках
80 и 15 - целевая позиция 
 
А еще стоит сказать что все элементы автоматически меняют свою позицию и размер во время расширения или сужения окна, что конечно можно отключить. getX возвращает число которое вы задали в конструкторе. Соответственно когда вы вызовете getScaledX он вернет подогнаный к экрану X если включена scalePos если нет вернет getX. Так же каждому элементу можно дать какую то свою трансформацию:
Код:
o.transformations.add(new Transformation() {
            @Override
            public void preTransform(ScaledOverlay scaledOverlay) {
                DrawHelper.enableAlpha();
                glColor4d(1, 0, 0, 0.4);
            }

            @Override
            public void postTransform(ScaledOverlay scaledOverlay) {
                DrawHelper.disableAlpha();
            }
        });


Кодер: Уже интересней, а что еще?

Ух ну тебе не угодить. Ну давай я тебе расскажу про VerticalScrollingOverlay. Это точно такой элемент и ты можешь его точно так же добавить в свой PichGui, но этот элемент в то же время является и родителем, то есть ты можешь в него добавлять другие элементы. Но помимо этого ему можно задать свои внутрение размеры и он будет работать как обычный ScrollingPanel(даже своя каретка есть).
Код:
AbstractPanelOverlay parent = new VerticalScrollingOverlay(50, 50, new Dimensions(3000, 3000), new Color(0.3, 0.5, 0.4, 0.2));
        addOverlay(parent);
        parent.addOverlay(o);
Параметры
x, y, innerDimensions, backgroundColor
Довольно крутой фичей библиотеки, является возможность добавления ScrollingOverlay в другой ScrollingOverlay(серьезная работа со Scissor, для тех кто шарит).

Кодер: Что ж заинтриговал, пойду попробую. Стоп, а где я могу его найти и как ее использовать?

Возьми весь код из моего репозитория, и скопируй его в src/main/java/ и наслаждайся. Не забудь удалить класс Main!

Кодер: Здорово, смотри какую крутую шнягу я уже сделал
Код:
public class SimpleGui extends PichGui {

    public SimpleGui() {
        super();
        setPauseGame(false);
        clear();

        addOverlay(new ButtonOverlay(40, 40, 20, "Тык", ()->{
            clear();
            scrollingExample();
        }));

    }

    @Override
    protected void actionPerformed(GuiButton p_146284_1_) {
        super.actionPerformed(p_146284_1_);
    }

    private void scrollingExample() {
        final HorizontalScrollingOverlay scrollingOverlay = new HorizontalScrollingOverlay(2, 50, 96, 48, new Dimensions(2000, 2000), new Color(0.2, 0.2, 0.2, 0.2));
        //scrollingOverlay.setScaleMode(ScaledOverlay.ScaleMode.HEIGHT_EQUAL_WIDTH);
        addOverlay(scrollingOverlay);

        TextOverlay o = new TextOverlay(10, 0, "Анимация");
        addOverlay(o);


        o.addAnimator(new QueuedAnimation.Builder().append(new MovingToAnimation(40, 90, 0)).append(new MovingToAnimation(40, 10, 0)).setCycled().build());


        scrollingOverlay.addOverlay(new TextInputOverlay(50, 60, 10, 2));
        AbstractPanelOverlay parent = new VerticalScrollingOverlay(2, 2, 96, 48, new Dimensions(2000, 2000), new Color(0.2, 0.2, 0.2, 1));
        scrollingOverlay.addOverlay(parent);

        ColorButtonOverlay button = new ColorButtonOverlay(2, 30, 20, 20, "Добавить", () -> {
            generateNew(scrollingOverlay);
            parent.toFront();

        }, 1, 0.5, 0.5, 1);
        scrollingOverlay.addOverlay(button);
        button.setScaleMode(ScaledOverlay.ScaleMode.DONT_SCALE_HEIGHT);


        for (int i = 0; i < 500; i++) {
            generateNew(parent);
        }
    }

    private void generateNew(OverlayParent parent) {
        ColorOverlay o = new ColorOverlay(randomFloat(0, 100), randomFloat(0, 100), 10, 10, 1, randomFloat(0, 1), randomFloat(0, 1), randomFloat(0, 1));

        o.dragListeners.add((scaledOverlay, from, to) -> scaledOverlay.setScaledPos(to.subtract(new Vector(5, 5))));
        o.setScaleSize(false);
        parent.addOverlay(o);

    }


}

Не плохо, удачи тебе в твоих изысканиях.

Немного скриншотов https://imgur.com/a/gS8S8
 

mod

156
2
12
то есть ставим этот мод в фордж эклипса (если да, то как? ) и проверяем скрипт?
 
5,018
47
783
Вставку gif анимаций твоя либа поддерживает? Если да, скачаю!
 
1,111
47
420
Ну товарищ, там столько всего накручено, столько всего, но gif нету. Сорян.


synchronized нужны. Честное слово. Тем более они там не везде.
 
1,990
18
105
Я не вдавался в подробности, но когда поверхностно пробегал глазками по коду, мне показалось, что расстановка syncronized действительно какая-то странная. Синхронизировать все на draw или инпуте - o_O.
 
1,111
47
420
Да гспд нашли к чему приколебаться. Хорошо я посмотрю, подумаю, уберу лишние.
 
1,111
47
420
Эх на скриншотах видна такая маленькая вершина айсберга
 
1,015
9
102
Выглядит круто. Если добавить еще в раза 2 больше фич и сделать хороший тутор по этой либе, то много кто её будет юзать
 
2,505
81
397
Назови причину, по который ты суешь synchronized в update, draw, etc методы?


Мне кажется, что создавать для каждого виджета (в твоем случае скаллед оверлея) целую кучу массивов с листенерами как-то дороговато. Да и на деле обычно не пригождаются. Проще анонимно переопределить. Удобны (для стандартны элементов) лишь onButtonClick (for button), onDoubleClick (for button), onTextChanged (for text box) и onScrollChanged (for scroll), но и то не для каждого примитива. Ну это лишь из моего опыта. Сделай хоть бы для этих списков ленивую инициализацию.


Еще я не нашел, где ты интерполируешь движение. Ты делаешь это?


Мне показалось или ты не диспозишь текстуру в BufferedImageOverlay? И зачем вообще нужен этот элемент? Собрался для одной и той же картинки отдельную текстуру заводить?


От создания каждый кадр векторов и прямоугольников тоже можно отказаться.


Код:
} catch (ConcurrentModificationException ignored) {}
А вот так точно не делается. Хотя бы выбрасывай в консоль стэк трейс. Пусть юзверь (другой кодер) знает, что косячит. Или твоя либа косячит.
 
Сверху