appel
|
 |
«
Posted
2009-12-01 00:42:18 » |
|
Please paste some solid applet templates in here.
|
|
|
|
kappa
|
 |
«
Reply #1 - Posted
2009-12-01 02:30:40 » |
|
one nice thing I just realised is that since 1.5 is the minimum, we can start using System.nanoTime() instead of System.currentTimeMillis(), this should make the game loop timing much better.
|
|
|
|
appel
|
 |
«
Reply #2 - Posted
2009-12-01 08:41:36 » |
|
one nice thing I just realised is that since 1.5 is the minimum, we can start using System.nanoTime() instead of System.currentTimeMillis(), this should make the game loop timing much better.
1.5 was also the default JRE last year 
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Morre
|
 |
«
Reply #3 - Posted
2009-12-03 20:59:56 » |
|
The other thread with applet templates is a bit of a mess, and there doesn't seem to be any consensus on which ones work. Does anybody have a template that seems to work well? I could always use what I've used before, but since one person couldn't start two of my applets last year, well... I'd very much appreciate a nice, reasonably stable template.
|
|
|
|
appel
|
 |
«
Reply #4 - Posted
2009-12-03 22:17:12 » |
|
I hacked something together from L4KD  Just stripped it down. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| import java.applet.Applet; import java.awt.AWTEvent; import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage;
public class G extends Applet implements Runnable {
public void start() { enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); new Thread(this).start(); }
public void run() { setSize(800, 600);
BufferedImage screen = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB); Graphics g = screen.getGraphics(); Graphics appletGraphics = getGraphics();
int tick = 0, fps = 0, acc = 0; long lastTime = System.nanoTime();
while (true) { long now = System.nanoTime(); acc += now - lastTime; tick++; if (acc >= 1000000000L) { acc -= 1000000000L; fps = tick; tick = 0; }
lastTime = now;
g.setColor(Color.black); g.fillRect(0, 0, 800, 600); g.setColor(Color.white); g.drawString("FPS " + String.valueOf(fps), 20, 30);
appletGraphics.drawImage(screen, 0, 0, null);
do { Thread.yield(); } while (System.nanoTime() - lastTime < 0);
if (!isActive()) { return; } } }
public void processEvent(AWTEvent e) { } } |
|
|
|
|
Groboclown
|
 |
«
Reply #5 - Posted
2009-12-03 22:54:28 » |
|
An alternate version of Appel's code reduces the size a bit. This trick was taken from the Preliminary thread as well. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| import java.applet.Applet; import java.awt.Event; import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage;
public class G extends Applet implements Runnable {
public void start() { new Thread(this).start(); }
public void run() { setSize(800, 600);
BufferedImage screen = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB); Graphics g = screen.getGraphics(); Graphics appletGraphics = getGraphics();
int tick = 0, fps = 0, acc = 0; long lastTime = System.nanoTime();
while (true) { long now = System.nanoTime(); acc += now - lastTime; tick++; if (acc >= 1000000000L) { acc -= 1000000000L; fps = tick; tick = 0; }
lastTime = now;
g.setColor(Color.black); g.fillRect(0, 0, 800, 600); g.setColor(Color.white); g.drawString("FPS " + String.valueOf(fps), 20, 30);
appletGraphics.drawImage(screen, 0, 0, null);
do { Thread.yield(); } while (System.nanoTime() - lastTime < 0);
if (!isActive()) { return; } } }
public boolean handleEvent(Event e) { switch (e.id) { case Event.KEY_PRESS: case Event.KEY_ACTION: break; case Event.KEY_RELEASE: break; case Event.MOUSE_DOWN: break; case Event.MOUSE_UP: break; case Event.MOUSE_MOVE: break; case Event.MOUSE_DRAG: break; } return false; } } |
|
|
|
|
Abuse
|
 |
«
Reply #6 - Posted
2009-12-03 23:39:12 » |
|
The one above looks like a good starting point.
The only other significant improvement worth suggesting would be to use an [Volatile]Image obtained from Component#create[Volatile]Image(width,height), rather than the BufferedImage - but obviously this is not useful for those doing any per-pixel rendering.
|
|
|
|
broumbroum
|
 |
