不同对象的坐标错误

时间:2014-10-04 18:54:06

标签: java libgdx coordinates coordinate-systems

简而言之:

我借助这种方法创建了Polygon对象:

   public static float[][] getPolygonArrays(float cx, float cy, float R, int sides) {
        float[] x = new float[sides];
        float[] y = new float[sides];
        double thetaInc = 2 * Math.PI / sides;
        double theta = (sides % 2 == 0) ? thetaInc : -Math.PI / 2;
        for (int j = 0; j < sides; j++) {
            x[j] = (float) (cx + R * Math.cos(theta));
            y[j] = (float) (cy + R * Math.sin(theta));
            theta += thetaInc;
        }
        return new float[][]{x, y};
    }

并将其合并到一个维度数组:

   public static float[] mergeCoordinates(float[][] vertices) throws Exception {
        if (vertices.length != 2 || vertices[0].length != vertices[1].length) throw new Exception("No valid data");
        ArrayList<Float> mergedArrayList = new ArrayList<Float>();
        float[] mergedArray = new float[vertices[0].length * 2];

        for(int i = 0; i < vertices[0].length; i++) {
            mergedArrayList.add(vertices[0][i]);
            mergedArrayList.add(vertices[1][i]);
        }

        int i = 0;
        for (Float f : mergedArrayList) {
            mergedArray[i++] = (f != null ? f : Float.NaN);
        }

        return mergedArray;
    }

对于所有新创建的多边形(在代码中以平台命名),我使用0作为X和Y的值。方法mergeCoordinates的结果我传递给Polygon对象的方法setVertices。

在此步骤之后,我使用x = Gdx.graphics.getWidth()/ 2和y = Gdx.graphics.getHeight()/ 2执行setPosition。多边形位置很好,就在游戏屏幕中心。

比我创建一个新的Polygon,它必须使用来自第一个Polygon对象的原点坐标,这个新的多边形我命名为Figure。要设置原点坐标,请使用Polygon类的方法setOrigin,并使用Platform Polygon对象的X和Y.

当我运行方法旋转平台多边形对象时,我也旋转图多边形对象,并且图必须围绕原点,平台中心旋转。但事实并非如此。

图围绕右下角旋转。

例如:

我的屏幕尺寸是640 x 480.中心点将是320 x 240.这是平台多边形对象的X和Y,我用getX和多边形的getY检查它。我在0,0处创建Figure,执行setPosition(320,200)(这是图到平台的首选轨道距离)。而且这个位置也很好。

我为图多边形对象运行setOrigin(320,240)。

我为Figure对象运行rotate。并且它以某种方式认为右下角有坐标x = 320和y = 240并围绕这一点旋转。

任何可以帮我解决这个问题吗?

您可以在下面找到有关问题的更多详细信息(详细信息,图片,GIF,方案以及来源)。

更详细的部分从此处开始

我试图理解libgdx中的坐标系是如何工作的,因为我在游戏世界中定位对象有问题。 我用一个大的Red Polygon对象(代码中的Platform)创建了简单的应用程序, Imgur

10个白色三角形多边形(代码中的扇区),包含在大多边形对象中并继承它的行为(如rotate,moveTo等)。 Imgur

我在每个扇区内添加一条绿色折线(代码方向),从扇形多边形的第一个顶点到第一个点的另一侧的中间点。 Imgur

这是技术线,我将使用它的顶点(两点的坐标)来移动小的红色多边形对象(代码中的图),从中心到对侧的中心点。 Imgur

当我点击舞台并且点击坐标位于平台内部时,我将其向左或向右旋转(取决于点击的位置)。在旋转时,所有扇区和技术线都正确旋转。 http://i.imgur.com/s5xaI8j.gif (670KB)

正如你在gif上看到的那样,数字围绕着你的中心点旋转。我发现Polygon类有方法setOrigin(float x,float y),并在下面说明这个方法的注释:

  

/ **设置所有多边形的局部顶点所在的原点   相对于。 * /

