Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (107)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  A question about Images and Graphics  (Read 1684 times)
0 Members and 1 Guest are viewing this topic.
Offline 3lek

Junior Newbie





« Posted 2008-11-15 07:49:54 »

Hi all, first post here  Grin

My question is, why does this work as expected:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
public class AppTest extends Applet
{
   Image i;
   public void init()
   {
   }
   
   public void paint(Graphics g)
   {
      i = createImage(this.getWidth(), this.getHeight());
      Graphics b = i.getGraphics();
      try
      {
         b.drawImage(this.getImage(new URL(this.getCodeBase(), "dude.png")), 0, 0, null);
      }
      catch (MalformedURLException e)
      {
         e.printStackTrace();
      }
      b.dispose();
      g.drawImage(i, 0, 0, null);
      repaint();
   }
}


But this doesn't draw anything:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
public class AppTest extends Applet
{
   Image i;
   public void init()
   {
      i = createImage(this.getWidth(), this.getHeight());
      Graphics b = i.getGraphics();
      try
      {
         b.drawImage(this.getImage(new URL(this.getCodeBase(), "dude.png")), 0, 0, null);
      }
      catch (MalformedURLException e)
      {
         e.printStackTrace();
      }
      b.dispose();
   }
   
   public void paint(Graphics g)
   {
      g.drawImage(i, 0, 0, null);
      repaint();
   }
}

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #1 - Posted 2008-11-15 09:24:36 »

Both of your methods will actually create an infinite loop if you ever got them to draw.

You call repaint() in order to tell your screen to refresh itself, and along the way repaint() automatically calls paint().

[EDIT] I think I should mention that you are really doing this more or less very very wrong and you should spend some time looking at examples and reading tutorials. It's clear to me that you don't really grasp what you're doing.

But here's a simple diagram of what's actually happening in your code.

In the first one:
1) Applet is created, repaint() is automatically called once upon creation.
2) Repaint() calls paintComponent(), update(), paint() and a lot of other stuff you don't see.
3) paint() runs your stuff: creates a new image, loads that image from a file, draws it, then calls repaint.
4) Go back to #2. Repeat infinitely.

In the second one:
1) Applet is created, repaint() is automatically called upon creation (see 1a), and after that's finished a new image is created and loaded from a file.
1a) Repaint() calls paintComponent(), update(), paint() and a lot of other stuff you don't see.
1b) paint() draws your image, which is null, then calls repaint.
1c) Go back to #1a. Repeat infinitely.

Notice that in the second one "after that's finished a new image is created and loaded from a file" never happens because repaint keeps going forever. The applet never gets initialized entirely.

Both methods are very wrong however because you're causing an infinite loop, which will eat up processor and inhibit you from doing absolutely anything. You'll want to use a separate timer or loop that separately calls repaint(), you absolutely do not want a derivative of repaint() to call it.

[/EDIT]

See my work:
OTC Software
Offline Abuse

JGO Coder


Medals: 11


falling into the abyss of reality


« Reply #2 - Posted 2008-11-15 15:12:13 »

You are suffering from several problems, DemonPants has pointed out your call to repaint() in the paint method is bad - it will cause the EDT (EventDispatchThread) to be flooded with repaint events continually redrawing your Applet. While this behaviour isn't inherently bad (it is essentially a primitive form of game loop), it probably isn't what you are intending.

As to the reason why your 1st sample appears to work, and your 2nd does not - that is a little more complicated.
Lets start with this :-

Quote
this.getImage(new URL(this.getCodeBase(), "dude.png"))