«
Reply #7 - Posted
2009-12-04 22:14:45 » |
|
1 2 3 4
| public void start() { new Thread(this).start(); } (...) |
this is a true mess, it runs an anonymous Thread "open in the sky" where it couldn't be checked for a termination, an aborting, ... in shorter words with no control over it. A correct impl. would handle native lnstallation and loading, with control over start-stop behaviours, window focus and a caching system.  an applet is implemented through init-destroy and start-stop methods. So this template should define ignition AND shutdown otherwise anyone terminating the applet into a middle-aged browser would see its system crushing down out of memory and busy... I like the one from LWJGL or appletLoader from JOGL which truely provide a powerful interface to such complex applet management with high-valueable capabilities.
|
|
|
|
Ranger
|
 |
«
Reply #8 - Posted
2009-12-04 23:15:26 » |
|
this is a true mess, it runs an anonymous Thread "open in the sky" where it couldn't be checked for a termination, an aborting, ... in shorter words with no control over it. A correct impl. would handle native lnstallation and loading, with control over start-stop behaviours, window focus and a caching system.
It has an isActive() check. Groboclown: Not including the enableEvents may not work on non Sun JVMs. Thanks Appel for the template. Spot on in my book. 
|
|
|
|
broumbroum
|
 |
«
Reply #9 - Posted
2009-12-04 23:28:23 » |
|
It has an isActive() check.
Sorry, but I've never seen this elsewhere and I really find this code unefficient... And writing a book over such mind-less lines, is more boring than ever. 
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Abuse
|
 |
«
Reply #10 - Posted
2009-12-05 00:24:12 » |
|
Groboclown: Not including the enableEvents may not work on non Sun JVMs. That would be true if he was using the Java1.1+ event model, however that template is using the Java 1.0 event model callback method. (Explained & discussed in further detail here)
|
|
|
|
Ranger
|
 |
«
Reply #11 - Posted
2009-12-05 00:25:12 » |
|
Sorry, but I've never seen this elsewhere and I really find this code unefficient... And writing a book over such mind-less lines, is more boring than ever.  Woops, I thought "Spot on in my book" was a common saying. Clearly not.  I just meant that it makes sense in my mind. While the template may not be Java best practice. I can't think of a better way of doing it for the amount of Java bytecode that it produces.
|
|
|
|
Ranger
|
 |
«
Reply #12 - Posted
2009-12-05 00:32:28 » |
|
That would be true if he was using the Java1.1+ event model, however that template is using the Java 1.0 event model callback method. (Explained & discussed in further detail here) Ah, yes! Sorry, I missed the fact that Groboclown swapped it from processEvent to handleEvent.
|
|
|
|
Groboclown
|
 |
«
Reply #13 - Posted
2009-12-09 15:54:23 » |
|
If anyone is wanting to add music to their applet, here's the template that I use for that. I've tested this on Linux, Mac, and Windows; it seems to correctly start and stop the audio, or ignore audio playback if no audio can be detected. Of course, the logic for generating sound is an exercise left to the user. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.FloatControl; import javax.sound.sampled.SourceDataLine;
public class A extends Applet implements Runnable { private static final float SAMPLE_RATE = 44100; private static final int BITS_PER_SAMPLE = 8; private static final int OUTPUT_CHANNELS = 1; private static final boolean SIGNED = true;
private static final int AUDIO_BUFFER_LENGTH = (int) (SAMPLE_RATE * BITS_PER_SAMPLE / 8);
private int t = 0; private SourceDataLine o;
public void start() { try { this.o = AudioSystem.getSourceDataLine( new AudioFormat(SAMPLE_RATE, BITS_PER_SAMPLE, OUTPUT_CHANNELS, SIGNED, true)); this.o.open( new AudioFormat(SAMPLE_RATE, BITS_PER_SAMPLE, OUTPUT_CHANNELS, SIGNED, true), AUDIO_BUFFER_LENGTH * 2); FloatControl volume = (FloatControl) this.o.getControl(FloatControl.Type.MASTER_GAIN); volume.setValue(volume.getMaximum()); this.o.start(); } catch (Exception e) { this.t = 1; } new Thread(this).start(); } public void run() { if (this.t == 0) { this.t = 1; new Thread(this).start(); while (this.o != null) { byte[] audio = new byte[AUDIO_BUFFER_LENGTH]; this.o.write(audio, 0, AUDIO_BUFFER_LENGTH); } return; }
if (!isActive()) { this.o.stop(); this.o.close(); this.o = null; return; } } } |
Alternatively, you can eliminate the launching of the music thread and use the SourceDataLine.write as the timer for waiting for the next frame (I did this in a not-so-successful DDR-style game), but then you can run into complicated issues around buffer underruns, which are difficult to deal with in a platform independent way.
|
|
|
|
steveyO
|
 |