所以我尝试使用这种方法,将图的原点X设置为平台的中心X,将原点Y设置为平台的中心Y,并尝试旋转平台。 http://i.imgur.com/pXpTuQi.gif (1.06MB)

如您所见,图多边形认为他的原点坐标位于右下角。并且图围绕右下角旋转。

我将原点更改为下一个值:x = 50且y = 50,这是一个结果: http://i.imgur.com/Iajb9sN.gif (640KB)

我无法理解为什么它表现得那样。我的逻辑应该改变什么?

我的项目中没有多少课程。我删除了所有导入和getter / setter以减少行数。

如果有必要,我可以提供整个项目。

GameScreen代码:

public class GameScreen extends DefaultScreen {

    private final GameWorld world;
    private final GameRenderer renderer;

    public GameScreen() {
        world = new GameWorld();
        renderer = new GameRenderer(world);
    }

    @Override
    public void render(float delta) {
        world.update(delta);
        renderer.render();
    }

    @Override
    public void resize(int width, int height) {
        world.resize(width, height);
    }
}

GameWorld代码:

public class GameWorld {

    private ArrayList < Platform > platforms = new ArrayList < Platform > ();
    private OrthographicCamera camera;
    private Stage stage;

    private Array < Figure > activeFigures;
    private Pool < Figure > figuresPool;

    private long lastFigureTime = TimeUtils.nanoTime();

    public GameWorld() {
        setCamera(new OrthographicCamera());
        getCamera().setToOrtho(true, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

        setStage(new Stage());
        getStage().setViewport(new ScreenViewport(getCamera()));

        initializePools();

        createPlatforms();

        getStage().addListener(new InputListener() {
            public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
                float degrees = Config.PLATFORM_ROTATE_DEGREES;
                if (x <= Gdx.graphics.getWidth() / 2) {
                    degrees *= -1;
                }
                int i = getPlatforms().size();
                while (i-- > 0) {
                    Platform platform = getPlatforms().get(i);
                    if (!platform.isLocked() && platform.isRotatable() && platform.getShape().getPolygon().contains(x, y)) {
                        platform.addAction(Actions.rotateBy(degrees, 1, Interpolation.bounceOut));
                        break;
                    }
                }
                return true;
            }
        });

        Gdx.input.setInputProcessor(getStage());
    }

    private void initializePools() {
        setActiveFigures(new Array < Figure > ());
        setFiguresPool(new Pool < Figure > () {@Override
            protected Figure newObject() {
                return new Figure();
            }
        });
    }


    private void createPlatforms() {
        float max = Gdx.graphics.getHeight() / (Gdx.graphics.getWidth() / (Gdx.graphics.getWidth() / 2));
        float x = Gdx.graphics.getWidth() / 2;
        float y = Gdx.graphics.getHeight() / 2;

        float sides = 10f;
        Color color = Color.RED;

        createPlatform(x, y, max * Config.THIRD_PLATFORM_RADIUS_MULTIPLIER, sides, color, true, false, false, null);
    }


    private Platform createPlatform(float x, float y, float radius, float sides, Color color, boolean rotatable, boolean locked, boolean isEmpty, Platform relatedTo) {
        Platform platform = new Platform(0, 0, radius, sides, color, isEmpty, this);
        platform.moveTo(x, y);

        platform.setRotatable(rotatable);
        platform.setLocked(locked);

        getPlatforms().add(platform);
        getStage().addActor(platform);

        if (relatedTo != null) {
            relatedTo.addRelation(platform);
        }

        return platform;
    }

    private Figure createFigure(float x, float y) {
        Figure figure = getFiguresPool().obtain();

        figure.init(this, 0, 0, 10f, 4f, Color.DARK_GRAY);

        figure.moveTo(x, y);

        getActiveFigures().add(figure);
        getStage().addActor(figure);

        return figure;
    }

