Help with Animator

I am trying to move a sprite around the screen when the user presses the arrow keys. Im using the animator class to drive the display meathod. This is working but the image moves in a jerky manner. Is there something im missing about use of the animator class? Could this be a frame rate issue?

Thanks

This is a pretty broad description. Some ideas:

Try not to draw at maximum speed. Limit the framerate to give the OS some time to do other tasks.

Maybe you move the sprite on a “+x pixels per frame” basis? The better way is to move a sprite on a “+x pixels per second” basis.

The System.currentTimeMillis() timer is not precise enough for animations at high frame rates. Use System.currentTimeNanos() or determine the position of the sprite relative to the time of the key press.

Originally, I was drawing my sprite after drawing an array of tile images under it. It was an array of 32X34 tiles, each being 32*32 pixles. After commenting out the tile map my sprite it moves smoothly. Could this be because i was displaying too many tiles on the screen?

I also notice that even with one sprite on the screen, if i hold down the arrow key it skips every few seconds while moving. How can i make this program run more smoothly?

First, are you drawing all of the tiles in your map? If so, you should modify your code to draw only the visible portions of the map. Second, use Timebased animation. It gives consistent movement regardless of frame rate.


...

long start = System.currentTimeMillis();
ong current = start;
long prev = current;
            
long el = 0;
            
while(!done)
{
      current = System.currentTimeMillis();
                  
      if(!canvas.getSize().equals(getSize()));
            canvas.setSize(getSize());
                        
      el = current-prev;
                  
      prev = current;
      
      canvas.display();
      
      update(el); //update your sprites in this method
                  
      Thread.yield();
}
...

To ShadowCaster:
It is System.nanoTime() not System.currentTimeNanos()

Im kind of confused. Wouldnt something like that be used to move a standalone sprite based on elapsed time? The sprite im talking about is controlled by the user.

Im now using FPSAnimate to lock the frame rate. The image moves better but still lags when more images are drawn to the screen. The files are soo small. Why am I experiencing this lag?

here is the code



import net.java.games.jogl.*;
import java.awt.event.*;
import javax.imageio.*;
import java.io.*;
import java.awt.*;
import javax.swing.JFrame;
import javax.imageio.ImageIO;
import java.lang.*; 
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.net.URL;


/**
 * For our purposes only two of the GLEventListeners matter.
 * Those would be init() and display().
 */
public class SecondGLEventListener implements GLEventListener, KeyListener {
      
      int heroXPosition=100,heroYPosition=100;
      private int texture;
      final int TILE_SIZE=32;
      final int WORLD_SIZEX=12;
      final int WORLD_SIZEY=12; 
      GL gl; 
    GLU glu;
      GLCanvas glc;
      boolean left;
      boolean right;
      boolean up;
      boolean down; 
      
      public void setglcanvas(GLCanvas glc)
      {
      this.glc=glc;      
      
      }
      
      public void init(GLDrawable gld) {
    
            gl = gld.getGL();
            glu = gld.getGLU();
            gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            gl.glViewport(0, 0, 1024, 768); //sets visible area of screen
            gl.glMatrixMode(GL.GL_PROJECTION);
            gl.glLoadIdentity();
            glu.gluOrtho2D(0.0, 1024.0, 0.0, 768.0); //sets coordinate system
            
      }

