OK I've done some debug-printing for you to get a feeling of the
behaviour. I use this debug-println:
                
public static void println(String str) {
  long millis = System.currentTimeMillis() - startMillis;
  String threadName = Thread.currentThread().getName();
  System.out.println("T="+millis+"\t"+threadName + ": " + str);
}

... which give me quite a lot of information. This is the printout
from a typical 5-second run:
(WARNING: many lines below!)

(ms)    (name of thread)                   (message)
T=0     thread applet-terraformer.TerraformerApplet.class: Setting up model.
T=0     thread applet-terraformer.TerraformerApplet.class: Setting up
graphics fundaments.
T=0     thread applet-terraformer.TerraformerApplet.class: Loading resources.
T=10    thread applet-terraformer.TerraformerApplet.class: Downloading images.
T=120   thread applet-terraformer.TerraformerApplet.class: Creating backbuffer.
T=130   thread applet-terraformer.TerraformerApplet.class: Creating
headsup display.
T=130   thread applet-terraformer.TerraformerApplet.class: Setting up
rendering state.
T=130   AWT-EventQueue-1: Accepting keyboard input once focused.
T=130   AWT-EventQueue-1: Doing first background render.
T=130   AWT-EventQueue-1: updateBackbuffer
T=130   AWT-EventQueue-1: repaint
T=130   AWT-EventQueue-1: paint
T=140   AWT-EventQueue-1: headsup.draw

T=1132  AWT-EventQueue-1: actionPerformed (by Swing-Timer)
T=1132  AWT-EventQueue-1: model.step
T=1132  AWT-EventQueue-1: updateBackbuffer
T=1132  AWT-EventQueue-1: repaint
T=1132  AWT-EventQueue-1: update
T=1132  AWT-EventQueue-1: paint
T=1132  AWT-EventQueue-1: headsup.draw

T=2133  AWT-EventQueue-1: actionPerformed (by Swing-Timer)
T=2133  AWT-EventQueue-1: model.step
T=2133  AWT-EventQueue-1: updateBackbuffer
T=2133  AWT-EventQueue-1: repaint
T=2133  AWT-EventQueue-1: update
T=2133  AWT-EventQueue-1: paint
T=2133  AWT-EventQueue-1: headsup.draw

