【问题标题】:Strange PolyBatch Positioning in libGDXlibGDX 中奇怪的 PolyBatch 定位
【发布时间】:2026-02-12 08:15:01
【问题描述】:

请原谅这个基本问题,只是进入 LibGDX 的胆量

我正在创建一个径向条来显示我的倒计时

我找到了一些我需要的代码,问题是径向精灵的定位。我似乎无法让它在 Image 对象中居中(因为它似乎忽略了 Image 的本地坐标并且默认为舞台的)所以 0,0 将它放在靠近屏幕左下角的位置。

我尝试使用 localtoStage 来计算正确的位置,反之亦然,但这似乎也没有给我正确的值。

请指教

    package com.goplayplay.klpoker.CSS.Classes;

        import com.badlogic.gdx.graphics.g2d.*;
        import com.badlogic.gdx.math.EarClippingTriangulator;
        import com.badlogic.gdx.math.Intersector;
        import com.badlogic.gdx.math.Vector2;
        import com.badlogic.gdx.scenes.scene2d.ui.Image;
        import com.badlogic.gdx.utils.ShortArray;

    public class ProgressCircle extends Image {

        TextureRegion texture;
        PolygonSpriteBatch polyBatch;
        Vector2 center;
        Vector2 centerTop;
        Vector2 leftTop;
        Vector2 leftBottom;
        Vector2 rightBottom;
        Vector2 rightTop;
        Vector2 progressPoint;
        float[] fv;
        IntersectAt intersectAt;

    public ProgressCircle(TextureRegion region, PolygonSpriteBatch polyBatch) {
        super(region);

        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
        //==> percent % => (percent * 360 / 100) degree

        float angle = convertToRadians(90); //percent = 0 => angle = -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) {
        //      super.draw(batch, parentAlpha);

        if (fv == null) return;

        batch.end();
        drawMe();
        batch.begin();



    }

    public void drawMe() {

        Vector2 acc = new Vector2();
        acc.set(getWidth() / 2, getHeight() / 2);
        localToStageCoordinates(acc);
        EarClippingTriangulator e = new EarClippingTriangulator();
        ShortArray sv = e.computeTriangles(fv);

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

        PolygonSprite poly = new PolygonSprite(polyReg);

        poly.setOrigin(this.getOriginX(), this.getOriginY());
        poly.setPosition(this.getX(), this.getY());
        //        poly.setPosition(acc.x, acc.y); //Attempting to calculate correct positioning - Doesnt work
        poly.setRotation(this.getRotation());
        poly.setColor(this.getColor());

        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;
    }

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


}

【问题讨论】:

    标签: java libgdx


    【解决方案1】:

    您忘记在多边形批次上设置相机的投影矩阵。您可以从传入的 Batch 中获取它的副本:

    public void draw(Batch batch, float parentAlpha) {
        //      super.draw(batch, parentAlpha);
    
        if (fv == null) return;
    
        batch.end();
        drawMe(batch.getProjectionMatrix());
        batch.begin();
    }
    
    public void drawMe(Matrix4 projection) {
        polyBatch.setProjectionMatrix(projection);
        //...
    }
    

    或者更简单地说,您可以使用 PolygonBatch 作为舞台的批次,因此您不必交换批次:

    stage = new Stage(myViewport, new PolygonBatch());
    
    //...
    
    public void draw(Batch batch, float parentAlpha) {
        //      super.draw(batch, parentAlpha);
    
        if (fv == null) return;
        //don't need to call begin and end on the batch
        drawMe((PolygonBatch)batch); 
    }
    
    public void drawMe(PolygonBatch polyBatch) {
        //...
        //don't need to call begin or end on the batch
    }
    

    顺便说一句,您的drawMe 方法实例化了很多对象,有些很大。如果您有多个执行此操作的演员,您应该避免这种情况,否则您会受到 GC 的卡顿。尝试在构造函数中只实例化一次对象并重用它们。

    【讨论】: