90 likes | 184 Views
Animation. To animate our programs, that is, to have real time interactions where objects move on the screen, we want to call repaint( ) every few milliseconds how does our program know when a few milliseconds elapse? there is a Timer class available
E N D
Animation • To animate our programs, that is, to have real time interactions where objects move on the screen, we want to call repaint( ) every few milliseconds • how does our program know when a few milliseconds elapse? • there is a Timer class available • set it for 20 milliseconds and every 20 milliseconds, the Timer generates an ActionEvent • In Java, we can have our program listen for an event and when the event arises, have it call a method • in this case, the Timer generates ActionEvents which will then cause a method called actionPerformed to execute • so we have to implement the actionPerformed method
actionPerformed • This method will look like this: • public void actionPerformed(ActionEvent e) • {…} • What should our actionPerformed method do? • we want to draw something on the Graphics panel and move it every time the Timer sends out an Event • so actionPerformed will “move” the object (change its location) and then call repaint( ) • repaint calls paintComponent • paintComponent first erases whatever had been previously drawn and then draws the object(s) anew, having possibly been moved
Timer class • A Timer object is instantiated by: • Timer t = new Timer(duration, handler); • duration is the time (in milliseconds) that elapses between Timer-generated events, such as 20 or 50 • handler is the object that handles the Timer-generated events – we will use this just like we have for our addActionListener statements • The steps are to add • import java.awt.event.*; • “implements ActionListener” to our class header • instantiate the Timer as t = new Timer(10, this); • but use whatever value you want for the duration, 10 or 20 would be adequate for most applications • start the timer by using t.start( ); • if we need to stop the timer, we use t.stop( ); • that’s about all there is to it!
import javax.swing.*; import java.awt.event.*; public class TimerSkeleton implements ActionListener { private Timer t; // other instance data go here as needed public TimerSkeleton( ) { t = new Timer(10, this); t.start( ); // other initialization operations go here as needed } // other methods go here as needed public void actionPerformed(ActionEvent e) { // whatever you want to happen when the Timer pulses go here } } TimerSkeleton
What Should actionPerformed Do? • This depends on why you are using a Timer • to move an object in a Graphics panel (e.g., a ball) • alter the x and y coordinates and call repaint( ) • for a Game: • calculate where game objects (say a spacecraft or a missile) have moved and redraw them • this may require the user of an array of x and an array of y values to store the various objects, or multiple variables such as myX, myY, yourX, yourY, or both (the arrays might store the X and Y coordinates of missiles launched from one to the other) • for Animation: • if our item being drawn is represented by an array of different figures • then just increment the array index and repaint( ) • we will see an example of a StickFigure, but this could also be done by having a series of jpg or gif files all pre-loaded into an array of Images
Moving an Image to Create Motion • Imagine that your class draws on a JPanel an ImageIcon (say of a spaceship) • currently, the spaceship is located at coordinates x, y • the following actionPerformed method will randomly move the spaceship on the screen • x and y should be class variables so that you could do g.drawImage(image, x, y, this); in your paintComponent method public void actionPerformed(ActionEvent e) { int dx = generator.nextInt(2); // generate a # from -1 to +1 int dy = generator.nextInt(2); // generate a # from -1 to +1 x += dx; // move the piece in a random x direction y += dy; // move the piece in a random y direction repaint( ); // assume repaint does drawImage at x, y }
Full Example Code public TimerExample( ) { t = new Timer(10, this); t.start( ); x = 150; y = 150; repaint( ); } public void actionPerformed(ActionEvent ev) { int distanceX = generator.nextInt(2)); int distanceY = generator.nextInt(2)); x += distanceX; y += distanceY; repaint( ); } public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.red); g.fillOval(x, y, 5, 5); } At each Timer Event, randomly move the object (a red circle) up/down/left/right by 0 or 1 unit Note: we could make it more realistic by generating a random int from 1-9 and move it in one of 8 directions or leave it stationary (1 = upper left, or subtract 1 from x and y, 2 = straight up, etc)
Better Motion • The random motion from the previous example would make the object on the screen look like a bee, buzzing around • What if we wanted a more purposeful movement? For instance in a straight line? • Lets add 2 more variables, dx and dy • (delta x means “change in x”, delta y means “change in y”, we use d because we don’t have the Greek letter delta) • For actionPerformed, just do x=x+dx; y=y+dy; • If dx=1 and dy=2, then our object will move in a straight line to the right 1 pixel and down 2 pixels at each movement, or a diagonal downward line • If dx=0 and dy=-1, then the object moves straight up • We should also make sure that x & y do not “go off” the screen (if x < 10 make x = 10 and dx = 0 to stop the motion there, or let x = X_SIZE to “wrap around”)
Moving Multiple Items • How would a game like Asteroids work? • we need to keep track of the <x, y> coordinates of multiple values, just like we did with our paint program • so we create an array of x, y, dx and dy int values • private int[ ] x, y, dx, dy; // dx, dy – velocity of x, y • private int num; // number of items in the arrays • actionPerformed now manipulates all items in the array and paintComponent draws them all public void actionPerformed(ActionEvent e) { for(int i=0;i<num;i++) { x[i]+=dx[i]; y[i]+=dy[i]; } } If x[i] or y[i] reaches a boundary (0 or max X/Y) then change dx or dy to be the opposite (multiply by -1)