Best Practices Tutorial

Index
chapter 1 | chapter 2 | chapter 3
chapter 4 | chapter 5
chapter 6 | chapter 7

home | developer central

Chapter 2 - Code Flow

previous chapter | next chapter

In the previous chapter, we've seen how to set up a robust Java applet, and how to check for conditions that might produce errors or poor performance on the user's machine. In this chapter, we'll look at ways to further improve your program's performance and stability from within the Java environment.

A well-written Java applet will have its code divided into the following areas:

Potential problem areas in Java code flow include:

Pausing

The Web Driver's render loop does the following in the course of a single render: If you insert a pause in this loop, such as to wait for a resource to load, you put a block on any other activity that is occurring- this means that the browser will be locked during your pause, which is generally considered a Bad Thing, since under some circumstances, this temporary lock can easily become a permanent one. If you're using a pause to wait for resources to load, you should use polling or a resource load callback instead.  Included in the downloadable version of this tutorial is a project called LoadCallbacks that demonstrates how to properly delay code execution until a resource has completely loaded. For the example application, the main class itself is used as the load callback, by adding WTOnLoadEvent to the classes that our main class implements:

public class LoadCallbackExample implements WTEventCallback, WTOnLoadEvent
{

The resource (in this case, a model) is then loaded in the setup code for the scene, and is immediately assigned the main class as the load callback:

rings = wt.createModel("rings.wt");
rings.setOnLoad(this);

The example project uses a state variable called loadPhase to keep track of what work has been done to load and show the scene; it's set to 0 (meaning nothing has loaded) during setup, and it's set to 1 (meaning that the resource has loaded and code can continue) in the load callback when the load completes for the model:

public void onLoadComplete( WTObject o )
{
    loadPhase = 1;
}

In the render event, we're polling the loadPhase variable to check if it's been changed to 1; we're also checking the load status of the level as well:

public void onRenderEvent( WTEvent e )
{
    if (loadPhase == 1)	//Model loaded; if level loaded, show scene
    {
        if (level.isLoadedWithChildren())
        {
            camera = (WTCamera)level.getObjectByName("Camera1");
            camera.resume();
            loadingDrop.setVisible(false);
            loadPhase = 2;
        }
    }
}

Once both items are loaded, processes that needed to wait for the resources to load (such as getting the camera from the scene, and hiding the loading drop) can continue.  After the delayed code has been run, loadPhase is set to 2, meaning that the delayed code has completed. The Walkthrough tutorial demonstrates a more complicated load scheme, in which a different event handler object is used after all resources have loaded (saving the effort of reading the state variable every render after your loading phases are complete).

Note that you shouldn't use a load callback for a level, since the callback will fire when just the level itself finishes loading, and before the child objects (such as the textures) load; this will result in having the level displayed with textureless, white walls. Poll the level with isLoadedWithChildren() in your render event instead to see when it's loaded, as demonstrated above.

Javascript functions

When you make a call to DHTML by using Javascript (particularly when opening another window), the function can take an indefinite time to execute, which will cause the same problem as using wt.sleep(). To avoid this, use the Javascript function setTimeout() to execute your function, rather than calling the function directly:

hostPage.eval("setTimeout('myFunction()', 100);

You should also avoid having Javascript functions that call functions inside the applet; if you need to pass in data from the page, use DHTML functions to set values in the document object that can be polled from inside the applet.

Code functions inside input events

The Web Driver makes it easy to add code to keyboard, mouse, and joystick events, but you need to be careful not to do too much processing in those events; the Render event is a much more stable code path to put processing in.  If you're doing more than setting the value of a few global variables for the user input that you're interested in, you might consider restructuring your code so that more is being done in the Render event, and less in Input events.   An example of a poor use of an input event would be moving the player in the mouse event; your application will be more stable if you set global variables in the mouse event, and use the values of those variables to move the player in the Render event..

In Chapter 3, we'll look at managing memory in Java.


previous chapter | next chapter

2000 WildTangent Inc. All Rights Reserved. Website Terms & Privacy Statement