I have a camera in my GameStage class and am trying to translate the camera when the left or right arrow keys are pressed. When I press either key and print the camera x position it changes, but nothing moves (actors on screen stay in the same position). What am I doing wrong?
Screen Render Method:
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl.glClearColor(255, 255, 255, 255);
gameStage.update();
gameStage.draw();
gameStage.act(delta);
}
Stage Code Involving the Camera:
public GameStage() {
super(new ScalingViewport(Scaling.stretch, Lib.WIDTH, Lib.HEIGHT, new OrthographicCamera(Lib.WIDTH, Lib.HEIGHT)));
initCamera();
Gdx.input.setInputProcessor(this);
}
public void initCamera() {
camera = new OrthographicCamera(Lib.WIDTH, Lib.HEIGHT);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0f);
camera.update();
}
public void updateCamera() {
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
camera.translate(-5, 0);
} else if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
camera.translate(5, 0);
}
camera.update();
}
public void update() {
updateCamera();
}
Thanks :)
From you visible code I would say that the problem is you have two cameras.
One is created when you are calling super constructor. And one created manually. Even if you are translating the camera you created, for rendering batch will use stages camera.
Remove the camera you created and work only with stages camera.
Related
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
I've a problem with setting my monster on the map. Firstly I create a Knight with camera coordinates. Now I want to set a monster on the map independent of the camera coordinates, so that when I am moving the player using keys the monster stays at the one position. I tried to implemets this and all I got was that the monster stayed at the bottom left corner of the screen all the time. Here is my Person class
public abstract class Person implements Stats {
public Person(String pathToFile,Vector2 position) {
...
}
public void update(float delta) {
spriteBatch.begin();
sprite.draw(spriteBatch);
spriteBatch.end();
}
And my bot class
public class Bot extends Person {
public Bot() {
super(toFilePath,new Vector2(500,550));
super.position.set(500,550);
}
#Override
public void update(float delta) {
super.update(delta);
}
#Override
public void dispose() {
super.dispose();
}
}
The Knight class
public class Knight extends Person {
public Knight(OrthographicCamera camera) {
super(toFilePath, new Vector2(MapScreen.startPositionX, MapScreen.startPositionY));
super.sprite.setCenter(camera.viewportWidth / 2, camera.viewportHeight / 2);
this.camera = camera;
// animation
...
}
public void update(float delta, MapScreen mapScreen) {
camera.update();
walkBatch.begin();
// input handling
walkBatch.end();
}
#Override
public void dispose() {
...
}
And the class where I set up all classes
public class MapScreen implements Screen {
...
#Override
public void show() {
init(startPositionX, startPositionY);
}
// initialize variable
private void init(float posX, float posY) {
camera = new OrthographicCamera();
camera.setToOrtho(false, width, height);
tiledMap = new TmxMapLoader(new ExternalFileHandleResolver()).load(mapName);
setTiledMapRenderer(new OrthogonalTiledMapRenderer(tiledMap));
knight = new Knight(camera);
camera.zoom = ZOOM;
camera.position.set(posX, posY, 0);
camera.update();
}
#Override
public void render(float delta) {
camera.update();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
getTiledMapRenderer().setView(camera);
getTiledMapRenderer().render(layerBottom);
knight.update(delta, this);
getTiledMapRenderer().render(layerTop);
}
When using a SpriteBatch (which you probably don't use at all, when looking at your code), then you can use your camera's matrix to calculate the offsets correctly.
use it like:
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.begin();
// draw your sprites here
spriteBatch.end();
You should then also consider improve performances by not rendering sprites off the screen:
Consider implementing some of the tips
I find a solution. I created a object layer in Tiled and there I set my monsters. Then in MapScreen I render it. Thanks for your help.
My goal is to create a game that is always displayed with an aspect ratio of 9:16 (basically 16:9, but upright) using FitViewport; it should be independet of a target device's resolution. In order to test this setup, I created the following minimal working example. A small green square indicates the origin of the coordinate system:
MyGame.java
public class MyGame extends ApplicationAdapter {
final int WORLD_WIDTH = 900;
final int WORLD_HEIGHT = 1600;
Stage stage;
Viewport vp;
public void create() {
stage = new Stage();
vp = new FitViewport(WORLD_WIDTH, WORLD_HEIGHT, stage.getCamera());
stage.setViewport(vp);
stage.addActor(new MySquare());
}
public void render() {
stage.act();
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.draw();
}
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
// dispose...
}
MySquare.java
public class MySquare extends Actor {
ShapeRenderer renderer = new ShapeRenderer();
#Override
public void draw(Batch batch, float alpha){
batch.end();
renderer.begin(ShapeRenderer.ShapeType.Filled);
renderer.setColor(Color.GREEN);
renderer.rect(0, 0, 50, 50);
renderer.end();
batch.begin();
}
}
Unfortunately, the result is not as expected: As you can see, the green square is actually not a square. This behavior is the same for both Windows and Android (in landscape mode):
However, when setting the size of the window programmatically and explicitly via LwjglApplicationConfiguration in DesktopLauncher.java to a valid 9:16 resolution, the green square is displayed correctly. Why is that and how can I avoid this workaround (which does not work for Android anyway)?
Your problem is that your shape renderer is ignoring the camera. Update it like this:
public void draw(Batch batch, float alpha){
batch.end();
renderer.setProjectionMatrix(batch.getProjectionMatrix()); // <<<<< Add this
renderer.begin(ShapeRenderer.ShapeType.Filled);
renderer.setColor(Color.GREEN);
renderer.rect(0, 0, 50, 50);
renderer.end();
batch.begin();
}
If you are planning to eventually use sprites, and you're simply wanting rectangle placeholders for your actors, you don't need a custom actor for this. You can use a generic Actor and call setDebug(true) on it, and Stage will automatically draw its outline using an internal ShapeRenderer. Of course, you must first set a size and position on the Actor.
I am creating a game and trying to set up a splash screen.
Whenever I render the sprite that i want to tween to by using the sprite.draw method which looks like this:
#Override
public void render(float delta)
{
Gdx.gl20.glClearColor(0.2F, 0.5F, 1F, 1F);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
tm.update(delta);
cam.update();
sb.setProjectionMatrix(cam.combined);
sb.begin();
Assets.splash_spr_bg.draw(sb);
sb.end();
}
The tweening works great except i can only see 1/4 of the picture on my screen, it is completely out of position.
And whenever I try to use this code in order to render the sprite by using the spritebatch to draw it, which looks like this:
#Override
public void render(float delta)
{
Gdx.gl20.glClearColor(0.2F, 0.5F, 1F, 1F);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
tm.update(delta);
cam.update();
sb.setProjectionMatrix(cam.combined);
sb.begin();
sb.draw(Assets.splash_spr_bg, 0, 0);
sb.end();
}
I can see the background great, great quality, correct size and position and all that. However, the tweening doesn't work at all; nothing happens.
Why does this not work? How can I fix it?
Here is some other code.
Initializion of the TweenHandler class:
package com.heavenapps.jumpdodge.handlers;
import com.badlogic.gdx.graphics.g2d.Sprite;
import aurelienribon.tweenengine.TweenAccessor;
public class TweenHandler implements TweenAccessor<Sprite>
{
public static final int ALPHA = 1;
#Override
public int getValues(Sprite target, int tweenType, float[] returnValues)
{
switch(tweenType)
{
case ALPHA:
returnValues[0] = target.getColor().a;
return 1;
default:
return 0;
}
}
#Override
public void setValues(Sprite target, int tweenType, float[] newValues)
{
switch(tweenType)
{
case ALPHA:
target.setColor(1, 1, 1, newValues[0]);
break;
}
}
}
Initializion of the sprite/texture:
package com.heavenapps.jumpdodge.handlers;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.Sprite;
public class Assets
{
public static Texture splash_tex_bg;
public static Sprite splash_spr_bg;
public static void init()
{
// Splash Screen
splash_tex_bg = new Texture(Gdx.files.internal("Splash Screen/Background.png"));
splash_tex_bg.setFilter(TextureFilter.Linear, TextureFilter.Linear);
splash_spr_bg = new Sprite(splash_tex_bg);
splash_spr_bg.setOrigin(splash_spr_bg.getWidth() / 2, splash_spr_bg.getHeight() / 2);
splash_spr_bg.setPosition(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
splash_spr_bg.setColor(1, 1, 1, 0);
}
}
Usage of the tweening:
public void fadeSplashScreen()
{
Tween.to(Assets.splash_spr_bg, TweenHandler.ALPHA, 2F).target(1).ease(TweenEquations.easeInBounce).start(tm);
}
You need to set the sprite's position if you want to draw it using your first method. (sprite.draw(spriteBatch)). And you need to use your first method if you want to use the sprite's color, which is being controlled by the tween.
It looks like you did give the background sprite an initial position, but you put it off screen. So change
splash_spr_bg.setPosition(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
to
splash_spr_bg.setPosition(0, 0);
The reason the second method you showed (spriteBatch.draw(sprite, x, y)) draws it in the correct position is that this method of drawing ignores the fact that it's a sprite and just draws the texture region owned by the sprite in whatever position you give it. And this method doesn't fade the sprite because it's ignoring the fact that it is a sprite (which has a color).
I'm trying to create a game with LibGDX. My problem comes when I put the background in the screen that I have. I created a Base Screen (abstract) in order to make easier. In Desktop, the screen fits good, but in Android, trying different devices, the screen doesn't scale to full screen. I solved this situation using the next easy code:
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(texture, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.end();
}
That was enough to see my game in full screen on android devices. Now, I want to use Scene2D(which I don't know so much...) So I create a Stage, I'm dealing with the background like an actor. Here's my code.
public class MenuScreen extends BaseScreen {
private FitViewport viewport;
private Stage stage;
private Image imageFondo, imagePrueba;
//private float escala;
public MenuScreen(MissingWords missingwords) {
super(missingwords);
}
#Override
public void show() {
//viewport = new StretchViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
viewport = new FitViewport(800, 480);
stage = new Stage(viewport, missingwords.getSB());
//Gdx.input.setInputProcessor(stage);
/* Crear fondo */
imageFondo = new Image(missingwords.getAM().get("fondo.png", Texture.class));
stage.addActor(imageFondo);
imagePrueba = new Image(missingwords.getAM().get("prueba.png", Texture.class));
imagePrueba.setPosition(50, 50);
stage.addActor(imagePrueba);
}
#Override
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
#Override
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
However, it doesn't work and I don't know if I'm using the Viewports in the correct way. How can I write this line in order to be compatible with Scene 2D and support android devices?
batch.draw(texture, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Thanks in advance.
Finally I "solved" it using a ScalingViewport. Like this:
viewport = new ScalingViewport(Scaling.stretch, 800, 480);
Scaling.stretch as javadoc says: the world is scaled to take the whole screen. So, it doesn't keep the aspect ratio but for me is good. Maybe it looks wrong using large screens, but I'm still learning and I don't know if this is the best solution. So, I hope this helps someone.