T=3135  AWT-EventQueue-1: actionPerformed (by Swing-Timer)
T=3145  AWT-EventQueue-1: model.step
T=3145  AWT-EventQueue-1: updateBackbuffer
T=3165  AWT-EventQueue-1: repaint
T=3165  AWT-EventQueue-1: update
T=3165  AWT-EventQueue-1: paint
T=3165  AWT-EventQueue-1: headsup.draw
T=3205  AWT-EventQueue-1: update
T=3205  AWT-EventQueue-1: paint
T=3205  AWT-EventQueue-1: headsup.draw
T=3245  AWT-EventQueue-1: update
T=3245  AWT-EventQueue-1: paint
T=3245  AWT-EventQueue-1: headsup.draw
T=3285  AWT-EventQueue-1: update
T=3285  AWT-EventQueue-1: paint
T=3285  AWT-EventQueue-1: headsup.draw
T=3325  AWT-EventQueue-1: update
T=3325  AWT-EventQueue-1: paint
T=3325  AWT-EventQueue-1: headsup.draw
T=3365  AWT-EventQueue-1: update
T=3365  AWT-EventQueue-1: paint
T=3365  AWT-EventQueue-1: headsup.draw
T=3405  AWT-EventQueue-1: update
T=3405  AWT-EventQueue-1: paint
T=3405  AWT-EventQueue-1: headsup.draw
T=3445  AWT-EventQueue-1: update
T=3445  AWT-EventQueue-1: paint
T=3445  AWT-EventQueue-1: headsup.draw
T=3495  AWT-EventQueue-1: update
T=3495  AWT-EventQueue-1: paint
T=3495  AWT-EventQueue-1: headsup.draw
T=3535  AWT-EventQueue-1: update
T=3535  AWT-EventQueue-1: paint
T=3535  AWT-EventQueue-1: headsup.draw
T=3575  AWT-EventQueue-1: update
T=3575  AWT-EventQueue-1: paint
T=3575  AWT-EventQueue-1: headsup.draw
T=3615  AWT-EventQueue-1: update
T=3615  AWT-EventQueue-1: paint
T=3615  AWT-EventQueue-1: headsup.draw
T=3655  AWT-EventQueue-1: update
T=3655  AWT-EventQueue-1: paint
T=3655  AWT-EventQueue-1: headsup.draw
T=3705  AWT-EventQueue-1: update
T=3705  AWT-EventQueue-1: paint
T=3705  AWT-EventQueue-1: headsup.draw
T=3745  AWT-EventQueue-1: update
T=3745  AWT-EventQueue-1: paint
T=3745  AWT-EventQueue-1: headsup.draw
T=3786  AWT-EventQueue-1: update
T=3786  AWT-EventQueue-1: paint
T=3786  AWT-EventQueue-1: headsup.draw
T=3826  AWT-EventQueue-1: update
T=3826  AWT-EventQueue-1: paint
T=3826  AWT-EventQueue-1: headsup.draw
T=3866  AWT-EventQueue-1: update
T=3866  AWT-EventQueue-1: paint
T=3866  AWT-EventQueue-1: headsup.draw
T=3906  AWT-EventQueue-1: update
T=3906  AWT-EventQueue-1: paint
T=3916  AWT-EventQueue-1: headsup.draw
T=3956  AWT-EventQueue-1: update
T=3956  AWT-EventQueue-1: paint
T=3956  AWT-EventQueue-1: headsup.draw
T=3996  AWT-EventQueue-1: update
T=3996  AWT-EventQueue-1: paint
T=3996  AWT-EventQueue-1: headsup.draw
T=4036  AWT-EventQueue-1: update
T=4036  AWT-EventQueue-1: paint
T=4036  AWT-EventQueue-1: headsup.draw
T=4076  AWT-EventQueue-1: update
T=4076  AWT-EventQueue-1: paint
T=4076  AWT-EventQueue-1: headsup.draw
T=4126  AWT-EventQueue-1: update
T=4126  AWT-EventQueue-1: paint
T=4126  AWT-EventQueue-1: headsup.draw

T=4136  AWT-EventQueue-1: actionPerformed (by Swing-Timer)
T=4136  AWT-EventQueue-1: model.step
T=4136  AWT-EventQueue-1: updateBackbuffer
T=4136  AWT-EventQueue-1: repaint
T=4136  AWT-EventQueue-1: update
T=4136  AWT-EventQueue-1: paint
T=4136  AWT-EventQueue-1: headsup.draw
T=4166  AWT-EventQueue-1: update
T=4166  AWT-EventQueue-1: paint
T=4166  AWT-EventQueue-1: headsup.draw
T=4206  AWT-EventQueue-1: update
T=4206  AWT-EventQueue-1: paint
T=4206  AWT-EventQueue-1: headsup.draw
T=4256  AWT-EventQueue-1: update
T=4256  AWT-EventQueue-1: paint
T=4256  AWT-EventQueue-1: headsup.draw
T=4296  AWT-EventQueue-1: update
T=4296  AWT-EventQueue-1: paint
T=4296  AWT-EventQueue-1: headsup.draw
T=4366  AWT-EventQueue-1: update
T=4366  AWT-EventQueue-1: paint
T=4366  AWT-EventQueue-1: headsup.draw
T=4406  AWT-EventQueue-1: update
T=4406  AWT-EventQueue-1: paint
T=4406  AWT-EventQueue-1: headsup.draw
T=4446  AWT-EventQueue-1: update
T=4446  AWT-EventQueue-1: paint
T=4446  AWT-EventQueue-1: headsup.draw
T=4487  AWT-EventQueue-1: update
T=4487  AWT-EventQueue-1: paint
T=4487  AWT-EventQueue-1: headsup.draw
T=4527  AWT-EventQueue-1: update
T=4527  AWT-EventQueue-1: paint
T=4527  AWT-EventQueue-1: headsup.draw
T=4577  AWT-EventQueue-1: update
T=4577  AWT-EventQueue-1: paint
T=4577  AWT-EventQueue-1: headsup.draw
T=4617  AWT-EventQueue-1: update
T=4617  AWT-EventQueue-1: paint
T=4617  AWT-EventQueue-1: headsup.draw
T=4657  AWT-EventQueue-1: update
T=4657  AWT-EventQueue-1: paint
T=4657  AWT-EventQueue-1: headsup.draw
T=4697  AWT-EventQueue-1: update
T=4697  AWT-EventQueue-1: paint
T=4697  AWT-EventQueue-1: headsup.draw

