I'm a newbie game developer. I've been trying to develop a game using LibGDX and Box2D physics engine, but when I export my android application, it is not working as it should be.
This problem is happening in some devices; it does not matter if it's an old device or a new one.
For example the app is working well in Sony Xperia Z1, Motorola XT615, LG L1, LG L3, LG L5,etc. However, in Sony Xperia U, Motorola Moto E,Samsung Galaxy's is not working like I expect.
You can see a non-fluid behavior when the object is moving across the screen. That's the problem I have. It's like a stutter effect, not fluid.
I read on forums that It could be a FPS (frames per second) problem when I set the time step in the world. So, I am using a fixed time step method and with the remainder time that I get in "accumulator" I interpolate it. I read these articles:
http://gafferongames.com/game-physics/fix-your-timestep/
http://saltares.com/blog/games/fixing-your-timestep-in-libgdx-and-box2d/
to learn the fixed time step and interpolation method, but I think that there is a fail in my code that I can't see.
Here is my code:
public class MyGame extends ApplicationAdapter {
SpriteBatch batch;
Texture img;
Sprite sprite;
Body body;
Box2DDebugRenderer debugRenderer;
OrthographicCamera camera;
World world;
final float PixelsToMeters=100f;
float step = 1.0f / 60.0f ,alpha;
Vector2 currentPosition,lastPosition,position;
double currentTime,accumulator,lastAngle,currentAngle;
final float BODY_WIDTH=95f,BODY_HEIGHT=95f;
#Override
public void create () {
world= new World(new Vector2(0f,-9.8f),true);
batch = new SpriteBatch();
img = new Texture("circulo.png");
sprite=new Sprite(img);
//BODY DEFINITION
BodyDef bodydef=new BodyDef();
bodydef.type= BodyType.DynamicBody;
bodydef.position.set(-3.5f,-2.4f);
body=world.createBody(bodydef);
CircleShape shape=new CircleShape();
shape.setRadius((sprite.getWidth()/2)/PixelsToMeters);
FixtureDef fixturedef=new FixtureDef();
fixturedef.shape=shape;
fixturedef.density=0.1f;
fixturedef.restitution=1f;
fixturedef.friction=0.5f;
body.createFixture(fixturedef);
shape.dispose();
//SET SPRITE POSITION
sprite.setPosition(body.getPosition().x *PixelsToMeters - BODY_WIDTH/2,
body.getPosition().y * PixelsToMeters - BODY_HEIGHT/2);
//THROW CIRCLE
body.setLinearVelocity(3.5f,9.5f);
lastPosition=new Vector2();
position=new Vector2();
camera=new
OrthographicCamera(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
}
#Override
public void render () {
camera.update();
double newTime = TimeUtils.millis() / 1000.0;
double frameTime = Math.min(newTime - currentTime, 0.25);
float deltaTime = (float)frameTime;
currentTime = newTime;
accumulator+=deltaTime;
while (accumulator >= step) {
//SAVE LAST BODY POSITION AND ANGLE
lastPosition.x=body.getPosition().x;
lastPosition.y=body.getPosition().y;
lastAngle=body.getAngle();
world.step(step, 8, 3);
accumulator -= step;
}
//SAVE CURRENT BODY POSITION AND ANGLE
currentPosition= new Vector2(body.getPosition().x,body.getPosition().y);
currentAngle=body.getAngle();
alpha=(float) (accumulator/step);
position.x = lastPosition.x + (currentPosition.x - lastPosition.x) * alpha;
position.y = lastPosition.y + (currentPosition.y - lastPosition.y) * alpha;
sprite.setPosition(position.x * PixelsToMeters - BODY_WIDTH/2, position.y * PixelsToMeters
-BODY_HEIGHT/2);
sprite.setRotation((float)Math.toDegrees(lastAngle+(currentAngle-lastAngle)*alpha));
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(sprite, sprite.getX(), sprite.getY(),
sprite.getOriginX(), sprite.getOriginY(),
sprite.getWidth(), sprite.getHeight(), sprite.getScaleX(),
sprite.getScaleY(), sprite.getRotation());
batch.end();
}
#Override
public void dispose() {
world.dispose();
batch.dispose();
img.dispose();
super.dispose();
}
}
I had this exact problem before using box2d, small stuttering when physics steps took longer than 1/60 seconds.
I also tried interpolation and read lots of articles about it without any success.
In the end I am not using fixed timestep at all (just delta to the world step) and all goes smoothly with box2d.
But if you still want to use fixed step, i have some suggestions:
Use Gdx.graphics.getDeltaTime() as it gives you a smoothed delta with n previous frames.
Use deltaTime in the world step loop:world.step(deltaTime, 8, 3); and accumulator -= deltaTime.
Hope it helps!
Related
I know there are quite some questions (and answers) on this topic, but they all have different solutions, and none of them seems to be working in my case.
I'm developing a small test project with libGDX, in which I tried to add a simple tilemap. I created the tilemap using Tiled, which seems to be working quite good, except for the texture bleeding, that causes black lines (the background color) to appear between the tiles sometimes.
What I've tried so far:
I read several SO-questions, tutorials and forum posts, and tried almost all of the solutions, but I just don't seem to get this working. Most of the answers said that I would need a padding between the tiles, but this doesn't seem to fix it. I also tried loading the tilemap with different parameters (e.g. to use the Nearest filter when loading them) or rounding the camera's position to prevent rounding problems, but this did even make it worse.
My current setup:
You can find the whole project on GitHub. The branch is called 'tile_map_scaling'
At the moment I'm using a tileset that is made of this tile-picture:
It has two pixels of space between every tile, to use as padding and margin.
My Tiled tileset settings look like this:
I use two pixels of margin and spacing, to (try to) prevent the bleeding here.
Most of the time it is rendered just fine, but still sometimes there are these lines between the tiles like in this picture (sometimes they seem to appear only on a part of the map):
I'm currently loading the tile map into the asset manager without any parameters:
public void load() {
AssetManager manager = new AssetManager();
manager.setLoader(TiledMap.class, new TmxMapLoader(new InternalFileHandleResolver()));
manager.setErrorListener(this);
manager.load("map/map.tmx", TiledMap.class, new AssetLoaderParameters());
}
... and use it like this:
public class GameScreen {
public static final float WORLD_TO_SCREEN = 4.0f;
public static final float SCENE_WIDTH = 1280f;
public static final float SCENE_HEIGHT = 720f;
//...
private Viewport viewport;
private OrthographicCamera camera;
private TiledMap map;
private OrthogonalTiledMapRenderer renderer;
public GameScreen() {
camera = new OrthographicCamera();
viewport = new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, camera);
map = assetManager.get("map/map.tmx");
renderer = new OrthogonalTiledMapRenderer(map);
}
#Override
public void render(float delta) {
//clear the screen (with a black screen)
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
moveCamera(delta);
renderer.setView(camera);
renderer.render();
//... draw the player, some debug graphics, a hud, ...
moveCameraToPlayer();
}
private void moveCamera(float delta) {
if (Gdx.input.isKeyPressed(Keys.LEFT)) {
camera.position.x -= CAMERA_SPEED * delta;
}
else if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
camera.position.x += CAMERA_SPEED * delta;
}
// ...
//update the camera to re-calculate the matrices
camera.update();
}
private void moveCameraToPlayer() {
Vector2 dwarfPosition = dwarf.getPosition();
//movement in positive X and Y direction
float deltaX = camera.position.x - dwarfPosition.x;
float deltaY = camera.position.y - dwarfPosition.y;
float movementXPos = deltaX - MOVEMENT_RANGE_X;
float movementYPos = deltaY - MOVEMENT_RANGE_Y;
//movement in negative X and Y direction
deltaX = dwarfPosition.x - camera.position.x;
deltaY = dwarfPosition.y - camera.position.y;
float movementXNeg = deltaX - MOVEMENT_RANGE_X;
float movementYNeg = deltaY - MOVEMENT_RANGE_Y;
camera.position.x -= Math.max(movementXPos, 0);
camera.position.y -= Math.max(movementYPos, 0);
camera.position.x += Math.max(movementXNeg, 0);
camera.position.y += Math.max(movementYNeg, 0);
camera.update();
}
// ... some other methods ...
}
The question:
I am using padding on the tilemap and also tried different loading parameters and rounding the camera position, but still I have this texture bleeding problem in my tilemap.
What am I missing? Or what am I doing wrong?
Any help on this would be great.
You need to pad the edges of your tiles in you tilesheet.
It looks like you've tried to do this but the padding is transparent, it needs to be of the color of the pixel it is padding.
So if you have an image like this (where each letter is a pixel and the tile size is one):
AB
CB
then padding it should look something like this
A B
AAABBB
A B
C C
CCCCCC
C C
The pixel being padded must be padded with a pixel of the same color.
(I'll try try create a pull request with a fix for your git-repo as well.)
As a little addition to bornander's answer, I created some python scripts, that do all the work to generate a tileset texture, that has the correct edge padding (that bornander explained in his answer) from a texture, that has no padding yet.
Just in case anyone can make use of it, it can be found on GitHub:
https://github.com/tfassbender/libGdxImageTools
There is also a npm package that can extrude the tiles. It was built for the Phaser JS game library, but you could still use it. https://github.com/sporadic-labs/tile-extruder
I am using Shaperender to render Circle and in the update function at everyloop I update che coordinates that rappresent my objects (the circles).
I am not using textures, only shaperender and I can't achieve a smooth movement, what am I doing wrong? (I am on Android)
As you can see there is some kind of trail/lag when the blue circle is moving.
Please watch the video instead of the gif: https://imgur.com/ECRVc2L
this is the code:
public void update(float dt){
x = centerX + (float)Math.cos(Math.toRadians(angle)) * trajectory;
y = centerY + (float)Math.sin(Math.toRadians(angle)) * trajectory;
}
public void render(SpriteBatch sb) {
// --- sr is a new ShapeRenderer declared in the constructor as sr = new ShapeRenderer()
sr.begin(ShapeRenderer.ShapeType.Filled);
sr.setColor(Color.BLUE);
sr.circle(x,y, radius , 100);
sr.end();
}
I have been playing around with LibGDX for a good bit now and haven't found a problem I couldn't solve until now. When I run my project sometimes everything works perfectly fine but about 1 out of 10 times the camera will just refuse to update it seems unless the game window is either over another programs existing window or I physically grab the window with my mouse and move it around while moving my sprite around so that I can see it updating. anyone have any ideas what could be causing this?
#Override
public void create () {
int tileSize = 16;
int w = 30 * tileSize;
int h = 17 * tileSize;
viewport.setScreenSize(w, h);
camera = new OrthographicCamera();
camera.setToOrtho(false,viewport.getScreenWidth(),viewport.getScreenHeight());
camera.update();
mapGenerator = new MapGenerator();
tiledMapRenderer = new OrthogonalTiledMapRenderer(mapGenerator.getTiledMap());
spawner = new EntitySpawner(mapGenerator.getMapObjects());
spawner.spawn();//there is a to do in the entity spawner class to move this else where
sb = new SpriteBatch();
hud = new Hud(camera);
Gdx.input.setInputProcessor(this);
Gdx.graphics.setResizable(false);//makes it so you can't just drag the game window to any size since its easy to distort it
Gdx.graphics.setWindowedMode(1280,720);//resolution size windowed
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);//background color
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//update the camera
camera.position.x = spawner.player.sprite.getX();
camera.position.y = spawner.player.sprite.getY();
camera.update();
tiledMapRenderer.setView(camera);
tiledMapRenderer.render();
timeElapsed += Gdx.graphics.getDeltaTime();//simply time that has passed based off delta time
sb.setProjectionMatrix(camera.combined);
sb.begin(); //start the sprite batch
spawner.draw(sb);//draw any entities with the spawner
hud.draw(sb);//draw the HUD
sb.end();//end the sprite batch
}
I pretty much finished my LibGDX project and now I'm just adding user-friendliness.
I have a Texture (also placed in a sprite) that I would like to fade in and fade out repeatedly (NOT fast blinking). It's just rectangular funky-text that says "Touch to Start".
I considered making an animation of 6 or so pictures with varying opacity and just keep changing slides. Is this the best way to go?
I'm also looking for a libGDX effect that controls the transparency to avoid all the overhead and not make my animation choppy.
Can't think of any relevant code to add, Thanks for your help
EDIT
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(touchToStartImage, screenWidth / 2 - touchToStartImage.getWidth() / 2, screenHeight / 2 - touchToStartImage.getHeight() / 2);
elapsed += Gdx.graphics.getDeltaTime();
blinkFontCache.setAlphas(Interpolation.fade.apply((elapsed / 0.01f) % 1f));
blinkFontCache.draw(batch);
blinkFontCache.translate(2f, 2f);
batch.end();
I also defined blinkFontCache = new BitmapFontCache(numberPrinter); where numberPrinter is bitmapfont that is supposed to draw text. I've read the API guide for Interpolation and blinkFontCache, but unfortunately with the above I do not notice any change in the screen I have. Thanks
SOLUTION
EDIT with INTERPOLATION
elapsed += Gdx.graphics.getDeltaTime();
touchToStartSprite.setAlpha(Interpolation.fade.apply((elapsed / FADE_TIME) % 1f));
blinker.begin();
touchToStartSprite.draw(batch);
blinker.end();
EDIT with ACTIONS
definitions
text = new Image(highScoreImage);
text.addAction(Actions.alpha(0));
text.act(0);
text.addAction(Actions.forever(Actions.sequence(Actions.fadeIn(FADE_TIME), Actions.fadeOut(FADE_TIME))));
render()
blinker.begin();
text.act(Gdx.graphics.getDeltaTime());
text.draw(blinker, 1);
blinker.end();
You could use the Image class from scene2d, which is an actor that can take a texture region and gives you several methods that can be useful. Here's an implementation.
Image text = new Image(clickToStartRegion);
Float fadeTime = 1f;
//...
text.addAction(Actions.alpha(0)); //make the text transparent.
text.act(0); //update the text once
text.addAction(Actions.sequence(Actions.fadeIn(fadeTime), Actions.fadeOut(fadeTime));
//...
text.act(deltaTime);
//...
text.draw(batch, 1);
You can use the Interpolation class for the alpha. Assuming you're using a Sprite to draw this:
private float elapsed;
private static final float FADE_TIME = 1f; //time between blinks
//...
elapsed += deltaTime;
sprite.setAlpha(Interpolation.fade.apply((elapsed / FADE_TIME) % 1f));
//...
spriteBatch.begin();
sprite.draw(spriteBatch);
spriteBatch.end();
I'm creating a 3D game but I don't know how to translate the camera according to my fingers. I'm creating a map(x = -30 to +30;y = -30 to 30;z = -1 to 1) where every coordinate is used for a model using .g3db files from my assets and put in place using model translation. This works so far, the map looks good and is viewed in a 67% angle. The map is so large it can't be viewed in the camera at once(no I don't want to zoom out). Whenever I'm touching the screen of my android phone it's just rotating around the center, but instead I want the gamemap to stay in place from my point of view and instead change the position of the perspective camera on the x and y axis. There's no game object that can be used for position tracking, everything should be depending on my finger actions. This way I want to move to visible screen to each x and y direction(think of it visualy like a 2D camera moving up, down and to the sides in front of a picture). Can you help me?
This is my code so far:
public class MyGdxGame extends ApplicationAdapter implements ApplicationListener{
//define variables
...
#Override
public void create() {
environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
modelBatch = new ModelBatch();
cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(10f, 10f, 10f);
cam.lookAt(0,0,0);
cam.near = 1f;
cam.far = 300f;
cam.update();
assets = new AssetManager();
//load assets
...
loading = true;
camController = new CameraInputController(cam);
camController.forwardTarget = true;
Gdx.input.setInputProcessor(camController);
}
private void doneLoading() {
//load models and add them to instances
loading = false
}
#Override
public void render() {
if (loading && assets.update())
doneLoading();
camController.update();
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
modelBatch.begin(cam);
modelBatch.render(instances, environment);
modelBatch.end();
}
I'm using the spring tool suite 3.5.1 as IDE and libgdx 1.0.1
Dont use a CameraInputController, but instead implement InputProcessor and use that class in the call to Gdx.input.setInputProcessor.
For example:
public class MyGdxGame extends ApplicationAdapter implements InputProcessor {
And in the create method:
Gdx.input.setInputProcessor(this);
You'll have to implement all methods as shown in this link, except for the touchDown and touchDragged method which require additional code:
private int dragX, dragY;
#Override
public boolean touchDown (int x, int y, int pointer, int button) {
dragX = x;
dragY = y;
return true;
}
#Override
public boolean touchDragged (int x, int y, int pointer) {
float dX = (float)(x-dragX)/(float)Gdx.graphics.getWidth();
float dY = (float)(dragY-y)/(float)Gdx.graphics.getHeight();
dragX = x;
dragY = y;
cam.position.add(dX * 10f, dY * 10f, 0f);
cam.update();
return true;
}
Here the dX and dY values is the amount that user has dragged on the screen within the range between -1f and +1f. E.g. for dX a value of 0.5f means that the user dragged half the screen size to the right. Note that these are delta values since the last time the method was called. The method is likely to be called many times per drag operation. Therefor, the dX and dY will be small values.
The call to cam.position.add(...) will actually move the camera and the call to cam.update(); will recalculate the values needed for rendering. I've used a multiplier of 10f for both the X and Y translation of the camera. This means that if the user fully drags from the left edge to the right edge of the screen, that the camera will move a total amount of 10 units to the right. You can adjust the value as needed.
Note that this moves the camera on XY plane. If you need to move on e.g. the XZ plane, you need to adjust the call the cam.position.add(...) accordingly. Also, this doesn't change the direction of the camera. If you want to move the camera, while looking at the same location, you'll need to add cam.lookAt(0,0,0); just before cam.update();.