LibGdx update with deltatime is not precise - java

I'm new in creating game.
I have several boxes that move from top to bottom of screen and i need to make 1 unit distance between them.
Every thing works fine except the distance is not precise and i think the deltatime cause this problem
This is how i move the boxes :
objX -= deltatime * speed;
Update
time += deltatime :if(time >= 3.0f) spawn
Im using libgdx

You can schedule your task in this way :
Array<Sprite> sprites;
Texture texture;
SpriteBatch batch;
float speed=35;
#Override
public void create() {
sprites=new Array<Sprite>();
texture=new Texture("badlogic.jpg");
batch=new SpriteBatch();
Timer.instance().scheduleTask(new Timer.Task() {
#Override
public void run() {
spawn();
}
},1,2);
}
private void spawn(){
Sprite sprite=new Sprite(texture);
sprite.setSize(50,50);
sprite.setPosition(Gdx.graphics.getWidth()/2,0);
sprites.add(sprite);
}
#Override
public void render() {
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
float delta=Gdx.graphics.getDeltaTime();
batch.begin();
for (Sprite sprite:sprites){
sprite.setY(sprite.getY()+delta*speed);
sprite.draw(batch);
}
batch.end();
}

After a lot of struggling i came up with an idea which is
instead of moving boxes and spawning them by deltatime , make boxes static and move camera over them!
So i just move camera here
public void render(float delta) {
posCameraDesired.y += 2000.0f * Gdx.graphics.getDeltaTime();
guiCam.position.lerp(posCameraDesired, 0.1f);
SemiRender();
}
and i have static Y that i'll update after each spawn
lastY = 10 + lastY + ((width / 4) / 2) * 3;
and some other logic to recycle them when they passed the viewport.
and every one is happy!

Related

Libgdx texture on key input too fast

I want to draw a texture when I press a key. I'm using isKeyJustPressed() method and because of this , the texture appears and dissapears really fast. How can I slow it down a bit, so I can see it appear?
Are you drawing the texture like this?
public void render() {
...
batch.begin();
...
if(isKeyJustPressed...) {
texture.draw()...
}
...
batch.end();
...
}
If so your texture will be drawn only for just one frame.
If this is the problem:
float timeRemaining = 0f; // in seconds
public void render() {
...
batch.begin();
...
if(isKeyJustPressed...) {
timeRemaining = 5; // will show the texture for 5 seconds
}
if (timeRemaining>0) {
timeRemaining -= Gdx.graphics.getDeltaTime();
texture.draw()...
}
...
batch.end();
...
}
Also I would highly suggest that you go through this tutorials before jumping into making games.
https://docs.oracle.com/javase/tutorial/

Libgdx x and y difference

