Libgdx - Как нарисовать заполненный прямоугольник в нужном месте в scene2d?

Я использую scene2d. Вот мой код:

    group.addActor(new Actor() {
        @Override
        public Actor hit(float arg0, float arg1) {return null;}
        @Override
        public void draw(SpriteBatch batch, float arg1) {
            batch.end();
            shapeRenderer.begin(ShapeType.FilledRectangle);
            shapeRenderer.setColor(Color.RED);
            shapeRenderer.filledRect(0, 0, 300, 20);
            shapeRenderer.end();
            batch.begin();
        }
    });

Проблема заключается в том, что он рисует этот прямоугольник относительно экрана (x = 0, y = 0), но мне нужно, чтобы он был оттянут относительно моей группы. Но если я рисую другие объекты с помощью:

batch.draw(texture, 0, 0, width, height);

он правильно рисует (x = 0, y = 0) относительно моей группы (0,0 пикселя из левого нижнего угла группы).

Любые предложения, как я могу реализовать рисование фигуры в scene2d? И может ли кто-нибудь объяснить, почему эти два вызова работают по-другому?

Ответ 1

ShapeRenderer имеет собственную матрицу преобразования и матрицу проекций. Они отделяются от SpriteBatch, которые использует сценарий Stage. Если вы обновите матрицы ShapeRenderer в соответствии с тем, что использует сценарий 2, когда вызывается Actor.draw(), вы должны получить нужные результаты.

Ответ 2

Как упоминает Род Хайд, ShapeRenderer имеет собственную матрицу преобразования и матрицу проекций. Поэтому сначала вы должны получить матрицу проектирования SpriteBatch. Я не уверен, есть ли элегантный способ сделать это, я сделал это так:

public class myActor extends Actor{

 private ShapeRenderer shapeRenderer;
 static private boolean projectionMatrixSet;

 public myActor(){
     shapeRenderer = new ShapeRenderer();
     projectionMatrixSet = false;
 }

 @Override
   public void draw(SpriteBatch batch, float alpha){
       batch.end();
       if(!projectionMatrixSet){
           shapeRenderer.setProjectionMatrix(batch.getProjectionMatrix());
       }
       shapeRenderer.begin(ShapeType.Filled);
       shapeRenderer.setColor(Color.RED);
       shapeRenderer.rect(0, 0, 50, 50);
       shapeRenderer.end();
       batch.begin();

   }
}

Ответ 3

Вам нужно преобразовать локальные координаты Актера в координаты экрана. Предполагая, что ваша сцена полноэкранная, вы можете просто использовать Actor.localToStageCoordinates:

vec.set(getX(), getY());
this.localToStageCoordinates(/* in/out */ vec);
shapeRenderer.filledRect(vec.x, vec.y, getWidth(), getHeight());

Где vec является закрытым Vector2d (вы не хотите выделять новый для каждого вызова рендеринга).

Это также предполагает, что ваш ShapeRenderer определяется как отображение на весь экран (который по умолчанию).

Кроме того, если вы перейдете от ShapeRenderer и вернитесь к SpriteBatch, обратите внимание, что batch уже настроен на координаты актера (и таким образом вы можете использовать getX() и getY() напрямую с помощью batch.draw(...).

Ответ 4

Лучшее решение для меня. Причина, когда вы используете ShapeRenderer, не реагирует на перемещение/масштабирование камеры.

public class Rectangle extends Actor {

    private Texture texture;

    public Rectangle(float x, float y, float width, float height, Color color) {
        createTexture((int)width, (int)height, color);

        setX(x);
        setY(y);
        setWidth(width);
        setHeight(height);
    }

    private void createTexture(int width, int height, Color color) {
        Pixmap pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888);
        pixmap.setColor(color);
        pixmap.fillRectangle(0, 0, width, height);
        texture = new Texture(pixmap);
        pixmap.dispose();
    }

    @Override
    public void draw(Batch batch, float parentAlpha) {
        Color color = getColor();
        batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
        batch.draw(texture, getX(), getY(), getWidth(), getHeight());
    }
}