在libGDX中实现循环进度条

时间:2017-04-20 14:23:27

标签: animation libgdx progress-bar geometry

我想创建一个圆形进度条,使用libgdx库看起来像this。目前我已经创建了简单的水平进度条,使用不同的图像作为重叠自己的图层,其中一个调整大小以模拟进度。我找到了this示例,如何绘制圆形进度条,但我不了解如何使用此实现以及如何处理它。构造函数中的textureRegion是进度指示器吗?我找不到负责设置实际进度的方法。

编辑:我已经在this implementation上完成了我的解决方案。我把3层重叠自己,每当中间层滑动时,显示进度。但是我有一个问题:每当我尝试调整我的ProgressCircle实例的大小时,它都会向下移动到背景层之下。

public class ProgressCircle extends Image {

    public enum IntersectAt {
        NONE, TOP, BOTTOM, LEFT, RIGHT;
    }

    TextureRegion texture;

    PolygonSpriteBatch polyBatch;

    Vector2 center;
    Vector2 centerTop;
    Vector2 leftTop;
    Vector2 leftBottom;
    Vector2 rightBottom;
    Vector2 rightTop;
    Vector2 progressPoint;

    float[] fv;


    IntersectAt intersectAt;
    private float PROGRESS_WIDTH=0f;
    private float PROGRESS_HEIGHT=0f;
    private float posX,posY;

    public ProgressCircle(TextureRegion region, PolygonSpriteBatch polyBatch,float width,float height,float posX,float posY) {
        super(region);
        PROGRESS_WIDTH=width;
        PROGRESS_HEIGHT=height;
        this.posX=posX;
        this.posY=posY;

        this.texture = region;
        this.polyBatch = polyBatch;

        center = new Vector2(this.getWidth() / 2, this.getHeight() / 2);
        centerTop = new Vector2(this.getWidth() / 2, this.getHeight());
        leftTop = new Vector2(0, this.getHeight());
        leftBottom = new Vector2(0, 0);
        rightBottom = new Vector2(this.getWidth(), 0);
        rightTop = new Vector2(this.getWidth(), this.getHeight());
        progressPoint = new Vector2(this.getWidth() / 2, this.getHeight() / 2);

        setPercentage(0);
    }

    private Vector2 IntersectPoint(Vector2 line) {
        Vector2 v = new Vector2();
        boolean isIntersect;

        //check top
        isIntersect = Intersector.intersectSegments(leftTop, rightTop, center, line, v);

        //check bottom
        if (isIntersect) {
            intersectAt = IntersectAt.TOP;
            return v;
        } else
            isIntersect = Intersector.intersectSegments(leftBottom, rightBottom, center, line, v);

        //check left
        if (isIntersect) {
            intersectAt = IntersectAt.BOTTOM;
            return v;
        } else isIntersect = Intersector.intersectSegments(leftTop, leftBottom, center, line, v);

        //check bottom
        if (isIntersect) {
            intersectAt = IntersectAt.LEFT;
            return v;
        } else isIntersect = Intersector.intersectSegments(rightTop, rightBottom, center, line, v);

        if (isIntersect) {
            intersectAt = IntersectAt.RIGHT;
            return v;
        } else {
            intersectAt = IntersectAt.NONE;
            return null;
        }
    }

    public void setPercentage(float percent) {
        //100 % = 360 degree

        float angle = convertToRadians(90);
        angle -= convertToRadians(percent * 360 / 100);

        float len = this.getWidth() > this.getHeight() ? this.getWidth() : this.getHeight();
        float dy = (float) (Math.sin(angle) * len);
        float dx = (float) (Math.cos(angle) * len);
        Vector2 line = new Vector2(center.x + dx, center.y + dy);

        Vector2 v = IntersectPoint(line);

        if (intersectAt == IntersectAt.TOP) {
            if (v.x >= this.getWidth() / 2) {
                fv = new float[]{
                        center.x,
                        center.y,
                        centerTop.x,
                        centerTop.y,
                        leftTop.x,
                        leftTop.y,
                        leftBottom.x,
                        leftBottom.y,
                        rightBottom.x,
                        rightBottom.y,
                        rightTop.x,
                        rightTop.y,
                        v.x,
                        v.y
                };
            } else {
                fv = new float[]{
                        center.x,
                        center.y,
                        centerTop.x,
                        centerTop.y,
                        v.x,
                        v.y
                };
            }
        } else if (intersectAt == IntersectAt.BOTTOM) {
            fv = new float[]{
                    center.x,
                    center.y,
                    centerTop.x,
                    centerTop.y,
                    leftTop.x,
                    leftTop.y,
                    leftBottom.x,
                    leftBottom.y,
                    v.x,
                    v.y
            };

        } else if (intersectAt == IntersectAt.LEFT) {
            fv = new float[]{
                    center.x,
                    center.y,
                    centerTop.x,
                    centerTop.y,
                    leftTop.x,
                    leftTop.y,
                    v.x,
                    v.y
            };

        } else if (intersectAt == IntersectAt.RIGHT) {
            fv = new float[]{
                    center.x,
                    center.y,
                    centerTop.x,
                    centerTop.y,
                    leftTop.x,
                    leftTop.y,
                    leftBottom.x,
                    leftBottom.y,
                    rightBottom.x,
                    rightBottom.y,
                    v.x,
                    v.y
            };

        } else // if (intersectAt == IntersectAt.NONE)
        {
            fv = null;
        }
    }


