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().
Related
I'm using opengl with android. I am just playing around and trying to learn some stuff and I've decided to make a simple game where there are falling triangles and you have to tap them to "collect" them (Don't steal my idea! xD).
I am using an Android Timer like this:
Timer t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
float[] p1Temp = mTriangle.getP1();
float[] p2Temp = mTriangle.getP2();
float[] p3Temp = mTriangle.getP3();
mTriangle.changeCoords(new float[] {p1Temp[0], p1Temp[1] - 0.01f, p1Temp[2],
p2Temp[0], p2Temp[1] - 0.01f, p2Temp[2],
p3Temp[0], p3Temp[1] - 0.01f, p3Temp[2]});
if (mTriangle.getP1()[1] <= -1.0f ||
mTriangle.getP2()[1] <= -1.0f ||
mTriangle.getP3()[1] <= -1.0f) {
t.cancel();
}
}
}, 0, 40);
So basically what this code is doing is this: there is a timer, and every 40 milliseconds, the y coordinate of every vertex of the falling triangle is decremented. This process stops when it hits the bottom of the screen (i.e. hit the ground).
My question is this, I'm new to using openGL in android, is this the correct way to handle "movement" of objects etc? Or are there methods I'm supposed to use to implement animation/movement.
The most common approach I have seen is somewhat different. It's more typical to update the animation while preparing to render each frame, and base the update on the amount of time that has passed since the last frame.
Since distance is velocity multiplied by time, you do this by assigning a velocity vector to each of your objects. Then when it's time to update the animation, you take the time difference since the last update, and the increment you apply to your positions is the time difference multiplied by the velocity. The velocity is constant as long as you just use a linear motion, but can also change over time for more complex animations, e.g. due to gravity, collision with other objects, etc.
If you're using OpenGL on Android, you're probably using a GLSurfaceView for your rendering. By default, the GLSurfaceView will already invoke your rendering function continuously, up to 60 fps if your rendering can keep up with the display refresh rate.
What you roughly do is keep the time when the last frame was rendered as a member variable in your GLSurfaceView.Renderer implementation. Then each time onDraw() is called, you get the new time, and subtract the last frame time from this time to get the time increment. Then you store away the new time in your member variable, multiply the time increment by the velocity, and add the result to your positions.
After the positions are updated, you render your objects as you normally would.
To give you the outline, the following is a slightly adapted piece of (pseudo-)code I copied from my answer to a similar question (Android timing in OpenGL ES thread is not monotonic):
public void onDrawFrame(GL10 gl) {
currentTime = SystemClock.elapsedRealtime()
deltaTime = currentTime - lastFrameTime
lastFrameTime = currentTime
update animation based on deltaTime
draw frame
}
Where lastFrameTime is a member variable, currentTime a local variable.
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.
I am able to rotate camera with this code
camera.zoom = 3//in constructor
if(camera.zoom>1)
{
camera.zoom-=0.01f;
camera.rotate(15);
}
this is done in render, Now zooming effect works properly but when zooming completes my screen is stay rotated with current angle. like below.
I want that my screen stops after zooming at 0 degree.
In your code snippet
**camera.zoom=3;**
and in each iteration you are zooming camera by 0.01 till camera.zoom > 1
so you have total 20 iteration for zooming
Then rotate with 18 degree angle after iteration it will rotate in 360 degree.
I wrote this method to calculate current angle of camera:
public float getCameraCurrentXYAngle(Camera cam)
{
return (float)Math.atan2(cam.up.x, cam.up.y)*MathUtils.radiansToDegrees;
}
Then I call rotate method like this:
camera.rotate(rotationAngle - getCameraCurrentXYAngle(camera));
This code works, but it will rotate immediately in one call. to rotate it by a speed, you need to calculate appropriate 'rotationAngle' for every frame.
Have you tried rotating a multiple of 1.8 degrees with each iteration? Then you're image should have completed a number of full rotations once the 200 iterations have passed.
attention, the computer can't correctly represent most real numbers!
in binary 0.01 is a periodic number, so it will be truncated/rounded.
substrating/adding float numbers a few hundred times will add the rounding error and thus give you horribly wrong results.
(e.g. after 200 substractions, your camera.zoom value will be ~ 1.0000019 - NOT 1.0!)
that's why your loop is repeated 201 times, giving you a zoom value of 0.9900019 and a rotation of 361.7996 ~ 361.8 (when using 1.8 as in alex's answer).
you could use libGDX Interpolation functions:
time += Gdx.graphics.getDeltaTime(); //the rounding error is futile here,
//because it'll increase the animation time by max. 1 frame
camera.zoom = Interpolation.linear.apply(3, 1, Math.min(time, 1));
camera.rotate = Interpolation.linear.apply(0, 360, Math.min(time, 1));
this code would create an one second long animation of zooming from 3 to 1 and rotating from 0 to 360 (simply one whole roation)
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.