CS 4773 Object Oriented Systems
A Simple Animation

Code for the programs can be found in
/usr/local/courses/cs4773/spring98/examples/set5


Previous Topic: Threads

Introduction
A Simple Animation
Adding a Scrollbar (end of class 2/10/98)
Adding Buffering
An External Animation Thread
Applet Summary

Next Topic: Object Oriented Programming Concepts



Introduction

The idea of (sprite) animation is simple.
  1. Draw the object in a position.
  2. Wait a while.
  3. Draw the object in a new position.
  4. Go back to 2.


A Simple Animation

/* < Applet code = MoveIt
     width = 300 height = 300 >
   < /Applet >
*/

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class MoveIt extends Applet implements ActionListener, Runnable {

   Button StartButton;
   int init_x = 50;
   int init_y = 50;
   int rect_width = 50;
   int rect_height = 20;
   int x;
   int y;
   int num = 100;
   Thread move_thread;
   

   public void init() {
      setBackground(Color.lightGray);
      setLayout(new BorderLayout());
      StartButton = new Button("Start");
      add("South",StartButton);
      StartButton.addActionListener(this);
      x = init_x;
      y = init_y;
   }

   public void paint(Graphics g) {
      g.setColor(Color.red);
      g.fillRect(x,y,rect_width,rect_height);
   }

   public void stop() {
      if (move_thread != null)
         move_thread.suspend();
   }

   public void start() {
       if (move_thread != null)
          move_thread.resume();
   }

   public void run() {
      try {
         for(int i=0;i < num;i++) {
            x++;
            y++;
            repaint(1);
            Thread.sleep(100);
         }
      }  catch (InterruptedException e) {
         return;                 // end this thread
      }
   }

   public void actionPerformed(ActionEvent e) {
      if (e.getSource() == StartButton) {
         x = init_x;
         y = init_y;
         move_thread = new Thread(this);
         move_thread.start();
      }
   }
}
Click Here to run MoveIt.


Adding a Scrollbar

Click Here for Scrollbar documentation.

/* < Applet code = MoveItSB
     width = 300 height = 300 >
   < /Applet >
*/

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class MoveItSB extends Applet implements ActionListener, 
                                     AdjustmentListener, Runnable {

   Button StartButton;
   int init_x = 50;
   int init_y = 50;
   int rect_width = 50;
   int rect_height = 20;
   int x;
   int y;
   int num = 100;
   int delay = 100;
   Thread move_thread;
   Label DelayLabel;
   Scrollbar DelayValue;

   public void init() {
      Panel p = new Panel();
      Panel q = new Panel();
      p.setLayout(new GridLayout(2,1));
      q.setLayout(new GridLayout(1,2));
      setBackground(Color.lightGray);
      setLayout(new BorderLayout());
      StartButton = new Button("Start");
      DelayLabel = new Label("Delay "+delay);
      q.add(DelayLabel);
      DelayValue = new Scrollbar(Scrollbar.HORIZONTAL,delay,10,0,1010);
      DelayValue.addAdjustmentListener(this);
      q.add(DelayValue);
      p.add(q);
      p.add(StartButton);
      add("South",p);
      StartButton.addActionListener(this);
      x = init_x;
      y = init_y;
   }

   public void paint(Graphics g) {
      g.setColor(Color.red);
      g.fillRect(x,y,rect_width,rect_height);
   }

   public void stop() {
      if (move_thread != null)
         move_thread.suspend();
   }

   public void start() {
       if (move_thread != null)
          move_thread.resume();
   }

   public void run() {
      try {
         for(int i=0;i < num;i++) {
            x++;
            y++;
            repaint(1);
            Thread.sleep(delay);
         }
      }  catch (InterruptedException e) {
         return;                 // end this thread
      }
   }

   public void actionPerformed(ActionEvent e) {
      if (e.getSource() == StartButton) {
         x = init_x;
         y = init_y;
         move_thread = new Thread(this);
         move_thread.start();
      }
   }

   public void adjustmentValueChanged(AdjustmentEvent e) {
      delay = DelayValue.getValue();
      DelayLabel.setText("Delay "+delay);
   }
}
Click Here to run MoveItSB.


Adding Buffering

