I have created a little screenmanager (to handle multiple scenes), where every class extends from a custom class called Screen, and does the following (for example) in its load method:
public Scene load() {
BitmapTextureAtlas mBitmapTextureAtlas = new BitmapTextureAtlas(512, 1024, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
SceneManager.loadTexture(mBitmapTextureAtlas);
scene.attachChild(bgSprite);
return scene;
}
The problem is that sometimes, if you move fast among screens, some sprites are not being rendered, sometimes they are (it depends on how fast I switch between scenes).
I guess the problem might be that I'm attaching the sprites to the scene when they still have been not fully loaded in memory. Can it be? Any idea how to solve this problem?
Yes it happens if you move across scenes, so you can set boolean flags for sprites. if true then perform operations. It is specially useful when perform collisionDetections.
Related
I am new to andengine and want to know that how I can switch between two BaseGameActivities. And also when switching from first activity to second, there is no black screen transition in between switching. Is there any possible way to do it.
Please help me out.
A BaseGameActivity can be used as any other Android Activity, too:
Intent intent = new Intent(this, MyOtherBaseGameActivity.class);
startActivity(intent);
So if you want to change from your program to another app (maybe by opening the browser…) you can do that as with any other Android App, too. However if both Activities are part of your own App, there is rarely a case where this is recommendable (It is like starting a second program). Although it is possible to exchange data between the activities as described in this post.
But maybe you are only looking for a way to switch between Views in AndEngine. If that's the case you can switch between Scenes without any transition necessary.
MyOtherScene secondScene = new MyOtherScene();
mEngine.setScene(secondScene);
That way you can switch between what is being displayed, without needing to load every image again.
EDIT:
Since you can't use AndEngine to switch between Activities, nor is a smooth switching between scenes possible. Here a quick example on how to switch between two screens (e.g. menus). In this example the screens are actually 2 different images (as big as the display … maybe some background images). Note: there is no such thing as 'screens' in AndEngine, it is simply a self made class that extends Entity.
Your Screen
public MyScreen extends Entity{
private float firstX;
public MyScreen(Sprite niceBackgroundImage1, Sprite niceBackgroundImage2){
this.attachChild(niceBackgroundImage1); // attach something to the screen, so you can see it (preferably an image that is as big as your camera)
this.attachChild(niceBackgroundImage2);
this.firstY=-1; // this is a variable to remember the first x coordinate touched
}
#Override
public boolean onAreaTouched(TouchEvent sceneTouchEvent, float touchAreaLocalX, float touchAreaLocalY) {
if(sceneTouchEvent.getAction()==TouchEvent.ACTION_DOWN){
this.firstY=touchAreaLocalX; // remember the x, on the first touch
}
if(sceneTouchEvent.getAction()==TouchEvent.ACTION_MOVE){
if(touchAreaLocalX>firstY+20){
// user swiped from left to right (at least 20 pixels)
niceBackgroundImage1.registerEntityModifier(new MoveModifier(3f, 0, niceBackgroundImage1.getWidth(), 0, 0, EaseBounceOut.getInstance()));
// the last line actualy moves the nice..image1 from left to right (in 3 seconds) and lets it bounce a little bit before it is completely out of the screen
return true;
}
}
return false;
}
...
}
Your Activity
private HUD hud; // create a HUD
...
#Override
protected void onCreateResources() {
this.hud = new HUD(); // init the HUD
this.myScreen = new MyScreen(image1, image2) // init the screen
this.hud.attachChild(myScreen); // attach the screen to the hud
mEngine.getCamera().setHud(hud); // attach your HUD to the camera
}
#Override
protected Scene onCreateScene() {
Scene myScene = new Scene();
myScene.registerTouchArea(myScreen); // you have to register the touch area of your Screen Class to the scene.
mEngine.setScene(myScene);
}
And this is how it works:
you create yourself a own screen class that extends Entity. An Entity can be everything visible in AndEngine (like a Sprite, Rectangle or even a whole scene). Put something in your screen class to make it look nice, preferably a big image that fills the whole display. That image will be responsible to register the touch afterwards. If the image is too small and the user misses the image, then no touch will be registered.
In this case I attach the instance of MyScreen to the cameras HUD. That way it will be at a fixed position on the display and it will have a fixed size (just in case you want to make the scene scrollable or zoomable).
Now when the app starts the HUD will be created and attached to the camera and with it your MyScreen class. Then the scene will be created and the screen's area will be registered as touch area to the scene. When a swipe movement on a horizontal axis gets noticed by the screen class, the first image will move outside the screen (in the same direction as the swipe).
But be careful, this is just an example. There is nothing defined on how the touch has to act when the first image was moved outside the screen or how big the screen actually is etc...
I know this is quite a long example, maybe it won't even work the first time and it is definitely not the only way on how switching between different screens can be done. But it shows you how to override the onAreaTouched() method and register the entity modifier to make the image move. Hopefully it will lead you in the right direction, to accomplish what you want to do.
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've got a problem with creating gameloop for my first game. I've read a lot about it but still can't figure it out. It's based on OpenGL so I've used onDrawFrame as a game loop and it works fine on my phone. Problem is that onDrawFrame is refresh time depends on hardware so it runs way too fast on some devices. So what I want is adding a separate game loop that will refresh itself at constant period of time on all smartphones. (and onDrawFrame will only take care of graphics as it should)
As for now I have:
myGameRenderer class with all openGl stuff an onDrawFrame
myGLSurfaceView that supports touch events
myGameActivity
onDrawFrame activates myGameUpdate function that controls changing positions of all objects in game depending on info from myGLSurfaceView
I've tried with creating new Runnable but it doesn't seem to work, I can't figure out how to start that runnable and where i should place it (I've tried to place it in myGameRenderer class, but it didn't seem to work, nothing was moving:
private final Runnable mUpdateDisplay = new Runnable() {
#Override
public void run() {
update();
}};
private void update() {
//some update stuff blablabla
//some update stuff blablabla
mHandler.postDelayed(mUpdateDisplay,40); //to refresh at 25 fps
}
but I guess I don't get the idea of it - I mean I create this runnable.
I've tried to place it in onCreateSurface to start it but no effect.
So - is the generall idea ok? And how to start the loop? Where to place it? Or should I use any other way?
Ok it was simple - I was just missing r.run();
But as allways there's something. Now it works as i wanted - I mean frames doesn't depend on hardware, but everything is not as smooth as it was - and part of objects in 3d are flickering. Seems like some objects visibly are drawn faster, some later and it looks ugly.
So what am I doing wrong? Is there a better way?
I am developing a game where I display different sprites on a scene on touch. Each scene has a set of (about 10 sprites) that gets displayed and removed based on user actions. When user navigates to next scenes, I load the sprites for that scene and remove the sprites for the first scene from the cache. I notice a small memory leak on scene change and pin pointed to TiledTextureRegion variables created on 1s scene.
I tried sprite.reset() call but that did not help. I am removing sprites from the scene. This is how the remove sprite code looks like:
private void removeSprite(final AnimatedSprite sprite) {
final PhysicsConnector facePhysicsConnector = this.mPhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(sprite);
this.mPhysicsWorld.unregisterPhysicsConnector(facePhysicsConnector);
this.mPhysicsWorld.destroyBody(facePhysicsConnector.getBody());
this.mScene.unregisterTouchArea(sprite);
this.mScene.detachChild(sprite);
System.gc();
}
But looks like its not clearing TiledTextureRegion objected associated with sprite. Since, I will have lot of different scenes in the app, I am worried memory leak would add up and cause issues.
Any ideas or suggestions will be highly appreciated.
Thanks!!
You can't clear TiledTextureRegion but you can clear BitmapTextureAtlas using BitmapTextureAtlas.unload();.
For example:
BitmapTextureAtlas Texture1 = new BitmapTextureAtlas(null, 1024, 1024, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
mEngine.getTextureManager().loadTexture(Texture7);
ITextureRegion example = BitmapTextureAtlasTextureRegionFactory.createFromAsset(Texture1, this, "picture.png", 0, 0);
And then, when you need:
Texture1.unload();
But probable you don't need to clear memory, because you will use your TiledTextureRegion again. You will recreate your TiledTextureRegion and it will slowdown your application.
I have a little experimentation app (essentially a very cut-down version of the LunarLander demo in the Android SDK), with a single SurfaceView. I have a Drawable "sprite" which I periodically draw into the SurfaceView's Canvas object in different locations, without attempting to erase the previous image. Thus:
private class MyThread extends Thread {
SurfaceHolder holder; // Initialised in ctor (acquired via getHolder())
Drawable sprite; // Initialised in ctor
Rect bounds; // Initialised in ctor
...
#Override
public void run() {
while (true) {
Canvas c = holder.lockCanvas();
synchronized (bounds) {
sprite.setBounds(bounds);
}
sprite.draw(c);
holder.unlockCanvasAndPost(c);
}
}
/**
* Periodically called from activity thread
*/
public void updatePos(int dx, int dy) {
synchronized (bounds) {
bounds.offset(dx, dy);
}
}
}
Running in the emulator, what I'm seeing is that after a few updates have occurred, several old "copies" of the image begin to flicker, i.e. appearing and disappearing. I initially assumed that perhaps I was misunderstanding the semantics of a Canvas, and that it somehow maintains "layers", and that I was thrashing it to death. However, I then discovered that I only get this effect if I try to update faster than roughly every 200 ms. So my next best theory is that this is perhaps an artifact of the emulator not being able to keep up, and tearing the display. (I don't have a physical device to test on, yet.)
Is either of these theories correct?
Note: I don't actually want to do this in practice (i.e. draw hundreds of overlaid copies of the same thing). However, I would like to understand why this is happening.
Environment:
Eclipse 3.6.1 (Helios) on Windows 7
JDK 6
Android SDK Tools r9
App is targetting Android 2.3.1
Tangential question:
My run() method is essentially a stripped-down version of how the LunarLander example works (with all the excess logic removed). I don't quite understand why this isn't going to saturate the CPU, as there seems to be nothing to prevent it running at full pelt. Can anyone clarify this?
Ok, I've butchered Lunar Lander in a similar way to you, and having seen the flickering I can tell you that what you are seeing is a simple artefact of the double-buffering mechanism that every Surface has.
When you draw anything on a Canvas attached to a Surface, you are drawing to the 'back' buffer (the invisible one). And when you unlockCanvasAndPost() you are swapping the buffers over... what you drew suddenly becomes visible as the "back" buffer becomes the "front", and vice versa. And so your next frame of drawing is done to the old "front" buffer...
The point is that you always draw to seperate buffers on alternate frames. I guess there's an implicit assumption in graphics architecture that you're always going to be writing every pixel.
Having understood this, I think the real question is why doesn't it flicker on hardware? Having worked on graphics drivers in years gone by, I can guess at the reasons but hesitate to speculate too far. Hopefully the above will be sufficient to satisfy your curiousity about this rendering artefact. :-)
You need to clear the previous position of the sprite, as well as the new position. This is what the View system does automatically. However, if you use a Surface directly and do not redraw every pixel (either with an opaque color or using a SRC blending mode) you must clear the content of the buffer yourself. Note that you can pass a dirty rectangle to lockCanvas() and it will do the union for you of the previous dirty rectangle and the one you are passing (this is the mechanism used by the UI toolkit.) It will also set the clip rect of the Canvas to be the union of these two rectangles.
As for your second question, unlockAndPost() will do a vsync, so you will never draw at more than ~60fps (most devices that I've seen have a display refresh rate set around 55Hz.)