This is hard to tell without seeing the code in the headsup.draw method...

                               ...jim

--On Thursday, August 25, 2005 10:19 PM +0200 Olof Bjarnason
<[EMAIL PROTECTED]> wrote:

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