appel
JGO Wizard     Posts: 1440 Medals: 22
I always win!
|
 |
«
on:
2009-11-30 19:42:18 » |
|
Please paste some solid applet templates in here.
|
|
|
|
kappa
« League of Dukes » JGO Kernel      Posts: 2268 Medals: 50
★★★★★
|
 |
«
Reply #1 on:
2009-11-30 21: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
JGO Wizard     Posts: 1440 Medals: 22
I always win!
|
 |
«
Reply #2 on:
2009-12-01 03: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! Go get 'em!
|
|
Morre
Sr. Member   Posts: 494
I'm Dragonene on IRC.
|
 |
«
Reply #3 on:
2009-12-03 15: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
JGO Wizard     Posts: 1440 Medals: 22
I always win!
|
 |
«
Reply #4 on:
2009-12-03 17: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
Jr. Member   Posts: 88 Medals: 2
|
 |
«
Reply #5 on:
2009-12-03 17: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
JGO Kernel      Posts: 1859 Medals: 5
falling into the abyss of reality
|
 |
«
Reply #6 on:
2009-12-03 18: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
Sr. Member   Posts: 384
|
 |
«
Reply #7 on:
2009-12-04 17: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
Sr. Member   Posts: 338
|
 |
«
Reply #8 on:
2009-12-04 18: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
Sr. Member   Posts: 384
|
 |
«
Reply #9 on:
2009-12-04 18: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! Go get 'em!
|
|
Abuse
JGO Kernel      Posts: 1859 Medals: 5
falling into the abyss of reality
|
 |
«
Reply #10 on:
2009-12-04 19: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
Sr. Member   Posts: 338
|
 |
«
Reply #11 on:
2009-12-04 19: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
Sr. Member   Posts: 338
|
 |
«
Reply #12 on:
2009-12-04 19: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
Jr. Member   Posts: 88 Medals: 2
|
 |
«
Reply #13 on:
2009-12-09 10: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
Sr. Member   Posts: 308 Medals: 4
|
 |
«
Reply #14 on:
2009-12-12 03: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
JGO Strike Force    Posts: 890 Medals: 17
|
 |
«
Reply #15 on:
2009-12-12 06: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
Sr. Member   Posts: 308 Medals: 4
|
 |
«
Reply #16 on:
2009-12-12 09: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
JGO Ninja    Posts: 732 Medals: 8
Java tames rock!
|
 |
«
Reply #17 on:
2009-12-12 11: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
Sr. Member   Posts: 308 Medals: 4
|
 |
«
Reply #18 on:
2009-12-12 17: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
JGO n00b  Posts: 35
|
 |
«
Reply #19 on:
2010-02-16 03: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
Jr. Member   Posts: 67 Medals: 1
|
 |
«
Reply #20 on:
2010-03-02 13: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
Jr. Member   Posts: 95
|
 |
«
Reply #21 on:
2010-04-07 06:08:23 » |
|
Any reason to use the deprecated public boolean handleEvent(Event e) function instead of protected void processEvent(AWTEvent e)?
|
|
|
|
Markus_Persson
JGO Kernel      Posts: 2092 Medals: 10
Mojang Specifications
|
 |
«
Reply #22 on:
2010-04-07 10:52:51 » |
|
It's smaller, and not removed yet.
|
|
|
|
ido
Jr. Member   Posts: 95
|
 |
«
Reply #23 on:
2010-04-13 17: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
Sr. Member   Posts: 338
|
 |
«
Reply #24 on:
2010-04-13 18: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
Jr. Member   Posts: 67 Medals: 1
|
 |
«
Reply #25 on:
2010-12-06 19: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
JGO Ninja    Posts: 732 Medals: 8
Java tames rock!
|
 |
«
Reply #26 on:
2010-12-07 00: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
JGO Strike Force    Posts: 890 Medals: 17
|
 |
«
Reply #27 on:
2010-12-07 05: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
Jr. Member   Posts: 88 Medals: 2
|
 |
«
Reply #28 on:
2010-12-20 01: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
Sr. Member   Posts: 286 Medals: 8
|
 |
«
Reply #29 on:
2010-12-20 10: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?
|
|
|
|
|
|