My applets have always ended up smaller than my stand-alone 4k games. You get a free component to paint on just by inheriting from Applet, no need to create it or set up any size or even make it visible.You can check the source code for Left 4k Dead if you wish: http://www.mojang.com/notch/j4k/l4kd/G.java

I wouldn't recommend running much logic in start() or init() as those are supposed to return as fast as possible, so you pretty much HAVE to create a Thread. I do this in start() instead of init() to be able to rely on isActive(). This means that the game could in theory stop and restart when someone opens another tab in some obscure browser or something, but in reality I've never seen it. (and it's not a HUGE problem anyway imo, people tend to stay on the game page)

Maybe we should offer some template code so that participants can get easily started with applets. I'm guessing some will have difficulties getting started with Applets, and I surely would like everyones Applets to work well in browsers.

I don't think you need to implement any of the Applet signalling methods start(), init(), stop() or destroy().

Spawn the Thread in the constructor.As you always have a constructor (even if none is declared), you might as well make use of the method signature being in the constants pool.Then, just use isActive() to control the behaviour of the Thread.

The only way I can think of improving upon this would be to eliminate the spawning of the Thread (along with Runnable interface and run() method).

Instead, you use the EDT to perform your animation loop by calling repaint() at the end of your overridden paint(Graphics) method.

It might work..... though you'd have to work out a way of throttling the frame time without halting the EDT for too long.And you might run into problems with outside events interrupting the repaint cycle....Big downside though is that you have to store all of your state in member variables rather than locals.

I don't think you need to implement any of the Applet signalling methods start(), init(), stop() or destroy().

Ingenious , although I suspect that if you navigate away from the page and then back again, you might get a blank page, as the 'run' thread will have terminated, but the applet may still be loaded. Of course one could just leave the thread running, but I guessing it might not stop until the browser was shut down.

Ingenious , although I suspect that if you navigate away from the page and then back again, you might get a blank page, as the 'run' thread will have terminated, but the applet may still be loaded. Of course one could just leave the thread running, but I guessing it might not stop until the browser was shut down.

Alan

you could also just use the seperate_jvm parameter so (at least on the new applet plugin) every time you visit the applet it'll be in a different vm.

I don't think you need to implement any of the Applet signalling methods start(), init(), stop() or destroy().

Spawn the Thread in the constructor.As you always have a constructor (even if none is declared), you might as well make use of the method signature being in the constants pool.Then, just use isActive() to control the behaviour of the Thread.

I wouldn't recommend this, since the applet would only be able to run once.

Ingenious , although I suspect that if you navigate away from the page and then back again, you might get a blank page, as the 'run' thread will have terminated, but the applet may still be loaded. Of course one could just leave the thread running, but I guessing it might not stop until the browser was shut down.

Or, instead of spawning the Thread in the constructor, spawn it from the EDT when the first Event is received.It can then safely be discarded when isActive() begins returning false, and re-animated if the Applet starts receiving Events again.

Or, instead of spawning the Thread in the constructor, spawn it from the EDT when the first Event is received.It can then safely be discarded when isActive() begins returning false, and re-animated if the Applet starts receiving Events again.

I discovered something else last-night, and while I should probably keep it to myself for the competitive advantage.....I just can't bare to see other peoples fantastic games reaching less than their full potencial because they were a few bytes short.

So, if you use the old Java1.0 event model, you significantly reduce the number of class and method references in the constants pool.

1

Component#handleEvent(Event)

1) It receives all events (no filtering), so you completely eliminate the call to Component#enableEvents(long).2) The Event class is general purpose (used for all Event types), so it completely eliminates references to java.awt.event.KeyEvent & java.awt.event.MouseEvent.3) The Event class even has public members, rather than getters! (eliminating references to getKeyCode(), getID(), getButton(), getX() and getY() !!!)5) "java.awt.Event" is 3 chars shorter than "java.awt.AWTEvent" =)4) "handleEvent" is 1 char shorter than "processEvent" =))))

