Типа рендер заполнения жизни игрока снизу верх

timaxa007

Модератор
5,831
409
672
Не думаю, что это достроена ресурса. Просто типа шпаргалки.
Java:
int hel = (int)((Minecraft.getMinecraft().thePlayer.getHealth() / Minecraft.getMinecraft().thePlayer.getMaxHealth()) * 42F);
Minecraft.getMinecraft().ingameGUI.drawTexturedModalRect(x, y + 42 - hel , 0, 42 - hel, 40, hel);
Делалось в эвенте RenderGameOverlayEvent.
Где 42 и 42F это размер текстуры по высоте. 40 это ширина, она не измена в этом случаи.
В случаи вопроса: "Как рендерить текстуру снизу в верх?" - или подобным вопросом.
 
516
11
39
Есть ли способ рендера полоски ха по кругу по часовой стрелки ?
 

timaxa007

Модератор
5,831
409
672
Темы не искал, типа сам сделал:
Java:
    public static void circleProgress(
            int x, int y,
            int u, int v, int sizeU, int sizeV,
            float radius, float radiusUV,
            float progress, float initialDegree, int segment, boolean clockwise) {

        float a = 360F / segment;
        float b = 0;

        double degree, sin, cos;
        double osin = 0;
        double ocos = 0;


        float offsetU = 1F / sizeU;
        float offsetV = 1F / sizeV;

        Tessellator tessellator = Tessellator.instance;
        tessellator.startDrawing(GL11.GL_TRIANGLES);

        for (int i = 0; i <= segment; ++i) {

            b = a * i;
            if (b < progress)
                degree = (initialDegree + b) * Math.PI / 180D;
            else
                degree = (initialDegree + progress) * Math.PI / 180D;

            if (clockwise) {
                //По часовой
                sin = Math.sin(-degree);
                cos = Math.cos(-degree);

                tessellator.addVertexWithUV((double)x + (osin * radius), (double)y + (ocos * radius), 0D,
                        (double)((float)(u + (osin * radiusUV)) * offsetU), (double)((float)(v + (ocos * radiusUV)) * offsetV));

                tessellator.addVertexWithUV((double)x, (double)y, 0D,
                        (double)((float)u * offsetU), (double)((float)v * offsetV));

                tessellator.addVertexWithUV((double)x + (sin * radius), (double)y + (cos * radius), 0D,
                        (double)((float)(u + (sin * radiusUV)) * offsetU), (double)((float)(v + (cos * radiusUV)) * offsetV));

                osin = sin;
                ocos = cos;
            }
            else {
                //Против часовой
                sin = Math.sin(degree);
                cos = Math.cos(degree);

                tessellator.addVertexWithUV((double)x + (sin * radius), (double)y + (cos * radius), 0D,
                        (double)((float)(u + (sin * radiusUV)) * offsetU), (double)((float)(v + (cos * radiusUV)) * offsetV));

                tessellator.addVertexWithUV((double)x, (double)y, 0D,
                        (double)((float)u * offsetU), (double)((float)v * offsetV));

                tessellator.addVertexWithUV((double)x + (osin * radius), (double)y + (ocos * radius), 0D,
                        (double)((float)(u + (osin * radiusUV)) * offsetU), (double)((float)(v + (ocos * radiusUV)) * offsetV));

                osin = sin;
                ocos = cos;
            }

            if (b > progress) break;
        }

        tessellator.draw();
    }

x, y - координаты центра круга положение на экране.
u, v - координаты центра круга на текстуре.
sizeU, sizeV - размеры текстуры.
radius - радиус (размер) круга от "x, y" на экране.
radiusUV - радиус (размер) круга от "u, v" на текстуре.
progress - от 0F до 360F, типа текцщие значения градуса.
initialDegree - начальный градус, смещение начального места рендера, когда это нужно чтобы не от 12 часов, а от 3 или 9 часов начанал.
segment - сколько сегментов/углов/треугольников будет иметь круг.
clockwise - создавать круг по часовой стрелки или нет.
-----
Да, как-бы на самом деле этот круг являеться многоугольником. Выбор количетва segment'ов, думал о оптимизации, так как 360 треугольников это много (но просадов особо не налюдал), по этому я сделал выбор сколько будет треугольников, особенно когда размер этого круга не большой.
-----
Пример использования в коде:
Java:
            Minecraft.getMinecraft().renderEngine.bindTexture(texture_hud);
            circleProgress(140, 70, 33, 33, 256, 256, 50F, 32F, progress, 0F, 32, true);
            circleProgress(280, 70, 99, 33, 256, 256, 50F, 32F, progress, 0F, 32, false);
            circleProgress(140, 190, 165, 33, 256, 256, 50F, 32F, progress, 180F, 32, true);
            GL11.glDisable(GL11.GL_TEXTURE_2D);
            GL11.glColor3f(0.125F, 0.5F, 1F);
            circleProgress(280, 190, 99, 33, 256, 256, 50F, 32F, progress, 90F, 32, false);
            GL11.glColor3f(1F, 1F, 1F);
            GL11.glEnable(GL11.GL_TEXTURE_2D);
Как выглядеть:

-----
Текстура:
hud.png
 
Последнее редактирование:

timaxa007

