Hi,
is it possible to have a splash-screen for a java-applet?
I don’t mean the loading screen in the html-code like: "al_logo:my-logo.jpg’’.
I tested the code from this thread: Help needed with splash screen and calling a GUI thereafter.
This works fine if I don’t use it as an applet.
The problem is, after loading the applet there are about 5-6 seconds (mainly depends on how complex the gui is) the user sees a white-screen. During this time nifty and some other things are initializing. I want to show an image or something else the user knows “ok loading finished, the app is starting now, pls wait some seconds…”
The root cause is, I think in AppletHarness
[java]
@Override
public void start(){
context.setAutoFlushFrames(true);
System.out.println(“applet:start”);
}
[/java]
After the first update cycle the applet appears in the browser. But this is a bit to late ^^
I would be happy about every suggestion
Try and do as little initialization as possible in the first frame, and execute some over proceeding frames (loading other gui screens etc), so that the initial loading time is minimal at the start. Seeing a blank screen is quite normal for a few seconds, so I think that’s acceptable (any more then it can become a problem). What’s the typical “blank” time for the most basic of scene/menu?
I am aware that my code isn’t optimized yet. Later I could push it down to 2-3 seconds, depends on the client computer-speed. But overall I use Nifty for the Gui and thats the most time consuming part during the initializing even the Gui is minimized.
If I understand you right you mean to load a minimized screen during initializing and later for example the rest in the Update-Loop of the application (except there is a method like postFrame() or something else) ?
So in the worst case the user sees the first screen and pushes the “next-Button” and nothing happens/ or it hangs because the app is initializing the other screens in the background. --> late-initializing
Also if I have blank screen for a few seconds, how should the user know that the applet is still initializing? For example there could be an exception and the blank screen would be there for a very long time
So my main problem is not how long the blank screen is there but to show a splash-screen/image before the first update cycle like in a normal application.
I suggest a simple quad with a loading image, then explicitly wait a few frames (like using a control and count to ten in its update) after that call/enqueue a custom load method that does all stuff prior in the initialize method.
Also you could
-> Load assets in a background thread as the assetloader is threadsafe. (just keep in mind the scenegraph is not)
I’d not count off frames, loading is somewhat nondeterministic.
I’d let the asset manager load stuff in a different thread, and signal completion to the main thread.
Otherwise, an unusually slow load (stuck harddrive or saturated DSL connection) can lead to very surprising and very hard-to-debug problems.
(This happened to Planeshift. Took them several months to even locate the cause, and another set of months to pinpoint it well enough to fix it. Made a considerable dent into their player base, too.)
Thanks for the suggestions. I have a solution now. It’s a little bit dirty and should be refactored but for the moment it works fine.
Code snippet:
[java]
boolean initialized = false;
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
Runnable loadingThread = new Runnable () {
@Override
public void run() {
Application.this.enqueue(new Callable<Object>() {
public Object call() throws Exception {
//change scenegraph + time consuming initializing methods (nifty, viewport etc.)
return null;
}
});
}
};
public void simpleInitApp() {
// splash-screen
}
public void simpleUpdate(float tpf) {
super.simpleUpdate(tpf);
if (!initialized) {
executor.execute(loadingThread);
initialized = true;
}
}
@Override
public void destroy() {
super.destroy();
executor.shutdown();
}
[/java]
What you have in simpleUpdate might as well be put in simpleInit… it will effectively be the same. Your initializes = true will run right away before the background process even gets to run.
I guess the difference is that app states will have been initialized… but that’s it. And if that’s what you wanted then writing an app state might have been better in the first place.
If i put the stuff from simpleUpdate to simpleInit I have instead a splash-screen a black-screen for few seconds XD The stuff will not be rendered till the first update cycle is done.
In simpleUpdate it works, the applet will be rendered and the splash-screen is shown immediately. In the first update cycle the Thread starts. After the Thread is finished nifty and everthing else is ready. The variable initialized is only there for starting the Thread once only.
To do that with app states would be an option but in the application root I have another variables like entitySystem, sceneBuilder and many more. If I initialize them in an appState I would need public getter/setters in my root app. Mmmmh …
<cite>@toolforger said:</cite> I'd not count off frames, loading is somewhat nondeterministic. I'd let the asset manager load stuff in a different thread, and signal completion to the main thread. Otherwise, an unusually slow load (stuck harddrive or saturated DSL connection) can lead to very surprising and very hard-to-debug problems. (This happened to Planeshift. Took them several months to even locate the cause, and another set of months to pinpoint it well enough to fix it. Made a considerable dent into their player base, too.)
read again this is only ot ensure the laodign scren is renderd at least a few frames.
@OPM87 said: If i put the stuff from simpleUpdate to simpleInit I have instead a splash-screen a black-screen for few seconds XD The stuff will not be rendered till the first update cycle is done.In simpleUpdate it works, the applet will be rendered and the splash-screen is shown immediately. In the first update cycle the Thread starts. After the Thread is finished nifty and everthing else is ready. The variable initialized is only there for starting the Thread once only.
To do that with app states would be an option but in the application root I have another variables like entitySystem, sceneBuilder and many more. If I initialize them in an appState I would need public getter/setters in my root app. Mmmmh …
It’s weird because the application class will call simpleInit() then stateManager.update() then simpleUpdate() all in the same pass basically.
I don’t understand why your main app would need public getters when all app states get passed the app… which has the state manager… which has all of the other app states. It’s such a common thing for me to have one app state refer to another one that I went ahead and added a getState() method to BaseAppState in lemur. Saves so much hassle.
It’s weird because the application class will call simpleInit() then stateManager.update() then simpleUpdate() all in the same pass basically.I didn't test it but i could imagine that if I put the splash screen into the simpleInit() also attaching an LoadingStuffAppState (inside the appstate I need enqueue new Callable etc.) the appstate blocks the main app and it can't arrive simpleUpdate() to finish the first cycle. So blank screen would be the result. I'm not sure whether this is, I must test this.
The variables I need aren’t appstates. It has nothing todo with state manager. At the moment they are only private attributes with getters. If I inititialize them in an appState I should return them to the mainapp where I need them. Maybe I could do an appState which contains important class instances but I need them more in the mainapp.
If that’s the way you want to go… my main app only has about 10 lines. I generally can’t think of a single thing (*) that should apply globally to both the main menus, the settings screens, the game, the save game screens, etc… so all of that logic is app states that get switched in and out.
But a giant main app class is ok, too, I guess.
(*) - that isn’t already on SimpleApplication.
I think we’re talking past each other.
The loading / initializing stuff is for me things like loading configuration settings from an external file, attaching AppStates, setFrameRate, DisplayFps, DisplayStatView, build first Nifty screen, attaching main-nodes to the scenegraph … in the main app these things are only a few lines.
Of course there isn’t any game logic in the main app like ai, wayfinding or anything else.
The attributes i mentioned above are essential things like rootnode.
To init the entitySystem I have a one liner entitySystem = new EntitySystem(…); in the simpleInit(). I can get the EntitySystem easy with app.getEntitySystem() like the rootnode, assetManager etc.
I can put all these things in an appstate but then I don’t know if these appstate blocks the first cycle and if I need the entitySystem or something else essential I should call the appstate first, also my main app would be empty except one line stateManager.attach(new loadingAppstate()).
WHY! do you instanciate that stuff even before the first few frames at all?
jsut do a own delayed method that runs after 10 frames and do everything! there. (Exception a quad with a loadingmessage)
<cite>@Empire Phoenix said:</cite> jsut do a own delayed method that runs after 10 frames and do everything! there. (Exception a quad with a loadingmessage)Yeah! And this is exactly I'm doing now to avoid blank screen (a similiar principle). If i hadn't an applet i wouldn't need a delayed method to initilialize stuff.
My app looks like:
[java]
public class MyApp extends SimpleApplication {
public static void main( String… args ) {
…standard main app settings boiler plate…
}
public MyApp() {
super( new EntitySystemState(), new MainMenuState(), new .... etc.);
}
public void handleError( Throwable t ) {
}
...and a few other methods that can only be overridden on application because app states don't support them and there are no listeners...
}
[/java]