/* & lt Applet code = MoveItDB
     width = 300 height = 300 >
   < /Applet >
*/

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class MoveItDB extends Applet implements ActionListener, 
                                     AdjustmentListener, Runnable {

   Button StartButton;
   int init_x = 50;
   int init_y = 50;
   int rect_width = 50;
   int rect_height = 20;
   int x;
   int y;
   int num = 100;
   int delay = 100;
   Thread move_thread;
   Label DelayLabel;
   Scrollbar DelayValue;
   Image buffer;
   Graphics GC;
   Graphics GCback;
   int width;
   int height;

   public void init() {
      Panel p = new Panel();
      Panel q = new Panel();
      p.setLayout(new GridLayout(2,1));
      q.setLayout(new GridLayout(1,2));
      setBackground(Color.lightGray);
      setLayout(new BorderLayout());
      StartButton = new Button("Start");
      DelayLabel = new Label("Delay "+delay);
      q.add(DelayLabel);
      DelayValue = new Scrollbar(Scrollbar.HORIZONTAL,delay,10,0,1010);
      DelayValue.addAdjustmentListener(this);
      q.add(DelayValue);
      p.add(q);
      p.add(StartButton);
      add("South",p);
      StartButton.addActionListener(this);
      x = init_x;
      y = init_y;
      width = getBounds().width;
      height = getBounds().height;
      buffer = createImage(width,height);
      GC = buffer.getGraphics();
      GCback = buffer.getGraphics();
      GC.setColor(Color.red);
      GCback.setColor(Color.yellow);
   }

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

   public void paint(Graphics g) {
      GCback.fillRect(0,0,width,height);
      GC.fillRect(x,y,rect_width,rect_height);
      g.drawImage(buffer,0,0,this);
   }

   public void stop() {
      if (move_thread != null)
         move_thread.suspend();
   }

   public void start() {
       if (move_thread != null)
          move_thread.resume();
   }

   public void run() {
      try {
         for(int i=0;i < num;i++) {
            x++;
            y++;
            repaint(1);
            Thread.sleep(delay);
         }
      }  catch (InterruptedException e) {
         return;                 // end this thread
      }
   }

   public void actionPerformed(ActionEvent e) {
      if (e.getSource() == StartButton) {
         x = init_x;
         y = init_y;
         move_thread = new Thread(this);
         move_thread.start();
      }
   }

   public void adjustmentValueChanged(AdjustmentEvent e) {
      delay = DelayValue.getValue();
      DelayLabel.setText("Delay "+delay);
   }
}
Click Here to run MoveItDB.


An External Animation Thread

The following can be used as an external thread for animation.
import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class SimpleAnimationThread extends Thread {

   private int num;
   private int delay;
   private Applet ap;
   private Point pos;

   public SimpleAnimationThread(Point init_pos, int num, int delay, 
                                Applet ap) {
      pos = new Point(init_pos);
      this.num = num;
      this.delay = delay;
      this.ap = ap;
   }

   public Point GetPosition() {
      return pos;
   }

   public void run() {
      try {
         for(int i=0;i < num;i++) {
            pos.x++;
            pos.y++;
            ap.repaint(1);
            Thread.sleep(delay);
         }
      }  catch (InterruptedException e) { }   
   }

}

Here is an applet that uses this external thread.
/* < Applet code = MoveItExt
     width = 300 height = 300 >
   < /Applet >
*/

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class MoveItExt extends Applet implements ActionListener, 
                                     AdjustmentListener {

   Button StartButton;
   int init_x = 50;
   int init_y = 50;
   int rect_width = 50;
   int rect_height = 20;
   int num = 100;
   int delay = 100;
   SimpleAnimationThread move_thread;
   Label DelayLabel;
   Scrollbar DelayValue;
   Image buffer;
   Graphics GC;
   Graphics GCback;
   int width;
   int height;
   Point init_pos;

   public void init() {
      Panel p = new Panel();
      Panel q = new Panel();
      p.setLayout(new GridLayout(2,1));
      q.setLayout(new GridLayout(1,2));
      setBackground(Color.lightGray);
      setLayout(new BorderLayout());
      StartButton = new Button("Start");
      DelayLabel = new Label("Delay "+delay);
      q.add(DelayLabel);
      DelayValue = new Scrollbar(Scrollbar.HORIZONTAL,delay,10,0,1010);
      DelayValue.addAdjustmentListener(this);
      q.add(DelayValue);
      p.add(q);
      p.add(StartButton);
      add("South",p);
      StartButton.addActionListener(this);
      init_pos = new Point(init_x,init_y);
      width = getBounds().width;
      height = getBounds().height;
      buffer = createImage(width,height);
      GC = buffer.getGraphics();
      GCback = buffer.getGraphics();
      GC.setColor(Color.red);
      GCback.setColor(Color.yellow);
   }

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

   public void paint(Graphics g) {
      Point pt;
      GCback.fillRect(0,0,width,height);
      if (move_thread == null)
         pt = init_pos;
      else
         pt = move_thread.GetPosition();
      GC.fillRect(pt.x,pt.y,rect_width,rect_height);
      g.drawImage(buffer,0,0,this);
   }

   public void stop() {
      if (move_thread != null)
         move_thread.suspend();
   }

   public void start() {
       if (move_thread != null)
          move_thread.resume();
   }

   public void actionPerformed(ActionEvent e) {
      if (e.getSource() == StartButton) {
         move_thread = new SimpleAnimationThread(init_pos, num, delay, this);
         move_thread.start();
      }
   }

   public void adjustmentValueChanged(AdjustmentEvent e) {
      delay = DelayValue.getValue();
      DelayLabel.setText("Delay "+delay);
   }
}
Click Here to run this applet.


Would the applet behave differently if the line in SimpleAnimationThread
pos = new Point(init_pos);
were replaced by
pos = init_pos?

Click Here to run the applet with this change.

Look at SimpleAnimationThread. In what ways can the coordinates represented by pos change?

Suggest a change to SimpleAnimationThread.

How would these classes have to be changed to allow two rectangles to move independently?


Applet Summary

MoveIt is a simple thread which moves a rectangle along a diagonal line with a 100 ms delay for each frame.

MoveItSB add a scrollbar for determining the delay between frames.

MoveItDB adds buffering to avoid flicker.

MoveItExt is a version that uses an external thread.

MoveItExt1 is a slight change which shows why it it necessary to be careful when passes objects to methods.


Next topic: Object Oriented Programming Concepts