Модератор
5,831
409
672
Если мало, то вот ещё. Как-бы тоже самое, но с дыркой/отверстием по середине.
Java:
    public static void circleDoubleProgress(
            int x, int y,
            int u, int v, int sizeU, int sizeV,
            float radius, float radiusDouble, float radiusUV, float radiusDoubleUV,
            float progress, float initialDegree, int segment, boolean clockwise) {

        float a = 360F / segment;
        float b;

        double degree, sin, cos;
        double osin = 0;
        double ocos = 0;

        float offsetU = 1F / sizeU;
        float offsetV = 1F / sizeV;

        Tessellator tessellator = Tessellator.instance;
        tessellator.startDrawing(GL11.GL_QUADS);

        for (int i = 0; i <= segment; ++i) {

            b = a * i;
            if (b < progress)
                degree = (initialDegree + b) * Math.PI / 180D;
            else
                degree = (initialDegree + progress) * Math.PI / 180D;

            if (clockwise) {
                //По часовой
                sin = Math.sin(-degree);
                cos = Math.cos(-degree);

                tessellator.addVertexWithUV((double)x + (osin * radius), (double)y + (ocos * radius), 0D,
                        (double)((float)(u + (osin * radiusUV)) * offsetU), (double)((float)(v + (ocos * radiusUV)) * offsetV));

                tessellator.addVertexWithUV((double)x + (osin * radiusDouble), (double)y + (ocos * radiusDouble), 0D,
                        (double)((float)(u + (osin * radiusDoubleUV)) * offsetU), (double)((float)(v + (ocos * radiusDoubleUV)) * offsetV));

                tessellator.addVertexWithUV((double)x + (sin * radiusDouble), (double)y + (cos * radiusDouble), 0D,
                        (double)((float)(u + (sin * radiusDoubleUV)) * offsetU), (double)((float)(v + (cos * radiusDoubleUV)) * offsetV));

                tessellator.addVertexWithUV((double)x + (sin * radius), (double)y + (cos * radius), 0D,
                        (double)((float)(u + (sin * radiusUV)) * offsetU), (double)((float)(v + (cos * radiusUV)) * offsetV));

                osin = sin;
                ocos = cos;
            } else {
                //Против часовой
                sin = Math.sin(degree);
                cos = Math.cos(degree);

                tessellator.addVertexWithUV((double)x + (sin * radius), (double)y + (cos * radius), 0D,
                        (double)((float)(u + (sin * radiusUV)) * offsetU), (double)((float)(v + (cos * radiusUV)) * offsetV));

                tessellator.addVertexWithUV((double)x + (sin * radiusDouble), (double)y + (cos * radiusDouble), 0D,
                        (double)((float)(u + (sin * radiusDoubleUV)) * offsetU), (double)((float)(v + (cos * radiusDoubleUV)) * offsetV));

                tessellator.addVertexWithUV((double)x + (osin * radiusDouble), (double)y + (ocos * radiusDouble), 0D,
                        (double)((float)(u + (osin * radiusDoubleUV)) * offsetU), (double)((float)(v + (ocos * radiusDoubleUV)) * offsetV));

                tessellator.addVertexWithUV((double)x + (osin * radius), (double)y + (ocos * radius), 0D,
                        (double)((float)(u + (osin * radiusUV)) * offsetU), (double)((float)(v + (ocos * radiusUV)) * offsetV));

                osin = sin;
                ocos = cos;
            }

            if (b > progress) break;
        }

        tessellator.draw();
    }
Теже аргументы, но плюс ещё 2 аргумента "radiusDouble" и "radiusDoubleUV":
radius - радиус (размер) большого круга от "x, y" на экране.
radiusDouble - радиус (размер) малого круга от "x, y" на экране.
radiusUV - радиус (размер) большого круга от "u, v" на текстуре.
radiusDoubleUV - радиус (размер) малого круга от "u, v" на текстуре.
Теперь место треугольников параллелепипеды.
Java:
            Minecraft.getMinecraft().renderEngine.bindTexture(texture_hud);
            circleDoubleProgress(140, 70, 33, 33, 256, 256, 40F, 10F, 32F, 8F, progress, 0F, 32, true);
            circleDoubleProgress(280, 70, 99, 33, 256, 256, 40F, 10F, 32F, 8F, progress, 0F, 32, false);
            circleDoubleProgress(140, 190, 165, 33, 256, 256, 40F, 10F, 32F, 8F, progress, 180F, 32, true);
            GL11.glDisable(GL11.GL_TEXTURE_2D);
            GL11.glColor3f(0.125F, 0.5F, 1F);
            circleDoubleProgress(280, 190, 99, 33, 256, 256, 40F, 10F, 32F, 8F, progress, 90F, 32, false);
            GL11.glColor3f(1F, 1F, 1F);
            GL11.glEnable(GL11.GL_TEXTURE_2D);

-----
Java:
    public static void circleProgress(
            int x, int y,
            int u, int v,
            float radius, float radiusUV,
            float progress) {
        circleProgress(x, y, u, v, 256, 256, radius, radiusUV, progress, 180F, 32, true);
    }

    public static void circleDoubleProgress(
            int x, int y,
            int u, int v,
            float radius, float radiusDouble, float radiusUV, float radiusDoubleUV,
            float progress) {
        circleDoubleProgress(x, y, u, v, 256, 256, radius, radiusDouble, radiusUV, radiusDoubleUV, progress, 180F, 32, true);
    }
Java:
            circleDoubleProgress(140, 70, 33, 33, 40F, 10F, 32F, 8F, progress);
            circleDoubleProgress(140, 190, 165, 33, 40F, 10F, 32F, 8F, progress);
           
            circleProgress(140, 70, 33, 33, 50F, 32F, progress);
            circleProgress(140, 190, 165, 33, 50F, 32F, progress);