By my guesstimates, that should save ~50-100 bytes of compressed code!Just think what Left4KDead could have done with that space! You could have made it a full-on 3D FPS no problemo

It's like the Java1.0 event model was written specifically for the 4K contest!!

Only problem (sounded too good to be true) is it's deprecated (obviously), and while it appears to work in Windows, there's no guarantee it'll work correctly on Mac or Linux.

It's like the Java1.0 event model was written specifically for the 4K contest!!

Only problem (sounded too good to be true) is it's deprecated (obviously), and while it appears to work in Windows, there's no guarantee it'll work correctly on Mac or Linux.

Works on Linux with 6.0.14, but two additional caveats for people handling key input:1. You may need to process 4 key event types, not 2, because "action" keys get different types.2. Some keys (meta, shift, ctrl) don't fire events. (Particular nuisance for me because I was thinking of making a Shift-like).

Or, instead of spawning the Thread in the constructor, spawn it from the EDT when the first Event is received.It can then safely be discarded when isActive() begins returning false, and re-animated if the Applet starts receiving Events again.

Tested and it increases code size. You need a field to be able to determine whether the event is the first one, so there go most of the savings from removing the start() method. Then you need additional logic to handle isActive() potentially being false when you enter run(). I tried two different approaches to the latter and they added respectively 18 and 27 bytes after proguard and kzip optimisation.

Of course, you might be able to argue that you shouldn't get events before start(), and so isActive() should be true. I tried that too, and it added 11 bytes. Instead of a method which unconditionally calls "new Thread(this).start()" you need a guard on isRunning==0 and to set isRunning to 1; and you also need to reset isRunning to 0 at the end of the run() method.