    public void spawnFigure() {
        if (getActiveFigures().size >= 10) return;
        if (TimeUtils.nanoTime() - getLastFigureTime() <= 2000000000) return;
        Platform platform = null;
        for (Platform p: getPlatforms()) {
            if (!p.isEmpty()) {
                platform = p;
                break;
            }
        }

        if (platform == null) {
            setLastFigureTime(TimeUtils.nanoTime());
            return;
        }

        Sector sector = platform.getSectors().get(MathUtils.random(platform.getSectors().size() - 1));

        float x = platform.getX();
        float y = platform.getY();

        Figure figure = createFigure(x, y);

        figure.origin(x, y);

        x = sector.getDirection().getTransformedVertices()[2];
        y = sector.getDirection().getTransformedVertices()[3];

        figure.addAction(Actions.moveTo(x, y, 1));

        setLastFigureTime(TimeUtils.nanoTime());
    }

    public void update(float delta) {
        updatePlatforms(delta);
        updateFigures(delta);

        spawnFigure();
    }


    private void updatePlatforms(float delta) {
        for (Platform platform: getPlatforms()) {
            platform.update(delta);
        }
    }

    private void updateFigures(float delta) {
        Figure figure;
        int figures = getActiveFigures().size;
        for (int i = figures; --i >= 0;) {
            figure = getActiveFigures().get(i);
            if (figure.isAlive() == false) {
                getActiveFigures().removeIndex(i);
                getFiguresPool().free(figure);
            } else {
                figure.update(delta);
            }
        }
    }

    public void resize(int width, int height) {
        getCamera().setToOrtho(true, width, height);
        getStage().getViewport().update(width, height, true);

        for (Platform platform: getPlatforms()) {
            platform.resize(true, width, height);
        }

        for (Figure figure: getActiveFigures()) {
            figure.resize(true, width, height);
        }
    }
}

GameRenderer代码:

public class GameRenderer {

    private ShapeRenderer shapeRenderer;
    private GameWorld world;
    private SpriteBatch spriteBatch;

    public GameRenderer(GameWorld world) {
        setWorld(world);

        setShapeRenderer(new ShapeRenderer());
        getShapeRenderer().setProjectionMatrix(getWorld().getCamera().combined);

        setSpriteBatch(new SpriteBatch());
        getSpriteBatch().setProjectionMatrix(getWorld().getCamera().combined);
    }

    public void render() {
        Gdx.gl.glClearColor(0f, 0.2f, 0.4f, 1f);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        getWorld().getCamera().update();

        getSpriteBatch().setProjectionMatrix(getWorld().getCamera().combined);
        getShapeRenderer().setProjectionMatrix(getWorld().getCamera().combined);

        getWorld().getStage().act(Gdx.graphics.getDeltaTime());
        getWorld().getStage().draw();

        renderGameObjects();
    }

    private void renderGameObjects() {
        renderPlatforms();
        renderFigures();
    }

    private void renderFigures() {
        getShapeRenderer().begin(ShapeRenderer.ShapeType.Line);
        for (Figure figure: getWorld().getActiveFigures()) {
            figure.render(getSpriteBatch(), getShapeRenderer());
        }
        getShapeRenderer().end();
    }

    private void renderPlatforms() {
        getShapeRenderer().begin(ShapeRenderer.ShapeType.Line);
        for (Platform platform: world.getPlatforms()) {
            platform.render(getSpriteBatch(), getShapeRenderer());
        }
        getShapeRenderer().end();
    }
}

平台代码:

public class Platform extends GameObject {

    private ArrayList < Sector > sectors = new ArrayList < Sector > ();
    private ArrayList < Platform > relations = new ArrayList < Platform > ();

    private boolean rotatable = true;
    private boolean locked = false;

    private void initialize(float cx, float cy, float radius, float sides, Color color) {
        setPosition(cx, cy);
        setRadius(radius);
        setShape(ShapeType.POLYGON.getInstance(new float[] {
            cx, cy, radius, sides
        }, color));
    }