-----
Java:
    public static void circleDoubleProgress(
            int x, int y,
            int u, int v,
            float radius, float radiusDouble, float radiusUV,
            float progress) {
        float radiusDoubleUV = radiusUV / (radius / radiusDouble);
        circleDoubleProgress(x, y, u, v, 256, 256, radius, radiusDouble, radiusUV, radiusDoubleUV, progress, 180F, 32, true);
    }
Java:
            circleDoubleProgress(140, 70, 33, 33, 50F, 40F, 32F, progress3);
            circleDoubleProgress(140, 190, 165, 33, 50F, 10F, 32F, progress3);
 
Последнее редактирование:

timaxa007

Модератор
5,831
409
672
Попробовал использовать "GL_TRIANGLE_FAN", против часовой стрелки рендериться нормально. Но если по часовой просто развернув направление, то он будет задом рендериться (на экране будет не видно, что рендериться). Сделал, что все вершины двигались, текстура чуть дёргается. Идей нет, что ещё можно сделать для "GL_TRIANGLE_FAN" по часовой стрелки. Но если кому надо, то:
Java:
    public static void circleProgress(
            int x, int y,
            int u, int v, int sizeU, int sizeV,
            float radius, float radiusUV,
            float progress, float initialDegree, int segment, boolean clockwise) {

        float a = 360F / segment;
        float b;

        double degree, sin, cos;

        float offsetU = 1F / sizeU;
        float offsetV = 1F / sizeV;

        Tessellator tessellator = Tessellator.instance;
        tessellator.startDrawing(GL11.GL_TRIANGLE_FAN);

        tessellator.addVertexWithUV((double)x, (double)y, 0D,
                (double)((float)u * offsetU), (double)((float)v * offsetV));

        for (int i = 0; i <= segment; ++i) {
            b = a * i;

            if (clockwise) {
                if (b < progress)
                    degree = -progress - initialDegree + b;
                else
                    degree = -progress - initialDegree + progress;
            } else {
                if (b <= progress)
                    degree = initialDegree + b;
                else
                    degree = initialDegree + progress;
            }

            degree = Math.toRadians(degree);
            sin = Math.sin(degree);
            cos = Math.cos(degree);

            tessellator.addVertexWithUV((double)x + (sin * radius), (double)y + (cos * radius), 0D,
                    (double)((float)(u + (sin * radiusUV)) * offsetU), (double)((float)(v + (cos * radiusUV)) * offsetV));

            if (b > progress) break;
        }

        tessellator.draw();
    }
Против часовой нормально использовать этот код. По часовой не рекомендуется использовать.
-----
Но а так-же чтобы можно было рендерить просто круг используя "GL_TRIANGLE_FAN":
Java:
    public static void circle(
            int x, int y,
            int u, int v, int sizeU, int sizeV,
            float radius, float radiusUV,
            int segment) {

        float a = 360F / segment;
        double degree, sin, cos;

        float offsetU = 1F / sizeU;
        float offsetV = 1F / sizeV;

        Tessellator tessellator = Tessellator.instance;
        tessellator.startDrawing(GL11.GL_TRIANGLE_FAN);

        tessellator.addVertexWithUV((double)x, (double)y, 0D,
                (double)((float)u * offsetU), (double)((float)v * offsetV));

        for (int i = 0; i <= segment; ++i) {
            degree = Math.toRadians(a * i);
            sin = Math.sin(degree);
            cos = Math.cos(degree);

            tessellator.addVertexWithUV((double)x + (sin * radius), (double)y + (cos * radius), 0D,
                    (double)((float)(u + (sin * radiusUV)) * offsetU), (double)((float)(v + (cos * radiusUV)) * offsetV));
        }

        tessellator.draw();
    }
circle(140, 190, 165, 33, 256, 256, 50F, 32F, 32);

(Специально сделал восьмиугольный.)
 
2,505
81
397
Лучше сделать функцию, которая рендерит сектор круга от угла A до B. В частном случае (0, 360) это будет круг.
А потом для прогресса интерполируем либо угол А, либо B, в зависимости от того, в какую сторону нужен прогресс. В этом случае не будет никаких проблем с GL_TRIANGLE_FAN и дублирования кода.
 

timaxa007

Модератор
5,831
409
672
если @Тимаха меня не опередит...
Только сейчас у меня появилось желание сделать такое.
Код не имеет универсального использования, адаптирует и реализует кто как хочет.
Выкладываю сейчас именно такую версию (следующую не известно когда выложу).
Java:
public class RadialMenuGui extends GuiScreen {

    private static final ResourceLocation texture = new ResourceLocation(HudMod.MODID, "textures/hud.png");
    RadialMenu radialMenu = new RadialMenu(0, 0, 33 + 66 + 66, 33, 80, 40, 32, 180);

    @Override
    public void initGui() {
        super.initGui();
        radialMenu.x = width / 2;
        radialMenu.y = height / 2;
        radialMenu.segments.clear();
        radialMenu.segments.add(new RadialMenu.Segment("Build"));
        radialMenu.segments.add(new RadialMenu.Segment("Destroy"));
        radialMenu.segments.add(new RadialMenu.Segment("Buy"));
        radialMenu.segments.add(new RadialMenu.Segment("Sell"));
        radialMenu.segments.add(new RadialMenu.Segment("Cash"));
        radialMenu.segments.add(new RadialMenu.Segment("Sudmit Admin"));
        radialMenu.segments.add(new RadialMenu.Segment("Something else"));
        radialMenu.segments.add(new RadialMenu.Segment("Some more"));
        radialMenu.segments.add(new RadialMenu.Segment("End"));
    }