    @Override
    public void draw(Batch batch, float parentAlpha) {
        if (fv == null) return;
        batch.end();
        drawMe();
        batch.begin();
    }


    public void drawMe() {

        EarClippingTriangulator e = new EarClippingTriangulator();
        ShortArray sv = e.computeTriangles(fv);

        PolygonRegion polyReg = new PolygonRegion(texture, fv, sv.toArray());

        PolygonSprite poly = new PolygonSprite(polyReg);
        poly.setSize(PROGRESS_WIDTH,PROGRESS_HEIGHT);
        poly.setPosition(posX,posY);
        poly.setOrigin(poly.getOriginX(), poly.getOriginY());
        poly.setRotation(this.getRotation());
        poly.setColor(Color.GREEN);

        polyBatch.begin();
        poly.draw(polyBatch);
        polyBatch.end();
    }


    float convertToDegrees(float angleInRadians) {
        float angleInDegrees = angleInRadians * 57.2957795f;
        return angleInDegrees;
    }

    float convertToRadians(float angleInDegrees) {
        float angleInRadians = angleInDegrees * 0.0174532925f;
        return angleInRadians;
    }
}

和我的初始化函数:

 ProgressCircle sprite;

 private void initCircleProgress() {

    Group group = new Group();
    Image downBackground = new Image(atlas.findRegion("progressBackground"));
    downBackground.setColor(Color.BLUE);
    downBackground.setSize(USER_SCREEN_SIZE_WIDTH/5,USER_SCREEN_SIZE_WIDTH/5);
    downBackground.setPosition(10,USER_SCREEN_SIZE_HEIGHT-(2*downBackground.getHeight()+20));

    sprite = new ProgressCircle(atlas.findRegion("progressBackground"), pbatch,
            downBackground.getWidth(),downBackground.getHeight(),downBackground.getX(),downBackground.getY());
    sprite.setSize(downBackground.getWidth(),downBackground.getHeight());
    sprite.setSize(downBackground.getX(),downBackground.getY());
    Image label = new Image(atlas.findRegion("progressBackground"));
    label.setSize(downBackground.getWidth()*0.8f,downBackground.getHeight()*0.8f);
    label.setPosition(downBackground.getX()+(downBackground.getWidth()-label.getWidth())/2,
            downBackground.getY()+(downBackground.getHeight()-label.getHeight())/2);
    label.setColor(Color.WHITE);
    group.addActor(downBackground);
    group.addActor(sprite);
    group.addActor(label);
    group.setPosition(10,GAME_SIZE_HEIGHT-(group.getHeight()+20));
    stage.addActor(group);

}

enter image description here

1 个答案:

答案 0 :(得分:0)

你需要一个圆形渐变来mask出所需的部分。

enter image description here

随着时间的推移增加掩蔽值将导致圆周运动。

正如您在link to masking中所看到的,有几种方法可以实现这一目标。模板缓冲区是一个不错的选择,但可能导致锯齿状边缘。编写自己的着色器将是完美的但有点难if you never wrote a shader。您还可以尝试解析两个像素图并决定在循环两个像素图时绘制哪些像素。如果掩蔽图像和你的源具有相同的纹理空间,你可以在一个循环中执行此操作,因此它不会比着色器慢得多,并且对你有用的是一个很好的解决方案,你可以随时优化。