      public void display(GLDrawable drawable) {
        
            
            BufferedImage image,image2,image3;
            gl.glClear (GL.GL_COLOR_BUFFER_BIT);
            try
            {
                  image = ImageIO.read(new BufferedInputStream(this.getClass().getClassLoader().getResourceAsStream ("tile1.gif")));
                  image2 = ImageIO.read(new BufferedInputStream(this.getClass().getClassLoader().getResourceAsStream ("tile2.gif")));
                  image3 = ImageIO.read(new BufferedInputStream(this.getClass().getClassLoader().getResourceAsStream ("moveobject.gif")));
                  ImageUtils utils;
        
                  ImageUtils.readPixels(gl, 0, 0, 1, 1, image);
                  ImageUtils.readPixels(gl, 0, 0, 1, 1, image2);
                  ImageUtils.readPixels(gl, 0, 0, 1, 1, image3);
      
                  char map[][] = {
                              {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
                              {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2},
                              {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2},
                              {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2},
                              {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2},
                              {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2},
                              {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2},
                              {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2},
                              {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2},
                              {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2},
                              {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2},
                              {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}};
        
                  int tile;
                  int x;
                  int y;
      
      for (y = 0; y < WORLD_SIZEY; y++)
        {
          for (x = 0; x < WORLD_SIZEX; x++)
          {
            tile = map[y][x];
            gl.glRasterPos2i (32*x,32*y);
            if(tile==2)
            ImageUtils.drawPixels(gl,image);
            if(tile==1)
            ImageUtils.drawPixels(gl,image2);
          }
        }
      
                  gl.glRasterPos2i (heroXPosition,heroYPosition);
                  ImageUtils.drawPixels(gl,image3);
      
      
                  GL gl = drawable.getGL();
                  gl.glEnd();
                  gl.glFlush();
    
                  }
                  catch(IOException e)
                  {
              //nothing
                  }
                  
                  if(left) heroXPosition-=10;
                if(right) heroXPosition+=10;
                if(up) heroYPosition+=10;
                if(down) heroYPosition-=10; 
  
      }

      public void reshape(
                        GLDrawable drawable, 
                        int x, 
                        int y, 
                        int width, 
                        int height
                      ) {}
  
      public void displayChanged(
                              GLDrawable drawable, 
                              boolean modeChanged, 
                              boolean deviceChanged
                            ) {}

public void keyPressed(KeyEvent e)
{
        
      if(e.getKeyCode() == KeyEvent.VK_LEFT) left = true;
        if(e.getKeyCode() == KeyEvent.VK_RIGHT) right= true;
        if(e.getKeyCode() == KeyEvent.VK_UP) up = true;
        if(e.getKeyCode() == KeyEvent.VK_DOWN) down = true; 
      
        
      
       
}


public void keyReleased(KeyEvent e)
{
      
      if(e.getKeyCode() == KeyEvent.VK_LEFT) left = false;
        if(e.getKeyCode() == KeyEvent.VK_RIGHT) right= false;
        if(e.getKeyCode() == KeyEvent.VK_UP) up = false;
        if(e.getKeyCode() == KeyEvent.VK_DOWN) down = false;      

}

public void keyTyped(KeyEvent e)
{
      

}



      
      
               
      
}










What we mean with time based animation is this:

Instead of:
if(left) heroXPosition -= 10;
if(right) heroXPosition += 10;
if(up) heroYPosition += 10;
if(down) heroYPosition -= 10;

You should write:
currentFrameTime = System.nanoTime();
double elapsed = (currentFrameTime - lastFrameTime) * 10E-9;
lastFrameTime = currentFrameTime;

double speed = 10; // adjust by experiment
if(left) heroXPosition -= speed * elapsed;
if(right) heroXPosition += speed * elapsed;
if(up) heroYPosition += speed * elapsed;
if(down) heroYPosition -= speed * elapsed;

The sprite is still controlled by the user, but the movement speed during the keypress is independent from the framerate. If you don’t do this your program will not work on very slow or very fast computers (basically any computer in existence in less than three years).

Don’t read the image files on every frame (ouch!). Move as much code as possible into init.

Use texture objects instead of drawPixels. To do this upload the tiles in the init method with texImage2D, then draw them on a quad in the display method. This causes the tiles to be stored in graphics memory instead of main memory. Your AGP bus will thank you.

Switch animation and drawing. Use this loop:

  1. Get time
  2. Animate scene
  3. Draw scene
  4. Yield or sleep
  5. Go to 1

Its working great!!!, Now I understand what you were saying and it makes alot of sense. Thank you! 8)

I will try that now

Do you mean to create 2d quad primitves and map the textures to them?