I'm using a GestureListener to try and create a panning menu, but even though the camera's coordinates are being changed and it's being updated, nothing moves. I think it might be because the stage is drawing relative to the camera but I'm not sure how I would change that.
How I'm going about it:
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
...
gesture = new GestureDetector(this);
InputMultiplexer im = new InputMultiplexer();
im.addProcessor(gesture);
im.addProcessor(stage);
Gdx.input.setInputProcessor(im);
} //end initialization of CustomizeScreen
public void render(float delta) {
Gdx.gl.glClearColor(0.2f, 0.2f, 0.2f, 1);
Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT);
stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 60f)); //0, 18, 31 for layer style
stage.draw();
Table.drawDebug(stage);
batch.setProjectionMatrix(camera.combined);
g.batch.begin();
g.font.setScale(2);
g.font.setColor(Color.WHITE);
g.font.draw(g.batch, "Coins: " + Filer.getCoins(), 15, Gdx.graphics.getHeight() - 15);
g.font.draw(g.batch, message, 0, 150);
g.batch.end();
camera.update();
}
...
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
message = "Pan, delta:" + Float.toString(deltaX) +
"," + Float.toString(deltaY);
camera.translate(deltaX, 0, 0);
camera.update();
return false;
}
I've checked for camera coordinates (camera.position.x) in the update method, so I know it's actually changing something. But all my buttons remain the same. They are placed in thirds of the screen width (Gdx.graphics.getWidth() / 3).
Am I missing something, or doing it wrong? I'd think I'm doing it correctly based on everything I'm found on Google.
Thanks :)
The Stage class has different constructors. Some of those constructors take a Viewport, which contains a Camera. If you use a constructor without Viewport, the Stage creates a new Viewport with a new Camera.
In that case it will use the created Viewport (and Camera) for all it's drawing, unless you switch the Viewport by calling setViewport.
As you don't show, how you create the Stage i am not sure if thats the porblem in your case, but if that is the problem, you can solve it by creating a Viewport with your Camera and passing it to the Stage or by changing the Camera of the Viewport (stage.getViewport().setCamera(myCamera)).
Hope it helps.
Related
I am trying to develop an Android app and I have stumbled across a really nasty problem.
I am trying to use a different viewport from my "main" one for a different stage to control certain elements. I have started using Scaling viewport with Scaling.none, as it seems the most appropriate for what I am looking for. The problem is, when I try to change its position, it simply does not move! It just stays in the center of the screen. Here is the code I am using in the contructor for the viewports:
viewport = new StretchViewport(720, 1280, cam);
viewport.apply();
cam.position.set(cam.viewportWidth / 2, cam.viewportHeight / 2,0);
secondaryViewport = new ScalingViewport(Scaling.none, 480, 421);
secondaryViewport.setScreenPosition(240, 0);
Can't Scaling viewports be moved?
EDIT: Here is my render() method:
#Override
public void render(SpriteBatch sb) {
cam.update();
secondaryViewport.getCamera().update();
sb.setProjectionMatrix(cam.combined);
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
sb.begin();
sb.setColor(Color.WHITE);
sb.draw(bg, cam.position.x - cam.viewportWidth / 2, 0, cam.viewportWidth, cam.viewportHeight);
sb.end();
stage.getViewport().apply();
stage.draw();
stage.act();
secondaryStage.getViewport().apply();
secondaryStage.draw();
secondaryStage.act();
}
By default camera position of Viewport is at at 0,0,0
Use this secondaryViewport.getCamera().position.set(100,100,0); to change position of secondaryViewport.
secondaryViewport = new ScalingViewport(Scaling.none, 480, 421);
By this statement you're creating a new Camera that is different from the camera which is used in your StretchViewport.
Ok, the solution was
secondaryStage.getViewport().setScreenPosition(x, y);
I have a bug object that I want to move across the screen as soon as the game starts. The bug starts from the bottom left of the screen and is supposed to move to the top right and stop. What I have is the bug never really gets to the top right because the game screen(X and Y) size are not equal. How do I make the bug move to that position?
This is what I have.
public void create() {
spriteBatch = new SpriteBatch();
bug = new Sprite(new Texture("EnemyBug.png"));
bug.setSize(50, 85);
bug.setPosition(0,0);
}
public void render() {
xdeg++;
ydeg++;
Gdx.gl.glClearColor(0.7f, 0.7f, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
spriteBatch.begin();
bug.translate(xdeg, ydeg);
bug.draw(spriteBatch);
spriteBatch.end();
}
I'll assume that you know your window width (W) and height (H). First find the W / H ratio:
float ratio = screenWidth / screenHeight;
Then update your bug position accordingly:
bug.translate(ratio, 1);
This will make the sprite move through the screen diagonal.
I want to make a button clickable, but it isn't working - it seems like I need to use unproject() but I can't figure out how. The code in question is:
Texture playButtonImage;
SpriteBatch batch;
ClickListener clickListener;
Rectangle playButtonRectangle;
Vector2 touchPos;
OrthographicCamera camera;
#Override
public void show() {
playButtonImage = new Texture(Gdx.files.internal("PlayButton.png"));
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
batch = new SpriteBatch();
playButtonRectangle = new Rectangle();
playButtonRectangle.x = 400;
playButtonRectangle.y = 250;
playButtonRectangle.width = 128;
playButtonRectangle.height = 64;
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(playButtonImage, playButtonRectangle.x, playButtonRectangle.y);
batch.end();
if (Gdx.input.isTouched()) {
Vector2 touchPos = new Vector2();
touchPos.set(Gdx.input.getX(), Gdx.input.getY());
if (playButtonRectangle.contains(touchPos)) {
batch.begin();
batch.draw(playButtonImage, 1, 1);
batch.end();
}
}
}
In general you use camera.unproject(Vector) to transform your screen coordinates from a click or touch to your gameworld. This is needed because the origin is not necessarily the same and using the camera you can also zoom in and out, move around, rotate and so on. Unprojecting will take care of all of that and give you your game world coordinate matching the pointers position.
In your example it would go like this:
Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
Having this said you should actually not do this UI task manually. Libgdx has also some shipped UI functionality which is called a Stage (see this). There are lots of widgets already available (see this). They use skins (you can get a basic one from here, you need all the uiskin.* files). They automatically forward inputevents to the socalled Actors, e.g. a button, and you just need to implement handling of those events.
with camera.unproject(Vector3); you can translate screen coordinates to game world coordinates.
Vector3 tmpCoords = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(tmpCoords);
tmpCoords.x //is now the touched X coordinate in the game world coordinate system
tmpCoords.y //is now the touched Y coordinate in the game world coordinate system.
In addition to that it is best practice to define a tmpVector as a field an Instantiate a Vector3 object only once. You can then do the same with the .set() method.
tmpCoords.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(tmpCoords);
tmpCoords.x //is now the touched X coordinate in the game world coordinate system
tmpCoords.y //is now the touched Y coordinate in the game world coordinate system.
Therefore you reduce object creation and remove unnecessary GC calls which lead to microlag.
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(playButtonImage, playButtonRectangle.x, playButtonRectangle.y);
batch.end();
if (Gdx.input.isTouched()) {
Vector3 touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(),0);
camera.unproject(touchPos);
if (playButtonRectangle.contains(touchPos.x, touchPos.y)) {
batch.begin();
batch.draw(playButtonImage, 1, 1);
batch.end();
}
}
}
when ever u need a touch point from user and to convert those touchpoints to camera u need to unproject them to camera coordinates by camera coordinates
camera.unproject(touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0));
I've been trying to create a game where there's a person falling. The size of my background texture is 480x3200, and I'm trying to create the game so that the camera keeps the person in the middle of the screen while falling down, and then stops at the bottom. But I can't get my background is extend beyond the screen it starts in, and then be able to see the rest of the image.
All of my code does right now is scale down the 480x3200 image down to fit onto my current screen (which I set to be 480x800), and then as the person falls, the background doesn't change.
Here's my WorldRenderer class where I've tried to do different things but every time, I can never get the person to see a different part of the image when it starts moving down.
public WorldRenderer(SpriteBatch b, World w) {
this.world = w;
this.cam = new OrthographicCamera(CAMERA_WIDTH, CAMERA_HEIGHT);
this.cam.position.set(CAMERA_WIDTH / 2, Person.position.y,0);
this.cam.setToOrtho(false, CAMERA_WIDTH, CAMERA_HEIGHT);
this.cam.update();
spriteBatch = b;
loadTextures();
}
public void render(float delta) {
person = world.getPerson();
moveCamera();
cam.update();
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.disableBlending();
spriteBatch.begin();
renderBackground();
spriteBatch.end();
spriteBatch.enableBlending();
spriteBatch.begin();
renderObjects();
spriteBatch.end();
}
private void moveCamera() {
cam.position.set(cam.position.x, Person.position.y, 0);
cam.update();
}
private void renderObjects() {
renderPerson();
renderBlocks();
renderPlatforms();
}
private void renderBackground() {
spriteBatch.draw(backgroundTexture, cam.position.x - CAMERA_WIDTH / 2, cam.position.y - CAMERA_HEIGHT / 2, CAMERA_WIDTH, CAMERA_HEIGHT);
}
}
Does anyone have any suggestions?
Edit:
Thanks, I changed the draw in renderBackground to
spriteBatch.draw(backgroundTexture,0,0, CAMERA_WIDTH, CAMERA_HEIGHT * 4); and it works now.
spriteBatch.draw(backgroundTexture, cam.position.x - CAMERA_WIDTH / 2,
cam.position.y - CAMERA_HEIGHT / 2, CAMERA_WIDTH, CAMERA_HEIGHT);
This code is drawing the background image relative to the camera's position. That's why changing the camera's position has no effect on the background image's position. Change it to something like this:
spriteBatch.draw(backgroundTexture,0,0);
Or u can simply use ParrallaxBackground and ParrallaxLayer class
This way u dont have to manage ur camera
Its done in an optimized manner in the mentioned class.
I am new and I just start my journey with libgdx. I would like to know how I can do image.png in resolution 960x640 as background in my game? This is possible? Thx for advices and forbearance. Maybe you hava a simply tutorial?
This is my render class:
public void render() {
texture = new Texture(Gdx.files.internal("E:/background.png"));
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(texture, 0, 0);
batch.end();
}
Second question. I need to insert two active images, active means when I click on that image, the next image show me on the screen. I want to implement action when I click on that picture.
In your create() method, create a new Texture referencing your image.png, and then use your existing SpriteBatch to render it in the render() loop. Immediately after your GL.clear() call, go your batch.draw(backgroundTexture, 0. 0) and make sure you're in OrthographicProjection mode for your camera.
first you have to set the view port
do this in your create method
`float scrw = 960;
float scrh = 640;
camera = new OrthographicCamera();
camera.viewportHeight = scrh;
camera.viewportWidth = scrw;
camera.position.set(camera.viewportWidth * .5f,
camera.viewportHeight * .5f, 0f);
camera.update();`
create a texture
texture = new Texture("data/background.png");
put this texture in a sprite like this
sprite=new sprite(texture);
and then set the size like this
sprite.setsize(960,640);
and draw it in your render methods between batch.begin
and batch.end
sprite.draw(batch);