Summary
I'm trying to reliably remove a view from my layout, from my GL Rendering thread.
Details
I've got a splash screen which is added to my main layout, so my views are in this order:
GLSurfaceView
Splashscreen (which is a simple Android View)
All my objects and anything that can be loaded in the background is loaded from an AsyncTask, then, my GL Textures are loaded on the GL Thread (as is required), I'm then removing the Splashscreen from my layout to reveal my app's main menu screen.
90% of the time it works perfectly, (load time on my device is approx 3.5 seconds), however, occasionally, it appears to either never remove the view, or can take up to 8 seconds.
This is my current implementation
In my Activity class, I have the following method setup
public void dismissSplashScreen(){
removeSplash = new Runnable(){
public void run(){
//Is splashscreen currently visible?
if (splash.isShown()){
//Remove the splashscreen
layout.removeView(splash);
//Recycle splash screen as it's no longer required
recycle();
}
}
};
//Remove it
handler.post(removeSplash);
}
And then in my GLRenderer's onSurfaceCreated method, I have this:
public void onSurfaceChanged(GL10 gl, int deviceWidth, int deviceHeight) {
GLES20.glViewport(offsetX, offsetY, width, height);
Matrix.orthoM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
loadGLTextures();
//Everything is done! Dismiss the splash to reveal main menu
activity.dismissSplashScreen();
}
I also attempted to use runOnUIThread, but the results were the same, if not worse. Is my implementation correct here? What things can I check and is there a simpler way to remove this view from my layout once everything is done? (I can't dismiss it from the activity class directly as I have to wait for the GL textures to load on the GL thread).
Sorted.
The reason was because I am calling activity.dismissSplashScreen from onSurfaceChanged and onSurfaceChanged is being called multiple times (a common problem I gather and one which I've not been able to get to the bottom of yet).
So what I think was happening, was it was posting my runnable to the queue and then posting another before the first one had either started or completed, sometimes a third time.
So everything was getting a bit confused.
I simply added a boolean flag to guarantee that the runnable was posted only once like so:
if (!splashIsGone){
activity.dismissSplash();
splashIsGone = true;
}
Related
I'm playing with stage2d.ui...
Just creating an empty stage with only a button, and it happens this in android (screenshot directly from a Nexus5):
Also, it looks ok in desktop, but if you resize the screen, you can see the image of the button flickering at its previous position like this (image after making the window a bit more width):
I'm not sure if I'm doing something wrong or it's just a graphic issue...
For the button widget, I'm using the test data like this:
stage = new Stage(new ScreenViewport());
Skin skin = new Skin(Gdx.files.internal("uiskin.json"));
TextButton button = new TextButton("Button 1", skin);
button.setSize(100, 50);
button.setPosition(10, 10);
stage.addActor(button);
And then in the main render method, stage.act(delta) and stage.draw() are called, of course.
For the resize part... here's the code
public void resize(int width, int height) {
stage.getViewport().update(width, height);
}
I have other stages without ui widgets working fine, but this is my first time with ui and I'm not sure about what's happening here...
Moved from comment above.
My guess is you are not clearing the screen at the start of your render method. Try adding Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); if it isn't there already.
I'm currently writing an Android app for one my customers that has a GLSurfaceView with a GLSurfaceView.Renderer.
My entire OpenGL stuff works just fine (it's basically a port of what another developer has written on iOS first). Except for one thing.
When the view is loaded and thus the OpenGL stuff is getting loaded my background quickly flashes black, and then the OpenGL starts to render correctly (with my background). So what I do is:
In the onSurfaceCreated I start with this:
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0.9f + 0.1f * (21.0f / 255),
0.9f + 0.1f * (36.0f / 255),
0.9f + 0.1f * (31.0f / 255), 1.0f);
// Here goes my other stuff, if I comment all my other stuff out I still get the flash at startup
}
In my onDrawFrame method I do this:
#Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
// My stuff, again, if I comment all this stuff out I still get the flash...
}
So if I remove all lines of code except for the glClearColor(..) in onSurfaceCreated I still see a black flash before my actual background color is set. If I only remove the glClearColor(..) from my code (and thus leave all other OpenGL stuff in place) everything is rendered on a black background.
What I would like to see is that I just get rid of the black flash and thus that my background color is initialised correctly at startup...
Any ideas how I can achieve that?
Dirk
I just hit the same problem and have worked around it by using the GLSurfaceView's background property. Here's my XML :
<view class="android.opengl.GLSurfaceView"
android:id="#+id/glview"
android:background="#drawable/window_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Where window_bg is the same drawable as the window background specified in the activity theme.
Having done this you then remove the background drawable in the first call to onDrawFrame(), using a boolean to track whether it's already been done or not :
boolean initialRenderHack;
//
// GLSurfaceView.Renderer
//
#Override
public void onDrawFrame(GL10 gl10) {
// ... drawing code goes here ...
// Remove the initial background
if (!initialRenderHack) {
initialRenderHack = true;
view.post(new Runnable() {
#Override
public void run() {
view.setBackgroundResource(0);
}
});
}
Note that you can only touch a View's background property from the UI thread, not the rendering thread that onDrawFrame() runs on, hence the need to post a runnable.
On Android 4.4 this gives a perfectly fluid startup with no horrible jarring black frame. I haven't yet tried it with older Androids.
My game displays texture correctly in the first launch, then I exit and launch it again and display nothing but white screen. I think there are some problems with texture loading and android activity life-cycle such as clean up things when pause or destroy.
The funny thing is it only display white screen when i run it, but display perfectly well when i debug.
Please give me some of your advice, thank you.
My experience so far:
Create your textures in power of two and make sure you scale and
clip them to the right ratio when you draw.
Don't stick to RBGA_8888 when you can do ALPHA_8 (text rendering)
Do whatever you can do in OnSurfaceCreated before you get called in
OnSurfaceDraw
Avoid the GL11 context cast. Some things won't work e.g glColor4ub
will compile but not work.
Balance your calls of enable and disable for each component draw
your call into your scene graph.
Pre-allocate your nio buffers
Use DrawElements but for the simplest shapes of one vertice
Test on as many devices as you can. Just don't settle for the
emulator e.g. non power of twos work on emulator but not on the phone.
If you can then use the on demand drawing.
Use the trick of putting a wait in the onTouchEvent call for 20ms
and a notify in your onDraw to reduce the deluge of motion events you
have to process. You can bypass onTouchEven and use a lower call to
save some cycles as well.
Use texture atlas as much as you can e.g. to draw score and text or
animations
Disable the fancy rendering options (DITHER_TEST etc...) Unless you
crave a realistic rendering on textures.
If you draw in 2D, then disable the DEPTH_TEST
Don't forget the Bitmap.recycle() call when you are done binding
your textures.
Avoid Object creation destruction (PointF Rect) in your rendering
routines. GC calls will slow down your frame rate.
Preload your textures extensively. don't wait until you draw at the
last minute to bind your textures. The lag is noticable if you do so
it's better at app start up time.
You should use the onPause and onResume methods, if its not solving the problem I will add more suggestions. I had the same problem a few months ago.
#Override
protected void onPause() {
super.onPause();
mGLView.onPause();
}
#Override
protected void onResume() {
super.onResume();
mGLView.onResume();
}
Ok then maybe:
public void onSurfaceChanged(GL10 gl, int w, int h) {
gl.glViewport(0, 0, w, h);
}
Are you reloading the textures in onSurfaceCreated() or in another place? You'll want to have that stuff in onSurfaceCreated().
I'm playing around with AndEngine. No docs available for reading, so I'm just shooting in the dark here.
Finally got a splash screen showing. Now I'm trying to add some transitions to it, but no luck here. Here's the code:
#Override
public void onLoadComplete() {
mHandler.postDelayed(fadeAway, 2500);
}
protected Runnable fadeAway = new Runnable() {
#Override
public void run() {
// The only child of the scene is our splash sprite
scene.getLastChild().registerEntityModifier(new SequenceEntityModifier(
new ScaleModifier(2500, 100.0f, 200.0f),
new RotationModifier(2500, 0.0f, 78.0f),
new AlphaModifier(2500, 1.0f, 0.0f)
));
}
};
What happens is that the postDelayed() runs fine (waiting for 2.5 secs), but then everything goes black immediately. What I was expecting was that the splash screen should zoom in to 200%, then rotate 78 degrees, then fade out, but since everything goes black it feels that the duration of the modifiers is not working.
Is there an apparent error here?
EDIT: Alright, found the errors: 1) Apparently the pDuration (first argument) is supposed to be in seconds, not milliseconds as everywhere else 2) In ScaleModifier(), 1.0f equals the original size, so that argument is not in percent as expected.
(No flame, but I'm truly amazed how people managed to learn how to use this library without any documentation. There's not a single comment or note in the whole source code. Did people trial-and-error-reverse-engineered everything to find out how it's supposed to work? Can't believe the author put this vast amount of work for this library and never supplied any docs.)
Your errors is listed below:
All durations in AndEngine are in seconds.
Normal scale is 1.0f not 100.0f.
There is no need for Android Handler. You should delay your works in onUpdate methods of the engine or other AndEngine stuff.
You should apply animations only in update thread not anywhere else. mEngine.runOnUpdateThread(...)
I've been doing trial and error for hours now and I have not yet come up with a solution for something that seems simple....
I am using the
public void onConfigurationChanged(Configuration newConfig)
method to detect if a user has changed their screen orientation.
Eventually, it gets sent to this method where the entitys are attached to the scene:
public void BuildScene(final Scene scene){
// Destroys current scene.
scene.detachChildren();
this.SpriteDayPortrait = new Sprite(-200, 0, 2000, 500, this.mParallaxLayerDayPortrait);
this.SpriteDayLandscape = new Sprite(0, 0, 750, 500, this.mParallaxLayerDayLandscape);
if (prefs.getString("frontImage", "1").equals("3"))
{
//Day
if (orientationValue.equals("PORTRAIT"))
{
Log.d("Orientation", "Portrait");
scene.detachChild(SpriteDayLandscape);
scene.attachChild(SpriteDayPortrait);
}
else if (orientationValue.equals("LANDSCAPE"))
{
Log.d("Orientation", "Landscape");
scene.detachChild(SpriteDayPortrait);
scene.attachChild(SpriteDayLandscape);
}
}
}
This method is called to when the wallpaper is first created, and also when a user changes screen orientation.
I have tested this on my phone and it successfully displays the log messages when I switch orientations, which means that it is doing it what I want it to do.
The Problem--
The sprite child does not detach when this method is called to. If I am in Portrait mode, and switch to Landscape, the portrait sprite remains and I would like it to disappear, and vice versa.
I would be extremely happy if anyone could answer this I've been having a headache over this for probably 20 hours.
It looks like the problem might be logic: You reassign the SpriteDayPortrait and SpriteDayLanscape before calling the branch about detaching them or attaching them.
So each time the detach script is called it is referring to a new instance of the sprite, rather than the old instance that you want to detach.
try moving the assignment of the sprites into another function that is only called when the scene is created:
// Move this
this.SpriteDayPortrait = new Sprite(-200, 0, 2000, 500, this.mParallaxLayerDayPortrait);
this.SpriteDayLandscape = new Sprite(0, 0, 750, 500, this.mParallaxLayerDayLandscape);
Keep in mind that since changing orientation in AndEngine doesn't exist (You are not allowed to change engine orientation), you should't make your game be using orientation changes (That would be weird for the user).
Anyways, onConfigurationChanged is called from the UI thread, and you should not manipulate objects of AndEngine but in the UpdateThread. It might cause some problems (However, if it would, your game would crash) so change it.
I think it happens because you didn't clear your ParallaxBackground before setting the new background (Perhaps the old background hides the new one?)
Keep a reference to your last ParallaxEntity then remove it from the background before adding a new one.