In the picture below you can see that I have drawn a black circle into the screen and in the code I have tried to get the black circle to match the coordinates of the clear circle which is my physics body which is completely working.
My problem is when I move the clear circle around my map the black circle stays there in the corner. The black circle moves a little about a few pixels so it seems its mmoves around a bit but very scaled down and I don't know why. Thanks.
public void update(float dt){
handleInput(dt);
world.step(1 / 60f, 6, 2);
player.update(dt);
camX();
gameCam.update();
renderer.setView(gameCam);
}
#Override
public void render(float delta) {
update(delta);
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.batch.setProjectionMatrix(hud.stage.getCamera().combined);
hud.stage.draw();
renderer.render();
b2dr.render(world, gameCam.combined);
game.batch.begin();
game.batch.draw(ball,player.getX() , player.getY(), 70, 70);
game.batch.end();
}
public void camX(){
gameCam.position.x = gamePort.getWorldWidth() / 2;
if(player.b2Body.getPosition().x >= gamePort.getWorldWidth() / 2){
gameCam.position.x = player.b2Body.getPosition().x;
}
}
public class Character extends Sprite {
public World world;
public Body b2Body;
public float x;
public float y;
public Character(World world){
this.world = world;
defineMario();
}
public void update(float dt) {
setPosition(b2Body.getPosition().x,b2Body.getPosition().y );
}
You set the Batch's projection matrix to the UI's camera for UI drawing, but you never change it to the gameCamera's projection before drawing your game elements. Before the game.batch.begin(); line you need to add game.batch.setProjectionMatrix(gameCamera.combined);.
By the way, it doesn't make sense for Character to extend Sprite, since you don't use Character for drawing anything, only for tracking a position.
Please try this :
public class Character extends Sprite {
public World world;
public Body b2Body;
public float x;
public float y;
public Character(World world){
this.world = world;
defineMario();
}
public void update(float dt) {
//so the sprite and body will have the same center
setPosition(b2Body.getPosition().x-getWidth()/2, b2Body.getPosition().y- getHeight()/2 );
setCenterOrigin(); // to handle when body does a rotation
}
please, tell me if it works or not in comment
Good luck

Java - LibGDX - Problems with the process of rendering a Tiled map

The problem
I cannot seem to be able to get Tiled maps to render properly. I am using LibGDX as a library for loading the map (Release 1.6.0).
Video demonstration
I have created a video to show you the actual problem and make things easier by skipping the whole process of explaining it. Here is a link to it.
The code I've used
protected Level level;
protected OrthogonalTiledMapRenderer mapRenderer;
protected OrthographicCamera camera;
protected TiledMap map;
protected MainGameLoop game;
protected SpriteBatch batch;
private BitmapFont font;
private int w, h;
public Level1(MainGameLoop game) {
this.game = game;
}
#Override
public void show() {
w = Gdx.graphics.getWidth();
h = Gdx.graphics.getHeight();
int CAMERA_WIDTH = 800;
int CAMERA_HEIGHT = 450 * (w / h);
camera = new OrthographicCamera(CAMERA_WIDTH, CAMERA_HEIGHT);
camera.setToOrtho(false);
camera.update();
map = new TmxMapLoader().load("maps/map1.tmx");
mapRenderer = new OrthogonalTiledMapRenderer(map);
Gdx.input.setInputProcessor(this);
font = new BitmapFont();
font.setColor(Color.BLUE);
batch = new SpriteBatch();
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
mapRenderer.setView(camera);
mapRenderer.render();
batch.begin();
font.draw(batch, "Camera zoom: " + camera.zoom, 40, 40);
batch.end();
}
#Override
public void resize(int width, int height) {
camera.viewportWidth = width;
camera.viewportHeight = height;
camera.update();
}
#Override
public void dispose() {
mapRenderer.dispose();
map.dispose();
background.dispose();
Gdx.input.setInputProcessor(null);
}
#Override
public boolean scrolled(int amount) {
camera.zoom += amount;
camera.update();
return true;
}
// Here go the rest of the methods, such as pause, resume, hide, keyDown, keyUp, keyTyped, touchDown, touchUp, touchDragged & mouseMoved.
Solutions I've tried
I have tried using different numbers for the camera's x and y with no luck. I have also tried tranlating the camera to the proper position (hardcoded it), as well as using another map (different tilemap and dimensions) but that did not work either.
Conclusion
I can't seem to find a way to fix this problem. Any help is much appreciated. Thank you very much.
Quick introduction
Ok after a good while, I managed to solve this matter by hardcoding some stuff. But it works properly, so I am happy with it.
What I did to solve the problem
First of all, I found out the exact number I had to use to scale up my Tiled map, which is this number: 3.125f .
Then, instead of using pixels for the camera, I used my own units (something I should have done from the the first moment).
After doing those two things, I noticed that the map was zoomed in a lot. So, by using the scrolled method from the InputProcessor, I managed to find the exact number the map had to be "unzoomed".
I also found out that if I call the setToOrtho(false) method from the OrthographicCamera object, it zooms the map in 19 times for some weird reason. If that method does not get called, the map is zoomed in only 1 time
The code I am currently using
TiledMap tiledMap;
OrthographicCamera camera;
TiledMapRenderer tiledMapRenderer;
final float WIDTH = 8000;
final float HEIGHT = 4500;
final float num = 3.125f;
#Override
public void show() {
tiledMap = MapLoader.realm1_level1;
tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap, num);
camera = new OrthographicCamera(WIDTH, HEIGHT);
Gdx.input.setInputProcessor(this);
camera.zoom += 1f;
camera.update();
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
tiledMapRenderer.setView(camera);
tiledMapRenderer.render();
}
// This method was just used for testing to see where
// the map was or should have been placed.
#Override
public boolean keyDown(int keycode) {
if (keycode == Input.Keys.LEFT)
camera.translate(-32, 0);
if (keycode == Input.Keys.RIGHT)
camera.translate(32, 0);
if (keycode == Input.Keys.UP)
camera.translate(0, 32);
if (keycode == Input.Keys.DOWN)
camera.translate(0, -32);
if (keycode == Input.Keys.NUM_1)
tiledMap.getLayers().get(0).setVisible(!tiledMap.getLayers().get(0).isVisible());
return true;
}
#Override
public void resize(int width, int height) {
camera.position.set(WIDTH, HEIGHT, 0);
camera.update();
}
#Override
public boolean scrolled(int amount) {
camera.zoom += amount;
camera.update();
return true;
}
#Override
public void dispose() {
tiledMap.dispose();
}
// And here go the rest of the methods that come from the
//Screen and the InputProcessor interfaces.
Notes
The numbers I used for the WIDTH and the HEIGHT variables work properly, strictly with tiled maps that their width is 80 tiles, and their height is 45 tiles.
If you are facing the same problem, you'll have to find the appropriate number to scale your map up/down, depending on the unit numbers you're using. Trial and error is your only guide. If we ignore StackOverflow of course.

Setting the applcation to use "y-down" in LibGDX

http://badlogicgames.com/forum/viewtopic.php?f=11&t=2447
http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/OrthographicCamera.html
There's hundreds of other links I could show you that I've looked at, but it's just not worth it because they all say the same thing.
public class InGame implements Screen {
SpriteBatch batch;
GameWorld world;
OrthographicCamera camera;
#Override
public void show() {
batch = new SpriteBatch();
world = new GameWorld();
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.setToOrtho(true, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
world.render(batch, delta);
batch.end();
}
}
What am I doing wrong? WHY is my world still being rendered with the 0,0 being at the bottom right. The math behind this while trying to work on my Tile-System is driving me absolutely insane.
World->Render
public void render(SpriteBatch batch, float delta) {
for(int xAxis = 0; xAxis < worldColumns; xAxis++) {
for(int yAxis = 0; yAxis < worldRows; yAxis++) {
tiles[xAxis][yAxis].render(batch, delta);
}
}
}
WorldTile->Render
public void render(SpriteBatch batch, float delta) {
myShape.begin(ShapeType.Filled);
myShape.setColor(tileColor);
myShape.rect(pos.getX(), pos.getY(), TILE_WIDTH, TILE_HEIGHT);
myShape.end();
}
The "pos" is the Position(x, y) that was passed in the World class.
If you are drawing a Sprite or TextureRegion using your SpriteBatch the code should work fine. However, you pass your SpriteBatch 'batch' all the way down to WorldTile.render and never use it?! Instead you use myShape which I assume is a ShapeRenderer. You need to set the projection matrix for the ShapeRenderer as well otherwise it will draw 'upside-down'.
Try calling myShape.setProjectionMatrix(camera.combined); before you use your myShape.
Its probably best to declare and initialise myShape in your InGame class, usemyShape.setProjectionMatrix(camera.combined);, and then pass myShape down to tiles.render() as you did with your SpriteBatch.
Hope this helps.

Draw a sprite onto the map not to the screen

I'm using libgdx and I have a tiled map which i want to draw the sprite onto. However the sprite is drawn onto the actual window so when I move the camera, the sprite stays in the same place. ?I want to the sprite to move on the map.
This is how i currently render my objects
#Override
public void render(float delta) {
translateCamera();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
renderer.setView(camera);
renderer.render(bgLayers);
batch.begin();
batch.draw(splayerSprite, Gdx.graphics.getWidth() / 2,
Gdx.graphics.getHeight() / 2);
batch.end();
renderer.render(fgLayers);
}
It always end up being in the middle of the screen, however I want to be able to move them seperatly like for example the camera with (W,A,S,D) and move my player with the direction keys. Then if I want the camera locks onto the player but other wise its free.
I'm new to libgdx so please bear with me, Thanks
The problem is the SpriteBatch projection matrix isn't being set to the Camera projection matrix. This means the Sprite is not being rendered relative to the Camera. This is why the camera is moving, but the sprite is not; the correct matrix is not being used.
Also the sprite is being rendered always at half the screen's width, and half the screen's height. To fix this Call sprite.draw. This will use the Sprite's internal position.
Set the SpriteBatch projection matrix via batch.setProjectionMatrix(camera.combined). This will cause the sprite to be rendered relative to the camera.
#Override
public void render(float delta) {
translateCamera();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
renderer.setView(camera);
renderer.render(bgLayers);
//here's the line that was missing.
batch.setProjectionMatrix(camera.combined);
batch.begin();
//be sure to call this instead of specifying position yourself!
splayerSprite.draw(batch);
batch.end();
renderer.render(fgLayers);
}
You'll still need to handle snapping the camera's position to the sprite's position whenever WASD is pressed, but that's trivial.
//snap the camera to the sprite's center.
if(wasd_isDown){
float centerX = sprite.getX()+sprite.getWidth()/2;
float centerY = sprite.getY()+sprite.getHeight()/2;
camera.position.set(x,y, 0);
}
If direction keys are pressed, just translate the camera's position vector via Vector3.add like so:
if(!wasd_isDown){
float deltaX = 0;
float deltaY = 0;
float MOVE_DIST = 10;//or whatever you need.
if(leftPressed) deltaX = -MOVE_DIST;
else if(rightPressed) deltaX = MOVE_DIST;
if(upPressed)deltaY = MOVE_DIST;
else if(downPressed)deltaY = -MOVE_DIST;
camera.position.add(deltaX, deltaY, 0);
}
This will allow the camera to move independently only when the player uses directional keys, and will allow the sprite be be rendered in relation to the camera's orientation. It will also snap the camera immediately back to the sprite when WASD is pressed.
batch.draw(splayerSprite, Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
You are telling the code to draw it to the center of your screen every time. You need to change Gdx.graphics.getWidth() / 2 and Gdx.graphics.getHeight() / 2 to actual values that change based on your input.
Edit #2: The line batch.setProjectionmatrix(camera.combined); is needed in addition to everything I have mentioned, I both did not notice that specific line was already in my code (it is included in the default libGDX project), and did not try running my demo with that line removed. I hope that clears up any confusion I may have caused.
Edit: Since apparently nobody really liked my answer, I went and wrote a demo using the controls specified in a clean libGDX game. Regardless of where the camera is aimed at (since it is being translated), the sprite was always being rendered in the center of the global screen. It is very much necessary to use the sprite's position in the batch.draw() instead of a static position, otherwise it will not move.
package com.me.mygdxgame;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
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.math.Vector2;
public class MyGdxGame implements ApplicationListener {
private OrthographicCamera camera;
private SpriteBatch batch;
private Texture texture;
private Sprite sprite;
private Sprite background;
private boolean lockToSprite;
private Vector2 vecCamera;
private Vector2 vecSprite;
#Override
public void create() {
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
camera = new OrthographicCamera(w, h);
batch = new SpriteBatch();
lockToSprite = true;
vecCamera = new Vector2();
vecSprite = new Vector2();
texture = new Texture(Gdx.files.internal("data/libgdx.png"));
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
TextureRegion region = new TextureRegion(texture, 0, 0, 512, 275);
sprite = new Sprite(region);
sprite.setSize(0.1f * sprite.getWidth(), 0.1f * sprite.getHeight());
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2);
background = new Sprite(region);
background.setOrigin(background.getWidth() / 2, background.getHeight() / 2);
System.out.println(background.getOriginX());
background.setPosition(-background.getWidth() / 2, -background.getHeight() / 2);
}
#Override
public void dispose() {
batch.dispose();
texture.dispose();
}
#Override
public void render() {
camera.translate(vecCamera);
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
camera.translate(vecCamera.cpy().mul(-1));
float moveSensitivity = 0.9f;
Vector2 vecInputSprite = new Vector2();
if (Gdx.input.isKeyPressed(Keys.UP))
vecInputSprite.y += moveSensitivity;
if (Gdx.input.isKeyPressed(Keys.DOWN))
vecInputSprite.y -= moveSensitivity;
if (Gdx.input.isKeyPressed(Keys.LEFT))
vecInputSprite.x -= moveSensitivity;
if (Gdx.input.isKeyPressed(Keys.RIGHT))
vecInputSprite.x += moveSensitivity;
if (Gdx.input.isKeyPressed(Keys.N))
vecSprite.set(new Vector2());
Vector2 vecInputCamera = new Vector2();
if (Gdx.input.isKeyPressed(Keys.W))
vecInputCamera.y += moveSensitivity;
if (Gdx.input.isKeyPressed(Keys.S))
vecInputCamera.y -= moveSensitivity;
if (Gdx.input.isKeyPressed(Keys.A))
vecInputCamera.x -= moveSensitivity;
if (Gdx.input.isKeyPressed(Keys.D))
vecInputCamera.x += moveSensitivity;
if (Gdx.input.isKeyPressed(Keys.R)) {
vecCamera.set(new Vector2());
lockToSprite = false;
}
if (vecInputCamera.len2() != 0)
lockToSprite = false;
else if (Gdx.input.isKeyPressed(Keys.L))
lockToSprite = true;
if (lockToSprite) {
vecCamera.set(vecSprite);
} else {
vecCamera.add(vecInputCamera);
}
vecSprite.add(vecInputSprite);
batch.setProjectionMatrix(camera.combined);
batch.begin();
background.draw(batch);
sprite.setPosition(vecSprite.x, vecSprite.y);
sprite.draw(batch);
//batch.draw(sprite, vecSprite.x, vecSprite.y);
batch.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}

Categories