Edit: also, note that I've just discovered that with appletviewer 1.6.0_14 the stuff in the API doc about "An applet is marked active just before its start method is called. It becomes inactive just before its stop method is called." is not true. Printing isActive() in the start() method prints "false". This explains a problem I've observed in the past... (Addendum: having added a workaround for it, I've finally got Gravitational Fourks to work reliably in the browser). Anyway, the prudent thing is to assume that !isActive() when entering run.

publicbooleanhandleEvent(Evente) {if(input==null) {// use the presence of the input [] to indicate whether the Thread has been started.input = newint[0xFFFF]; //TODO, change the dimension of the array to be a value used elsewhere in the program. newThread(this).start(); }finalintid = e.id;if((id&~3)==MOUSE_EVENTS) {input[MOUSE_X] = e.x;input[MOUSE_Y] = e.y;//input[MOUSE_DOWN] = blahblah TODO }input[e.key] = id&1;returntrue; }

and (with my skeleton class, at least) it uses exactly the same number of bytes as the version with a start() method. (It's slightly larger uncompressed, but compresses better).

I don't think that is necessary.The Thread I spawn only ever sets the input [] to null.The EDT Thread only ever assigns a value to the input [] if it is already null.

Multiple Threads can never be concurrently executing the EDT method handleEvent(...).Multiple Threads can only be concurrently executing run(...) in the code immediately proceeding the 'input = null' assignment. (and as this assignment is the last action the Thread takes, it's safe)

There's a risk of NPE if the run thread sets input to null between the EDT starting the run thread and finishing the handleEvent call, and Murphy's law says that it will happen when the judges are testing your game...

There's a risk of NPE if the run thread sets input to null between the EDT starting the run thread and finishing the handleEvent call, and Murphy's law says that it will happen when the judges are testing your game...

Ahhhhhhh, NPEs in the EDT handleEvent(...).....yeah, IAOOB is possible in there too; but who cares - the EDT isn't killed by Exceptions.The one thing that mustn't happen is the application Thread dying to an Exception, as it'll exit without the input [] being set to null. Consequently preventing the app. ever restarting (until the Browser is restarted).

Edit: also, note that I've just discovered that with appletviewer 1.6.0_14 the stuff in the API doc about "An applet is marked active just before its start method is called. It becomes inactive just before its stop method is called." is not true. Printing isActive() in the start() method prints "false". This explains a problem I've observed in the past... (Addendum: having added a workaround for it, I've finally got Gravitational Fourks to work reliably in the browser). Anyway, the prudent thing is to assume that !isActive() when entering run.

Supposing I want to grab the graphics context once (before entering the main game loop), it may be worth doing the following:

1 2 3 4 5 6 7

run() {// Game Initialisationwhile((g=getGraphics())==null)); // Wait for a valid graphics contextdo {// Game Loopyield(); // Allow the other threads some execution time} while (isActive()); // Possibly leave this test to the end of the game loop and hope it is set by now.

Edit: I wonder if the graphics context can go invalid, before I catch isActive() going inactive. Not a nice thought.

I checked the JavaDoc for start() and it suggests that the component may not be showing when start() is called, which potentially means that it still might not be showing when run() starts, in which case a call to getGraphics() will probably return null. I found the following article which suggests this can happen

Edit: I wonder if the graphics context can go invalid, before I catch isActive() going inactive. Not a nice thought.

Yes. Minimise and maximise the browser. If you're holding onto the graphics object you can get some serious weirdness, especially with Windows (due to Sun deliberately violating the contract with DirectX).

Updated: Here's my current skeleton for keyboard-only games, using various of Abuse's suggestions from this thread. 934 bytes compressed with Proguard 4.2 and kzip.Updated again following criticism of starting the thread in the ctor and making run() contain an infinite loop.

/** * Testbed for the basics. */publicclassSkeletonextendsAppletimplementsRunnable{// Constants.// Must be at least 1026 if using Java 1.0 event model or someone accidentally// hitting Ins will get AIOOBE. Pick a number used elsewhere and reuse it to// save a constant pool entry.privatestaticfinalintNUM_KEYS = 1026;

privatestaticfinalintWIDTH = 640;privatestaticfinalintHEIGHT = 480;

// Shared state. In the spirit of lock-free synchronisation, this is written// only by the event thread, and it advances values rather than setting /// resetting. This ensures that quick key presses aren't lost.privateint[] keyEventCount = newint[NUM_KEYS];

@Overridepublicvoidstart() {newThread(this).start(); }

publicvoidrun() {// Set up event handling. Note: keyDown[key] and keyPressed[key] are 0// for false; any other value should be interpreted as true.int[] prevKeyEventCounts = newint[NUM_KEYS];int[] keyDown = newint[NUM_KEYS];int[] keyPressed = newint[NUM_KEYS];

// Game state.intx = 320;inty = 320;

// Set up backbuffer for rendering.BufferedImagebuf = newBufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);// Uncomment if you want to set pixels directly.//int[] ibuf = ((DataBufferInt)buf.getRaster().getDataBuffer()).getData();

// Events.for (inti = 0; i < NUM_KEYS; i++) {inteventCount = keyEventCount[i];// An odd number of events means that it's down. Simple!// NB If you're worried about key repeat you might want// instead to say// keyDown[i] = (delta >> 1) + (eventCount & 1);keyDown[i] = eventCount & 1;// The key was pressed since the last loop if the number of events// since then is at least two, by the pigeonhole principle, or if// the number of events since then is positive and the key is down.// Since we only need to catch the second case when delta == 1,// we can simplify the key-is-down test a bit.intdelta = eventCount - prevKeyEventCounts[i];keyPressed[i] = (delta >> 1) + (delta & eventCount);prevKeyEventCounts[i] = eventCount; }

So in your Skeleton example you've opted for leaving the Thread running forever (until the browser is killed)?If everyone does that, the judges machines might start to choke by the time they come to play the 30th entrant =D

Other than that, worth highlighting these two:

1) If you arn't interested in preventing crashes as a result of erroneous Exceptions

1

publicvoidrun() throwsException

instead of try/catch.

2) As far as i'm aware calling g.dispose() is unnecessary for Graphics objects that draw onto offscreen images (BufferedImage in your Skeleton example)As you are calling dispose() anyway, the saving will be minimal. Though you could always be naughty and not call dispose() on your onscreen Graphics object too; that'd reap more significant size savings, with only a small chance of it blowing up someones machine

So in your Skeleton example you've opted for leaving the Thread running forever (until the browser is killed)?If everyone does that, the judges machines might start to choke by the time they come to play the 30th entrant =D

I am very worried about this. Some programmers might bypass some formalities to make _their_ game work, not caring about what effect leaving idle resources running in the browser will cause, or they might do so inadvertently.

I guess we'll need a rule to ensure this doesn't happen, and also some code templates to help programmers to make sure their applet works right.

So in your Skeleton example you've opted for leaving the Thread running forever (until the browser is killed)?If everyone does that, the judges machines might start to choke by the time they come to play the 30th entrant =D

I was rather assuming that the plugin was more intelligent than that. Bah.

Quote

2) As far as i'm aware calling g.dispose() is unnecessary for Graphics objects that draw onto offscreen images (BufferedImage in your Skeleton example)As you are calling dispose() anyway, the saving will be minimal. Though you could always be naughty and not call dispose() on your onscreen Graphics object too; that'd reap more significant size savings, with only a small chance of it blowing up someones machine

You're probably correct on the first, but it's only about 3 bytes. On the second, I believe I have had issues with this also in the past.

Using Appletviewer, isActive() is still false about 50% of the time on entry to run(); Internet Explorer, Firefox and JNLP Applet seem to set isActive() earlier. Adding a yield() before checking isActive() improves matters, although sometimes it takes more than one yield(). Adding while(!isActive()) Thread.yield(); at the start of run() makes AppletViewer work 100%, but is it worth the overhead to fix what is predominantly an Appletviewer problem.

If you grab the Graphics context on Internet Explorer at the start of run(), it doesn't return null (so no exception), but it isn't linked to the native peer, so nothing displays. Also Internet Explorer changes the device context everytime you minimise and then maximise the browser. Thus we must do getGraphics() inside the game loop. While you can skip the dispose(), this means that unreleased graphics contexts build up until a garbage collection occurs. The question is whether it is worth including the overhead of dispose() to add robustness to the applet.

Lastly, if the browser navigates away from the page containing the applet or you close the browser, then the graphics context obtained at the start of the loop becomes null, even if it wasn't null when you performed getGraphics(). The probability of this can be reduced by postponing getGraphics() until just before you need it, testing for null and only drawing on the device if it's valid. However I found that occasionally, even this isn't sufficient as windows manages a context switch between the test for null and the draw. i.e. the operation is not atomic. Using try {...} catch (Exception e){} around the draw routine catches the exception, but costs more bytes. The question is whether it is worth adding the overhead of try/catch to catch an exception that only occurs when the user is navigating away from your applet. As far as I can see this error doesn't actually matter, provided you recreate the Thread when the page is revisited. This suggests creating the thread in start() and terminating it when isActive() goes false is prudent. I'm tempted to omit the try/catch and accept the exception occurs.

If we don't try to catch exceptions when the graphics context goes null, it becomes more important to postpone grabbing the context to as late as possible in the main loop, just in case some browser returns null the first time through the loop. I haven't seen this, but haven't tried every possible browser.

Thus there are tradeoffs between robustness and code size. If you don't care about appletviewer and null pointer exceptions, then IMO a minimum size template would: create the thread in start(); grab the graphics context as late as possible within the game loop and use it immediately; testing for inActive() at the end of the game loop and terminating the thread if it is false. If the game spends a fair bit of time initialising it may even work in Appletviewer.

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org