I created small test, with the following code, and tried doing these steps to use the hotswap functionality.
Run the program using the Debug button
Create a break point in the render function, to pause the program.
Change the value of rectangle.width
Compile the program
Let intelliJ reload the code.
But this doesn't seem to change the size of the rectangle on the screen.
public class HotSwapTest extends ApplicationAdapter {
OrthographicCamera camera;
ShapeRenderer shapeRenderer;
private static final int SCREEN_WIDTH = 800;
private static final int SCREEN_HEIGHT = 480;
Rectangle rectangle;
#Override
public void create() {
shapeRenderer = new ShapeRenderer();
camera = new OrthographicCamera();
camera.setToOrtho(false, SCREEN_WIDTH, SCREEN_HEIGHT);
rectangle = new Rectangle();
rectangle.x = SCREEN_WIDTH / 2 - 64 / 2;
rectangle.y = 20;
rectangle.width = 100;
rectangle.height = 30;
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(1, 1, 0, 1);
shapeRenderer.rect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
shapeRenderer.end();
camera.update(); // only if we're moving the screen though
}
}
Realized after typing this that I should have changed the width of the rectangle in the render function. Since create function won't be run again.
The following code works properly.
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
rectangle.width = 5; // Change this line while debugging.
rectangle.height = 10;
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(1, 1, 0, 1);
shapeRenderer.rect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
shapeRenderer.end();
camera.update(); // only if we're moving the screen though
}
Related
My goal is to draw all my visuals to a framebuffer which has a size that matches 1 by 1 with my pixel art assets. And then output the framebuffer texture to the current screen size. (A common solution for scaling pixel art).
The problem I am having while trying to achieve this is 2-fold
The frameBuffer texture is drawn too small. I expect the texture to match the whole window.
resizing the screen further distorts the proportions and position. I expect the frameBuffer texture to keep filling the screen after resizing it.
This is my trimmed down code.
public class BattleScreen extends GameScreen {
public static final int VISIBLE_WIDTH = 21;
public static final int VISIBLE_HEIGHT = 21;
private static OrthographicCamera mapCamera = null;
private SpriteBatch spriteBatch;
private OrthographicCamera hudCamera;
private Hud hud;
private EntityStage entityStage;
private FrameBuffer fbo;
private void initializeVariables(UnitOwner enemy, MapManager mapMgr) {
mapCamera = new OrthographicCamera();
mapCamera.setToOrtho(false, VISIBLE_WIDTH, VISIBLE_HEIGHT);
fbo = new FrameBuffer(Pixmap.Format.RGBA8888, 672, 672, false);
spriteBatch = new SpriteBatch(900);
entityStage = new EntityStage();
hudCamera = new OrthographicCamera();
hudCamera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
#Override
public void show() {
resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
mapCamera.position.set(currentMap.getMapWidth() * 0.5f, currentMap.getMapHeight() * 0.5f, 0f);
mapRenderer = new OrthogonalTiledMapRenderer(mapMgr.getCurrentTiledMap(), Map.UNIT_SCALE, spriteBatch);
mapRenderer.setView(mapCamera);
final FitViewport vp = new FitViewport(VISIBLE_WIDTH, VISIBLE_HEIGHT, mapCamera);
currentMap.getTiledMapStage().setViewport(vp);
entityStage.setViewport(vp);
}
private void update(final float delta) {
mapCamera.position.x = Utility.clamp(mapCamera.position.x, currentMap.getTilemapWidthInTiles() - (mapCamera.viewportWidth * 0.5f), 0 + (mapCamera.viewportWidth * 0.5f));
mapCamera.position.y = Utility.clamp(mapCamera.position.y, currentMap.getTilemapHeightInTiles() - (mapCamera.viewportHeight * 0.5f), 0 + (mapCamera.viewportHeight * 0.5f));
mapCamera.update();
hudCamera.update();
}
private void renderElements(final float delta) {
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
fbo.begin();
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderMap();
renderUnits();
renderHUD(delta);
fbo.end();
spriteBatch.begin();
Texture texture = fbo.getColorBufferTexture();
TextureRegion textureRegion = new TextureRegion(texture);
textureRegion.flip(false, true);
spriteBatch.draw(textureRegion, 0, 0, fbo.getWidth(), fbo.getHeight());
spriteBatch.end();
}
private void renderMap() {
spriteBatch.setProjectionMatrix(mapCamera.combined);
mapRenderer.setView(mapCamera);
currentMap.getTiledMapStage().getViewport().apply();
mapRenderer.render();
}
private void renderUnits() {
spriteBatch.begin();
entityStage.getViewport().apply();
for (Entity unit : units) {
final Color temp = spriteBatch.getColor();
spriteBatch.setColor(new Color(temp.r, temp.g, temp.b, unit.getEntityactor().getColor().a));
spriteBatch.draw(getFrame(), getEntityactor().getX(), unit.getEntityactor().getY(), 1.0f, 1.0f);
spriteBatch.setColor(temp);
}
}
private void renderHUD(final float delta) {
spriteBatch.setProjectionMatrix(hud.getStage().getCamera().combined);
hud.getStage().getViewport().apply();
hud.render(delta);
}
#Override
public void resize(final int width, final int height) {
currentMap.getTiledMapStage().getViewport().update(width, height, false);
entityStage.getViewport().update(width, height, false);
hud.resize(width, height);
pauseMenu.resize(width, height);
}
}
What I tried is changing the width and height on this line in the render method
spriteBatch.draw(textureRegion, 0, 0, 1000, 1000);
And then it does fill up the whole screen nicely
Which is weird because the screen is 672 x 672 in size.
Fixed problem 1 with the following adaptation
mapCamera.setToOrtho(false, fbo.getWidth(), fbo.getHeight()); //adapt camera to fbo
mapCamera.update();
spriteBatch.setProjectionMatrix(mapCamera.combined);
spriteBatch.draw(textureRegion, 0, 0, fbo.getWidth(), fbo.getHeight());
spriteBatch.end();
mapCamera.setToOrtho(false, VISIBLE_WIDTH, VISIBLE_HEIGHT); //reset camera
mapCamera.update();
The spriteBatch is being reused for the map, the entities and the ui for efficiency. So I had to configure it to project the buffer texture on the screen
I have a problem with my TouchListener on a Libgdx game.
On my Gamerenderer I have this:
private OrthographicCamera camera;
private Vector3 input;
private Array<Objects> objects;
private SpriteBatch batch;
//In Constructor
camera = new OrthographicCamera();
camera.setToOrtho(false, Configuration.screenWidth, Configuration.screenHeight);
batch = new SpriteBatch();
batch.setProjectionMatrix(camera.combined);
objects = myGame.Objects();
input = new Vector3(0, 0, 0);
//My Renderer
public void render(float runtime){
Gdx.app.log("GameRenderer: ", "Render()");
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
input.x = Gdx.input.getX();
input.y = Gdx.input.getY();
camera.unproject(input);
batch.begin();
for (Objects object:objects) {
object.getFont().draw(batch,object.getGlyphLayout(),object.getX(),object.getY());
object.getRec().set(object.getX(),object.getY(),object.getGlyphLayout().width,object.getGlyphLayout().height);
if(Gdx.input.isTouched()){
Gdx.app.log("Clicked", "Touched");
if(object.getRec().contains(input.x, input.y)) {
Gdx.app.log("Clicked", "Great");
}
else {
Gdx.app.log("Clicked", "Noooooooooooo");
}
}
}
}
batch.end();
}
When I run my game it's working fine except the touchlistener sometimes work fine but after several secondes from the touch.
the Gdx.app.log("Clicked", "Touched"); is fired with the touch.
but the Gdx.app.log("Clicked", "Great"); OR the Gdx.app.log("Clicked", "Noooooooooooo"); i must perform a long press until the touch is fired.
Thank You
Edit
I added a ShapeRenderer to see what exactely my objects do like that:
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
for(Objects object:objects) {
shapeRenderer.setColor(255 / 255.0f, 0 / 255.0f, 0 / 255.0f, 1);
shapeRenderer.rect(object.getRec().x, object.getRec().y, object.getRec().width, object.getRec().height);
shapeRenderer.setColor(0 / 255.0f, 0 / 255.0f, 255 / 255.0f, 1);
shapeRenderer.rect(object.getX(), object.getY(), object.getGlyphLayout().width, object.getGlyphLayout().height);
}
shapeRenderer.end();
Then I have this result:
The Black Rectangle is the object and the Blue one is the ShapeRenderer of the object on top of ShapeRenderer of object's Rectangle.
Now when I click on the object it don't fire the click, but when I click on the ShapeRenderer it fire it.
Check this solution :
#Override
public void create() {
// Codes
Gdx.input.setInputProcessor(new InputAdapter () {
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
// Insert your code
return true;
}
}
);
//Codes
}
Putting Gdx.input.isTouched() inside the loop is not a good idea.
Finnaly I solved it, just in case if someone have the same problem it has been located at:
object.getRec().set(object.getX(),object.getY(),object.getGlyphLayout().width,object.getGlyphLayout().height);
I replaced object.getY()
with object.getY()-object.getGlyphLayout().height
Because of my design, i want to get rid of NinePatch object, but i use it to initialize textures at the desired size using framebuffer, and then apply that textures to my custom objects
Im new to LibGDX and GL stuff.
The problem is when i draw FBO texture to screen the image is so small, idk why
I grab skeleton of all this from here: https://stackoverflow.com/a/7632680/401529
My RenderToTexture class is:
public class RenderToTexture {
private float fbScaler = 1f;
private boolean fbEnabled = true;
private FrameBuffer fb = null;
private TextureRegion fbReg = null;
[... more constructors ... ]
/**
*
* #param scale
*/
public RenderToTexture(int width, int height, float scale, boolean hasDepth) {
if(width == -1){
width = (int) (Gdx.graphics.getDisplayMode().width * scale);
}
if(height == -1){
height = (int) (Gdx.graphics.getDisplayMode().height * scale);
}
fb = new FrameBuffer(
Pixmap.Format.RGBA8888,
(int)(width * fbScaler),
(int)(height * fbScaler),
hasDepth
);
fbReg = new TextureRegion(fb.getColorBufferTexture());
fbReg.flip(false,false);
}
public void begin(){
if(fbEnabled) {
fb.begin();
Gdx.gl.glClearColor(0, 0,0,0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
}
public TextureRegion end(){
if(fb != null)
{
fb.end();
return fbReg;
// batch.draw(fboRegion, 0, 0);
}
return null;
}
}
And my util class:
public class ImageUtils {
public static TextureRegion ninePatchToTextureRegion(NinePatch patch, int width, int height){
return ninePatchToTextureRegion(new NinePatchDrawable(patch), width, height);
}
public static TextureRegion ninePatchToTextureRegion(NinePatchDrawable patch, int width, int height){
RenderToTexture r2t = new RenderToTexture(width, height, 1, false);
SpriteBatch sb = new SpriteBatch();
r2t.begin();
sb.begin();
patch.draw(sb, 0, 0, width, height);
sb.end();
sb.dispose();
return r2t.end();
}
}
Then i call this util class when i create a sprite:
NinePatchDrawable ninepatchtest = new NinePatchDrawable(
new NinePatch(new Texture(Gdx.files.internal("img/ui/btn-retro-blue.png")), 5, 5, 5, 5)
);
TextureRegion result = ImageUtils.ninePatchToTextureRegion(ninepatchtest, 200, 100);
sprite = new Sprite(result);
The current result is (left) and the size simulated desired result (right)
EDIT: Camera size is displaymode size, glued to screen, no zoom, no movement.
EDIT: Fixed missing dispose suggested by #Tenfour04
If this way is not the best way to do it, im open to new alternatives
Well i found a "HALF" solution of my problem:
As i see here in this example LibGDX - Drawing to a FrameBuffer does not work i miss the setProjectionMatrix to SpriteBatch object, so render to texture class begin() method now is:
public SpriteBatch begin(){
SpriteBatch batch = null;
if(fbEnabled) {
fb.begin();
Gdx.gl.glClearColor(0, 0,0,0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Matrix4 m = new Matrix4();
m.setToOrtho2D(0, 0, fb.getWidth(), fb.getHeight());
batch = new SpriteBatch();
batch.setProjectionMatrix(m);
}
return batch;
}
Now renderToTexture begin() returns spritebatch, so:
public static TextureRegion ninePatchToTextureRegion(NinePatchDrawable patch, int width, int height){
RenderToTexture r2t = new RenderToTexture(width, height, 1, false);
SpriteBatch sb = r2t.begin();
sb.begin();
patch.draw(sb, 0, 0, width, height);
sb.end();
sb.dispose();
return r2t.end();
}
This solves the size of drawed texture from FBO, but ninepatch is drawed ok outside framebuffer, and stretched with framebuffer...
I have an issue in LibGDX where when i call upon Gdx.input.getY(), it selects a pixel that's on the other side of the application relative to the center of the screen.
public class Main extends ApplicationAdapter {
private SpriteBatch batch;
private Texture img;
private OrthographicCamera camera;
int xPos;
int yPos;
private Vector3 tp = new Vector3();
BitmapFont font;
#Override
public void create () {
batch = new SpriteBatch();
img = new Texture("crosshair.png");
camera = new OrthographicCamera();
camera.setToOrtho(false, 1280, 720);
font = new BitmapFont();
}
#Override
public void render () {
yPos = Gdx.input.getY();
xPos = Gdx.input.getX();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.unproject(tp.set(xPos, yPos, 0));
batch.begin();
font.draw(batch,xPos + " , " + yPos, Gdx.input.getX() - 25, Gdx.input.getY() - 5);
batch.draw(img, xPos, yPos);
batch.end();
}
#Override
public void dispose () {
batch.dispose();
img.dispose();
}
Subtracting the viewport height with the touch location won't work, because that would be subtracting world coordinates with touch coordinates. (and even for a pixel perfect projection it would be height - 1 - y). Instead use the unproject method to convert touch coordinates to world coordinates.
There are two problems with your code:
You are never setting the batch projection matrix.
Even though you are using the unproject method, you are never using its result.
So instead use the following:
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
camera.unproject(tp.set(Gdx.input.getX(), Gdx.input.getY(), 0));
font.draw(batch,tp.x+ " , " + tp.y, tp.x - 25, tp.y - 5);
batch.draw(img, tp.x, tp.y);
batch.end();
}
I would suggest to read the following pages, which describe this and the reasoning behind it in detail:
https://github.com/libgdx/libgdx/wiki/Coordinate-systems
https://xoppa.github.io/blog/pixels/
https://github.com/libgdx/libgdx/wiki/Viewports
It's better to try this
yPos = camera.viewportHeight - Gdx.input.getY();
I'm a newbie in libgdx and working on a simple 2d game and I want that my box2d world(or background) move with the input touch(move upward when I press the button) but I don't know how to move the world and place my player on the center. I want to know:
How to move my world with the input control.
Place my player in the center.
and also it looks like that my player is moving whenever I play that game, not the world.
if you can just provide an example with your answer.
so, Here is my code
public void show() {
world = new World(new Vector2(0, 25), true);
renderer = new Box2DDebugRenderer();
cam = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
/* cam.position.set(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, 0);
cam.update();*/
shapeRenderer = new ShapeRenderer();
batch = new SpriteBatch();
texture = new Texture("img/imgs.png");
sprite = new Sprite(texture);
sprite.setSize(10, 10);
sprite.setOrigin(sprite.getWidth() / 2, sprite.getHeight() / 2);
sprite.setPosition(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2);
//sprite.setBounds(200, 200, 64, 64);
//sprite.setPosition(Gdx.graphics.getWidth()/2 -sprite.getWidth()/2, Gdx.graphics.getHeight()/2-sprite.getHeight()/2);
/* //Body definition
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(0, Gdx.graphics.getHeight() / 2 - 250);
box = world.createBody(bodyDef);
//Polygon Shape
PolygonShape shape = new PolygonShape();
shape.setAsBox(10, 20);
//fixture definition
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 5f;
fixtureDef.friction = .5f;
box.createFixture(fixtureDef);
box.setUserData(sprite);
shape.dispose();
*/ }
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
world.step(1 / 60f, 6, 2);
cam.translate(0, 12);
cam.update();
batch.setProjectionMatrix(cam.combined);
if(Gdx.input.isKeyPressed(Input.Keys.A))
spriteY += Gdx.graphics.getDeltaTime() * spriteSpeed;
if(Gdx.input.isKeyPressed(Input.Keys.D))
spriteY += Gdx.graphics.getDeltaTime() * sprite1Speed;
batch.begin();
batch.draw(sprite, spriteX, spriteY);
batch.end();
shapeRenderer.setColor(Color.RED);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.rect(0, 200, 50, 50);
shapeRenderer.translate(1, 0, 0);
shapeRenderer.end();
}
#Override
public void resize(int width, int height) {
cam.viewportWidth = width;
cam.viewportHeight = height;
cam.update();
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
dispose();
}
#Override
public void dispose() {
//world.dispose();
shapeRenderer.dispose();
batch.dispose();
}
}
Sorry, for the mess(I'm a novice) in code and I want that my world moves upwards with input controls and my sprite just placed in the center.
Thank you in advance.
Your question sounds like you want to create a platformer or kinda.
I'll let you know that the best way to build your logic on when creating a (2d) platformer game is your character should always keep it's position the same and the background and other solid objects should move towards the player (based on input controls or automatic) so giving the look like your player is naturally moving and the background & objects appear in his way.
My answer is pretty general as your question is pretty general. If you need code you must provide us code so we know where you're stuck. Good luck :)