«
Reply #14 - Posted
2009-12-12 08:03:09 » |
|
One of the rules is "The Applet may not cause "leaks" in the browser, resulting in browser instability.". I remember there was some brief discussion on this a few weeks ago, however I can't see any code in any of the templates that handles this.
How is this generally handled? Main reason I ask, is in my game after a few browser refreshes the game becomes choppy/slow. I guess the applet is not cleaning up my many BufferedImage objects. Last years entry suffered from a similar problem.
|
|
|
|
pjt33
|
 |
«
Reply #15 - Posted
2009-12-12 11:52:39 » |
|
One of the rules is "The Applet may not cause "leaks" in the browser, resulting in browser instability.". I remember there was some brief discussion on this a few weeks ago, however I can't see any code in any of the templates that handles this.
IIRC the main point here was that your main loop should exit and your thread finish when the user moves away from the page.
|
|
|
|
steveyO
|
 |
«
Reply #16 - Posted
2009-12-12 14:19:41 » |
|
What I meant is most of the templates I have seen have a start()/init() to start the main Thread and a run() method. Do we not need a destoy() method too (to stop thread) or is this handled automatically?
|
|
|
|
Alan_W
|
 |
«
Reply #17 - Posted
2009-12-12 16:46:49 » |
|
What I meant is most of the templates I have seen have a start()/init() to start the main Thread and a run() method. Do we not need a destoy() method too (to stop thread) or is this handled automatically?
If the thread terminates when isActive() goes false, then everything closes down cleanly when the player leaves the page, so we can omit destroy().
|
Time flies like a bird. Fruit flies like a banana.
|
|
|
steveyO
|
 |
«
Reply #18 - Posted
2009-12-12 22:23:42 » |
|
Ok thanks Alan.. I get it now.. The template I was using from last year didnt have the isActive check... Have added it and problem solved!
|
|
|
|
bysse
|
 |
«
Reply #19 - Posted
2010-02-16 08:18:16 » |
|
I've had some problems with Thread.yield-loop on some systems. It makes the CPU go to 100% which makes the applets input really slow. It works much better for me with an ordinary Thread.sleep(10) construct. The systems I've had problems with were all Ubuntu 9.10 x64 with Java 1.6.0u16. (EDIT) Here's my edit to the template: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| import java.applet.Applet; import java.awt.Event; import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage;
public class G extends Applet implements Runnable {
public void start() { new Thread(this).start(); }
public void run() { setSize(800, 600);
BufferedImage screen = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB); Graphics g = screen.getGraphics(); Graphics appletGraphics = getGraphics();
int tick = 0, fps = 0, acc = 0; long lastTime = System.nanoTime();
while (true) { long now = System.nanoTime(); acc += now - lastTime; tick++; if (acc >= 1000000000L) { acc -= 1000000000L; fps = tick; tick = 0; }
lastTime = now;
g.setColor(Color.black); g.fillRect(0, 0, 800, 600); g.setColor(Color.white); g.drawString("FPS " + String.valueOf(fps), 20, 30);
appletGraphics.drawImage(screen, 0, 0, null);
try { Thread.sleep(10); } catch (Exception e) { };
if (!isActive()) { return; } } }
public boolean handleEvent(Event e) { switch (e.id) { case Event.KEY_PRESS: case Event.KEY_ACTION: break; case Event.KEY_RELEASE: break; case Event.MOUSE_DOWN: break; case Event.MOUSE_UP: break; case Event.MOUSE_MOVE: break; case Event.MOUSE_DRAG: break; } return false; } } |
|
|
|
|
SquashMonster
|
 |
«
Reply #20 - Posted
2010-03-02 18:45:41 » |
|
I didn't use this on either of my entries because I didn't realize that it's smaller than the method I was using until too late, but here's a template that maintains a relatively steady frame rate and goes easier on your CPU. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| import java.applet.Applet; import java.awt.Event; import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage;
public class G extends Applet implements Runnable {
public void start() { new Thread(this).start(); }
public void run() { setSize(800, 600);
BufferedImage screen = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB); Graphics g = screen.getGraphics(); Graphics appletGraphics = getGraphics();
while (true) { long lastTime = System.nanoTime();
g.setColor(Color.black); g.fillRect(0, 0, 800, 600); g.setColor(Color.white); g.drawString("FPS " + String.valueOf(fps), 20, 30);
appletGraphics.drawImage(screen, 0, 0, null);
long delta = System.nanoTime() - lastTime; if(delta < 20000000L) { try { Thread.sleep((20000000L - delta) / 1000000L); } catch(Exception e) { } }
if (!isActive()) { return; } } }
public boolean handleEvent(Event e) { switch (e.id) { case Event.KEY_PRESS: case Event.KEY_ACTION: break; case Event.KEY_RELEASE: break; case Event.MOUSE_DOWN: break; case Event.MOUSE_UP: break; case Event.MOUSE_MOVE: break; case Event.MOUSE_DRAG: break; } return false; } } |
Replace the 20000000L with your desired frame delay.
|
|
|
|
ido
|
 |
