6 Replies Latest reply: Mar 4, 2010 3:16 AM by 843853 RSS

    Java animation isn't smooth :(

    843853
      Hi,
      I am trying to make a simple game in java. every thing is fine. But the

      problem is that the animation in not smooth. It has a lot of fluctuations

      ... and the 2nd problem is that when I keep pressing a key the object

      detects it very late ... I mean if i press left arrow key and keep pressing

      it then the object should immediately move towards left and keep moving

      until I release the key. But in my case when I keep pressing a key the

      object is paused for some time and then it starts moving.. which is a big

      issue in a game
      Can anyone help me with this ???
      Here is my code:
      import java.awt.*;
      import java.awt.event.FocusEvent;
      import java.awt.event.FocusListener;
      import java.awt.event.KeyEvent;
      import java.awt.event.KeyListener;
      import java.awt.event.MouseEvent;
      import java.awt.event.MouseListener;
      import java.awt.image.BufferedImage;
      import java.applet.*;
      import java.io.File;
      import java.io.IOException;
      import javax.imageio.ImageIO;
      
      public class main extends Applet implements Runnable, KeyListener, 
      
      FocusListener, MouseListener{
      
           private static final long serialVersionUID = 1L;
           Thread runner;
      
           // Add KeyListener In the Constructor of the class which you want 
      
      to listeb keys from
           int flagStartGame = 0;
           int Xpos = 230;
           boolean flagRight=false;
           int outerWidth = 320;
           int outerHight = 200;
           int xInner = 340;
           int innerSpeed = 40;
           boolean flagLeft=false;
           int innerWidth = 100;
           int innerHight = 100;
           int flag = 0;
           private int width = -1;
           private int height = -1;
           private Image OSC;
           private Graphics OSG;
           boolean focussed = false;
           int sleepTime = 2;
           
           
           public main(){
                addKeyListener(this);
                addFocusListener(this); 
                addMouseListener(this);
           }
              public void drawFrame(Graphics g, int width, int height) {
                 g.setColor(Color.lightGray);
                 g.fillRect(0,0,width,height);
                 g.setColor(Color.black);
              }
           
           
           
           //
           public void start(){
                if (runner == null){
                     runner = new Thread(this);
                     runner.start();
                }
           }
           public void stop(){
                if(runner != null)
                {
                     runner = null;
                }
           }
           public void run(){
                while(true){
                     repaint();
                     try {
                          Thread.sleep(sleepTime);
                     } catch (InterruptedException e) {
                          // TODO Auto-generated catch block
                          e.printStackTrace();
                     }
                }
           }
           //
           public void paint(Graphics g){
                ///////
              // Draw the current frame on the applet drawing area.  If the 
              // applet has focus, draw a cyan border around the frame.  
      
      Otherwise,
              // draw a message telling the user to click on the applet to 
              // activate it.
      
         if (width != getSize().width || height != getSize().height) { // if size 
      
      has changed, recreate frame
            doSetup();
            if (OSC != null)
               drawFrame(OSG,width-6,height-6);
         }
      
         if (OSC == null) { // if not enough memory for OSC, draw an error 
      
      message
            g.setColor(getBackground());
            g.fillRect(0,0,width,height);
            g.setColor(getForeground());
            g.drawString("Sorry, out of Memory!", 10,25);
            return;
         }
      
         g.drawImage(OSC,3,3,this);
         
         if (focussed)                     // Draw a 3-pixel border.  If the 
      
      applet has the
           // g.setColor(focusBorderColor);  //   focus, draw it in 
      
      focusBorderColor; otherwise,
         //else                              //   draw it in the background 
      
      color.
         g.setColor(getBackground());
         g.drawRect(0,0,width-1,height-1);
         g.drawRect(1,1,width-3,height-3);
         g.drawRect(2,2,width-5,height-5);
      
         if (!focussed) {                      // If the applet does not have the 
      
      focus,
            g.setColor(getForeground());       //    print a message for the 
      
      user.
            g.drawString("Click to activate",10,height-12);
         }
                
                //////
                  File file = new File("outer.bmp");
                  File file2 = new File("inner.bmp");
                try {
                     BufferedImage img = ImageIO.read(file);
                     BufferedImage img2 = ImageIO.read(file2);
                     
                     if(!g.drawImage(img, Xpos, 30, outerWidth, 
      
      outerHight, null))
                     {
                          System.out.println("Error opening image 
      
      file");
                     }
                     if(!g.drawImage(img2, xInner, 80, innerWidth, 
      
      innerHight, null))
                     {
                          System.out.println("Error opening image 
      
      file2");
                     }
                } catch (IOException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                }
                //g.fill3DRect(Xpos, 30, 100, 100, true);
                if(flag == 0 && focussed)
                {
                     Xpos--;
                     if(flagLeft == true)
                     {
                          xInner-=innerSpeed;
                          flagLeft=false;
                     }
                     else if(flagRight == true)
                     {
                          xInner+=innerSpeed;
                          flagRight=false;
                     }
                }
                else if(flag == 1 && focussed)
                {
                     Xpos++;
                     if(flagLeft == true)
                     {
                          xInner-=innerSpeed;
                          flagLeft=false;
                     }
                     else if(flagRight == true)
                     {
                          xInner+=innerSpeed;
                          flagRight=false;
                     }
                }
                
                if(Xpos<0)
                {
                     flag = 1;
                }
                else if(Xpos>550)
                {
                     flag = 0;
                }
                if (Xpos<50 || Xpos>500)
                {
                     sleepTime = 10;
                }
                else
                {
                     sleepTime = 2;
                }
                if(Xpos >= xInner)
                {
                     System.out.println("Out ..!!");
                }
                if(Xpos+outerWidth < xInner+innerWidth)
                {
                     System.out.println("Out2 ..!!");
                }
           }
      To be continued in next post...
        • 1. Re: Java animation isn't smooth :(
          843853
               @Override
               public void keyPressed(KeyEvent ke) {
                    // TODO Auto-generated method stub
                    if(ke.getKeyCode() == KeyEvent.VK_DOWN)
                  {     
                         
                    //     System.out.println("Down...!!");
                  repaint();
              }
              if(ke.getKeyCode() == KeyEvent.VK_UP)
                  {
                   //System.out.println("Up...!!");
                  repaint();
              }
              if(ke.getKeyCode() == KeyEvent.VK_LEFT)
                  {
                   //System.out.println("Left...!!");
                   flagLeft=true;
                  repaint();
              }
              if(ke.getKeyCode() == KeyEvent.VK_RIGHT)
                  {
                   //System.out.println("Right...!!");
                   flagRight=true;
                  repaint();
              }
                    
               }
          
          
               @Override
               public void keyReleased(KeyEvent ke) {
                    // TODO Auto-generated method stub
                    if(ke.getKeyCode() == KeyEvent.VK_DOWN)
                  {
                         
                    //     System.out.println("Down...!!");
                  repaint();
              }
              if(ke.getKeyCode() == KeyEvent.VK_UP)
                  {
                   //System.out.println("Up...!!");
                  repaint();
              }
              if(ke.getKeyCode() == KeyEvent.VK_LEFT)
                  {
                   //System.out.println("Left...!!");
                   flagLeft=true;
                  repaint();
              }
              if(ke.getKeyCode() == KeyEvent.VK_RIGHT)
                  {
                   flagRight=true;
                  repaint();
              }
               }
          
          
               @Override
               public void keyTyped(KeyEvent arg0) {
                    // TODO Auto-generated method stub
                    
               }
               @Override
               public void mouseClicked(MouseEvent arg0) {
                    // TODO Auto-generated method stub
                    
               }
               @Override
               public void mouseEntered(MouseEvent arg0) {
                    // TODO Auto-generated method stub
                    
               }
               @Override
               public void mouseExited(MouseEvent arg0) {
                    // TODO Auto-generated method stub
                    
               }
               @Override
               public void mousePressed(MouseEvent arg0) {
                    // TODO Auto-generated method stub
                    
               }
               @Override
               public void mouseReleased(MouseEvent arg0) {
                    // TODO Auto-generated method stub
                    System.out.println("Clicked!!");
                    focussed = true;
                   repaint();
                   //notify();
               }
               @Override
               public void focusGained(FocusEvent arg0) {
                    // TODO Auto-generated method stub
                    System.out.println("Focussed!!");
                    focussed = true;
                   repaint();
                   //notify();
               }
               @Override
               public void focusLost(FocusEvent arg0) {
                    // TODO Auto-generated method stub
                    
               }
                  
                  private void doSetup() {
                          // creates OSC and graphics context for OSC
                     width = getSize().width;
                     height = getSize().height;
                     OSC = null;  // free up any memory currently used by OSC 
          
          before allocating new memory
                     try {
                        OSC = createImage(width-6,height-6);
                        OSG = OSC.getGraphics();
                        OSG.setColor(Color.black);
                        OSG.setFont(new Font("Serif",Font.PLAIN,12));
                     }
                     catch (OutOfMemoryError e) {
                        OSC = null;
                        OSG = null;
                     }
                  }
               
          }
          Please rename the following image as: "outer.bmp"
          http://www.freephotoserver.com/photo/f02/u6140065.bmp

          Please rename the following image as: "inner.bmp"
          http://www.freephotoserver.com/photo/f09/u2570704.bmp
          • 2. Re: Java animation isn't smooth :(
            843853
            Yes, I do not doubt that at all, you have, in my opinion, a truck load of code in the paint method. Try rendering to a BufferedImage and then simplify your paint to:
            public void paint(Graphics g){
              g.drawImage(bi, 0, 0, this);
            }
            I don't see a timer loop in this, just some sleeps in your paint: you should have a main animation loop with a set frame rate called by a Timer object's events.
            • 3. Re: Java animation isn't smooth :(
              843853
              Besides morgalr's suggestions (somewhat implied, but I thought I'd be explicit on this point), you shouldn't be loading images (via ImageIO.read() or any other means) in your paint() method. This will load the images from disk each frame - if you're going for 60 frames per second, your images will be loaded 60 times per second. Images should be loaded once, before the game starts, and simply painted via Graphics.drawImage() in your painting loop. File I/O in a game loop is a bad idea. This is probably the main cause of your game's stuttering.
              • 4. Re: Java animation isn't smooth :(
                843853
                for your first problem you can use double buffering...consider the following code:
                Graphics off;
                int width,height;
                Image img;
                public void init(){

                width=this.getWidth();
                          height=this.getHeight();
                          img=createImage(width,height);
                          off=img.getGraphics();
                }
                public void paint(Graphics g){
                off.drawImage(....);
                g.drawImage(img,0,0,this);
                }
                you also need to change the update method:

                public void update(Graphics g){
                          paint(g);
                     }

                this basically draws an image on offscreen rather than drawing directly on the screen..which removes the flickering problem..

                for your second problem i would recommend you not to use java for animation purpose because it is very slow...
                • 5. Re: Java animation isn't smooth :(
                  gimbal2
                  pg77 wrote:
                  for your second problem i would recommend you not to use java for animation purpose because it is very slow...
                  sigh. Another one-day fly living in the past...
                  • 6. Re: Java animation isn't smooth :(
                    843853
                    Sorry I don't read the whole code you posted. But I have a general suggestion for coding animation:

                    Make paint operation as fast as possible.

                    I once wrote an application which has a rococo wheel which is rotating in the center of screen. It works very smoothly in my working computer however it's not good in my friend's laptop on which she will show the application to customer. :( I investigated this and find the operation to draw that rococo wheel is very CPU consuming. The reason is I used a lot of GeneralPath and Area boolean-calculations to make such a rococo wheel; not even mention many GradientPaint are used. To keep the wheel cool, it just looked there's no way to improve anymore. But later I find a good way: paint the wheel in a BufferedImage, then paint this image on screen and let AffinedTransformation to do the rotation. In this way, the wheel rotating really fast and smoothly in my friend's laptop. The reason is Java paint a image with transformation is much faster. And the most important key is if I want to make the wheel more complicated, the final painting speed is constant. I don't know if this helps you but I hope it does.

                    By the way, I don't agree people just simply blame Java's performance. I think all those gorgeous games not only ask hardware do the render calculation but also implement many good practice/algorithm to improve...FPS :)