    @Override
    public void mouseClicked(int mouseX, int mouseY, int button) {
        super.mouseClicked(mouseX, mouseY, button);
        radialMenu.mouseClicked(mouseX, mouseY, button);
    }

    @Override
    public void drawScreen(int mouseX, int mouseY, float parTick) {
        GL11.glColor4f(1F, 1F, 1F, 1F);
        Minecraft.getMinecraft().getTextureManager().bindTexture(texture);
        radialMenu.draw(mouseX, mouseY, parTick);
    }

}
Java:
public class RadialMenu {


    public int x, y, u, v, select = -1;
    public float radius, radiusDouble, radiusUV, radiusDoubleUV, initialDegree;
    List<Segment> segments = new ArrayList<Segment>();

    public RadialMenu(int x, int y, int u, int v, float radius, float radiusDouble, float radiusUV, float initialDegree) {
        this.x = x;
        this.y = y;
        this.u = u;
        this.v = v;
        this.radius = radius;
        this.radiusDouble = radiusDouble;
        this.radiusUV = radiusUV;
        radiusDoubleUV = radiusUV / (radius / radiusDouble);
        this.initialDegree = initialDegree;
    }

    public void action(int select, Segment segment) {
        //to-do
    }

    public void mouseClicked(int mouseX, int mouseY, int button) {
        if (button == 0) {
            float a = 360F / (float)segments.size();

            float offsetMX = mouseX - x;
            float offsetMY = mouseY - y;
            float dist = MathHelper.sqrt_float(offsetMX * offsetMX + offsetMY * offsetMY);

            if (dist < radius * (select != -1 ? 1.125 : 1) && dist >= radiusDouble) {
                double mouseR = Math.toDegrees(Math.atan2(offsetMX, offsetMY));
                mouseR += initialDegree;
                if (mouseR < 0) mouseR += 360D;
                if (mouseR > 360D) mouseR -= 360D;
                select = (int)(mouseR / a);

                if ((select >= segments.size() || select < 0) && select != -1)
                    select = -1;
                else
                    action(select, segments.get(select));

                //System.out.println("mouseClicked " + select);
            }

        }
    }

    public void draw(int mouseX, int mouseY, float parTick) {
        float a = 360F / (float)segments.size();
        float b;

        float degree, sin, cos;
        float osin = 0;
        float ocos = 0;

        float offsetU = 1F / 256;
        float offsetV = 1F / 256;

        float offsetMX = mouseX - x;
        float offsetMY = mouseY - y;
        float dist = MathHelper.sqrt_float(offsetMX * offsetMX + offsetMY * offsetMY);

        if (dist < radius * (select != -1 ? 1.125 : 1) && dist >= radiusDouble) {
            double mouseR = Math.toDegrees(Math.atan2(offsetMX, offsetMY));
            mouseR += initialDegree;
            if (mouseR < 0) mouseR += 360D;
            if (mouseR >= 360D) mouseR -= 360D;
            select = (int)(mouseR / a);
        } else
            select = -1;

        if ((select >= segments.size() || select < 0) && select != -1)
            select = -1;

        //GL11.glDisable(GL11.GL_TEXTURE_2D);

        GL11.glEnable(GL11.GL_BLEND);
        OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);


        Tessellator tessellator = Tessellator.instance;
        tessellator.startDrawing(GL11.GL_QUADS);

        int segmet;
        if (segments.size() >= 36)
            segmet = segments.size();
        else
            segmet = (int)((36 / segments.size()) * segments.size());

        a = 360F / segmet;
        int test = segmet / segments.size();
        int c;
        for (int i = 0; i <= segmet; ++i) {
            b = a * i;
            degree = (b + initialDegree) * (float)Math.PI / 180F;
            sin = MathHelper.sin(degree);
            cos = MathHelper.cos(degree);

            if (select != -1) {
                c = select * test;
                if (i > c && i <= c + test) {

                    //tessellator.setColorRGBA_F(0.75F, 0.5F, 0F, 0.5F);
                    tessellator.setColorRGBA_F(1F, 1F, 1F, 0.75F);

                    tessellator.addVertexWithUV(x + (sin * radius * 1.125), y + (cos * radius * 1.125), 0D,
                            (u + (sin * radiusUV)) * offsetU, (v + (cos * radiusUV)) * offsetV);

                    tessellator.addVertexWithUV(x + (sin * radiusDouble), y + (cos * radiusDouble), 0D,
                            (u + (sin * radiusDoubleUV)) * offsetU, (v + (cos * radiusDoubleUV)) * offsetV);

                    tessellator.addVertexWithUV(x + (osin * radiusDouble), y + (ocos * radiusDouble), 0D,
                            (u + (osin * radiusDoubleUV)) * offsetU, (v + (ocos * radiusDoubleUV)) * offsetV);

                    tessellator.addVertexWithUV(x + (osin * radius * 1.125), y + (ocos * radius * 1.125), 0D,
                            (u + (osin * radiusUV)) * offsetU, (v + (ocos * radiusUV)) * offsetV);

                    osin = sin;
                    ocos = cos;

                    continue;
                }
            }

            //tessellator.setColorRGBA_F(0.125F, 0.5F, 1F, 0.5F);
            tessellator.setColorRGBA_F(0.375F, 0.375F, 0.375F, 0.25F);

            tessellator.addVertexWithUV(x + (sin * radius), y + (cos * radius), 0D,
                    (u + (sin * radiusUV)) * offsetU, (v + (cos * radiusUV)) * offsetV);

            tessellator.addVertexWithUV(x + (sin * radiusDouble), y + (cos * radiusDouble), 0D,
                    (u + (sin * radiusDoubleUV)) * offsetU, (v + (cos * radiusDoubleUV)) * offsetV);

            tessellator.addVertexWithUV(x + (osin * radiusDouble), y + (ocos * radiusDouble), 0D,
                    (u + (osin * radiusDoubleUV)) * offsetU, (v + (ocos * radiusDoubleUV)) * offsetV);

            tessellator.addVertexWithUV(x + (osin * radius), y + (ocos * radius), 0D,
                    (u + (osin * radiusUV)) * offsetU, (v + (ocos * radiusUV)) * offsetV);

            osin = sin;
            ocos = cos;
        }