«
Reply #21 - Posted
2010-04-07 10:08:23 » |
|
Any reason to use the deprecated public boolean handleEvent(Event e) function instead of protected void processEvent(AWTEvent e)?
|
|
|
|
Markus_Persson
|
 |
«
Reply #22 - Posted
2010-04-07 14:52:51 » |
|
It's smaller, and not removed yet.
|
|
|
|
ido
|
 |
«
Reply #23 - Posted
2010-04-13 21:22:20 » |
|
And is there a reason to run it in its own thread? I.e what's the difference between: 1 2 3
| public void start() { new Thread(this).start(); } |
and: 1 2 3
| public void start() { run(); } |
|
|
|
|
Ranger
|
 |
«
Reply #24 - Posted
2010-04-13 22:05:39 » |
|
And is there a reason to run it in its own thread? I.e what's the difference between: 1 2 3
| public void start() { new Thread(this).start(); } |
and: 1 2 3
| public void start() { run(); } |
If you tried that, you'd find it wouldn't work. For a reason called the Java Event Dispatching Thread (EDT). The loop in the run method would block any user input, drawing, etc, that the EDT needs to do.
|
|
|
|
SquashMonster
|
 |
«
Reply #25 - Posted
2010-12-07 00:02:09 » |
|
Does anyone have a good method for passing mouse input to the main function?
For key input there's the giant array of booleans that we al know and love, but passing mouse events over is hard.
What I've been doing is maintaining a LinkedList of Events and using it as a queue. HandleEvent adds them, your input loop does while(!events.isEmpty()) {Event e = events.removeFirst(); [Input Code]}
That requires you to wrap your entire event handler in an exception handler though, or you'll get concurrent modification issues that don't make any sense. On the bright side, wrapping something in an exception handler is free if you're doing anything else that requires exception handling, such as the Thread.sleep() in my version of the template.
But requiring a LinkedList is kinda crappy. You could also do it with an array and an index, which might be smaller, but I haven't checked.
|
|
|
|
Alan_W
|
 |
«
Reply #26 - Posted
2010-12-07 05:17:57 » |
|
I detect mouse presses and releases and write them into an boolean array (dimension needs to be 5 iirc). I also read the current mouse position and store that in mouseX and mouseY. Bear in mind that other mouse events may update mouseX & mouseY. Thus it works very much like the keyboard boolean array. To action a mouse click, the main loop does something like: 1 2 3 4 5
| if (mouse[1]) { mouse[1] = false;
} |
Mouse drag events are not supported, but could be faked in the main game loop by maintaining a second array of mouse button states and copying current state into last state on every loop. Incidentally I only have one event handler which does both keyboard and mouse.
|
Time flies like a bird. Fruit flies like a banana.
|
|
|
pjt33
|
 |
«
Reply #27 - Posted
2010-12-07 10:00:22 » |
|
For key input there's the giant array of booleans that we al know and love, but passing mouse events over is hard.
Cheat and use the keyboard array. There are plenty of unused codes, especially if you size your array using a larger int which is already in the constant pool (although IIRC I use 0-3).
|
|
|
|
Groboclown
|
 |
«
Reply #28 - Posted
2010-12-20 06:12:24 » |
|
For the current versions of Mac Java, the run() method needs to include a wait at the beginning to ensure that the applet is ready before running:
public void run() { while (! isActive()) { // Wait technique, such as Thread.yield() or Thread.sleep() } // rest of the code }
|
|
|
|
zeroone
|
 |
«
Reply #29 - Posted
2010-12-20 15:38:01 » |
|
For the current versions of Mac Java, the run() method needs to include a wait at the beginning to ensure that the applet is ready before running:
public void run() { while (! isActive()) { // Wait technique, such as Thread.yield() or Thread.sleep() } // rest of the code } Which method calls fail if we do not do this?
|
|
|
|
|