美文网首页
Libgdx实现圆形进度条

Libgdx实现圆形进度条

作者: 贼噶人 | 来源:发表于2021-01-11 14:43 被阅读0次
image.png
package com.mytian.mgarden.stages.other;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;

public class CircularSeekBar extends Group {
    private Texture backgroundT;
    private Texture progressT;
    private float progress = 0;
    private float backgroundX;
    private float backgroundY;
    private float progressX;
    private float progressY;
    private float barX;
    private float barY;
    private float radius;
    private Image bar;
    private ISeekProgressUpdate iSeekProgressUpdate;
    public int duration;
    private float[] polygonVertices;
    private short[] polygonTriangles;

    public void setiSeekProgressUpdate(ISeekProgressUpdate iSeekProgressUpdate) {
        this.iSeekProgressUpdate = iSeekProgressUpdate;
    }

    public interface ISeekProgressUpdate {
        void OnSeekProgressUpdate(float progress);
    }


    public CircularSeekBar(final Texture backgroundT
            , final Texture progressT, final Texture barT) {
        this.backgroundT = backgroundT;
        this.progressT = progressT;
        backgroundT.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
        progressT.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
        barT.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
        setSize(Math.max(backgroundT.getWidth(), progressT.getWidth())
                        + barT.getWidth() / 2
                , Math.max(backgroundT.getHeight(), progressT.getHeight())
                        + barT.getHeight() / 2);
        backgroundX = (getWidth() - backgroundT.getWidth()) / 2;
        backgroundY = (getHeight() - backgroundT.getHeight()) / 2;
        progressX = (getWidth() - progressT.getWidth()) / 2;
        progressY = (getHeight() - progressT.getHeight()) / 2;
        radius = progressT.getWidth() / 2;
        bar = new Image(barT);
        barY = (float) (getHeight() / 2 + (getHeight() / 2 - 8)
                * Math.cos(Math.toRadians(360 * progress)));
        barX = (float) (getWidth() / 2 + (getWidth() / 2 - 8)
                * Math.sin(Math.toRadians(360 * progress)));
        addActor(bar);
        bar.setPosition(barX - bar.getWidth() / 2
                , barY - bar.getHeight() / 2);
        bar.setTouchable(Touchable.disabled);
        addListener(new ClickListener() {
            @Override
            public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
                super.touchDown(event, x, y, pointer, button);
                if (bar.getX() + bar.getWidth() > x && x > bar.getX() - bar.getWidth()
                        && bar.getY() + bar.getHeight() > y && y > bar.getY() - bar.getHeight()) {
                    return true;
                }
                return false;
            }

            @Override
            public void touchDragged(InputEvent event, float x, float y, int pointer) {
                super.touchDragged(event, x, y, pointer);
                final Vector2 vector21 = new Vector2(0, getHeight() / 2);
                final Vector2 vector22 = new Vector2(x - getWidth() / 2
                        , y - getHeight() / 2);
                float m =
                        (float) ((vector21.x * vector22.x + vector21.y * vector22.y) / (Math.sqrt(vector21.x * vector21.x + vector21.y * vector21.y)
                                * Math.sqrt(vector22.x * vector22.x + vector22.y * vector22.y)));
                float degrees = (float) Math.toDegrees(Math.acos(m));
                if (x > getWidth() / 2) {
                    progress = degrees / 360;
                } else {
                    progress = (360 - degrees) / 360;
                }
                barY = (float) (getHeight() / 2 + (getHeight() / 2 - 8)
                        * Math.cos(Math.toRadians(360 * progress)));
                barX = (float) (getWidth() / 2 + (getWidth() / 2 - 8)
                        * Math.sin(Math.toRadians(360 * progress)));
                bar.setPosition(barX - bar.getWidth() / 2
                        , barY - bar.getHeight() / 2);
            }

            @Override
            public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
                super.touchUp(event, x, y, pointer, button);
                if (null != iSeekProgressUpdate) {
                    iSeekProgressUpdate
                            .OnSeekProgressUpdate(progress);
                }
            }
        });
    }


    public void setProgress(final float progress, final int duration) {
        this.progress = Math.min(1, progress);
        barY = (float) (getHeight() / 2 + (getHeight() / 2 - 8)
                * Math.cos(Math.toRadians(360 * progress)));
        barX = (float) (getWidth() / 2 + (getWidth() / 2 - 8)
                * Math.sin(Math.toRadians(360 * progress)));
        bar.setPosition(barX - bar.getWidth() / 2, barY - bar.getHeight() / 2);
        this.duration = duration;
    }


    static int SPLIT_NUMS = 180;

    @Override
    protected void positionChanged() {
        super.positionChanged();
        backgroundX += getX();
        backgroundY += getY();
        progressX += getX();
        progressY += getY();
        barY = (float) (getHeight() / 2 + (getHeight() / 2 - 8)
                * Math.cos(Math.toRadians(360 * progress)));
        barX = (float) (getWidth() / 2 + (getWidth() / 2 - 8)
                * Math.sin(Math.toRadians(360 * progress)));
        bar.setPosition(barX - bar.getWidth() / 2, barY - bar.getHeight() / 2);
        polygonVertices = new float[(SPLIT_NUMS + 1) * 5];
        float color = Color.WHITE.toFloatBits();
        polygonVertices[0] = radius + progressX;
        polygonVertices[1] = radius + progressY;
        polygonVertices[2] = color;
        polygonVertices[3] = 0.5f;
        polygonVertices[4] = 0.5f;
        for (int i = 0; i < SPLIT_NUMS; i++) {
            polygonVertices[5 * (i + 1)] =
                    (float) (radius + radius * Math.sin(2 * Math.PI / SPLIT_NUMS * i)) + progressX;
            polygonVertices[5 * (i + 1) + 1] =
                    (float) (radius + radius * Math.cos(2 * Math.PI / SPLIT_NUMS * i)) + progressY;
            polygonVertices[5 * (i + 1) + 2] = color;
            polygonVertices[5 * (i + 1) + 3] =
                    (float) (0.5f + 0.5f * Math.sin(2 * Math.PI / SPLIT_NUMS * i));
            polygonVertices[5 * (i + 1) + 4] =
                    (float) (0.5f + 0.5f * Math.cos(2 * Math.PI / SPLIT_NUMS * i));
        } // 三角形坐标点,颜色、U、V坐标
        polygonTriangles = new short[SPLIT_NUMS * 3];
        for (int i = 0; i < SPLIT_NUMS; i++) {
            polygonTriangles[3 * i] = 0;
            polygonTriangles[3 * i + 1] = (short) (i + 1);
            if (i == SPLIT_NUMS - 1) {
                polygonTriangles[3 * i + 2] = 1;
            } else {
                polygonTriangles[3 * i + 2] = (short) (i + 2);
            }
        } // 画三角形时的顶点索引坐标
    }

    @Override
    public void draw(final Batch batch, final float parentAlpha) {
        batch.draw(backgroundT, backgroundX, backgroundY);
        if (batch instanceof PolygonSpriteBatch) {
            final int nums = (int) (SPLIT_NUMS * progress);
            ((PolygonSpriteBatch) batch).draw(progressT, polygonVertices
                    , 0, Math.min((nums + 2) * 5, polygonVertices.length),
                    polygonTriangles, 0
                    , Math.min(nums * 3, polygonTriangles.length)); //画圆
        }
        super.draw(batch, parentAlpha);
    }
}

原理是根据OpenGL 画三角形,来生成圆,然后把纹理UV坐标映射到三角形。

相关文章

网友评论

      本文标题:Libgdx实现圆形进度条

      本文链接:https://www.haomeiwen.com/subject/qwrdaktx.html