As you can see, the mad-updating begins at T=3205 and continues then
on. Note that the actionPerformed from the Swing-Timer is still
functioning, and that the method that keeps getting called is update
(which in turn calls paint, which call headsup.draw).

/Olof

On 8/25/05, Olof Bjarnason <[EMAIL PROTECTED]> wrote:
> This is a very thourough answer. I will try to reply ...
> 
> On 8/25/05, Jim Graham <[EMAIL PROTECTED]> wrote:
> > >>  From the Component javadocs:
> > >>         The update method of Component calls this component's paint
> > >>         method to redraw this component.
> > >> and:
> > >>         Subclasses of Component that override this method should
> > >>         either call super.update(g), or call paint(g) directly
> > >>         from their update method.
> > >
> > > OK, guess I misread the docs. Actually, I followed this tutorial to begin
> > > with: http://www.dgp.toronto.edu/~mjmcguff/learn/java/
> >
> > either direction will work as long as you override both.  Our docs show the
> > guts in paint() and then update() redirecting to paint() since it reflects
> > what would otherwise go on underneath the covers.  Typically an animation
> > program overrides paint() to start out with to draw a frame, because that
> > is where a program should put its paint() code and that is where someone
> > reading the code would go first to find the painting code.  The override of
> > update() is then added to stop the "erase to background color" flickering.
> > When you look at it that way, it seems more logical to have the actual
> > painting code in the paint() method, but both work as long as you override
> > both.
> I'm with you and I tried both, same result.
> 
> >
> > >> Of course, you've overridden update(), so this changes the
> > >> behavior, but it's a bit confusing at the least.  But there could
> > >> be more wrong here: it could be that by changing the nature of
> > >> update/paint interaction, you're getting in the way of the
> > >> regular system of issuing and consuming repaint() events, which
> > >> could cause the paint calls to keep being issued.
> > >>
> > >> The solution here is to simply override paint() and do your
> > >> painting there.  Or if you're using Swing, override paintComponent()
> > >> instead.  Don't override update, or at least not in the manner you
> > >> are doing currently.
> > > I'm using AWT I guess, no Swing. I'm trying to go for old-API in order
> > > to make the game runnable on more computers. I compile for 1.4.2, but
> > > I guess 1.4.2 has Swing so I could go for paintComponent, but my
> > > feeling is I should use paint(), eg.the tutorial uses paint().
> > > Comments?
> >
> > I don't see how the way you've overridden paint/update() can lead to the
> > problem in and of itself.  It would be an interesting experiment, but I
> > wouldn't abandon your architecture to try to fix this.
> I started "porting" my Applet to JApplet but it proved horrendously
> errorprone (basically had to cut the file in three --- more work to
> fix this than starting from scratch) so I am back at the
> AWT/paint/update stage again.
> 
> >
> > >> To improve performance in general:
> > >>         - use a timer to schedule regular repaints so you don't get
> > >>         swamped with constant repaint events (similar to what you're
> > >>         doing, but I don't follow the complexity of using key actions
> > >>         for this.  Why not simply issue a repaint call?)
> >
> > This is a hard call.  While I still need to think about the ramifications
> > of what you've done with sending ActionEvents to yourself, simply using a
> > Timer instead of rolling your own Thread would not change anything here if
> > the action of the Timer was to send the ActionEvent.
> I've tried both, same result. A potential error with my previous
> "virtual-click-a-button" method was that it used the postEvent from a
> custom thread. Given that the documents state that all AWT/Swing code
> should execute using the invokeLater technique, this i not
> recommended. Anyway, the Swing Timer didn't work either in my setting.
> 
> >
> > If you switched to periodic repaint() calls instead of sending an
> > ActionEvent then it would mean that the calls to update() would happen
> > directly instead of as a result of a frame update.  You would either have
> > to move the frame update code to the update() method, or you would have to
> > have two timer events - one to update the frame, and another to call
> > repaint - and the two would happen asynchronously.
> >
> > This points out a potential problem with the way you've written the code
> > and could be the root cause of the flood of repaints.  Are there ever any
> > frames that take longer than 1 second to render?  If so, then there is no
> > inherent throttling of your ActionEvents to match the extended compute
> > time.  If, say, you have one frame update that takes 10 seconds to
> > complete, then by the time it is done, there will be 10 ActionEvents in the
> > queue waiting to be processed.  If those events take less time to process
> > then you will run through all 10 of them at once and see 10 updates very
> > quickly in a row which could look like what is happening to you.  If it is
> > much more likely to encounter frame updates that take longer than 1 second
> > then the backup will be constantly increasing.
> Simple answer: no. My updateBackbuffer code paints at most 64 tile
> images sized 32x32 each, and actually even when the
> non-stopping-updates is going on, there is no performance problem more
> than the CPU getting up to like 10% (I'm sorry stated 90% earlier post
> but that was a misreading must have been something else..). The way I
> know there is mad-updating is via the console output (println) and
> flickering (the headsup display widgets are flickering).
> 
> >
> > Instead of sending an ActionEvent every second which forces a frame update,
> > you might want to have some way of creating back-pressure.  Either:
> >
> > - have something in your frame update code which requests the subsequent
> > frame when it is done and don't send another ActionEvent until it is
> > requested - that guarantees a delay of N milliseconds "between" frames so
> > if frames take longer than your delay, the ActionEvents don't accumulate.
> > This is kind of hard to implement, though.
> >
> > - have your frame update code check the last time a frame was updated and
> > if it was less than 1 second ago, skip this ActionEvent to catch up
> > (another will come along in less than a second).
> >
> > - you can also look at the time-stamp of the ActionEvent and if it was sent
> > more than 1 second ago, skip it in favor of one that you know will be
> > coming along very soon.
> >
> > - have your frame update code increment "number of frames handled" and have
> > the event sending code increment "number of frames requested" and if the
> > requested count is too far ahead of the handled count (like more than 1
> > greater), skip a beat by not sending the ActionEvent this time.
> >
> > - use calls to update to trigger your frame updates and use "timed repaint"
> > events which coalesce:
> >
> >         Timer thread {
> >             loop {
> >                     sleep(1000);
> >                     repaint(10);  // Will coalesce with other repaint(ms) 
> > calls
> >             }
> >         }
> >
> >         update(Graphics g) {
> >             updateframe();
> >             paint(g);
> >         }
> >
> >         paint(Graphics g) {
> >             g.drawImage(backbuffer);
> >             drawheadsup(g);
> >         }
> >
> > Note that calls to repaint() with no delay will be queued and result in
> > calls to update() on a 1 for 1 basis so you could end up with the same
> > backlog, but calls to repaint() with a delay (as above) will be coalesced
> > with each other.
> >
> > >>         - only draw the area that's changed.  So if only one rectangle
> > >>         of the playing area has changed, draw that updated region
> > >>         into the back buffer, and copy that region of the back buffer
> > >>         into the window.
> >
> > That will help keep the frame update code from getting too far behind the
> > event sending thread...
> >
> >                                 ...jim
> >
> >
> Thanks for your time,
> 
> /Olof
>

===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff JAVA2D-INTEREST".  For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".

Reply via email to