I am trying to build my first game with Libgdx and Box2d.
The game has a similar concept as Flappy Bird. My issue is rendering the pipes.
I have tried drawing rectangles and then drawing new sprite which I can size down to different pipe sizes every time the render method is called. the issue with doing so is that I cant dispose of the texture once the rectangle leaves the screen because it will make all the other rectangles that are still visible lose their texture. if I don't dispose of the texture once it leaves the screen it will make the game very slow after 20 seconds.
The other option is to use about 10 different textures for different pipe sizes but still there is the issue of disposing of the textures.
I would appreciate any suggestions how to efficiently render different pipe sizes. I have attached my render code below
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0,0,0,0);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
world.step(BOX_STEP, BOX_VELOCITY_ITERATIONS, BOX_POSITION_ITERATIONS);
batch.setProjectionMatrix(camera.combined);
batch.begin();
//background.setPosition(camera.position.x-camera.viewportWidth/2, camera.position.y-14);
//background.draw(batch);
batch.end();
//bg1.update();
//bg2.update();
updateAnimation();
if((TimeUtils.nanoTime()/10) - (lastDropTime/10) > 300000000)
createPipes();
batch.begin();
for(Rectangle raindrop: raindrops) {
pipe_top.setSize(4, raindrop.height);
pipe_top.setPosition(raindrop.x, raindrop.y);
pipe_top.draw(batch);
pipe_bottom.setSize(4, raindrop.height);
pipe_bottom.setPosition(raindrop.x, camera.position.y + (camera.viewportHeight/2-pipe_bottom.getHeight()));
pipe_bottom.draw(batch);
}
batch.end();
if(pipe.getX() < 0){
pipe.getTexture().dispose();
}
Iterator<Rectangle> iter = raindrops.iterator();
while(iter.hasNext()) {
Rectangle raindrop = iter.next();
raindrop.x -= 4 * Gdx.graphics.getDeltaTime();
if(raindrop.x < -35) iter.remove();
}
debug.render(world, camera.combined);
}
You have to maintain the render() method as fast as possible. Loading resources is pretty slow, so you should create your textures and sprites in the create() method.
Also, you don't need as many sprites as raindrops, you can reuse the same sprite, change its position and size and draw it multples times.
Hope this helps.
Related
I've a Sprite that I draw in the render method, I also set the position (x and y) on the screen there while drawing.
The render method looks like this for me (Doesn't work with the try and catch below and it would not be device independent):
#Override
public void render(float delta) {
game.batch.begin();
game.batch.draw(backgroundgame, 0, 0, Gdx.graphics.getWidth(),
Gdx.graphics.getHeight());
game.batch.draw(car.sprite, xcar,
(ycar));
game.batch.end();
/*try {
xcar++;
this.wait(50);
game.batch.end();
} catch (Exception e) {
e.printStackTrace();
}*/
}
In the consructor of the class I set the x and y-position of the sprite.
I was just wondering how I can move the sprite along the x-axis device-independent? Can I do it in the render method or do I need a new Thread for the Sprite?
Any help is much appreciated!
Every frame, if you want to move the sprite along x axis, do:
sprite.setposition(lastx + 1*Gdx.graphics.getdeltatime(), some y)
lastx = sprite.getX()
And do not do batch.draw() instead use sprite.draw(batch). Batch.draw uses sprite as a dumb texture with no position. With sprite.draw, it does all the position and size drawing for you.
And threading in games is a bad thing to do. Never use threads unless you absolutely need to.
I. E. Loading something
Everything in games is done each frame(using the main thread). Or else you get sync issues with other threads and it becomes a mess.
And that's why you get fps drops and lag in games if your hardware cannot run them, because the time to process all the commands per frame becomes noticeable.
I have a game thread which draws on surface view. It processes game variables and then draws on canvas. board is a bitmap which would be drawn on canvas of the view. callDrawHelper re-draws on board, first simple background image (same size as board). Then clusters list has set of images to be drawn on canvas based on game variable data. This entire process executes each frame.
callDrawHelper takes close to 80 milliseconds, which is highest components of thread processing. This really lowers the frame rate as well. How can I improve performance this code segment.
protected void callDrawHelper() {
Canvas gfx = drawJustBackground();
for (int i = 0; i < clusters.size(); i++) {
PieceCluster cluster = clusters.get(i);
if (cluster.isVisible) {
gfx.drawBitmap(cluster.Picture, cluster.BoardLocation.left,
cluster.BoardLocation.top, null);
}
}
}
protected Canvas drawJustBackground() {
Canvas gfx = new Canvas(board);
gfx.drawBitmap(background, 0, 0, null);
return gfx;
}
It's hard to say what's the problem without further investigation. I would start with using Traceview to analyze CPU usage as suggested here: Android drawBitmap Performance For Lots of Bitmaps? Also make sure that your images are already scaled as suggested here: Improve performance of Canvas.drawBitmap() on android.
I have a texture pack made of 9 images.
Out of the 9 images, I am using 3 of them as animation frames. So my animation is made of 3 images.
The images have a fixed resolution of 128x128.
TextureRegion sprite1 = atlas.findRegion("sprite1");
TextureRegion sprite2 = atlas.findRegion("sprite2");
TextureRegion sprite3 = atlas.findRegion("sprite3");
...
...
Animation spriteAnimation = new Animation(.130f,new TextureRegion[sprite1,sprite2,sprite3]);
// similarly I am creating 4 more animation instance using same 3 regions
Animation spriteAnimation2 = new Animation(.130f,new TextureRegion[sprite1,sprite2,sprite3]);
...
...
Game loop :-
{
update();
render();
}
I have following code in update() and render().
update()
{
...
// because images are of fixed resolution 128x128
// I will calculate the scale factor as per the device screen
// so for each device width and height will vary..
// GameUnits is giving scaled width and height need for device
x = get new x;
y = get new y;
width = GameUnits.getWidth();
height = GameUnits.getHeight();
// similarly updating 4 more width & height, each of them are different.
...
...
}
render()
{
...
spriteBatch.begin();
spriteBatch.draw(spriteAnimation.getKeyFrame(totalTime),x,y,width1,height1);
// similarly rendering total of 5 animation
spriteBatch.draw(spriteAnimation2.getKeyFrame(totalTime),x,y,width2,height2);
...
spriteBatch.end();
...
}
Now, update() method is taking 0.045ms on average, whereas render() method is taking 16ms on average, giving me FPS of ~60.
At some instant render() method takes 22ms or high or low and hence creating lags. Render method has same work load every frame, i.e to render 5 animation.
I am new to libgdx without any prior experience in gaming.
May I know what mistake I made in implementing Animations?
The update() code is working well for me, but it looks like there are serious holes in render().
Hey all I'm at a crossroads with my app that I've been working on.
It's a game and an 'arcade / action' one at that, but I've coded it using Surfaceview rather than Open GL (it just turned out that way as the game changed drastically from it's original design).
I find myself plagued with performance issues and not even in the game, but just in the first activity which is an animated menu (full screen background with about 8 sprites floating across the screen).
Even with this small amount of sprites, I can't get perfectly smooth movement. They move smoothly for a while and then it goes 'choppy' or 'jerky' for a split second.
I noticed that (from what I can tell) the background (a pre-scaled image) is taking about 7 to 8 ms to draw. Is this reasonable? I've experimented with different ways of drawing such as:
canvas.drawBitmap(scaledBackground, 0, 0, null);
the above code produces roughly the same results as:
canvas.drawBitmap(scaledBackground, null, screen, null);
However, if I change my holder to:
getHolder().setFormat(PixelFormat.RGBA_8888);
The the drawing of the bitmap shoots up to about 13 MS (I am assuming because it then has to convert to RGB_8888 format.
The strange thing is that the rendering and logic move at a very steady 30fps, it doesn't drop any frames and there is no Garbage Collection happening during run-time.
I've tried pretty much everything I can think of to get my sprites moving smoothly
I recently incorporated interpolation into my gameloop:
float interpolation = (float)(System.nanoTime() + skipTicks - nextGameTick)
/ (float)(skipTicks);
I then pass this into my draw() method:
onDraw(interpolate)
I have had some success with this and it has really helped smooth things out, but I'm still not happy with the results.
Can any one give me any final tips on maybe reducing the time taken to draw my bitmaps or any other tips on what may be causing this or do you think it's simply a case of Surfaceview not being up to the task and therefore, should I scrap the app as it were and start again with Open GL?
This is my main game loop:
int TICKS_PER_SECOND = 30;
int SKIP_TICKS = 1000 / TICKS_PER_SECOND;
int MAX_FRAMESKIP = 10;
long next_game_tick = GetTickCount();
int loops;
bool game_is_running = true;
while( game_is_running ) {
loops = 0;
while( GetTickCount() > next_game_tick && loops < MAX_FRAMESKIP) {
update_game();
next_game_tick += SKIP_TICKS;
loops++;
}
interpolation = float( GetTickCount() + SKIP_TICKS - next_game_tick )
/ float( SKIP_TICKS );
display_game( interpolation );
}
Thanks
You shouldn't use Canvas to draw fast sprites, especially if you're drawing a fullscreen image. Takes way too long, I tell you from experience. I believe Canvas is not hardware accelerated, which is the main reason you'll never get good performance out of it. Even simple sprites start to move slow when there are ~15 on screen. Switch to OpenGL, make an orthographic projection and for every Sprite make a textured quad. Believe me, I did it, and it's worth the effort.
EDIT: Actually, instead of a SurfaceView, the OpenGL way is to use a GLSurfaceView. You create your own class, derive from it, implement surfaceCreated, surfaceDestroyed and surfaceChanged, then you derive from Renderer too and connect both. Renderer handles an onDraw() function, which is what will render, GLSurfaceView manages how you will render (bit depth, render modes, etc.)
I want to do an "chain" or circular loop of animations as can be described below:
LABEL start
do Anim1->Anim2->Anim3->Anim4
GOTO start
The above will do a circular loop: Anim1->Anim2->Anim3->Anim4 and back to Anim1 and so on.
I am not able to merge all the PNGs in one Texture because Andengine/Android is limited in loading the resources. However, when I split my initial large tile into 4 smaller tiles, everything works fine.
I tried to use an AnimationListener inside Anim1. When onAnimationFinished() is called, I detach Anim1, and run Anim2 and do this in chain of inner functions. However, when I am in Anim4, I do not know how to go back to the start and attach Anim1.
Note: All this problem could be solved if you know how I can pack a set of 150 PNGs that individually quite large but fit in a tile of 4096x4096 px.
Thank you for your help!
EDIT (following JiMMaR's proposed solution):
I am using Texture Packer and the overall Texture exceeds 4096*4096, causing an OutOfMemory error on Android.
At the moment, I have split the Textures into four tiles and I four PNG tilemaps.
You can use 'Texture Packer' to see if all your images can fit in 4096 x 4096.
You can download Texture Packer from here. (NOTE: Texture Packer supports AndEngine data output too)
You can use "BuildableBitmapTextureAtlas" and "BlackPawnTextureAtlasBuilder" classes to pack your PNGs into one texture atlas.
You should post some code so we can see the implementation.
Try to use several AnimatedSprites with animation listeners in each one. This way you can start the animation of the next sprite in the onAnimationFinished() call.
private class AnimationLooperListener implements IAnimationListener{
private AnimatedSprite nextSpriteToAnimate;
public AnimationLooperListener(AnimatedSprite sprite){
nextSpriteToAnimate = sprite;
}
/** other methods are hidden */
public void onAnimationFinished(AnimatedSprite sprite){
sprite.setVisible(false);
nextSpriteToAnimate.setVisible(true);
nextSpriteToAnimate.animate(100, new AnimationLooperListener(sprite);
}
}
AnimatedSprite sprite1 = new AnimatedSprite(0, 0, tiledTextureRegion, vertex);
AnimatedSprite sprite2 = new AnimatedSprite(0, 0, tiledTextureRegion, vertex);
AnimatedSprite sprite2 = new AnimatedSprite(0, 0, tiledTextureRegion, vertex);
AnimationLooperListener listener1 = new AnimationLooperListener(sprite2);
AnimationLooperListener listener2 = new AnimationLooperListener(sprite3);
AnimationLooperListener listener3 = new AnimationLooperListener(sprite1);
sprite1.animate(100, listener1);
sprite2.animate(100, listener2);
sprite3.animate(100, listener3);
This way, you have an animation loop, between several sprites that can be created using several TiledTextureRegions.