        tessellator.draw();
        GL11.glColor4f(1F, 1F, 1F, 1F);


        GL11.glDisable(GL11.GL_BLEND);

        //GL11.glEnable(GL11.GL_TEXTURE_2D);


        if (select != -1)
            Minecraft.getMinecraft().fontRenderer.drawStringWithShadow(segments.get(select).text,
                    x - Minecraft.getMinecraft().fontRenderer.getStringWidth(segments.get(select).text) / 2, y - 10, 0xFFFFFF);

    }


    public static class Segment {

        public String text;

        public Segment(String text) {
            this.text = text;
        }

    }

}
--- update 13.05.2020 ---
Java:
public class RadialMenu {

    public int x, y, u, v, select = -1;
    public float radius, radiusDouble, radiusUV, radiusDoubleUV, initialDegree;
    List<Segment> segments = new ArrayList<Segment>();

    public RadialMenu(int x, int y, int u, int v, float radius, float radiusDouble, float radiusUV, float initialDegree) {
        this.x = x;
        this.y = y;
        this.u = u;
        this.v = v;
        this.radius = radius;
        this.radiusDouble = radiusDouble;
        this.radiusUV = radiusUV;
        radiusDoubleUV = radiusUV / (radius / radiusDouble);
        this.initialDegree = initialDegree;
    }

    public void action(int select, Segment segment) {
        //to-do
    }

    public void mouseClicked(int mouseX, int mouseY, int button) {
        if (button == 0) {
            float a = 360F / (float)segments.size();

            float offsetMX = mouseX - x;
            float offsetMY = mouseY - y;
            float dist = MathHelper.sqrt(offsetMX * offsetMX + offsetMY * offsetMY);

            if (dist < radius * (select != -1 ? 1.125 : 1) && dist >= radiusDouble) {
                double mouseR = Math.toDegrees(Math.atan2(offsetMX, offsetMY));
                mouseR += initialDegree;
                if (mouseR < 0) mouseR += 360D;
                if (mouseR > 360D) mouseR -= 360D;
                select = (int)(mouseR / a);

                if ((select >= segments.size() || select < 0) && select != -1)
                    select = -1;
                else
                    action(select, segments.get(select));

                //System.out.println("mouseClicked " + select);
            }

        }
    }

    public void draw(int mouseX, int mouseY, float parTick) {
        float a = 360F / (float)segments.size();
        float b;

        float degree, sin, cos;
        float osin = 0;
        float ocos = 0;

        float offsetU = 1F / 256;
        float offsetV = 1F / 256;

        float offsetMX = mouseX - x;
        float offsetMY = mouseY - y;
        float dist = MathHelper.sqrt(offsetMX * offsetMX + offsetMY * offsetMY);

        if (dist < radius * (select != -1 ? 1.125 : 1) && dist >= radiusDouble) {
            double mouseR = Math.toDegrees(Math.atan2(offsetMX, offsetMY));
            mouseR += initialDegree;
            if (mouseR < 0) mouseR += 360D;
            if (mouseR >= 360D) mouseR -= 360D;
            select = (int)(mouseR / a);
        } else
            select = -1;

        if ((select >= segments.size() || select < 0) && select != -1)
            select = -1;

        GlStateManager.disableTexture2D();

        GlStateManager.enableBlend();
        GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);


        Tessellator tessellator = Tessellator.getInstance();
        BufferBuilder bufferbuilder = tessellator.getBuffer();
        bufferbuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
        //bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX);
        int segmet;
        if (segments.size() >= 36)
            segmet = segments.size();
        else
            segmet = (int)((36 / segments.size()) * segments.size());

