If anyone wants to post help in this thread, I'll post a link to here in my other thread. I don't want to waste anyone's time, but I can't seem to locate where the experts are.

05-07-2010, 06:29 AM

toadaly

I really don't feel like analyzing your code line by line to figure out what you're trying to do and why it works with one approach but not the other. What are you trying to accomplish, and why are you worried about the overhead of synchronization...are you runnign on a TRS-80?

05-07-2010, 06:40 AM

JavaRulez

So sorry, I guess some comments may have been more helpful? Would you like me to decorate the code with comments and repost it? (that might sound sarcastic but I am being sincere)

I'm trying to ensure that changes in state are synchronized with the display. I know synchronizing isn't hurting my performance much, but I know it slows it down slightly. This isn't too critical, however being a perfectionist, I'll feel disappointed if I can't optimize this.

The actual project is an API (or extension, I don't know which term is more appropriate) for developing 2D graphics games. The problem I foresee is that a person (The Player) is playing my game with less than desirable graphics acceleration. Lots of sprites on the screen could cause slow down in rendering. If the logic portion of the program moves a "monster" close to The Player, the player should react within one cycle. If however, the rendering is lagging behind, the player won't react (which is appropriate for their knowledge of the game state). Upon the next iteration, the "monster" will kill the player. At this point The Player may have been made aware of the previous game state (graphics is lagging) and react to the impending danger. Subsequently the player is made aware of dieing despite reacting appropriately. Clearly I could attempt to prevent players from playing the game if it detects that it is cycling too slowly, but I'd rather not. Old console games frequently slowed down when too many sprites were on the screen and the game was still perfectly playable.

I had previously downloaded someone else's "game engine" and it suffered from this very problem (graphics and game state not synchronized). I revisited some of my previous work with AWT and Swing and noticed that my code too demonstrated these problems. This is why I developed the AWT algorithm that uses synchronization. After reading a tutorial on Painting in AWT and Swing located at sun's site I noticed a section describing this problem related to JScrollPane, it mentioned paintImmediately(); I'm trying to adapt my code to use this mechanism so that it will be single-threaded. You may notice that my AWT example uses 2 threads (what I wish to avoid).

05-07-2010, 07:28 AM

toadaly

Ok. "repaint" queues an asynchronous paint event, it does not cause an immediate update of the screen. I noticed you're using that along with SwingUtilities.invokeLater, which is also asynchronous. If you use 'paint' and 'paintImmediately' instead, you can make things much more responsive. A word of caution though, don't synchronize around swing calls. Swing is not thread safe and you will almost assuredly end up with a hard to track deadlock.

If your goal is a realtime game, I'd consider something other than Java. If you want portability and realtime graphics, use OpenGL. If you don't care about portability and need even higher performance, use a platform specific optimized graphics engine such as DirectX on Windows, or X on linux.

However, I've found that swing is more than acceptable in most cases. I write graphical programs in Java all the time that are much faster than a human eye can even see on moderate machines. It's easier to specify a minimum machine configuration than it is to try to make your program work on anything that anyone might have.

05-07-2010, 08:08 AM

JavaRulez

I hear what you are saying, but the ability to deploy this as a downloadable application, applet, or webstart application is what interests me most. The computer I'm developing this on uses Linux on an x86_64 processor, graphics hardware is onboard (nearly no acceleration). The games that would use this code shouldn't be processor intensive, yet the code is designed to be an abstraction, removing graphics from the game module with the added bonus of improving the appeal of the game by adding richer effects (full alpha vs bitmask, etc) on a system which has the power to provide it. I believe my code may have been a bit unreadable, and I apologize for not providing more comments. Following is the same code with liberal commenting applied:

//Our common synchronized method allows only the EDT or our main execution thread
//to be in this method, not both
public static synchronized void sync(boolean logic, Graphics g) {
// If we need to run logic but haven't, yet we have already painted at least once
// prevent EDT from entering our method
if (painted && !logic && logictimer < 1) return;
// If we need to run logic but we haven't yet painted the last change of state to
// the display, force logic to wait until EDT has a chance to paint
if (!painted && logic && logictimer < 1) {
// This call to repaint is asynchronous and may be coalesced, we simply want to assure that if
// previous calls were coalesced, we queue a new one so we don't wait forever
pp.repaint();
return;
}
// Simple calculation of elapsed time since either thread has passed through this
// method
long now = System.currentTimeMillis();
long delta = now - last;
last = now;
logictimer -= delta;
// main() called this method with logic == true, following is the section of this
// method that will run for that thread
if (logic) {
// 50 milliseconds have passed, our logic should be cycling at as close to 20hz
// as possible
if (logictimer < 0) {
logictimer += 50;
// Once logic has occured the display is invalidated, signify that condition so
// that we may not proceed with the next logic iteration until the display
// reflects the change in state
painted = false;
// ... <- Put a call to some method which contains our logic here.
} else pp.repaint();
// This call to repaint() allows smaller granularity for graphics vs
// logic. Perhaps sprites animate at 30hz while logic runs at 20hz
//
// paint() called this method with logic == false, following is the code that would
// normally appear in paint() but must be synchronized with logic
} else {
g.setColor(bg_color);
g.fillRect(0, 0, 640, 480);
// By setting painted == true, we can assure that logic may run when it is time to
// do so, or if that time has already elapsed, logic can now pass our test at the
// beginning of this method and is not prevented from entering
painted = true;
}
}

public void keyPressed(KeyEvent e) {
// With every key press we change the paint color. If everything goes
// according to plan, there will be no latency for this state change to
// appear in the display
if (bg_color == Color.black) bg_color = Color.white;
else bg_color = Color.black;
}

// This method was scheduled with SwingUtilities.invokeLater() from main()
// and subsequently schedules successive execution before exiting.
protected void executionHook() {
// calculate elapsed time, just as before
long now = System.currentTimeMillis();
long delta = now - lastexecution;
lastexecution = now;
logictimer -= delta;
// Run logic when it is time, but switch to painting if we haven't yet
if (logictimer < 1 && painted) {
logictimer += 50;
// State has changed, we must paint before we can enter this block again
painted = false;
} else {
// If it is not time for logic or we have yet to paint, paint
// according to the documentation, this should execute synchronously,
// performing our paint operation (including a call to paintComponent())
paintImmediately(0, 0, 640, 480);
painted = true;
}
// Schedule this method to run again, possibly immediately, or possibly after the
// EDT has dispatched keyEvents
SwingUtilities.invokeLater(new Runnable() {
public void run() {
pp.executionHook();
}
});
}

And that code example is single threaded. Clearly I've made a mistake somewhere in the second example, because my understanding of the documentation leads me to believe that the second example should produce an identical result as the first, yet it does not.

05-07-2010, 08:42 AM

JavaRulez

PS I appreciate your help. I as well have been programming since I was quite young, started in BASIC, then Pascal, C, C++, and Java since around '99. I'm not old enough to remember a TRS-80, but I did have an 8086.

05-08-2010, 05:30 AM

toadaly

Your first listing has a potential deadlock condition, and it's almost certain it will lock up from time to time. You are calling several swing methods within a synchronized method (sync), and that method is itself called from another method overriding a swing call (paint).

05-09-2010, 08:34 AM

JavaRulez

I still don't see it. As far as I know, repaint(), Graphics.setColor(), and Graphics.fillRect() are not Swing methods. Also, is not paint() more of an AWT method? The lock is associated with my main class, not the components, and neither thread will ever try to acquire another lock, so they have nothing to wait on. I still don't see how calling repaint() could cause dead-lock. Either way, it doesn't matter as I don't want to use that example, I want to get the second one to work, and since it is single-threaded, the possibility of dead-lock disappears if I can get it to work.