Component.getImage(...) (which falls through to Toolkit.getImage(...) does return an Image object - however it is returned unloaded. This means it is not ready to be drawn to the screen.
The data for the Image only begins to be loaded the first time you try and use the Image (in your case, this is the first time you attempt to draw it). This loading process however occurs asynchronously, and until it is complete any attempt to draw the image will result in nothing happening.

This is the cause of your 2nd code example not working - your init() method is invoked only once, therefore your first attempt to copy the "dude.png" onto your "i Image" results in failure because the image has yet to be loaded.

As to the reason your 1st code example DOES work - this is yet more complex!
If we go back to:-
Quote
this.getImage(new URL(this.getCodeBase(), "dude.png"))

if you take a look at the javadoc for Toolkit.getImage(...) you will see the documentation mentions that it attempts to cache requests for the same image:
Quote
The underlying toolkit attempts to resolve multiple requests with the same filename to the same returned Image.

This cache is unwittingly the reason why your first code example works. As your first example repeatedly attempts to load the same image each repaint cycle, the Toolkits underlying cache will be returning you the same Image object. Eventually the Image's loading will complete and the subsequent copy onto the "i Image" will be successful.

I'll annotate your code to better explain the exact sequence of steps, so you can better see this:

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  
public class AppTest extends Applet
{
   Image i;
   public void init() //  Called by the browser or applet viewer to inform this applet that it has been loaded into the system.
  {
               // once this method completes, a repaint event will be pushed onto the EDT (EventDispatchThread), so at some future point the paint(Graphics) method will be called.
  }
   
   public void paint(Graphics g) // called by the EDT each time it encounters a paint event in it's queue
  {
                // LABEL 1
     i = createImage(this.getWidth(), this.getHeight()); // creates an empty image
     Graphics b = i.getGraphics(); // gets the graphics context to draw onto the empty image
     try
      {
                        // attempts to get the image "dude.png" from the Toolkit's image cache
                       // if it isn't present, it will be added.
                       Image img = this.getImage(new URL(this.getCodeBase(), "dude.png"));
                        // attempts to draw the image
                       // if the image is completely loaded, it will be drawn, otherwise no drawing will occur.
                       // for images that are not completely loaded, the loading process will commence (if it hasn't already)
        b.drawImage(img, 0, 0, null);
      }
      catch (MalformedURLException e)
      {
         e.printStackTrace();
      }
      b.dispose();
                // draws the (potencially empty) image to the screen
     g.drawImage(i, 0, 0, null);
                // pushes another repaint event onto the EDT queue - for the sake of simplicity, just imagine flow-of-control returns to the beginning of this paint(Graphics) method. (GOTO LABEL 1)
     repaint();
   }
}


Here is a modified version of your code, i've left the repaint() call at the end of the paint method, so you can see it allows for a primitive way of animating.

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  
import java.applet.Applet;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.net.MalformedURLException;
import java.net.URL;

public class DudeApplet extends Applet {
    Image dude;
   public void init()
   {
      try {
         dude = getImage(new URL(this.getCodeBase(), "dude.png"));
         // this class provides a mechanism for waiting on a set of resources to load.
        MediaTracker imageLoader = new MediaTracker(this);
         // adds the dude png to the list of images it is tracking
        imageLoader.addImage(dude, 0);
         // now initiate the loading, and wait.
        imageLoader.waitForAll();
      } catch (MalformedURLException e) {
         // TODO Auto-generated catch block
        e.printStackTrace();
      } catch (InterruptedException e) {
         // TODO Auto-generated catch block
        e.printStackTrace();
      }
   }
   
   /**
    * Overridden because we don't want the default behaviour of clearing
    * the Component to it's background color. (which by default is white)
    * @see Component#update(Graphics)
    */

   public void update(Graphics g) {
      paint(g);
   }
   
   public void paint(Graphics g)
   {
      try {
         // note this is a VERY BAD way of throttling,
        // it is halting the EDT for 100ms,
        // preventing it from processing any other user inputs. (keyboard, mouse etc etc)
        // you should replace this with a proper
        // game loop & frame rate throttling mechanism
        Thread.sleep(100);
      } catch (InterruptedException e) {
         // TODO Auto-generated catch block
        e.printStackTrace();
      }

      g.setColor(Color.BLACK);
      g.fillRect(0, 0, getWidth(), getHeight());

      // redraw the dude image @ a random location
     g.drawImage(dude,
            (int)((getWidth()-dude.getWidth(null)) *Math.random()),
            (int)((getWidth()-dude.getWidth(null)) *Math.random()), null);
   
      // this is essentially a very primitive way of making a game loop.
     repaint();
   }
}

Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! https://dl.dropbox.com/u/54785909/EliteIVsmaller.png
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline 3lek

Junior Newbie





« Reply #3 - Posted 2008-11-15 18:31:05 »

Great explanation! Thanks guys - I guess I will be creating another thread for drawing so that it doesn't interfere with the EDT while I'm at it.

Cheers  Smiley
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Riven (18 views)
2014-07-29 18:09:19

Riven (13 views)
2014-07-29 18:08:52

Dwinin (12 views)
2014-07-29 10:59:34

E.R. Fleming (31 views)
2014-07-29 03:07:13

E.R. Fleming (12 views)
2014-07-29 03:06:25

pw (42 views)
2014-07-24 01:59:36

Riven (41 views)
2014-07-23 21:16:32

Riven (28 views)
2014-07-23 21:07:15

Riven (29 views)
2014-07-23 20:56:16

ctomni231 (60 views)
2014-07-18 06:55:21
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!