        a = 360F / segmet;
        int test = segmet / segments.size();
        int c;
        for (int i = 0; i <= segmet; ++i) {
            b = a * i;
            degree = (b + initialDegree) * (float)Math.PI / 180F;
            sin = MathHelper.sin(degree);
            cos = MathHelper.cos(degree);

            if (select != -1) {
                c = select * test;
                if (i > c && i <= c + test) {

                    //bufferbuilder.setColorRGBA_F(0.75F, 0.5F, 0F, 0.5F);
                    //bufferbuilder.color(1F, 1F, 1F, 0.75F);

                    bufferbuilder.pos(x + (sin * radius * 1.125), y + (cos * radius * 1.125), 0D)
                    .tex((u + (sin * radiusUV)) * offsetU, (v + (cos * radiusUV)) * offsetV)
                    .color(255, 255, 255, 127)
                    .endVertex();

                    bufferbuilder.pos(x + (sin * radiusDouble), y + (cos * radiusDouble), 0D)
                    .tex((u + (sin * radiusDoubleUV)) * offsetU, (v + (cos * radiusDoubleUV)) * offsetV)
                    .color(255, 255, 255, 127)
                    .endVertex();

                    bufferbuilder.pos(x + (osin * radiusDouble), y + (ocos * radiusDouble), 0D)
                    .tex((u + (osin * radiusDoubleUV)) * offsetU, (v + (ocos * radiusDoubleUV)) * offsetV)
                    .color(255, 255, 255, 127)
                    .endVertex();

                    bufferbuilder.pos(x + (osin * radius * 1.125), y + (ocos * radius * 1.125), 0D)
                    .tex((u + (osin * radiusUV)) * offsetU, (v + (ocos * radiusUV)) * offsetV)
                    .color(255, 255, 255, 127)
                    .endVertex();

                    osin = sin;
                    ocos = cos;

                    continue;
                }
            }

            //bufferbuilder.setColorRGBA_F(0.125F, 0.5F, 1F, 0.5F);
            //bufferbuilder.color(0.375F, 0.375F, 0.375F, 0.25F);

            bufferbuilder.pos(x + (sin * radius), y + (cos * radius), 0D)
            .tex((u + (sin * radiusUV)) * offsetU, (v + (cos * radiusUV)) * offsetV)
            .color(64, 64, 64, 96)
            .endVertex();

            bufferbuilder.pos(x + (sin * radiusDouble), y + (cos * radiusDouble), 0D)
            .tex((u + (sin * radiusDoubleUV)) * offsetU, (v + (cos * radiusDoubleUV)) * offsetV)
            .color(64, 64, 64, 96)
            .endVertex();

            bufferbuilder.pos(x + (osin * radiusDouble), y + (ocos * radiusDouble), 0D)
            .tex((u + (osin * radiusDoubleUV)) * offsetU, (v + (ocos * radiusDoubleUV)) * offsetV)
            .color(64, 64, 64, 96)
            .endVertex();

            bufferbuilder.pos(x + (osin * radius), y + (ocos * radius), 0D)
            .tex((u + (osin * radiusUV)) * offsetU, (v + (ocos * radiusUV)) * offsetV)
            .color(64, 64, 64, 96)
            .endVertex();

            osin = sin;
            ocos = cos;
        }

        tessellator.draw();
        GlStateManager.color(1F, 1F, 1F, 1F);

        GlStateManager.disableBlend();

        GlStateManager.enableTexture2D();


        if (select != -1)
            Minecraft.getMinecraft().fontRenderer.drawStringWithShadow(segments.get(select).text,
                    x - Minecraft.getMinecraft().fontRenderer.getStringWidth(segments.get(select).text) / 2, y - 10, 0xFFFFFF);

    }


    public static class Segment {

        public String text;

        public Segment(String text) {
            this.text = text;
        }

    }

}
Java:
public class RadialMenuGui extends GuiScreen {

    private static final ResourceLocation texture = new ResourceLocation(HudMod.MODID, "textures/hud.png");
    RadialMenu radialMenu = new RadialMenu(0, 0, 33 + 66 + 66, 33, 80, 40, 32, 180);

    @Override
    public void initGui() {
        super.initGui();
        radialMenu.x = width / 2;
        radialMenu.y = height / 2;
        radialMenu.segments.clear();
        radialMenu.segments.add(new RadialMenu.Segment("Build"));
        radialMenu.segments.add(new RadialMenu.Segment("Destroy"));
        radialMenu.segments.add(new RadialMenu.Segment("Buy"));
        radialMenu.segments.add(new RadialMenu.Segment("Sell"));
        radialMenu.segments.add(new RadialMenu.Segment("Cash"));
        radialMenu.segments.add(new RadialMenu.Segment("Sudmit Admin"));
        radialMenu.segments.add(new RadialMenu.Segment("Something else"));
        radialMenu.segments.add(new RadialMenu.Segment("Some more"));
        radialMenu.segments.add(new RadialMenu.Segment("End"));
    }

    @Override
    public void mouseClicked(int mouseX, int mouseY, int button) throws IOException {
        super.mouseClicked(mouseX, mouseY, button);
        radialMenu.mouseClicked(mouseX, mouseY, button);
    }

    @Override
    public void drawScreen(int mouseX, int mouseY, float parTick) {
        GlStateManager.color(1F, 1F, 1F, 1F);
        Minecraft.getMinecraft().getTextureManager().bindTexture(texture);
        radialMenu.draw(mouseX, mouseY, parTick);
    }

}
---

Два элемента.
---

3 элемента.
---

9 элементов.
---

72 элемента (а может и больше).
---
При выделеном элементе радиус взаимодействие с элементом увеличивается.
 
Последнее редактирование:

Icosider

