libGDXのSprite座標の謎

  • 7
    Like
  • 0
    Comment
More than 1 year has passed since last update.

libGDXでは基本的に、原点が左下になります。
Spriteも左下の座標を基準に描画されます。
では拡大縮小した際は?回転した際は?

それぞれ検証してみました。

スプライト生成(共通)

// テクスチャー読み込み (256x256 px)
img = new Texture("badlogic.jpg");
// スプライト初期化
sprite = new Sprite( new TextureRegion(img,0,0,256,256));
sprite.setSize(256, 256);

badlogic.jpg

スプライトサイズは256x256 pixelです。

描画1:スプライトを使わず直接描画

batch.draw(img, 200, 200);

2014-04-20 06.55.32.png

スプライトの左下を起点に描画されました。

描画2:スプライトで200,200座標に描画

sprite.setPosition(200, 200);
sprite.draw(batch);

2014-04-20 06.55.32.png
スプライトを使わない時と同様にスプライトの左下を起点に描画されました。

描画3:スプライトを2倍に拡大して描画

sprite.setPosition(200, 200);
sprite.setScale(2);
sprite.draw(batch);

2014-04-20 07.10.53.png

ちょっとこれは予想外です。
スプライトの中心を基準に拡大されました。
※ 拡大縮小や回転の基準となるorigin座標はスプライトの中心がデフォルトのようです。

描画4:スプライトを45度回転して描画

sprite.setPosition(200, 200);
sprite.setRotation(45);
sprite.draw(batch);

2014-04-20 07.19.46.png

スプライトの中心を基準に回転しました。
また正の値で反時計回りに回転します。
※ 拡大縮小や回転の基準となるorigin座標はスプライトの中心がデフォルトのようです。

描画5:Originを指定してスプライトを2倍に拡大して描画

sprite.setPosition(200, 200);
sprite.setOrigin(0, 0);
sprite.setScale(2);
sprite.draw(batch);

2014-04-20 07.15.54.png

スプライトの左下(原点指定した 0,0)を基準に拡大されました。

描画6:Originを指定してスプライトを45度回転して描画

sprite.setPosition(200, 200);
sprite.setOrigin(0, 0);
sprite.setRotation(45);
sprite.draw(batch);

2014-04-20 07.18.47.png

スプライトの左下(原点指定した 0,0)を基準に回転しました。

ふむふむなるほど…

BitMapフォントの描画

フォントは左上が原点なので注意

1倍で200,200に描画

font.setScale(1f);
font.setColor(Color.RED);
font.draw(batch,"Font Draw Test!",200,200);

2014-04-20 07.26.40.png

赤い文字で「Font Draw Test!」と描画しています。
座標値とかぶって見辛いですが・・・
フォントの場合は左上が原点となります。

4倍サイズで200,200に描画

font.setScale(4f);
font.setColor(Color.RED);
font.draw(batch,"Font Draw Test!",200,200);

2014-04-20 07.27.07.png

赤い文字で「Font Draw Test!」と描画しています。
拡大もフォントの場合は左上が起点となります。

テキスト描画サイズの取得

font.setScale(4f);
font.setColor(Color.RED);
font.draw(batch,"Font Draw Test!",200,200);

TextBounds bounds = font.getBounds("Font Draw Test!");
font.setScale(2f);
font.setColor(Color.YELLOW);
font.draw(batch, "TextBounds width:" + bounds.width + " height:" + bounds.height, 200, 50);

2014-04-20 07.43.09.png

Scaleで拡大したサイズが反映される。

Bitmapフォントにいては、以下のサイトが大変参考になります。
libgdxメモ
http://doc.tir.ne.jp/devel/clan/libgdx

今回使用したソース全体

package com.dokokano.gdxviewporttest1;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.BitmapFont.TextBounds;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.utils.Scaling;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.ScalingViewport;
import com.badlogic.gdx.utils.viewport.ScreenViewport;

public class GdxViewportTest extends ApplicationAdapter {

    static final int LOGICAL_WIDTH = 800;       // ゲーム内の論理座標 幅
    static final int LOGICAL_HEIGHT = 600;  // ゲーム内の論理座標 高さ