    public Platform(float cx, float cy, float radius, float sides, Color color, boolean isEmpty, GameWorld gameWorld) {
        setGameWorld(gameWorld);
        initialize(cx, cy, radius, sides, color);
        setEmpty(isEmpty);

        if (!isEmpty()) {
            generateSectors();
        }
    }

    private void generateSectors() {
        float[] vertices = getShape().getVertices();
        for (int i = 0; i < vertices.length; i += 2) {
            try {
                Color color = Color.WHITE;
                if (i + 3 > vertices.length) {
                    getSectors().add(new Sector(new float[] {
                        getX(), getY(), vertices[i], vertices[i + 1], vertices[0], vertices[1]
                    }, color, this, i / 2));
                } else {
                    getSectors().add(new Sector(new float[] {
                        getX(), getY(), vertices[i], vertices[i + 1], vertices[i + 2], vertices[i + 3]
                    }, color, this, i / 2));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void rotateBy(float degrees) {
        setRotation(degrees);
        getShape().rotate(degrees);

        for (Sector sector: getSectors()) {
            sector.rotate(degrees);
        }

        for (Platform platform: getRelations()) {
            platform.rotateBy(degrees);
        }

        for (Figure figure: getGameWorld().getActiveFigures()) {
            figure.rotate(degrees);
        }
    }

    @Override
    public void moveTo(float x, float y) {
        super.moveTo(x, y);

        getShape().moveTo(x, y);

        for (Sector sector: getSectors()) {
            sector.moveTo(x, y);
        }

        for (Platform platform: getRelations()) {
            platform.moveTo(x, y);
        }
    }

    public void addRelation(Platform platform) {
        if (platform.equals(this)) return;
        getRelations().add(platform);
    }

    @Override
    public void update(float delta) {
        for (Sector sector: getSectors()) {
            sector.update(delta);
        }
    }

    @Override
    public void dispose() {
        for (Sector sector: getSectors()) {
            sector.dispose();
        }
    }

    @Override
    public void render(SpriteBatch spriteBatch, ShapeRenderer shapeRenderer) {
        render(spriteBatch);
        if (Config.DEBUG_LAYOUTS) render(shapeRenderer);

        for (Sector sector: getSectors()) {
            sector.render(spriteBatch, shapeRenderer);
        }
    }

    private void render(ShapeRenderer shapeRenderer) {
        shapeRenderer.setColor(getShape().getColor());
        shapeRenderer.polygon(getShape().getVertices());
    }

    public void resize(boolean reposition, int width, int height) {
        if (reposition) {
            moveTo(width / 2, height / 2);
        }
    }
}

行业代码:

public class Sector extends GameObject {

    private Polyline direction;
    private float[] vertices;
    private Platform platform;
    private int sectorId;

    public Sector(float[] vertices, Color color, Platform platform, int sectorId) throws Exception {
        setSectorId(sectorId);
        setVertices(vertices);
        initialize(vertices, color, platform);
    }

    private void createDirection() {
        float[] vertices = getShape().getPolygon().getVertices();
        float x1 = vertices[0];
        float y1 = vertices[1];

        float x2 = (vertices[2]+vertices[4])/2;
        float y2 = (vertices[3]+vertices[5])/2;

        setDirection(new Polyline(new float[]{ x1, y1, x2, y2 }));
    }

    public Sector(float[] vertices, Color color, boolean isEmpty) throws Exception {
        initialize(vertices, color);
        setEmpty(isEmpty);
    }

    private void initialize(float[] vertices, Color color) throws Exception {
        if (vertices.length != 6) {
            throw new Exception("Sector constructor expects 6 vertices");
        }
        setShape(ShapeType.TRIANGLE.getInstance(vertices, color));
        createDirection();
    }

    private void initialize(float[] vertices, Color color, Platform platform) throws Exception {
        if (vertices.length != 6) {
            throw new IllegalArgumentException("Sector constructor expects 6 vertices");
        }
        setShape(ShapeType.TRIANGLE.getInstance(vertices, color));
        setPlatform(platform);
        createDirection();
    }

    public void rotate(float degrees) {
        getShape().rotate(degrees);
        getDirection().rotate(degrees);
    }

    @Override
    public void moveTo(float x, float y) {
        super.moveTo(x, y);

        getShape().moveTo(x, y);

        getDirection().setPosition(x, y);
    }

    @Override
    public void render(SpriteBatch spriteBatch, ShapeRenderer shapeRenderer) {
        render(spriteBatch);
        if (Config.DEBUG_LAYOUTS) render(shapeRenderer);
    }

    private void render(ShapeRenderer shapeRenderer) {
        shapeRenderer.setColor(getShape().getColor());
        shapeRenderer.polygon(getShape().getVertices());


        shapeRenderer.setColor(Color.GREEN);
        shapeRenderer.line(getDirection().getTransformedVertices()[0], getDirection().getTransformedVertices()[1], getDirection().getTransformedVertices()[2], getDirection().getTransformedVertices()[3]);
    }
}

图代码:

public class Figure extends GameObject {

    private GameWorld world;

    public void init(GameWorld world, float cx, float cy, float radius, float sides, Color color) {
        super.init();
        setWorld(world);
        initialize(cx, cy, radius, sides, color);
    }

    private void initialize(float cx, float cy, float radius, float sides, Color color) {
        super.moveTo(cx, cy);

        setRadius(radius);
        setShape(ShapeType.POLYGON.getInstance(new float[] {
            cx, cy, radius, sides
        }, color));
    }

    @Override
    public void moveTo(float x, float y) {
        super.moveTo(x, y);
        getShape().moveTo(x, y);
    }

    @Override
    public void setPosition(float x, float y) {
        if (!isAllowedToFlyFuther()) {
            clearActions();
            return;
        }
        moveTo(x, y);
    }

    private boolean isAllowedToFlyFuther() {
        for (Figure figure: getWorld().getActiveFigures()) {
            if (!figure.equals(this) && Intersector.overlapConvexPolygons(figure.getShape().getPolygon(), getShape().getPolygon())) {
                return false;
            }
        }
        return true;
    }

    @Override
    public void reset() {
        super.reset();
        remove();
    }

    @Override
    public void update(float delta) {}

    private void render(SpriteBatch spriteBatch) {}

    @Override
    public void dispose() {}

    @Override
    public void render(SpriteBatch spriteBatch, ShapeRenderer shapeRenderer) {
        render(spriteBatch);
        if (Config.DEBUG_LAYOUTS) render(shapeRenderer);
    }

    private void render(ShapeRenderer shapeRenderer) {
        shapeRenderer.setColor(getShape().getColor());
        shapeRenderer.polygon(getShape().getVertices());
    }

    public void rotate(float degrees) {
        setRotation(degrees);
        getShape().rotate(degrees);
    }

    public void origin(float originX, float originY) {
        setOrigin(originX, originY);
        getShape().setOrigin(originX, originY);
    }

    public void resize(boolean reposition, int width, int height) {
        if (reposition) {
            //TODO: implement reposition for figures
        }
    }

}

GameObject代码:

public abstract class GameObject extends Actor implements Poolable {
    private int speed = 200;
    private int baseSpeed = 200;
    private boolean alive;

    private float radius;
    private GameWorld gameWorld;
    private Shape shape;
    private boolean empty = false;

    public GameObject() {
        setAlive(false);
    }

    public void init() {
        setAlive(true);
    }

    public void reset() {
        setAlive(false);
    }

    public abstract void update(float delta);
    public abstract void render(SpriteBatch spriteBatch, ShapeRenderer shapeRenderer);
    public abstract void dispose();

    public void moveTo(float x, float y) {
        super.setPosition(x, y);
    }
}

形状代码:

public class Shape {
    private Color color = new Color(Color.RED);
    private float[] vertices;
    private int sides;
    private float radius;
    private Polygon polygon = new Polygon();

    public void rotate(float degrees) {
        getPolygon().rotate(degrees);
        setVertices(getPolygon().getTransformedVertices());
    }

    public void moveTo(float x, float y) {
        getPolygon().setPosition(x, y);
        setVertices(getPolygon().getTransformedVertices());
    }

    public void setOrigin(float originX, float originY) {
        getPolygon().setOrigin(originX, originY);
        setVertices(getPolygon().getTransformedVertices());
    }

    public void scale(float ratio) {
        getPolygon().setScale(ratio, ratio);
        setVertices(getPolygon().getTransformedVertices());
    }
}

ShapeType代码:

public enum ShapeType {

    POLYGON {@Override
        public Shape getInstance(float[] settings, Color color) {
            try {
                return new PolygonShape(settings, color);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return new BaseShape();
        }
    },

    TRIANGLE {@Override
        public Shape getInstance(float[] settings, Color color) {
            try {
                return new TriangleShape(settings, color);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return new BaseShape();
        }
    };

    public abstract Shape getInstance(float[] settings, Color color);
}

PolygonShape代码:

public class PolygonShape extends Shape {
    public PolygonShape(float[] settings, Color color) throws Exception {
        if (settings.length < 4) {
            throw new IllegalArgumentException("Polygon shape constructor expects minimum 4 items in settings");
        }
        setSides((int) settings[3]);
        setRadius(settings[2]);

        setVertices(Utils.mergeCoordinates(Utils.getPolygonArrays(settings[0], settings[1], settings[2], (int) settings[3])));

        getPolygon().setVertices(getVertices());
    }
}

TriangleShape代码:

public class TriangleShape extends Shape {
    public TriangleShape(float[] settings, Color color) throws Exception {
        if (settings.length < 6) {
            throw new IllegalArgumentException("Triangle shape constructor expects minimum 6 items in settings");
        }
        setVertices(settings);
        setColor(color);
        getPolygon().setVertices(getVertices());
    }
}

实用程序代码:

public class Utils {
    public static float[] mergeCoordinates(float[][] vertices) throws Exception {
        if (vertices.length != 2 || vertices[0].length != vertices[1].length) throw new Exception("No valid data");
        ArrayList < Float > mergedArrayList = new ArrayList < Float > ();
        float[] mergedArray = new float[vertices[0].length * 2];

        for (int i = 0; i < vertices[0].length; i++) {
            mergedArrayList.add(vertices[0][i]);
            mergedArrayList.add(vertices[1][i]);
        }

        int i = 0;
        for (Float f: mergedArrayList) {
            mergedArray[i++] = (f != null ? f : Float.NaN);
        }

        return mergedArray;
    }

    public static float[][] getPolygonArrays(float cx, float cy, float R, int sides) {
        float[] x = new float[sides];
        float[] y = new float[sides];
        double thetaInc = 2 * Math.PI / sides;
        double theta = (sides % 2 == 0) ? thetaInc : -Math.PI / 2;
        for (int j = 0; j < sides; j++) {
            x[j] = (float)(cx + R * Math.cos(theta));
            y[j] = (float)(cy + R * Math.sin(theta));
            theta += thetaInc;
        }
        return new float[][] {
            x, y
        };
    }
}

配置代码:

public class Config {
    public static final String LOG = TheGame.class.getSimpleName();

    public static final boolean DEBUG_LAYOUTS = true;
    public static final boolean SHOW_LOG = false;

    public static final float PLATFORM_ROTATE_DEGREES = 36;
}

DesktopLauncher代码:

public class DesktopLauncher {
    public static void main(String[] arg) {
        LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
        config.title = "The Game!";
        config.width = 1920 / 3;
        config.height = 1080 / 3;

        new LwjglApplication(new TheGame(), config);
    }
}

项目结构: Imgur

平台对象结构和依赖关系: Imgur

渲染对象工作流程 Imgur

0 个答案:

没有答案