Kotliner
Администратор
3,601
99
664
Ну почему ArrayList?((( Почему Math.sin/Math.cos, когда есть MathHelper.sin/cos?(((((
 

timaxa007

Модератор
5,831
409
672
Сделал по типу как GuiButton.
Не знаю что сказать. Не анализировал я MathHelper. Как-то видел пару методов в MathHelper (не знаю на какую версию), там использовался тоже Math, просто возвращал в менее увесистый приметив (типа не double, а float). Часто видел примеры с Java и OpenGL, которые использовали Math. Вот так я и использовать начал.
MathHelper мб точности не хватит
Вроде нормально сейчас получилось. У меня подобные проблемы были, когда я константу PI не из Math брал.
---

360 элементов.
---
Код обновил.
 

tox1cozZ

aka Agravaine
8,455
598
2,892
там использовался тоже Math, просто возвращал в менее увесистый приметив (типа не double, а float)
Там заранее рассчитаны значения синусов и косинусов и закешированы. Это работает быстрее, но нельзя же закешировать прям все возможные значения синусов и косинусов для любых аргументов, поэтому если важна высокая точность - нужно юзать Math.
 
7,099
324
1,510
прям все возможные значения синусов и косинусов для любых аргументов
А их много всевозможных? Разрешение экрана не бесконечное, может, если ограничить точность, то вполне влезут в память. А используя int-bits можно в качестве кэша юзать массив для быстрого получения значений
 
7,099
324
1,510
7,099
324
1,510
Возможно 0.0001 и 0.0002 визуально не отличаются
 

timaxa007

Модератор
5,831
409
672
На 1.12.2, с рендером ItemStack'а:
Java:
public class RadialMenuGui extends GuiScreen {

    private static final ResourceLocation texture = new ResourceLocation(HudMod.MODID, "textures/hud.png");
    RadialMenu radialMenu = new RadialMenu(0, 0, 33 + 66 + 66, 33, 80, 40, 32, 180);

    @Override
    public void initGui() {
        super.initGui();
        radialMenu.x = width / 2;
        radialMenu.y = height / 2;
        radialMenu.segments.clear();
        radialMenu.segments.add(new RadialMenu.Segment("Build", new ItemStack(Items.STICK)));
        radialMenu.segments.add(new RadialMenu.Segment("Destroy", new ItemStack(Items.APPLE)));
        radialMenu.segments.add(new RadialMenu.Segment("Buy", new ItemStack(Items.BRICK)));
        radialMenu.segments.add(new RadialMenu.Segment("Sell", new ItemStack(Items.BONE)));
        radialMenu.segments.add(new RadialMenu.Segment("Cash", new ItemStack(Items.FIREWORKS)));
        radialMenu.segments.add(new RadialMenu.Segment("Sudmit Admin", new ItemStack(Items.BOWL)));
        radialMenu.segments.add(new RadialMenu.Segment("Something else", new ItemStack(Items.GLOWSTONE_DUST)));
        radialMenu.segments.add(new RadialMenu.Segment("Some more", new ItemStack(Items.GLASS_BOTTLE)));
        radialMenu.segments.add(new RadialMenu.Segment("End", new ItemStack(Items.NAME_TAG)));
    }

    @Override
    public void mouseClicked(int mouseX, int mouseY, int button) throws IOException {
        super.mouseClicked(mouseX, mouseY, button);
        radialMenu.mouseClicked(mouseX, mouseY, button);
    }

    @Override
    public void drawScreen(int mouseX, int mouseY, float parTick) {
        GlStateManager.color(1F, 1F, 1F, 1F);
        Minecraft.getMinecraft().getTextureManager().bindTexture(texture);
        radialMenu.draw(mouseX, mouseY, parTick);
    }

}
Java:
public class RadialMenu {

    public int x, y, u, v, select = -1;
    public float radius, radiusDouble, radiusUV, radiusDoubleUV, initialDegree;
    List<Segment> segments = new ArrayList<Segment>();

    public RadialMenu(int x, int y, int u, int v, float radius, float radiusDouble, float radiusUV, float initialDegree) {
        this.x = x;
        this.y = y;
        this.u = u;
        this.v = v;
        this.radius = radius;
        this.radiusDouble = radiusDouble;
        this.radiusUV = radiusUV;
        radiusDoubleUV = radiusUV / (radius / radiusDouble);
        this.initialDegree = initialDegree;
    }

    public void action(int select, Segment segment) {
        //to-do
    }

    public void mouseClicked(int mouseX, int mouseY, int button) {
        if (button == 0) {
            float a = 360F / (float)segments.size();

            float offsetMX = mouseX - x;
            float offsetMY = mouseY - y;
            float dist = MathHelper.sqrt(offsetMX * offsetMX + offsetMY * offsetMY);

            if (dist < radius * (select != -1 ? 1.125 : 1) && dist >= radiusDouble) {
                double mouseR = Math.toDegrees(Math.atan2(offsetMX, offsetMY));
                mouseR += initialDegree;
                if (mouseR < 0) mouseR += 360D;
                if (mouseR > 360D) mouseR -= 360D;
                select = (int)(mouseR / a);

                if ((select >= segments.size() || select < 0) && select != -1)
                    select = -1;
                else
                    action(select, segments.get(select));

                //System.out.println("mouseClicked " + select);
            }

        }
    }

    public void draw(int mouseX, int mouseY, float parTick) {
        float a = 360F / (float)segments.size();
        float b;

        float degree, sin, cos;
        float osin = 0;
        float ocos = 0;

        float offsetU = 1F / 256;
        float offsetV = 1F / 256;

        float offsetMX = mouseX - x;
        float offsetMY = mouseY - y;
        float dist = MathHelper.sqrt(offsetMX * offsetMX + offsetMY * offsetMY);

        if (dist < radius * (select != -1 ? 1.125 : 1) && dist >= radiusDouble) {
            double mouseR = Math.toDegrees(Math.atan2(offsetMX, offsetMY));
            mouseR += initialDegree;
            if (mouseR < 0) mouseR += 360D;
            if (mouseR >= 360D) mouseR -= 360D;
            select = (int)(mouseR / a);
        } else
            select = -1;

        if ((select >= segments.size() || select < 0) && select != -1)
            select = -1;

        GlStateManager.disableTexture2D();

        GlStateManager.enableBlend();
        GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);


        Tessellator tessellator = Tessellator.getInstance();
        BufferBuilder bufferbuilder = tessellator.getBuffer();
        bufferbuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
        //bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX);
        int segmet;
        if (segments.size() >= 36)
            segmet = segments.size();
        else
            segmet = (int)((36 / segments.size()) * segments.size());

        a = 360F / segmet;
        int test = segmet / segments.size();
        int c;
        for (int i = 0; i <= segmet; ++i) {
            b = a * i;
            degree = (b + initialDegree) * (float)Math.PI / 180F;
            sin = MathHelper.sin(degree);
            cos = MathHelper.cos(degree);

            if (select != -1) {
                c = select * test;
                if (i > c && i <= c + test) {

                    //bufferbuilder.setColorRGBA_F(0.75F, 0.5F, 0F, 0.5F);
                    //bufferbuilder.color(1F, 1F, 1F, 0.75F);

                    bufferbuilder.pos(x + (sin * radius * 1.125), y + (cos * radius * 1.125), 0D)
                    .tex((u + (sin * radiusUV)) * offsetU, (v + (cos * radiusUV)) * offsetV)
                    .color(255, 255, 255, 127)
                    .endVertex();

                    bufferbuilder.pos(x + (sin * radiusDouble), y + (cos * radiusDouble), 0D)
                    .tex((u + (sin * radiusDoubleUV)) * offsetU, (v + (cos * radiusDoubleUV)) * offsetV)
                    .color(255, 255, 255, 127)
                    .endVertex();

                    bufferbuilder.pos(x + (osin * radiusDouble), y + (ocos * radiusDouble), 0D)
                    .tex((u + (osin * radiusDoubleUV)) * offsetU, (v + (ocos * radiusDoubleUV)) * offsetV)
                    .color(255, 255, 255, 127)
                    .endVertex();

                    bufferbuilder.pos(x + (osin * radius * 1.125), y + (ocos * radius * 1.125), 0D)
                    .tex((u + (osin * radiusUV)) * offsetU, (v + (ocos * radiusUV)) * offsetV)
                    .color(255, 255, 255, 127)
                    .endVertex();

                    osin = sin;
                    ocos = cos;

                    continue;
                }
            }

            //bufferbuilder.setColorRGBA_F(0.125F, 0.5F, 1F, 0.5F);
            //bufferbuilder.color(0.375F, 0.375F, 0.375F, 0.25F);

            bufferbuilder.pos(x + (sin * radius), y + (cos * radius), 0D)
            .tex((u + (sin * radiusUV)) * offsetU, (v + (cos * radiusUV)) * offsetV)
            .color(64, 64, 64, 96)
            .endVertex();

            bufferbuilder.pos(x + (sin * radiusDouble), y + (cos * radiusDouble), 0D)
            .tex((u + (sin * radiusDoubleUV)) * offsetU, (v + (cos * radiusDoubleUV)) * offsetV)
            .color(64, 64, 64, 96)
            .endVertex();

            bufferbuilder.pos(x + (osin * radiusDouble), y + (ocos * radiusDouble), 0D)
            .tex((u + (osin * radiusDoubleUV)) * offsetU, (v + (ocos * radiusDoubleUV)) * offsetV)
            .color(64, 64, 64, 96)
            .endVertex();

            bufferbuilder.pos(x + (osin * radius), y + (ocos * radius), 0D)
            .tex((u + (osin * radiusUV)) * offsetU, (v + (ocos * radiusUV)) * offsetV)
            .color(64, 64, 64, 96)
            .endVertex();

            osin = sin;
            ocos = cos;
        }

        tessellator.draw();
        GlStateManager.color(1F, 1F, 1F, 1F);

        GlStateManager.disableBlend();

        GlStateManager.enableTexture2D();


        GlStateManager.enableRescaleNormal();
        RenderHelper.enableGUIStandardItemLighting();
        RenderItem ri = Minecraft.getMinecraft().getRenderItem();

        a = 360F / segments.size();
        for (int i = 0; i < segments.size(); ++i) {
            b = a * i;
            c = (int)((b + (a * (i + 1))) / 2);
            degree = (c + initialDegree) * (float)Math.PI / 180F;
            sin = MathHelper.sin(degree);
            cos = MathHelper.cos(degree);
            ri.renderItemIntoGUI(segments.get(i).itemStack,
                    x + (int)(sin * ((radius + radiusDouble) / 2)) - 8,
                    y + (int)(cos * ((radius + radiusDouble) / 2)) - 8);
        }
        RenderHelper.disableStandardItemLighting();
        GlStateManager.disableRescaleNormal();


        if (select != -1)
            Minecraft.getMinecraft().fontRenderer.drawStringWithShadow(segments.get(select).text,
                    x - Minecraft.getMinecraft().fontRenderer.getStringWidth(segments.get(select).text) / 2, y - 10, 0xFFFFFF);

    }


    public static class Segment {

        public final String text;
        public final ItemStack itemStack;

        public Segment(String text, ItemStack itemStack) {
            this.text = text;
            this.itemStack = itemStack;
        }

    }

}
2020-05-14_15.55.22.png
 
Сверху