    Stage stage;    // ViewportとCameraの管理をさせる

    SpriteBatch batch;
    private ShapeRenderer renderer;

    Texture img;
    BitmapFont font;
    private Sprite sprite;

    @Override
    public void create () {
        renderer = new ShapeRenderer();
        batch = new SpriteBatch();
        img = new Texture("badlogic.jpg");  // 256x256 px
        font = new BitmapFont();

        // スプライト初期化
        sprite = new Sprite( new TextureRegion(img,0,0,256,256));
        sprite.setSize(256, 256);

        // Initialite Stage & View port
        stage = new Stage(new FitViewport(LOGICAL_WIDTH,LOGICAL_HEIGHT));
//      stage = new Stage(new ExtendViewport(LOGICAL_WIDTH,LOGICAL_HEIGHT));
//      stage = new Stage(new ScalingViewport(Scaling.fill ,  LOGICAL_WIDTH,LOGICAL_HEIGHT));
//      stage = new Stage(new ScreenViewport());

        Matrix4 cameraMatrix = stage.getViewport().getCamera().combined;
        batch.setProjectionMatrix(cameraMatrix);
        renderer.setProjectionMatrix(cameraMatrix);
    }

    @Override
    public void render () {

        // 背景塗りつぶし(全体を黒)
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);


        // 論理表示領域を青で塗りつぶし
        renderer.begin(ShapeType.Filled);
        renderer.setColor(0,0,0.5f,1);
        renderer.rect(0, 0,LOGICAL_WIDTH,LOGICAL_HEIGHT);
        renderer.end();

        batch.begin();
        // ビットマップ描画(0,0)-(256,256)
//      batch.setColor(1,1,1,0.5f);

//      // 1
//      batch.draw(img, 200, 200);

        // スプライト描画
//      // 2
//      sprite.setPosition(200, 200);
//      sprite.draw(batch);

//      // 3
//      sprite.setPosition(200, 200);
//      sprite.setScale(2);
//      sprite.draw(batch);

//      // 4
//      sprite.setPosition(200, 200);
//      sprite.setRotation(45);
//      sprite.draw(batch);


//      // 5
//      sprite.setPosition(200, 200);
//      sprite.setOrigin(0, 0);
//      sprite.setScale(2);
//      sprite.draw(batch);

        // 6
        sprite.setPosition(200, 200);
        sprite.setOrigin(0, 0);
        sprite.setRotation(45);
        sprite.draw(batch);


        // 100x100グリッドにあわせて座標の数値描画
        for ( int x=-1000; x<=1000; x+=100) {
            for ( int y=-1000; y<1000; y+=100) {
                font.setScale(1f);
                font.setColor(Color.WHITE);
                font.draw(batch, "("+x + ","+y +")" , x, y);
            }
        }

        // bitmap font
        font.setScale(4f);
        font.setColor(Color.RED);
        font.draw(batch,"Font Draw Test!",200,200);

        TextBounds bounds = font.getBounds("Font Draw Test!");
        font.setScale(2f);
        font.setColor(Color.YELLOW);
        font.draw(batch, "TextBounds width:" + bounds.width + " height:" + bounds.height, 200, 50);


        batch.end();

        renderer.begin(ShapeType.Line);
        // 原点からの100pxごとに四角形描画(緑)
        for ( int i=-1000; i<=1000; i+=100 ) {
            renderer.setColor(Color.GREEN);
            renderer.rect(0, 0, i   , i);
        }
        // 100x100グリッドを描画(白いクロス)
        for ( int x=-1000; x<=1000; x+=100) {
            for ( int y=-1000; y<1000; y+=100) {
                renderer.setColor(Color.WHITE);
                renderer.x(x, y, 10);
            }
        }
        renderer.end();


        if (Gdx.input.isTouched()) {
            Vector3 touchPos = new Vector3();
            touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
            stage.getViewport().getCamera().unproject(touchPos);

            renderer.begin(ShapeType.Filled);
            renderer.setColor(Color.RED);
            renderer.circle(touchPos.x, touchPos.y, 50);
            renderer.end();
        }


    }

    @Override
    public void resize(int width, int height) {
        stage.getViewport().update(width, height,true);
    }


}